From dc7ff6306d7a15b53479e2fb8e5546404b82e6fc Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 12 May 2016 15:06:50 -0700 Subject: [PATCH 001/544] Fix a typo. --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 926209e5..c9ce7c4d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,7 +8,7 @@ brevity. Much more detail can be found in the git revision history: New features: - Add the arena..reset mallctl, which makes it possible to discard all of - an arena's allocations in a single operation. (@jasone@) + an arena's allocations in a single operation. (@jasone) - Add the stats.retained and stats.arenas..retained statistics. (@jasone) - Add the --with-version configure option. (@jasone) - Support --with-lg-page values larger than actual page size. (@jasone) -- GitLab From a397045323d743a787c7efff17c0619dcf25f0b4 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 12 May 2016 21:07:08 -0700 Subject: [PATCH 002/544] Use TSDN_NULL rather than NULL as appropriate. --- include/jemalloc/internal/mb.h | 4 ++-- src/jemalloc.c | 4 ++-- src/tsd.c | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/jemalloc/internal/mb.h b/include/jemalloc/internal/mb.h index 437c86f7..5384728f 100644 --- a/include/jemalloc/internal/mb.h +++ b/include/jemalloc/internal/mb.h @@ -105,8 +105,8 @@ mb_write(void) malloc_mutex_t mtx; malloc_mutex_init(&mtx, "mb", WITNESS_RANK_OMIT); - malloc_mutex_lock(NULL, &mtx); - malloc_mutex_unlock(NULL, &mtx); + malloc_mutex_lock(TSDN_NULL, &mtx); + malloc_mutex_unlock(TSDN_NULL, &mtx); } #endif #endif diff --git a/src/jemalloc.c b/src/jemalloc.c index 40eb2eaa..941c1c85 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1251,9 +1251,9 @@ malloc_init_hard_needed(void) if (malloc_initializer != NO_INITIALIZER && !IS_INITIALIZER) { /* Busy-wait until the initializing thread completes. */ do { - malloc_mutex_unlock(NULL, &init_lock); + malloc_mutex_unlock(TSDN_NULL, &init_lock); CPU_SPINWAIT; - malloc_mutex_lock(NULL, &init_lock); + malloc_mutex_lock(TSDN_NULL, &init_lock); } while (!malloc_initialized()); return (false); } diff --git a/src/tsd.c b/src/tsd.c index aeaa5e18..ec69a51c 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -171,10 +171,10 @@ tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block) tsd_init_block_t *iter; /* Check whether this thread has already inserted into the list. */ - malloc_mutex_lock(NULL, &head->lock); + malloc_mutex_lock(TSDN_NULL, &head->lock); ql_foreach(iter, &head->blocks, link) { if (iter->thread == self) { - malloc_mutex_unlock(NULL, &head->lock); + malloc_mutex_unlock(TSDN_NULL, &head->lock); return (iter->data); } } @@ -182,7 +182,7 @@ tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block) ql_elm_new(block, link); block->thread = self; ql_tail_insert(&head->blocks, block, link); - malloc_mutex_unlock(NULL, &head->lock); + malloc_mutex_unlock(TSDN_NULL, &head->lock); return (NULL); } @@ -190,8 +190,8 @@ void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block) { - malloc_mutex_lock(NULL, &head->lock); + malloc_mutex_lock(TSDN_NULL, &head->lock); ql_remove(&head->blocks, block, link); - malloc_mutex_unlock(NULL, &head->lock); + malloc_mutex_unlock(TSDN_NULL, &head->lock); } #endif -- GitLab From 9a8add1510456464bc496320990ec234798bd381 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 5 Apr 2016 16:25:44 -0700 Subject: [PATCH 003/544] Remove Valgrind support. --- INSTALL | 3 - Makefile.in | 4 - README | 12 +- configure.ac | 30 ----- doc/jemalloc.xml.in | 41 ++----- .../jemalloc/internal/jemalloc_internal.h.in | 13 -- .../internal/jemalloc_internal_defs.h.in | 3 - include/jemalloc/internal/private_symbols.txt | 5 - include/jemalloc/internal/quarantine.h | 3 - include/jemalloc/internal/valgrind.h | 114 ------------------ .../projects/vc2015/jemalloc/jemalloc.vcxproj | 3 +- .../vc2015/jemalloc/jemalloc.vcxproj.filters | 5 +- src/arena.c | 41 +------ src/base.c | 3 - src/chunk.c | 10 -- src/chunk_dss.c | 5 +- src/ctl.c | 6 +- src/jemalloc.c | 95 ++------------- src/quarantine.c | 7 +- src/stats.c | 1 - src/valgrind.c | 34 ------ test/unit/arena_reset.c | 3 +- test/unit/mallctl.c | 1 - 23 files changed, 33 insertions(+), 409 deletions(-) delete mode 100644 include/jemalloc/internal/valgrind.h delete mode 100644 src/valgrind.c diff --git a/INSTALL b/INSTALL index 68787165..36306fec 100644 --- a/INSTALL +++ b/INSTALL @@ -169,9 +169,6 @@ any of the following arguments (not a definitive list) to 'configure': See the "opt.junk", "opt.zero", "opt.quarantine", and "opt.redzone" option documentation for usage details. ---disable-valgrind - Disable support for Valgrind. - --disable-zone-allocator Disable zone allocator for Darwin. This means jemalloc won't be hooked as the default allocator on OSX/iOS. diff --git a/Makefile.in b/Makefile.in index 652f01f2..34facf43 100644 --- a/Makefile.in +++ b/Makefile.in @@ -49,7 +49,6 @@ cfgoutputs_out := @cfgoutputs_out@ enable_autogen := @enable_autogen@ enable_code_coverage := @enable_code_coverage@ enable_prof := @enable_prof@ -enable_valgrind := @enable_valgrind@ enable_zone_allocator := @enable_zone_allocator@ MALLOC_CONF := @JEMALLOC_CPREFIX@MALLOC_CONF DSO_LDFLAGS = @DSO_LDFLAGS@ @@ -104,9 +103,6 @@ C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/tsd.c \ $(srcroot)src/util.c \ $(srcroot)src/witness.c -ifeq ($(enable_valgrind), 1) -C_SRCS += $(srcroot)src/valgrind.c -endif ifeq ($(enable_zone_allocator), 1) C_SRCS += $(srcroot)src/zone.c endif diff --git a/README b/README index 9b268f42..67cbf6da 100644 --- a/README +++ b/README @@ -3,12 +3,12 @@ fragmentation avoidance and scalable concurrency support. jemalloc first came into use as the FreeBSD libc allocator in 2005, and since then it has found its way into numerous applications that rely on its predictable behavior. In 2010 jemalloc development efforts broadened to include developer support features -such as heap profiling, Valgrind integration, and extensive monitoring/tuning -hooks. Modern jemalloc releases continue to be integrated back into FreeBSD, -and therefore versatility remains critical. Ongoing development efforts trend -toward making jemalloc among the best allocators for a broad range of demanding -applications, and eliminating/mitigating weaknesses that have practical -repercussions for real world applications. +such as heap profiling and extensive monitoring/tuning hooks. Modern jemalloc +releases continue to be integrated back into FreeBSD, and therefore versatility +remains critical. Ongoing development efforts trend toward making jemalloc +among the best allocators for a broad range of demanding applications, and +eliminating/mitigating weaknesses that have practical repercussions for real +world applications. The COPYING file contains copyright and licensing information. diff --git a/configure.ac b/configure.ac index 7f19715d..df5cf25a 100644 --- a/configure.ac +++ b/configure.ac @@ -988,35 +988,6 @@ if test "x$enable_utrace" = "x1" ; then fi AC_SUBST([enable_utrace]) -dnl Support Valgrind by default. -AC_ARG_ENABLE([valgrind], - [AS_HELP_STRING([--disable-valgrind], [Disable support for Valgrind])], -[if test "x$enable_valgrind" = "xno" ; then - enable_valgrind="0" -else - enable_valgrind="1" -fi -], -[enable_valgrind="1"] -) -if test "x$enable_valgrind" = "x1" ; then - JE_COMPILABLE([valgrind], [ -#include -#include - -#if !defined(VALGRIND_RESIZEINPLACE_BLOCK) -# error "Incompatible Valgrind version" -#endif -], [], [je_cv_valgrind]) - if test "x${je_cv_valgrind}" = "xno" ; then - enable_valgrind="0" - fi - if test "x$enable_valgrind" = "x1" ; then - AC_DEFINE([JEMALLOC_VALGRIND], [ ]) - fi -fi -AC_SUBST([enable_valgrind]) - dnl Do not support the xmalloc option by default. AC_ARG_ENABLE([xmalloc], [AS_HELP_STRING([--enable-xmalloc], [Support xmalloc option])], @@ -1782,7 +1753,6 @@ AC_MSG_RESULT([prof-gcc : ${enable_prof_gcc}]) AC_MSG_RESULT([tcache : ${enable_tcache}]) AC_MSG_RESULT([fill : ${enable_fill}]) AC_MSG_RESULT([utrace : ${enable_utrace}]) -AC_MSG_RESULT([valgrind : ${enable_valgrind}]) AC_MSG_RESULT([xmalloc : ${enable_xmalloc}]) AC_MSG_RESULT([munmap : ${enable_munmap}]) AC_MSG_RESULT([lazy_lock : ${enable_lazy_lock}]) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index c4a44e3c..2f8f150a 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -869,16 +869,6 @@ for (i = 0; i < nbins; i++) { build configuration. - - - config.valgrind - (bool) - r- - - was specified during - build configuration. - - config.xmalloc @@ -1046,9 +1036,8 @@ for (i = 0; i < nbins; i++) { "false", junk filling be disabled entirely. This is intended for debugging and will impact performance negatively. This option is "false" by default unless is specified - during configuration, in which case it is "true" by default unless - running inside Valgrind. + during configuration, in which case it is "true" by + default. @@ -1063,13 +1052,9 @@ for (i = 0; i < nbins; i++) { specified number of bytes of memory. The quarantined memory is not freed until it is released from quarantine, though it is immediately junk-filled if the opt.junk option is - enabled. This feature is of particular use in combination with Valgrind, which can detect attempts - to access quarantined objects. This is intended for debugging and will - impact performance negatively. The default quarantine size is 0 unless - running inside Valgrind, in which case the default is 16 - MiB. + linkend="opt.junk">opt.junk option is enabled. + This is intended for debugging and will impact performance negatively. + The default quarantine size is 0. @@ -1083,12 +1068,8 @@ for (i = 0; i < nbins; i++) { allocations have redzones before and after them. Furthermore, if the opt.junk option is enabled, the redzones are checked for corruption during deallocation. - However, the primary intended purpose of this feature is to be used in - combination with Valgrind, - which needs redzones in order to do effective buffer overflow/underflow - detection. This option is intended for debugging and will impact - performance negatively. This option is disabled by - default unless running inside Valgrind. + This option is intended for debugging and will impact performance + negatively. This option is disabled by default. @@ -1155,9 +1136,7 @@ malloc_conf = "xmalloc:true";]]> increased memory use. See the opt.lg_tcache_max option for related tuning information. This option is enabled by - default unless running inside Valgrind, in which case it is - forcefully disabled. + default. @@ -2746,9 +2725,7 @@ MAPPED_LIBRARIES: This implementation does not provide much detail about the problems it detects, because the performance impact for storing such information - would be prohibitive. However, jemalloc does integrate with the most - excellent Valgrind tool if the - configuration option is enabled. + would be prohibitive. DIAGNOSTIC MESSAGES diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 51bf8974..4c845e30 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -113,13 +113,6 @@ static const bool config_utrace = false #endif ; -static const bool config_valgrind = -#ifdef JEMALLOC_VALGRIND - true -#else - false -#endif - ; static const bool config_xmalloc = #ifdef JEMALLOC_XMALLOC true @@ -361,7 +354,6 @@ typedef unsigned szind_t; #endif #include "jemalloc/internal/nstime.h" -#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/prng.h" @@ -393,7 +385,6 @@ typedef unsigned szind_t; #define JEMALLOC_H_STRUCTS #include "jemalloc/internal/nstime.h" -#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/prng.h" @@ -441,8 +432,6 @@ extern bool opt_xmalloc; extern bool opt_zero; extern unsigned opt_narenas; -extern bool in_valgrind; - /* Number of CPUs. */ extern unsigned ncpus; @@ -489,7 +478,6 @@ void jemalloc_postfork_parent(void); void jemalloc_postfork_child(void); #include "jemalloc/internal/nstime.h" -#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/prng.h" @@ -521,7 +509,6 @@ void jemalloc_postfork_child(void); #define JEMALLOC_H_INLINES #include "jemalloc/internal/nstime.h" -#include "jemalloc/internal/valgrind.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/prng.h" diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 7de0cf7c..c9aa5fd5 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -148,9 +148,6 @@ /* Support utrace(2)-based tracing. */ #undef JEMALLOC_UTRACE -/* Support Valgrind. */ -#undef JEMALLOC_VALGRIND - /* Support optional abort() on OOM. */ #undef JEMALLOC_XMALLOC diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index f2b6a55d..15b8ceec 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -296,7 +296,6 @@ iallocztm iarena_cleanup idalloc idalloctm -in_valgrind index2size index2size_compute index2size_lookup @@ -591,10 +590,6 @@ tsdn_fetch tsdn_null tsdn_tsd u2rz -valgrind_freelike_block -valgrind_make_mem_defined -valgrind_make_mem_noaccess -valgrind_make_mem_undefined witness_assert_lockless witness_assert_not_owner witness_assert_owner diff --git a/include/jemalloc/internal/quarantine.h b/include/jemalloc/internal/quarantine.h index ae607399..1ab4345e 100644 --- a/include/jemalloc/internal/quarantine.h +++ b/include/jemalloc/internal/quarantine.h @@ -4,9 +4,6 @@ typedef struct quarantine_obj_s quarantine_obj_t; typedef struct quarantine_s quarantine_t; -/* Default per thread quarantine size if valgrind is enabled. */ -#define JEMALLOC_VALGRIND_QUARANTINE_DEFAULT (ZU(1) << 24) - #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ #ifdef JEMALLOC_H_STRUCTS diff --git a/include/jemalloc/internal/valgrind.h b/include/jemalloc/internal/valgrind.h deleted file mode 100644 index 1a868082..00000000 --- a/include/jemalloc/internal/valgrind.h +++ /dev/null @@ -1,114 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -#ifdef JEMALLOC_VALGRIND -#include - -/* - * The size that is reported to Valgrind must be consistent through a chain of - * malloc..realloc..realloc calls. Request size isn't recorded anywhere in - * jemalloc, so it is critical that all callers of these macros provide usize - * rather than request size. As a result, buffer overflow detection is - * technically weakened for the standard API, though it is generally accepted - * practice to consider any extra bytes reported by malloc_usable_size() as - * usable space. - */ -#define JEMALLOC_VALGRIND_MAKE_MEM_NOACCESS(ptr, usize) do { \ - if (unlikely(in_valgrind)) \ - valgrind_make_mem_noaccess(ptr, usize); \ -} while (0) -#define JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ptr, usize) do { \ - if (unlikely(in_valgrind)) \ - valgrind_make_mem_undefined(ptr, usize); \ -} while (0) -#define JEMALLOC_VALGRIND_MAKE_MEM_DEFINED(ptr, usize) do { \ - if (unlikely(in_valgrind)) \ - valgrind_make_mem_defined(ptr, usize); \ -} while (0) -/* - * The VALGRIND_MALLOCLIKE_BLOCK() and VALGRIND_RESIZEINPLACE_BLOCK() macro - * calls must be embedded in macros rather than in functions so that when - * Valgrind reports errors, there are no extra stack frames in the backtraces. - */ -#define JEMALLOC_VALGRIND_MALLOC(cond, tsdn, ptr, usize, zero) do { \ - if (unlikely(in_valgrind && cond)) { \ - VALGRIND_MALLOCLIKE_BLOCK(ptr, usize, p2rz(tsdn, ptr), \ - zero); \ - } \ -} while (0) -#define JEMALLOC_VALGRIND_REALLOC(maybe_moved, tsdn, ptr, usize, \ - ptr_maybe_null, old_ptr, old_usize, old_rzsize, old_ptr_maybe_null, \ - zero) do { \ - if (unlikely(in_valgrind)) { \ - size_t rzsize = p2rz(tsdn, ptr); \ - \ - if (!maybe_moved || ptr == old_ptr) { \ - VALGRIND_RESIZEINPLACE_BLOCK(ptr, old_usize, \ - usize, rzsize); \ - if (zero && old_usize < usize) { \ - valgrind_make_mem_defined( \ - (void *)((uintptr_t)ptr + \ - old_usize), usize - old_usize); \ - } \ - } else { \ - if (!old_ptr_maybe_null || old_ptr != NULL) { \ - valgrind_freelike_block(old_ptr, \ - old_rzsize); \ - } \ - if (!ptr_maybe_null || ptr != NULL) { \ - size_t copy_size = (old_usize < usize) \ - ? old_usize : usize; \ - size_t tail_size = usize - copy_size; \ - VALGRIND_MALLOCLIKE_BLOCK(ptr, usize, \ - rzsize, false); \ - if (copy_size > 0) { \ - valgrind_make_mem_defined(ptr, \ - copy_size); \ - } \ - if (zero && tail_size > 0) { \ - valgrind_make_mem_defined( \ - (void *)((uintptr_t)ptr + \ - copy_size), tail_size); \ - } \ - } \ - } \ - } \ -} while (0) -#define JEMALLOC_VALGRIND_FREE(ptr, rzsize) do { \ - if (unlikely(in_valgrind)) \ - valgrind_freelike_block(ptr, rzsize); \ -} while (0) -#else -#define RUNNING_ON_VALGRIND ((unsigned)0) -#define JEMALLOC_VALGRIND_MAKE_MEM_NOACCESS(ptr, usize) do {} while (0) -#define JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ptr, usize) do {} while (0) -#define JEMALLOC_VALGRIND_MAKE_MEM_DEFINED(ptr, usize) do {} while (0) -#define JEMALLOC_VALGRIND_MALLOC(cond, tsdn, ptr, usize, zero) do {} while (0) -#define JEMALLOC_VALGRIND_REALLOC(maybe_moved, tsdn, ptr, usize, \ - ptr_maybe_null, old_ptr, old_usize, old_rzsize, old_ptr_maybe_null, \ - zero) do {} while (0) -#define JEMALLOC_VALGRIND_FREE(ptr, rzsize) do {} while (0) -#endif - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -#ifdef JEMALLOC_VALGRIND -void valgrind_make_mem_noaccess(void *ptr, size_t usize); -void valgrind_make_mem_undefined(void *ptr, size_t usize); -void valgrind_make_mem_defined(void *ptr, size_t usize); -void valgrind_freelike_block(void *ptr, size_t usize); -#endif - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ - diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj index 9315022d..432d1f24 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj @@ -74,7 +74,6 @@ - @@ -395,4 +394,4 @@ - \ No newline at end of file + diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters index 88c15efa..c0e568ec 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters @@ -161,9 +161,6 @@ Header Files\internal - - Header Files\internal - Header Files\msvc_compat @@ -257,4 +254,4 @@ Source Files - \ No newline at end of file + diff --git a/src/arena.c b/src/arena.c index c605bcd3..4e6d3d60 100644 --- a/src/arena.c +++ b/src/arena.c @@ -350,27 +350,16 @@ JEMALLOC_INLINE_C void arena_run_zero(arena_chunk_t *chunk, size_t run_ind, size_t npages) { - JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + - (run_ind << LG_PAGE)), (npages << LG_PAGE)); memset((void *)((uintptr_t)chunk + (run_ind << LG_PAGE)), 0, (npages << LG_PAGE)); } -JEMALLOC_INLINE_C void -arena_run_page_mark_zeroed(arena_chunk_t *chunk, size_t run_ind) -{ - - JEMALLOC_VALGRIND_MAKE_MEM_DEFINED((void *)((uintptr_t)chunk + (run_ind - << LG_PAGE)), PAGE); -} - JEMALLOC_INLINE_C void arena_run_page_validate_zeroed(arena_chunk_t *chunk, size_t run_ind) { size_t i; UNUSED size_t *p = (size_t *)((uintptr_t)chunk + (run_ind << LG_PAGE)); - arena_run_page_mark_zeroed(chunk, run_ind); for (i = 0; i < PAGE / sizeof(size_t); i++) assert(p[i] == 0); } @@ -471,12 +460,9 @@ arena_run_split_large_helper(arena_t *arena, arena_run_t *run, size_t size, } if (zero) { - if (flag_decommitted != 0) { - /* The run is untouched, and therefore zeroed. */ - JEMALLOC_VALGRIND_MAKE_MEM_DEFINED((void - *)((uintptr_t)chunk + (run_ind << LG_PAGE)), - (need_pages << LG_PAGE)); - } else if (flag_dirty != 0) { + if (flag_decommitted != 0) + ; /* The run is untouched, and therefore zeroed. */ + else if (flag_dirty != 0) { /* The run is dirty, so all pages must be zeroed. */ arena_run_zero(chunk, run_ind, need_pages); } else { @@ -492,15 +478,9 @@ arena_run_split_large_helper(arena_t *arena, arena_run_t *run, size_t size, else if (config_debug) { arena_run_page_validate_zeroed(chunk, run_ind+i); - } else { - arena_run_page_mark_zeroed(chunk, - run_ind+i); } } } - } else { - JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + - (run_ind << LG_PAGE)), (need_pages << LG_PAGE)); } /* @@ -564,8 +544,6 @@ arena_run_split_small(arena_t *arena, arena_run_t *run, size_t size, if (config_debug && flag_dirty == 0 && flag_unzeroed == 0) arena_run_page_validate_zeroed(chunk, run_ind+i); } - JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED((void *)((uintptr_t)chunk + - (run_ind << LG_PAGE)), (need_pages << LG_PAGE)); return (false); } @@ -700,19 +678,9 @@ arena_chunk_init_hard(tsdn_t *tsdn, arena_t *arena) * the chunk is not zeroed. */ if (!zero) { - JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED( - (void *)arena_bitselm_get_const(chunk, map_bias+1), - (size_t)((uintptr_t)arena_bitselm_get_const(chunk, - chunk_npages-1) - - (uintptr_t)arena_bitselm_get_const(chunk, map_bias+1))); for (i = map_bias+1; i < chunk_npages-1; i++) arena_mapbits_internal_set(chunk, i, flag_unzeroed); } else { - JEMALLOC_VALGRIND_MAKE_MEM_DEFINED((void - *)arena_bitselm_get_const(chunk, map_bias+1), - (size_t)((uintptr_t)arena_bitselm_get_const(chunk, - chunk_npages-1) - - (uintptr_t)arena_bitselm_get_const(chunk, map_bias+1))); if (config_debug) { for (i = map_bias+1; i < chunk_npages-1; i++) { assert(arena_mapbits_unzeroed_get(chunk, i) == @@ -2571,13 +2539,11 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) } else if (unlikely(opt_zero)) memset(ret, 0, usize); } - JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, usize); } else { if (config_fill && unlikely(opt_junk_alloc)) { arena_alloc_junk_small(ret, &arena_bin_info[binind], true); } - JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, usize); memset(ret, 0, usize); } @@ -3311,7 +3277,6 @@ arena_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, size_t size, */ copysize = (usize < oldsize) ? usize : oldsize; - JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, copysize); memcpy(ret, ptr, copysize); isqalloc(tsd, ptr, oldsize, tcache, true); } else { diff --git a/src/base.c b/src/base.c index 81b0801f..1b0bf697 100644 --- a/src/base.c +++ b/src/base.c @@ -24,7 +24,6 @@ base_node_try_alloc(tsdn_t *tsdn) return (NULL); node = base_nodes; base_nodes = *(extent_node_t **)node; - JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(node, sizeof(extent_node_t)); return (node); } @@ -34,7 +33,6 @@ base_node_dalloc(tsdn_t *tsdn, extent_node_t *node) malloc_mutex_assert_owner(tsdn, &base_mtx); - JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(node, sizeof(extent_node_t)); *(extent_node_t **)node = base_nodes; base_nodes = node; } @@ -123,7 +121,6 @@ base_alloc(tsdn_t *tsdn, size_t size) base_resident += PAGE_CEILING((uintptr_t)ret + csize) - PAGE_CEILING((uintptr_t)ret); } - JEMALLOC_VALGRIND_MAKE_MEM_DEFINED(ret, csize); label_return: malloc_mutex_unlock(tsdn, &base_mtx); return (ret); diff --git a/src/chunk.c b/src/chunk.c index adc666ff..7af7bb91 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -316,7 +316,6 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, size_t i; size_t *p = (size_t *)(uintptr_t)ret; - JEMALLOC_VALGRIND_MAKE_MEM_DEFINED(ret, size); for (i = 0; i < size / sizeof(size_t); i++) assert(p[i] == 0); } @@ -376,8 +375,6 @@ chunk_alloc_base(size_t size) ret = chunk_alloc_mmap(NULL, size, chunksize, &zero, &commit); if (ret == NULL) return (NULL); - if (config_valgrind) - JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, size); return (ret); } @@ -401,8 +398,6 @@ chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, if (ret == NULL) return (NULL); assert(commit); - if (config_valgrind) - JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, size); return (ret); } @@ -434,8 +429,6 @@ chunk_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero, commit, arena->dss_prec); if (ret == NULL) return (NULL); - if (config_valgrind) - JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, size); return (ret); } @@ -478,8 +471,6 @@ chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, return (NULL); } - if (config_valgrind && chunk_hooks->alloc != chunk_alloc_default) - JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, chunksize); return (ret); } @@ -494,7 +485,6 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert(!cache || !zeroed); unzeroed = cache || !zeroed; - JEMALLOC_VALGRIND_MAKE_MEM_NOACCESS(chunk, size); malloc_mutex_lock(tsdn, &arena->chunks_mtx); chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); diff --git a/src/chunk_dss.c b/src/chunk_dss.c index 0b1f82bd..d42aeb0b 100644 --- a/src/chunk_dss.c +++ b/src/chunk_dss.c @@ -138,11 +138,8 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, &chunk_hooks, cpad, cpad_size, false, true); } - if (*zero) { - JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED( - ret, size); + if (*zero) memset(ret, 0, size); - } if (!*commit) *commit = pages_decommit(ret, size); return (ret); diff --git a/src/ctl.c b/src/ctl.c index dad80086..d2e94269 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -86,7 +86,6 @@ CTL_PROTO(config_stats) CTL_PROTO(config_tcache) CTL_PROTO(config_tls) CTL_PROTO(config_utrace) -CTL_PROTO(config_valgrind) CTL_PROTO(config_xmalloc) CTL_PROTO(opt_abort) CTL_PROTO(opt_dss) @@ -260,7 +259,6 @@ static const ctl_named_node_t config_node[] = { {NAME("tcache"), CTL(config_tcache)}, {NAME("tls"), CTL(config_tls)}, {NAME("utrace"), CTL(config_utrace)}, - {NAME("valgrind"), CTL(config_valgrind)}, {NAME("xmalloc"), CTL(config_xmalloc)} }; @@ -1270,7 +1268,6 @@ CTL_RO_CONFIG_GEN(config_stats, bool) CTL_RO_CONFIG_GEN(config_tcache, bool) CTL_RO_CONFIG_GEN(config_tls, bool) CTL_RO_CONFIG_GEN(config_utrace, bool) -CTL_RO_CONFIG_GEN(config_valgrind, bool) CTL_RO_CONFIG_GEN(config_xmalloc, bool) /******************************************************************************/ @@ -1622,8 +1619,7 @@ arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, READONLY(); WRITEONLY(); - if ((config_valgrind && unlikely(in_valgrind)) || (config_fill && - unlikely(opt_quarantine))) { + if (config_fill && unlikely(opt_quarantine)) { ret = EFAULT; goto label_return; } diff --git a/src/jemalloc.c b/src/jemalloc.c index 941c1c85..cfe6ed32 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -42,9 +42,6 @@ bool opt_xmalloc = false; bool opt_zero = false; unsigned opt_narenas = 0; -/* Initialized to true if the process is running inside Valgrind. */ -bool in_valgrind; - unsigned ncpus; /* Protects arenas initialization. */ @@ -80,8 +77,7 @@ enum { flag_opt_quarantine = (1U << 2), flag_opt_zero = (1U << 3), flag_opt_utrace = (1U << 4), - flag_in_valgrind = (1U << 5), - flag_opt_xmalloc = (1U << 6) + flag_opt_xmalloc = (1U << 5) }; static uint8_t malloc_slow_flags; @@ -894,9 +890,6 @@ malloc_slow_flag_init(void) | (opt_utrace ? flag_opt_utrace : 0) | (opt_xmalloc ? flag_opt_xmalloc : 0); - if (config_valgrind) - malloc_slow_flags |= (in_valgrind ? flag_in_valgrind : 0); - malloc_slow = (malloc_slow_flags != 0); } @@ -908,24 +901,6 @@ malloc_conf_init(void) const char *opts, *k, *v; size_t klen, vlen; - /* - * Automatically configure valgrind before processing options. The - * valgrind option remains in jemalloc 3.x for compatibility reasons. - */ - if (config_valgrind) { - in_valgrind = (RUNNING_ON_VALGRIND != 0) ? true : false; - if (config_fill && unlikely(in_valgrind)) { - opt_junk = "false"; - opt_junk_alloc = false; - opt_junk_free = false; - assert(!opt_zero); - opt_quarantine = JEMALLOC_VALGRIND_QUARANTINE_DEFAULT; - opt_redzone = true; - } - if (config_tcache && unlikely(in_valgrind)) - opt_tcache = false; - } - for (i = 0; i < 4; i++) { /* Get runtime configuration. */ switch (i) { @@ -1183,19 +1158,7 @@ malloc_conf_init(void) CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc", true) } if (config_tcache) { - CONF_HANDLE_BOOL(opt_tcache, "tcache", - !config_valgrind || !in_valgrind) - if (CONF_MATCH("tcache")) { - assert(config_valgrind && in_valgrind); - if (opt_tcache) { - opt_tcache = false; - malloc_conf_error( - "tcache cannot be enabled " - "while running inside Valgrind", - k, klen, v, vlen); - } - continue; - } + CONF_HANDLE_BOOL(opt_tcache, "tcache", true) CONF_HANDLE_SSIZE_T(opt_lg_tcache_max, "lg_tcache_max", -1, (sizeof(size_t) << 3) - 1) @@ -1508,8 +1471,7 @@ ialloc_body(size_t size, bool zero, tsdn_t **tsdn, size_t *usize, if (unlikely(ind >= NSIZES)) return (NULL); - if (config_stats || (config_prof && opt_prof) || (slow_path && - config_valgrind && unlikely(in_valgrind))) { + if (config_stats || (config_prof && opt_prof)) { *usize = index2size(ind); assert(*usize > 0 && *usize <= HUGE_MAXCLASS); } @@ -1562,7 +1524,6 @@ je_malloc(size_t size) ret = ialloc_body(size, false, &tsdn, &usize, true); ialloc_post_check(ret, tsdn, usize, "malloc", true, true); UTRACE(0, size, ret); - JEMALLOC_VALGRIND_MALLOC(ret != NULL, tsdn, ret, usize, false); } return (ret); @@ -1664,8 +1625,6 @@ label_return: *tsd_thread_allocatedp_get(tsd) += usize; } UTRACE(0, size, result); - JEMALLOC_VALGRIND_MALLOC(result != NULL, tsd_tsdn(tsd), result, usize, - false); witness_assert_lockless(tsd_tsdn(tsd)); return (ret); label_oom: @@ -1684,11 +1643,8 @@ JEMALLOC_EXPORT int JEMALLOC_NOTHROW JEMALLOC_ATTR(nonnull(1)) je_posix_memalign(void **memptr, size_t alignment, size_t size) { - int ret; - - ret = imemalign(memptr, alignment, size, sizeof(void *)); - return (ret); + return (imemalign(memptr, alignment, size, sizeof(void *))); } JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN @@ -1703,7 +1659,6 @@ je_aligned_alloc(size_t alignment, size_t size) ret = NULL; set_errno(err); } - return (ret); } @@ -1739,7 +1694,6 @@ je_calloc(size_t num, size_t size) ret = ialloc_body(num_size, true, &tsdn, &usize, true); ialloc_post_check(ret, tsdn, usize, "calloc", true, true); UTRACE(0, num_size, ret); - JEMALLOC_VALGRIND_MALLOC(ret != NULL, tsdn, ret, usize, false); } return (ret); @@ -1792,7 +1746,6 @@ JEMALLOC_INLINE_C void ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { size_t usize; - UNUSED size_t rzsize JEMALLOC_CC_SILENCE_INIT(0); witness_assert_lockless(tsd_tsdn(tsd)); @@ -1802,25 +1755,20 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) if (config_prof && opt_prof) { usize = isalloc(tsd_tsdn(tsd), ptr, config_prof); prof_free(tsd, ptr, usize); - } else if (config_stats || config_valgrind) + } else if (config_stats) usize = isalloc(tsd_tsdn(tsd), ptr, config_prof); if (config_stats) *tsd_thread_deallocatedp_get(tsd) += usize; if (likely(!slow_path)) iqalloc(tsd, ptr, tcache, false); - else { - if (config_valgrind && unlikely(in_valgrind)) - rzsize = p2rz(tsd_tsdn(tsd), ptr); + else iqalloc(tsd, ptr, tcache, true); - JEMALLOC_VALGRIND_FREE(ptr, rzsize); - } } JEMALLOC_INLINE_C void isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) { - UNUSED size_t rzsize JEMALLOC_CC_SILENCE_INIT(0); witness_assert_lockless(tsd_tsdn(tsd)); @@ -1831,10 +1779,7 @@ isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) prof_free(tsd, ptr, usize); if (config_stats) *tsd_thread_deallocatedp_get(tsd) += usize; - if (config_valgrind && unlikely(in_valgrind)) - rzsize = p2rz(tsd_tsdn(tsd), ptr); isqalloc(tsd, ptr, usize, tcache, slow_path); - JEMALLOC_VALGRIND_FREE(ptr, rzsize); } JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN @@ -1846,7 +1791,6 @@ je_realloc(void *ptr, size_t size) tsdn_t *tsdn JEMALLOC_CC_SILENCE_INIT(NULL); size_t usize JEMALLOC_CC_SILENCE_INIT(0); size_t old_usize = 0; - UNUSED size_t old_rzsize JEMALLOC_CC_SILENCE_INIT(0); if (unlikely(size == 0)) { if (ptr != NULL) { @@ -1871,18 +1815,13 @@ je_realloc(void *ptr, size_t size) witness_assert_lockless(tsd_tsdn(tsd)); old_usize = isalloc(tsd_tsdn(tsd), ptr, config_prof); - if (config_valgrind && unlikely(in_valgrind)) { - old_rzsize = config_prof ? p2rz(tsd_tsdn(tsd), ptr) : - u2rz(old_usize); - } if (config_prof && opt_prof) { usize = s2u(size); ret = unlikely(usize == 0 || usize > HUGE_MAXCLASS) ? NULL : irealloc_prof(tsd, ptr, old_usize, usize); } else { - if (config_stats || (config_valgrind && - unlikely(in_valgrind))) + if (config_stats) usize = s2u(size); ret = iralloc(tsd, ptr, old_usize, size, 0, false); } @@ -1913,8 +1852,6 @@ je_realloc(void *ptr, size_t size) *tsd_thread_deallocatedp_get(tsd) += old_usize; } UTRACE(ptr, size, ret); - JEMALLOC_VALGRIND_REALLOC(true, tsdn, ret, usize, true, ptr, old_usize, - old_rzsize, true, false); witness_assert_lockless(tsdn); return (ret); } @@ -2143,8 +2080,7 @@ imallocx_body(size_t size, int flags, tsdn_t **tsdn, size_t *usize, szind_t ind = size2index(size); if (unlikely(ind >= NSIZES)) return (NULL); - if (config_stats || (config_prof && opt_prof) || (slow_path && - config_valgrind && unlikely(in_valgrind))) { + if (config_stats || (config_prof && opt_prof)) { *usize = index2size(ind); assert(*usize > 0 && *usize <= HUGE_MAXCLASS); } @@ -2181,8 +2117,6 @@ je_mallocx(size_t size, int flags) p = imallocx_body(size, flags, &tsdn, &usize, true); ialloc_post_check(p, tsdn, usize, "mallocx", false, true); UTRACE(0, size, p); - JEMALLOC_VALGRIND_MALLOC(p != NULL, tsdn, p, usize, - MALLOCX_ZERO_GET(flags)); } return (p); @@ -2261,7 +2195,6 @@ je_rallocx(void *ptr, size_t size, int flags) tsd_t *tsd; size_t usize; size_t old_usize; - UNUSED size_t old_rzsize JEMALLOC_CC_SILENCE_INIT(0); size_t alignment = MALLOCX_ALIGN_GET(flags); bool zero = flags & MALLOCX_ZERO; arena_t *arena; @@ -2291,8 +2224,6 @@ je_rallocx(void *ptr, size_t size, int flags) tcache = tcache_get(tsd, true); old_usize = isalloc(tsd_tsdn(tsd), ptr, config_prof); - if (config_valgrind && unlikely(in_valgrind)) - old_rzsize = u2rz(old_usize); if (config_prof && opt_prof) { usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment); @@ -2307,7 +2238,7 @@ je_rallocx(void *ptr, size_t size, int flags) tcache, arena); if (unlikely(p == NULL)) goto label_oom; - if (config_stats || (config_valgrind && unlikely(in_valgrind))) + if (config_stats) usize = isalloc(tsd_tsdn(tsd), p, config_prof); } assert(alignment == 0 || ((uintptr_t)p & (alignment - 1)) == ZU(0)); @@ -2317,8 +2248,6 @@ je_rallocx(void *ptr, size_t size, int flags) *tsd_thread_deallocatedp_get(tsd) += old_usize; } UTRACE(ptr, size, p); - JEMALLOC_VALGRIND_REALLOC(true, tsd_tsdn(tsd), p, usize, false, ptr, - old_usize, old_rzsize, false, zero); witness_assert_lockless(tsd_tsdn(tsd)); return (p); label_oom: @@ -2413,7 +2342,6 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) { tsd_t *tsd; size_t usize, old_usize; - UNUSED size_t old_rzsize JEMALLOC_CC_SILENCE_INIT(0); size_t alignment = MALLOCX_ALIGN_GET(flags); bool zero = flags & MALLOCX_ZERO; @@ -2443,9 +2371,6 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) if (unlikely(HUGE_MAXCLASS - size < extra)) extra = HUGE_MAXCLASS - size; - if (config_valgrind && unlikely(in_valgrind)) - old_rzsize = u2rz(old_usize); - if (config_prof && opt_prof) { usize = ixallocx_prof(tsd, ptr, old_usize, size, extra, alignment, zero); @@ -2460,8 +2385,6 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) *tsd_thread_allocatedp_get(tsd) += usize; *tsd_thread_deallocatedp_get(tsd) += old_usize; } - JEMALLOC_VALGRIND_REALLOC(false, tsd_tsdn(tsd), ptr, usize, false, ptr, - old_usize, old_rzsize, false, zero); label_not_resized: UTRACE(ptr, size, ptr); witness_assert_lockless(tsd_tsdn(tsd)); diff --git a/src/quarantine.c b/src/quarantine.c index 18903fb5..9658ffad 100644 --- a/src/quarantine.c +++ b/src/quarantine.c @@ -150,12 +150,7 @@ quarantine(tsd_t *tsd, void *ptr) quarantine->curbytes += usize; quarantine->curobjs++; if (config_fill && unlikely(opt_junk_free)) { - /* - * Only do redzone validation if Valgrind isn't in - * operation. - */ - if ((!config_valgrind || likely(!in_valgrind)) - && usize <= SMALL_MAXCLASS) + if (usize <= SMALL_MAXCLASS) arena_quarantine_junk_small(ptr, usize); else memset(ptr, JEMALLOC_FREE_JUNK, usize); diff --git a/src/stats.c b/src/stats.c index 073be4fe..97f901f6 100644 --- a/src/stats.c +++ b/src/stats.c @@ -517,7 +517,6 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, OPT_WRITE_BOOL(redzone) OPT_WRITE_BOOL(zero) OPT_WRITE_BOOL(utrace) - OPT_WRITE_BOOL(valgrind) OPT_WRITE_BOOL(xmalloc) OPT_WRITE_BOOL(tcache) OPT_WRITE_SSIZE_T(lg_tcache_max) diff --git a/src/valgrind.c b/src/valgrind.c deleted file mode 100644 index 8e7ef3a2..00000000 --- a/src/valgrind.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "jemalloc/internal/jemalloc_internal.h" -#ifndef JEMALLOC_VALGRIND -# error "This source file is for Valgrind integration." -#endif - -#include - -void -valgrind_make_mem_noaccess(void *ptr, size_t usize) -{ - - VALGRIND_MAKE_MEM_NOACCESS(ptr, usize); -} - -void -valgrind_make_mem_undefined(void *ptr, size_t usize) -{ - - VALGRIND_MAKE_MEM_UNDEFINED(ptr, usize); -} - -void -valgrind_make_mem_defined(void *ptr, size_t usize) -{ - - VALGRIND_MAKE_MEM_DEFINED(ptr, usize); -} - -void -valgrind_freelike_block(void *ptr, size_t usize) -{ - - VALGRIND_FREELIKE_BLOCK(ptr, usize); -} diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 8ba36c21..c602f0ff 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -88,8 +88,7 @@ TEST_BEGIN(test_arena_reset) size_t mib[3]; tsdn_t *tsdn; - test_skip_if((config_valgrind && unlikely(in_valgrind)) || (config_fill - && unlikely(opt_quarantine))); + test_skip_if(config_fill && unlikely(opt_quarantine)); sz = sizeof(unsigned); assert_d_eq(mallctl("arenas.extend", &arena_ind, &sz, NULL, 0), 0, diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 69f8c20c..641138ac 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -139,7 +139,6 @@ TEST_BEGIN(test_mallctl_config) TEST_MALLCTL_CONFIG(tcache, bool); TEST_MALLCTL_CONFIG(tls, bool); TEST_MALLCTL_CONFIG(utrace, bool); - TEST_MALLCTL_CONFIG(valgrind, bool); TEST_MALLCTL_CONFIG(xmalloc, bool); #undef TEST_MALLCTL_CONFIG -- GitLab From ba5c7095175d490b1d3d008e40efa74a66de9eab Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 5 Apr 2016 16:52:36 -0700 Subject: [PATCH 004/544] Remove quarantine support. --- INSTALL | 6 +- Makefile.in | 2 - configure.ac | 2 +- doc/jemalloc.xml.in | 17 -- include/jemalloc/internal/arena.h | 3 +- include/jemalloc/internal/huge.h | 2 +- .../jemalloc/internal/jemalloc_internal.h.in | 49 +---- .../internal/jemalloc_internal_defs.h.in | 2 +- include/jemalloc/internal/private_symbols.txt | 11 -- include/jemalloc/internal/quarantine.h | 57 ------ include/jemalloc/internal/tsd.h | 2 - .../projects/vc2015/jemalloc/jemalloc.vcxproj | 2 - .../vc2015/jemalloc/jemalloc.vcxproj.filters | 6 - src/arena.c | 30 +-- src/ctl.c | 8 - src/huge.c | 10 +- src/jemalloc.c | 67 +++---- src/quarantine.c | 178 ------------------ src/stats.c | 1 - test/unit/arena_reset.c | 2 - test/unit/junk.c | 2 +- test/unit/mallctl.c | 1 - test/unit/quarantine.c | 108 ----------- test/unit/zero.c | 2 +- 24 files changed, 51 insertions(+), 519 deletions(-) delete mode 100644 include/jemalloc/internal/quarantine.h delete mode 100644 src/quarantine.c delete mode 100644 test/unit/quarantine.c diff --git a/INSTALL b/INSTALL index 36306fec..4f57b365 100644 --- a/INSTALL +++ b/INSTALL @@ -165,9 +165,9 @@ any of the following arguments (not a definitive list) to 'configure': normal jemalloc operation. --disable-fill - Disable support for junk/zero filling of memory, quarantine, and redzones. - See the "opt.junk", "opt.zero", "opt.quarantine", and "opt.redzone" option - documentation for usage details. + Disable support for junk/zero filling of memory and redzones. See the + "opt.junk", "opt.zero", and "opt.redzone" option documentation for usage + details. --disable-zone-allocator Disable zone allocator for Darwin. This means jemalloc won't be hooked as diff --git a/Makefile.in b/Makefile.in index 34facf43..8cd6af98 100644 --- a/Makefile.in +++ b/Makefile.in @@ -95,7 +95,6 @@ C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/pages.c \ $(srcroot)src/prng.c \ $(srcroot)src/prof.c \ - $(srcroot)src/quarantine.c \ $(srcroot)src/rtree.c \ $(srcroot)src/stats.c \ $(srcroot)src/tcache.c \ @@ -157,7 +156,6 @@ TESTS_UNIT := \ $(srcroot)test/unit/prof_thread_name.c \ $(srcroot)test/unit/ql.c \ $(srcroot)test/unit/qr.c \ - $(srcroot)test/unit/quarantine.c \ $(srcroot)test/unit/rb.c \ $(srcroot)test/unit/rtree.c \ $(srcroot)test/unit/run_quantize.c \ diff --git a/configure.ac b/configure.ac index df5cf25a..92192d4d 100644 --- a/configure.ac +++ b/configure.ac @@ -946,7 +946,7 @@ fi dnl Support the junk/zero filling option by default. AC_ARG_ENABLE([fill], [AS_HELP_STRING([--disable-fill], - [Disable support for junk/zero filling, quarantine, and redzones])], + [Disable support for junk/zero filling and redzones])], [if test "x$enable_fill" = "xno" ; then enable_fill="0" else diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 2f8f150a..7ed03330 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -1040,23 +1040,6 @@ for (i = 0; i < nbins; i++) { default. - - - opt.quarantine - (size_t) - r- - [] - - Per thread quarantine size in bytes. If non-zero, each - thread maintains a FIFO object quarantine that stores up to the - specified number of bytes of memory. The quarantined memory is not - freed until it is released from quarantine, though it is immediately - junk-filled if the opt.junk option is enabled. - This is intended for debugging and will impact performance negatively. - The default quarantine size is 0. - - opt.redzone diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index b1de2b61..1c63620d 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -551,7 +551,6 @@ extern arena_dalloc_junk_small_t *arena_dalloc_junk_small; #else void arena_dalloc_junk_small(void *ptr, arena_bin_info_t *bin_info); #endif -void arena_quarantine_junk_small(void *ptr, size_t usize); void *arena_malloc_large(tsdn_t *tsdn, arena_t *arena, szind_t ind, bool zero); void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, @@ -581,7 +580,7 @@ extern arena_ralloc_junk_large_t *arena_ralloc_junk_large; #endif bool arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, bool zero); -void *arena_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, +void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache); dss_prec_t arena_dss_prec_get(tsdn_t *tsdn, arena_t *arena); bool arena_dss_prec_set(tsdn_t *tsdn, arena_t *arena, dss_prec_t dss_prec); diff --git a/include/jemalloc/internal/huge.h b/include/jemalloc/internal/huge.h index b5fa9e63..8b501e5a 100644 --- a/include/jemalloc/internal/huge.h +++ b/include/jemalloc/internal/huge.h @@ -14,7 +14,7 @@ void *huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero); bool huge_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t usize_min, size_t usize_max, bool zero); -void *huge_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, +void *huge_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, size_t usize, size_t alignment, bool zero, tcache_t *tcache); #ifdef JEMALLOC_JET typedef void (huge_dalloc_junk_t)(tsdn_t *, void *, size_t); diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 4c845e30..c6aa5743 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -377,7 +377,6 @@ typedef unsigned szind_t; #include "jemalloc/internal/huge.h" #include "jemalloc/internal/tcache.h" #include "jemalloc/internal/hash.h" -#include "jemalloc/internal/quarantine.h" #include "jemalloc/internal/prof.h" #undef JEMALLOC_H_TYPES @@ -412,7 +411,6 @@ typedef unsigned szind_t; #include "jemalloc/internal/huge.h" #include "jemalloc/internal/tcache.h" #include "jemalloc/internal/hash.h" -#include "jemalloc/internal/quarantine.h" #include "jemalloc/internal/prof.h" #include "jemalloc/internal/tsd.h" @@ -425,7 +423,6 @@ extern bool opt_abort; extern const char *opt_junk; extern bool opt_junk_alloc; extern bool opt_junk_free; -extern size_t opt_quarantine; extern bool opt_redzone; extern bool opt_utrace; extern bool opt_xmalloc; @@ -500,7 +497,6 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/huge.h" #include "jemalloc/internal/tcache.h" #include "jemalloc/internal/hash.h" -#include "jemalloc/internal/quarantine.h" #include "jemalloc/internal/prof.h" #include "jemalloc/internal/tsd.h" @@ -878,7 +874,6 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) #include "jemalloc/internal/arena.h" #undef JEMALLOC_ARENA_INLINE_B #include "jemalloc/internal/hash.h" -#include "jemalloc/internal/quarantine.h" #ifndef JEMALLOC_ENABLE_INLINE arena_t *iaalloc(const void *ptr); @@ -898,15 +893,12 @@ size_t p2rz(tsdn_t *tsdn, const void *ptr); void idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool is_metadata, bool slow_path); void idalloc(tsd_t *tsd, void *ptr); -void iqalloc(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path); void isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, bool slow_path); -void isqalloc(tsd_t *tsd, void *ptr, size_t size, tcache_t *tcache, - bool slow_path); -void *iralloct_realign(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, +void *iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); -void *iralloct(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, +void *iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); void *iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero); @@ -1064,16 +1056,6 @@ idalloc(tsd_t *tsd, void *ptr) idalloctm(tsd_tsdn(tsd), ptr, tcache_get(tsd, false), false, true); } -JEMALLOC_ALWAYS_INLINE void -iqalloc(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) -{ - - if (slow_path && config_fill && unlikely(opt_quarantine)) - quarantine(tsd, ptr); - else - idalloctm(tsd_tsdn(tsd), ptr, tcache, false, slow_path); -} - JEMALLOC_ALWAYS_INLINE void isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, bool slow_path) @@ -1082,18 +1064,8 @@ isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, arena_sdalloc(tsdn, ptr, size, tcache, slow_path); } -JEMALLOC_ALWAYS_INLINE void -isqalloc(tsd_t *tsd, void *ptr, size_t size, tcache_t *tcache, bool slow_path) -{ - - if (slow_path && config_fill && unlikely(opt_quarantine)) - quarantine(tsd, ptr); - else - isdalloct(tsd_tsdn(tsd), ptr, size, tcache, slow_path); -} - JEMALLOC_ALWAYS_INLINE void * -iralloct_realign(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, +iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) { void *p; @@ -1102,7 +1074,7 @@ iralloct_realign(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, usize = sa2u(size + extra, alignment); if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) return (NULL); - p = ipalloct(tsd_tsdn(tsd), usize, alignment, zero, tcache, arena); + p = ipalloct(tsdn, usize, alignment, zero, tcache, arena); if (p == NULL) { if (extra == 0) return (NULL); @@ -1110,8 +1082,7 @@ iralloct_realign(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, usize = sa2u(size, alignment); if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) return (NULL); - p = ipalloct(tsd_tsdn(tsd), usize, alignment, zero, tcache, - arena); + p = ipalloct(tsdn, usize, alignment, zero, tcache, arena); if (p == NULL) return (NULL); } @@ -1121,12 +1092,12 @@ iralloct_realign(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, */ copysize = (size < oldsize) ? size : oldsize; memcpy(p, ptr, copysize); - isqalloc(tsd, ptr, oldsize, tcache, true); + isdalloct(tsdn, ptr, oldsize, tcache, true); return (p); } JEMALLOC_ALWAYS_INLINE void * -iralloct(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment, +iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) { @@ -1139,11 +1110,11 @@ iralloct(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment, * Existing object alignment is inadequate; allocate new space * and copy. */ - return (iralloct_realign(tsd, ptr, oldsize, size, 0, alignment, + return (iralloct_realign(tsdn, ptr, oldsize, size, 0, alignment, zero, tcache, arena)); } - return (arena_ralloc(tsd, arena, ptr, oldsize, size, alignment, zero, + return (arena_ralloc(tsdn, arena, ptr, oldsize, size, alignment, zero, tcache)); } @@ -1152,7 +1123,7 @@ iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero) { - return (iralloct(tsd, ptr, oldsize, size, alignment, zero, + return (iralloct(tsd_tsdn(tsd), ptr, oldsize, size, alignment, zero, tcache_get(tsd, true), NULL)); } diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index c9aa5fd5..5e5b0a78 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -142,7 +142,7 @@ */ #undef JEMALLOC_DSS -/* Support memory filling (junk/zero/quarantine/redzone). */ +/* Support memory filling (junk/zero/redzone). */ #undef JEMALLOC_FILL /* Support utrace(2)-based tracing. */ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 15b8ceec..02377809 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -99,7 +99,6 @@ arena_prof_tctx_reset arena_prof_tctx_set arena_ptr_small_binind_get arena_purge -arena_quarantine_junk_small arena_ralloc arena_ralloc_junk_large arena_ralloc_no_move @@ -303,13 +302,11 @@ index2size_tab ipalloc ipalloct ipallocztm -iqalloc iralloc iralloct iralloct_realign isalloc isdalloct -isqalloc isthreaded ivsalloc ixalloc @@ -385,7 +382,6 @@ opt_prof_leak opt_prof_prefix opt_prof_thread_active_init opt_purge -opt_quarantine opt_redzone opt_stats_print opt_tcache @@ -454,10 +450,6 @@ prof_thread_active_set prof_thread_name_get prof_thread_name_set purge_mode_names -quarantine -quarantine_alloc_hook -quarantine_alloc_hook_work -quarantine_cleanup register_zone rtree_child_read rtree_child_read_hard @@ -561,9 +553,6 @@ tsd_nominal tsd_prof_tdata_get tsd_prof_tdata_set tsd_prof_tdatap_get -tsd_quarantine_get -tsd_quarantine_set -tsd_quarantinep_get tsd_set tsd_tcache_enabled_get tsd_tcache_enabled_set diff --git a/include/jemalloc/internal/quarantine.h b/include/jemalloc/internal/quarantine.h deleted file mode 100644 index 1ab4345e..00000000 --- a/include/jemalloc/internal/quarantine.h +++ /dev/null @@ -1,57 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -typedef struct quarantine_obj_s quarantine_obj_t; -typedef struct quarantine_s quarantine_t; - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -struct quarantine_obj_s { - void *ptr; - size_t usize; -}; - -struct quarantine_s { - size_t curbytes; - size_t curobjs; - size_t first; -#define LG_MAXOBJS_INIT 10 - size_t lg_maxobjs; - quarantine_obj_t objs[1]; /* Dynamically sized ring buffer. */ -}; - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -void quarantine_alloc_hook_work(tsd_t *tsd); -void quarantine(tsd_t *tsd, void *ptr); -void quarantine_cleanup(tsd_t *tsd); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#ifndef JEMALLOC_ENABLE_INLINE -void quarantine_alloc_hook(void); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_QUARANTINE_C_)) -JEMALLOC_ALWAYS_INLINE void -quarantine_alloc_hook(void) -{ - tsd_t *tsd; - - assert(config_fill && opt_quarantine); - - tsd = tsd_fetch(); - if (tsd_quarantine_get(tsd) == NULL) - quarantine_alloc_hook_work(tsd); -} -#endif - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ - diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h index bf113411..f4ff8d76 100644 --- a/include/jemalloc/internal/tsd.h +++ b/include/jemalloc/internal/tsd.h @@ -572,7 +572,6 @@ struct tsd_init_head_s { O(narenas_tdata, unsigned) \ O(arenas_tdata_bypass, bool) \ O(tcache_enabled, tcache_enabled_t) \ - O(quarantine, quarantine_t *) \ O(witnesses, witness_list_t) \ O(witness_fork, bool) \ @@ -588,7 +587,6 @@ struct tsd_init_head_s { 0, \ false, \ tcache_enabled_default, \ - NULL, \ ql_head_initializer(witnesses), \ false \ } diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj index 432d1f24..537cb6ab 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj @@ -65,7 +65,6 @@ - @@ -107,7 +106,6 @@ - diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters index c0e568ec..d2b5595f 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters @@ -134,9 +134,6 @@ Header Files\internal - - Header Files\internal - Header Files\internal @@ -232,9 +229,6 @@ Source Files - - Source Files - Source Files diff --git a/src/arena.c b/src/arena.c index 4e6d3d60..607679d7 100644 --- a/src/arena.c +++ b/src/arena.c @@ -2484,21 +2484,6 @@ arena_dalloc_junk_small_t *arena_dalloc_junk_small = JEMALLOC_N(n_arena_dalloc_junk_small); #endif -void -arena_quarantine_junk_small(void *ptr, size_t usize) -{ - szind_t binind; - arena_bin_info_t *bin_info; - cassert(config_fill); - assert(opt_junk_free); - assert(opt_quarantine); - assert(usize <= SMALL_MAXCLASS); - - binind = size2index(usize); - bin_info = &arena_bin_info[binind]; - arena_redzones_validate(ptr, bin_info, true); -} - static void * arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) { @@ -3243,8 +3228,8 @@ arena_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, } void * -arena_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, size_t size, - size_t alignment, bool zero, tcache_t *tcache) +arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, + size_t size, size_t alignment, bool zero, tcache_t *tcache) { void *ret; size_t usize; @@ -3257,8 +3242,7 @@ arena_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, size_t size, size_t copysize; /* Try to avoid moving the allocation. */ - if (!arena_ralloc_no_move(tsd_tsdn(tsd), ptr, oldsize, usize, 0, - zero)) + if (!arena_ralloc_no_move(tsdn, ptr, oldsize, usize, 0, zero)) return (ptr); /* @@ -3266,8 +3250,8 @@ arena_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, size_t size, * the object. In that case, fall back to allocating new space * and copying. */ - ret = arena_ralloc_move_helper(tsd_tsdn(tsd), arena, usize, - alignment, zero, tcache); + ret = arena_ralloc_move_helper(tsdn, arena, usize, alignment, + zero, tcache); if (ret == NULL) return (NULL); @@ -3278,9 +3262,9 @@ arena_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, size_t size, copysize = (usize < oldsize) ? usize : oldsize; memcpy(ret, ptr, copysize); - isqalloc(tsd, ptr, oldsize, tcache, true); + isdalloct(tsdn, ptr, oldsize, tcache, true); } else { - ret = huge_ralloc(tsd, arena, ptr, oldsize, usize, alignment, + ret = huge_ralloc(tsdn, arena, ptr, oldsize, usize, alignment, zero, tcache); } return (ret); diff --git a/src/ctl.c b/src/ctl.c index d2e94269..f4c775db 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -97,7 +97,6 @@ CTL_PROTO(opt_decay_time) CTL_PROTO(opt_stats_print) CTL_PROTO(opt_junk) CTL_PROTO(opt_zero) -CTL_PROTO(opt_quarantine) CTL_PROTO(opt_redzone) CTL_PROTO(opt_utrace) CTL_PROTO(opt_xmalloc) @@ -273,7 +272,6 @@ static const ctl_named_node_t opt_node[] = { {NAME("stats_print"), CTL(opt_stats_print)}, {NAME("junk"), CTL(opt_junk)}, {NAME("zero"), CTL(opt_zero)}, - {NAME("quarantine"), CTL(opt_quarantine)}, {NAME("redzone"), CTL(opt_redzone)}, {NAME("utrace"), CTL(opt_utrace)}, {NAME("xmalloc"), CTL(opt_xmalloc)}, @@ -1281,7 +1279,6 @@ CTL_RO_NL_GEN(opt_lg_dirty_mult, opt_lg_dirty_mult, ssize_t) CTL_RO_NL_GEN(opt_decay_time, opt_decay_time, ssize_t) CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool) CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *) -CTL_RO_NL_CGEN(config_fill, opt_quarantine, opt_quarantine, size_t) CTL_RO_NL_CGEN(config_fill, opt_redzone, opt_redzone, bool) CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool) CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool) @@ -1619,11 +1616,6 @@ arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, READONLY(); WRITEONLY(); - if (config_fill && unlikely(opt_quarantine)) { - ret = EFAULT; - goto label_return; - } - arena_ind = (unsigned)mib[1]; if (config_debug) { malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); diff --git a/src/huge.c b/src/huge.c index 1aa02a0f..b1ff918a 100644 --- a/src/huge.c +++ b/src/huge.c @@ -359,7 +359,7 @@ huge_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, } void * -huge_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, +huge_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, size_t usize, size_t alignment, bool zero, tcache_t *tcache) { void *ret; @@ -369,8 +369,7 @@ huge_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, assert(usize > 0 && usize <= HUGE_MAXCLASS); /* Try to avoid moving the allocation. */ - if (!huge_ralloc_no_move(tsd_tsdn(tsd), ptr, oldsize, usize, usize, - zero)) + if (!huge_ralloc_no_move(tsdn, ptr, oldsize, usize, usize, zero)) return (ptr); /* @@ -378,14 +377,13 @@ huge_ralloc(tsd_t *tsd, arena_t *arena, void *ptr, size_t oldsize, * different size class. In that case, fall back to allocating new * space and copying. */ - ret = huge_ralloc_move_helper(tsd_tsdn(tsd), arena, usize, alignment, - zero); + ret = huge_ralloc_move_helper(tsdn, arena, usize, alignment, zero); if (ret == NULL) return (NULL); copysize = (usize < oldsize) ? usize : oldsize; memcpy(ret, ptr, copysize); - isqalloc(tsd, ptr, oldsize, tcache, true); + isdalloct(tsdn, ptr, oldsize, tcache, true); return (ret); } diff --git a/src/jemalloc.c b/src/jemalloc.c index cfe6ed32..4dd77e68 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -35,7 +35,6 @@ bool opt_junk_free = #endif ; -size_t opt_quarantine = ZU(0); bool opt_redzone = false; bool opt_utrace = false; bool opt_xmalloc = false; @@ -74,10 +73,9 @@ static bool malloc_slow = true; enum { flag_opt_junk_alloc = (1U), flag_opt_junk_free = (1U << 1), - flag_opt_quarantine = (1U << 2), - flag_opt_zero = (1U << 3), - flag_opt_utrace = (1U << 4), - flag_opt_xmalloc = (1U << 5) + flag_opt_zero = (1U << 2), + flag_opt_utrace = (1U << 3), + flag_opt_xmalloc = (1U << 4) }; static uint8_t malloc_slow_flags; @@ -265,23 +263,6 @@ malloc_initialized(void) return (malloc_init_state == malloc_init_initialized); } -JEMALLOC_ALWAYS_INLINE_C void -malloc_thread_init(void) -{ - - /* - * TSD initialization can't be safely done as a side effect of - * deallocation, because it is possible for a thread to do nothing but - * deallocate its TLS data via free(), in which case writing to TLS - * would cause write-after-free memory corruption. The quarantine - * facility *only* gets used as a side effect of deallocation, so make - * a best effort attempt at initializing its TSD by hooking all - * allocation events. - */ - if (config_fill && unlikely(opt_quarantine)) - quarantine_alloc_hook(); -} - JEMALLOC_ALWAYS_INLINE_C bool malloc_init_a0(void) { @@ -297,8 +278,6 @@ malloc_init(void) if (unlikely(!malloc_initialized()) && malloc_init_hard()) return (true); - malloc_thread_init(); - return (false); } @@ -885,7 +864,6 @@ malloc_slow_flag_init(void) */ malloc_slow_flags |= (opt_junk_alloc ? flag_opt_junk_alloc : 0) | (opt_junk_free ? flag_opt_junk_free : 0) - | (opt_quarantine ? flag_opt_quarantine : 0) | (opt_zero ? flag_opt_zero : 0) | (opt_utrace ? flag_opt_utrace : 0) | (opt_xmalloc ? flag_opt_xmalloc : 0); @@ -1146,8 +1124,6 @@ malloc_conf_init(void) } continue; } - CONF_HANDLE_SIZE_T(opt_quarantine, "quarantine", - 0, SIZE_T_MAX, false) CONF_HANDLE_BOOL(opt_redzone, "redzone", true) CONF_HANDLE_BOOL(opt_zero, "zero", true) } @@ -1761,9 +1737,9 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) *tsd_thread_deallocatedp_get(tsd) += usize; if (likely(!slow_path)) - iqalloc(tsd, ptr, tcache, false); + idalloctm(tsd_tsdn(tsd), ptr, tcache, false, false); else - iqalloc(tsd, ptr, tcache, true); + idalloctm(tsd_tsdn(tsd), ptr, tcache, false, true); } JEMALLOC_INLINE_C void @@ -1779,7 +1755,11 @@ isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) prof_free(tsd, ptr, usize); if (config_stats) *tsd_thread_deallocatedp_get(tsd) += usize; - isqalloc(tsd, ptr, usize, tcache, slow_path); + + if (likely(!slow_path)) + isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, false); + else + isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, true); } JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN @@ -1809,7 +1789,6 @@ je_realloc(void *ptr, size_t size) tsd_t *tsd; assert(malloc_initialized() || IS_INITIALIZER); - malloc_thread_init(); tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); @@ -2123,7 +2102,7 @@ je_mallocx(size_t size, int flags) } static void * -irallocx_prof_sample(tsd_t *tsd, void *old_ptr, size_t old_usize, +irallocx_prof_sample(tsdn_t *tsdn, void *old_ptr, size_t old_usize, size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena, prof_tctx_t *tctx) { @@ -2132,13 +2111,13 @@ irallocx_prof_sample(tsd_t *tsd, void *old_ptr, size_t old_usize, if (tctx == NULL) return (NULL); if (usize <= SMALL_MAXCLASS) { - p = iralloct(tsd, old_ptr, old_usize, LARGE_MINCLASS, alignment, - zero, tcache, arena); + p = iralloct(tsdn, old_ptr, old_usize, LARGE_MINCLASS, + alignment, zero, tcache, arena); if (p == NULL) return (NULL); - arena_prof_promoted(tsd_tsdn(tsd), p, usize); + arena_prof_promoted(tsdn, p, usize); } else { - p = iralloct(tsd, old_ptr, old_usize, usize, alignment, zero, + p = iralloct(tsdn, old_ptr, old_usize, usize, alignment, zero, tcache, arena); } @@ -2158,11 +2137,11 @@ irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size, old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr); tctx = prof_alloc_prep(tsd, *usize, prof_active, true); if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { - p = irallocx_prof_sample(tsd, old_ptr, old_usize, *usize, - alignment, zero, tcache, arena, tctx); + p = irallocx_prof_sample(tsd_tsdn(tsd), old_ptr, old_usize, + *usize, alignment, zero, tcache, arena, tctx); } else { - p = iralloct(tsd, old_ptr, old_usize, size, alignment, zero, - tcache, arena); + p = iralloct(tsd_tsdn(tsd), old_ptr, old_usize, size, alignment, + zero, tcache, arena); } if (unlikely(p == NULL)) { prof_alloc_rollback(tsd, tctx, true); @@ -2203,7 +2182,6 @@ je_rallocx(void *ptr, size_t size, int flags) assert(ptr != NULL); assert(size != 0); assert(malloc_initialized() || IS_INITIALIZER); - malloc_thread_init(); tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); @@ -2234,8 +2212,8 @@ je_rallocx(void *ptr, size_t size, int flags) if (unlikely(p == NULL)) goto label_oom; } else { - p = iralloct(tsd, ptr, old_usize, size, alignment, zero, - tcache, arena); + p = iralloct(tsd_tsdn(tsd), ptr, old_usize, size, alignment, + zero, tcache, arena); if (unlikely(p == NULL)) goto label_oom; if (config_stats) @@ -2349,7 +2327,6 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) assert(size != 0); assert(SIZE_T_MAX - size >= extra); assert(malloc_initialized() || IS_INITIALIZER); - malloc_thread_init(); tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); @@ -2399,7 +2376,6 @@ je_sallocx(const void *ptr, int flags) tsdn_t *tsdn; assert(malloc_initialized() || IS_INITIALIZER); - malloc_thread_init(); tsdn = tsdn_fetch(); witness_assert_lockless(tsdn); @@ -2577,7 +2553,6 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) tsdn_t *tsdn; assert(malloc_initialized() || IS_INITIALIZER); - malloc_thread_init(); tsdn = tsdn_fetch(); witness_assert_lockless(tsdn); diff --git a/src/quarantine.c b/src/quarantine.c deleted file mode 100644 index 9658ffad..00000000 --- a/src/quarantine.c +++ /dev/null @@ -1,178 +0,0 @@ -#define JEMALLOC_QUARANTINE_C_ -#include "jemalloc/internal/jemalloc_internal.h" - -/* - * Quarantine pointers close to NULL are used to encode state information that - * is used for cleaning up during thread shutdown. - */ -#define QUARANTINE_STATE_REINCARNATED ((quarantine_t *)(uintptr_t)1) -#define QUARANTINE_STATE_PURGATORY ((quarantine_t *)(uintptr_t)2) -#define QUARANTINE_STATE_MAX QUARANTINE_STATE_PURGATORY - -/******************************************************************************/ -/* Function prototypes for non-inline static functions. */ - -static quarantine_t *quarantine_grow(tsd_t *tsd, quarantine_t *quarantine); -static void quarantine_drain_one(tsdn_t *tsdn, quarantine_t *quarantine); -static void quarantine_drain(tsdn_t *tsdn, quarantine_t *quarantine, - size_t upper_bound); - -/******************************************************************************/ - -static quarantine_t * -quarantine_init(tsdn_t *tsdn, size_t lg_maxobjs) -{ - quarantine_t *quarantine; - size_t size; - - size = offsetof(quarantine_t, objs) + ((ZU(1) << lg_maxobjs) * - sizeof(quarantine_obj_t)); - quarantine = (quarantine_t *)iallocztm(tsdn, size, size2index(size), - false, NULL, true, arena_get(TSDN_NULL, 0, true), true); - if (quarantine == NULL) - return (NULL); - quarantine->curbytes = 0; - quarantine->curobjs = 0; - quarantine->first = 0; - quarantine->lg_maxobjs = lg_maxobjs; - - return (quarantine); -} - -void -quarantine_alloc_hook_work(tsd_t *tsd) -{ - quarantine_t *quarantine; - - if (!tsd_nominal(tsd)) - return; - - quarantine = quarantine_init(tsd_tsdn(tsd), LG_MAXOBJS_INIT); - /* - * Check again whether quarantine has been initialized, because - * quarantine_init() may have triggered recursive initialization. - */ - if (tsd_quarantine_get(tsd) == NULL) - tsd_quarantine_set(tsd, quarantine); - else - idalloctm(tsd_tsdn(tsd), quarantine, NULL, true, true); -} - -static quarantine_t * -quarantine_grow(tsd_t *tsd, quarantine_t *quarantine) -{ - quarantine_t *ret; - - ret = quarantine_init(tsd_tsdn(tsd), quarantine->lg_maxobjs + 1); - if (ret == NULL) { - quarantine_drain_one(tsd_tsdn(tsd), quarantine); - return (quarantine); - } - - ret->curbytes = quarantine->curbytes; - ret->curobjs = quarantine->curobjs; - if (quarantine->first + quarantine->curobjs <= (ZU(1) << - quarantine->lg_maxobjs)) { - /* objs ring buffer data are contiguous. */ - memcpy(ret->objs, &quarantine->objs[quarantine->first], - quarantine->curobjs * sizeof(quarantine_obj_t)); - } else { - /* objs ring buffer data wrap around. */ - size_t ncopy_a = (ZU(1) << quarantine->lg_maxobjs) - - quarantine->first; - size_t ncopy_b = quarantine->curobjs - ncopy_a; - - memcpy(ret->objs, &quarantine->objs[quarantine->first], ncopy_a - * sizeof(quarantine_obj_t)); - memcpy(&ret->objs[ncopy_a], quarantine->objs, ncopy_b * - sizeof(quarantine_obj_t)); - } - idalloctm(tsd_tsdn(tsd), quarantine, NULL, true, true); - - tsd_quarantine_set(tsd, ret); - return (ret); -} - -static void -quarantine_drain_one(tsdn_t *tsdn, quarantine_t *quarantine) -{ - quarantine_obj_t *obj = &quarantine->objs[quarantine->first]; - assert(obj->usize == isalloc(tsdn, obj->ptr, config_prof)); - idalloctm(tsdn, obj->ptr, NULL, false, true); - quarantine->curbytes -= obj->usize; - quarantine->curobjs--; - quarantine->first = (quarantine->first + 1) & ((ZU(1) << - quarantine->lg_maxobjs) - 1); -} - -static void -quarantine_drain(tsdn_t *tsdn, quarantine_t *quarantine, size_t upper_bound) -{ - - while (quarantine->curbytes > upper_bound && quarantine->curobjs > 0) - quarantine_drain_one(tsdn, quarantine); -} - -void -quarantine(tsd_t *tsd, void *ptr) -{ - quarantine_t *quarantine; - size_t usize = isalloc(tsd_tsdn(tsd), ptr, config_prof); - - cassert(config_fill); - assert(opt_quarantine); - - if ((quarantine = tsd_quarantine_get(tsd)) == NULL) { - idalloctm(tsd_tsdn(tsd), ptr, NULL, false, true); - return; - } - /* - * Drain one or more objects if the quarantine size limit would be - * exceeded by appending ptr. - */ - if (quarantine->curbytes + usize > opt_quarantine) { - size_t upper_bound = (opt_quarantine >= usize) ? opt_quarantine - - usize : 0; - quarantine_drain(tsd_tsdn(tsd), quarantine, upper_bound); - } - /* Grow the quarantine ring buffer if it's full. */ - if (quarantine->curobjs == (ZU(1) << quarantine->lg_maxobjs)) - quarantine = quarantine_grow(tsd, quarantine); - /* quarantine_grow() must free a slot if it fails to grow. */ - assert(quarantine->curobjs < (ZU(1) << quarantine->lg_maxobjs)); - /* Append ptr if its size doesn't exceed the quarantine size. */ - if (quarantine->curbytes + usize <= opt_quarantine) { - size_t offset = (quarantine->first + quarantine->curobjs) & - ((ZU(1) << quarantine->lg_maxobjs) - 1); - quarantine_obj_t *obj = &quarantine->objs[offset]; - obj->ptr = ptr; - obj->usize = usize; - quarantine->curbytes += usize; - quarantine->curobjs++; - if (config_fill && unlikely(opt_junk_free)) { - if (usize <= SMALL_MAXCLASS) - arena_quarantine_junk_small(ptr, usize); - else - memset(ptr, JEMALLOC_FREE_JUNK, usize); - } - } else { - assert(quarantine->curbytes == 0); - idalloctm(tsd_tsdn(tsd), ptr, NULL, false, true); - } -} - -void -quarantine_cleanup(tsd_t *tsd) -{ - quarantine_t *quarantine; - - if (!config_fill) - return; - - quarantine = tsd_quarantine_get(tsd); - if (quarantine != NULL) { - quarantine_drain(tsd_tsdn(tsd), quarantine, 0); - idalloctm(tsd_tsdn(tsd), quarantine, NULL, true, true); - tsd_quarantine_set(tsd, NULL); - } -} diff --git a/src/stats.c b/src/stats.c index 97f901f6..16e5b1a3 100644 --- a/src/stats.c +++ b/src/stats.c @@ -513,7 +513,6 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, OPT_WRITE_SSIZE_T_MUTABLE(decay_time, arenas.decay_time) OPT_WRITE_BOOL(stats_print) OPT_WRITE_CHAR_P(junk) - OPT_WRITE_SIZE_T(quarantine) OPT_WRITE_BOOL(redzone) OPT_WRITE_BOOL(zero) OPT_WRITE_BOOL(utrace) diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index c602f0ff..d7a02e0f 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -88,8 +88,6 @@ TEST_BEGIN(test_arena_reset) size_t mib[3]; tsdn_t *tsdn; - test_skip_if(config_fill && unlikely(opt_quarantine)); - sz = sizeof(unsigned); assert_d_eq(mallctl("arenas.extend", &arena_ind, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); diff --git a/test/unit/junk.c b/test/unit/junk.c index acddc601..cb262ec1 100644 --- a/test/unit/junk.c +++ b/test/unit/junk.c @@ -5,7 +5,7 @@ # define JEMALLOC_TEST_JUNK_OPT "junk:true" # endif const char *malloc_conf = - "abort:false,zero:false,redzone:true,quarantine:0," JEMALLOC_TEST_JUNK_OPT; + "abort:false,zero:false,redzone:true," JEMALLOC_TEST_JUNK_OPT; #endif static arena_dalloc_junk_small_t *arena_dalloc_junk_small_orig; diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 641138ac..151e7ad0 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -168,7 +168,6 @@ TEST_BEGIN(test_mallctl_opt) TEST_MALLCTL_OPT(ssize_t, decay_time, always); TEST_MALLCTL_OPT(bool, stats_print, always); TEST_MALLCTL_OPT(const char *, junk, fill); - TEST_MALLCTL_OPT(size_t, quarantine, fill); TEST_MALLCTL_OPT(bool, redzone, fill); TEST_MALLCTL_OPT(bool, zero, fill); TEST_MALLCTL_OPT(bool, utrace, utrace); diff --git a/test/unit/quarantine.c b/test/unit/quarantine.c deleted file mode 100644 index bbd48a51..00000000 --- a/test/unit/quarantine.c +++ /dev/null @@ -1,108 +0,0 @@ -#include "test/jemalloc_test.h" - -#define QUARANTINE_SIZE 8192 -#define STRINGIFY_HELPER(x) #x -#define STRINGIFY(x) STRINGIFY_HELPER(x) - -#ifdef JEMALLOC_FILL -const char *malloc_conf = "abort:false,junk:true,redzone:true,quarantine:" - STRINGIFY(QUARANTINE_SIZE); -#endif - -void -quarantine_clear(void) -{ - void *p; - - p = mallocx(QUARANTINE_SIZE*2, 0); - assert_ptr_not_null(p, "Unexpected mallocx() failure"); - dallocx(p, 0); -} - -TEST_BEGIN(test_quarantine) -{ -#define SZ ZU(256) -#define NQUARANTINED (QUARANTINE_SIZE/SZ) - void *quarantined[NQUARANTINED+1]; - size_t i, j; - - test_skip_if(!config_fill); - - assert_zu_eq(nallocx(SZ, 0), SZ, - "SZ=%zu does not precisely equal a size class", SZ); - - quarantine_clear(); - - /* - * Allocate enough regions to completely fill the quarantine, plus one - * more. The last iteration occurs with a completely full quarantine, - * but no regions should be drained from the quarantine until the last - * deallocation occurs. Therefore no region recycling should occur - * until after this loop completes. - */ - for (i = 0; i < NQUARANTINED+1; i++) { - void *p = mallocx(SZ, 0); - assert_ptr_not_null(p, "Unexpected mallocx() failure"); - quarantined[i] = p; - dallocx(p, 0); - for (j = 0; j < i; j++) { - assert_ptr_ne(p, quarantined[j], - "Quarantined region recycled too early; " - "i=%zu, j=%zu", i, j); - } - } -#undef NQUARANTINED -#undef SZ -} -TEST_END - -static bool detected_redzone_corruption; - -static void -arena_redzone_corruption_replacement(void *ptr, size_t usize, bool after, - size_t offset, uint8_t byte) -{ - - detected_redzone_corruption = true; -} - -TEST_BEGIN(test_quarantine_redzone) -{ - char *s; - arena_redzone_corruption_t *arena_redzone_corruption_orig; - - test_skip_if(!config_fill); - - arena_redzone_corruption_orig = arena_redzone_corruption; - arena_redzone_corruption = arena_redzone_corruption_replacement; - - /* Test underflow. */ - detected_redzone_corruption = false; - s = (char *)mallocx(1, 0); - assert_ptr_not_null((void *)s, "Unexpected mallocx() failure"); - s[-1] = 0xbb; - dallocx(s, 0); - assert_true(detected_redzone_corruption, - "Did not detect redzone corruption"); - - /* Test overflow. */ - detected_redzone_corruption = false; - s = (char *)mallocx(1, 0); - assert_ptr_not_null((void *)s, "Unexpected mallocx() failure"); - s[sallocx(s, 0)] = 0xbb; - dallocx(s, 0); - assert_true(detected_redzone_corruption, - "Did not detect redzone corruption"); - - arena_redzone_corruption = arena_redzone_corruption_orig; -} -TEST_END - -int -main(void) -{ - - return (test( - test_quarantine, - test_quarantine_redzone)); -} diff --git a/test/unit/zero.c b/test/unit/zero.c index 30ebe37a..80b8fe13 100644 --- a/test/unit/zero.c +++ b/test/unit/zero.c @@ -2,7 +2,7 @@ #ifdef JEMALLOC_FILL const char *malloc_conf = - "abort:false,junk:false,zero:true,redzone:false,quarantine:0"; + "abort:false,junk:false,zero:true,redzone:false"; #endif static void -- GitLab From 17c021c1775c2b5f5f73e3c0f0d19e9b3e9c23b9 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 5 Apr 2016 18:18:15 -0700 Subject: [PATCH 005/544] Remove redzone support. This resolves #369. --- INSTALL | 5 +- configure.ac | 3 +- doc/jemalloc.xml.in | 15 -- include/jemalloc/internal/arena.h | 65 ++------ .../jemalloc/internal/jemalloc_internal.h.in | 25 --- .../internal/jemalloc_internal_defs.h.in | 2 +- include/jemalloc/internal/private_symbols.txt | 4 - src/arena.c | 153 ++---------------- src/ctl.c | 3 - src/jemalloc.c | 15 +- src/stats.c | 1 - test/unit/junk.c | 48 +----- test/unit/mallctl.c | 1 - test/unit/zero.c | 2 +- 14 files changed, 41 insertions(+), 301 deletions(-) diff --git a/INSTALL b/INSTALL index 4f57b365..e4f7bbd5 100644 --- a/INSTALL +++ b/INSTALL @@ -165,9 +165,8 @@ any of the following arguments (not a definitive list) to 'configure': normal jemalloc operation. --disable-fill - Disable support for junk/zero filling of memory and redzones. See the - "opt.junk", "opt.zero", and "opt.redzone" option documentation for usage - details. + Disable support for junk/zero filling of memory. See the "opt.junk" and + "opt.zero" option documentation for usage details. --disable-zone-allocator Disable zone allocator for Darwin. This means jemalloc won't be hooked as diff --git a/configure.ac b/configure.ac index 92192d4d..538e53f4 100644 --- a/configure.ac +++ b/configure.ac @@ -945,8 +945,7 @@ fi dnl Support the junk/zero filling option by default. AC_ARG_ENABLE([fill], - [AS_HELP_STRING([--disable-fill], - [Disable support for junk/zero filling and redzones])], + [AS_HELP_STRING([--disable-fill], [Disable support for junk/zero filling])], [if test "x$enable_fill" = "xno" ; then enable_fill="0" else diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 7ed03330..eddc88c1 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -1040,21 +1040,6 @@ for (i = 0; i < nbins; i++) { default. - - - opt.redzone - (bool) - r- - [] - - Redzones enabled/disabled. If enabled, small - allocations have redzones before and after them. Furthermore, if the - opt.junk option is - enabled, the redzones are checked for corruption during deallocation. - This option is intended for debugging and will impact performance - negatively. This option is disabled by default. - - opt.zero diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 1c63620d..6e71b5f6 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -7,12 +7,6 @@ #define LG_RUN_MAXREGS (LG_PAGE - LG_TINY_MIN) #define RUN_MAXREGS (1U << LG_RUN_MAXREGS) -/* - * Minimum redzone size. Redzones may be larger than this if necessary to - * preserve region alignment. - */ -#define REDZONE_MINSIZE 16 - /* * The minimum ratio of active:dirty pages per arena is computed as: * @@ -205,42 +199,22 @@ struct arena_chunk_s { * * Each run has the following layout: * - * /--------------------\ - * | pad? | - * |--------------------| - * | redzone | - * reg0_offset | region 0 | - * | redzone | - * |--------------------| \ - * | redzone | | - * | region 1 | > reg_interval - * | redzone | / - * |--------------------| - * | ... | - * | ... | - * | ... | - * |--------------------| - * | redzone | - * | region nregs-1 | - * | redzone | - * |--------------------| - * | alignment pad? | - * \--------------------/ - * - * reg_interval has at least the same minimum alignment as reg_size; this - * preserves the alignment constraint that sa2u() depends on. Alignment pad is - * either 0 or redzone_size; it is present only if needed to align reg0_offset. + * /--------------------\ + * | region 0 | + * |--------------------| + * | region 1 | + * |--------------------| + * | ... | + * | ... | + * | ... | + * |--------------------| + * | region nregs-1 | + * \--------------------/ */ struct arena_bin_info_s { /* Size of regions in a run for this bin's size class. */ size_t reg_size; - /* Redzone size. */ - size_t redzone_size; - - /* Interval between regions (reg_size + (redzone_size << 1)). */ - size_t reg_interval; - /* Total size of a run for this bin's size class. */ size_t run_size; @@ -252,9 +226,6 @@ struct arena_bin_info_s { * bin. */ bitmap_info_t bitmap_info; - - /* Offset of first region in a run for this bin's size class. */ - uint32_t reg0_offset; }; struct arena_bin_s { @@ -543,9 +514,6 @@ void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, void arena_alloc_junk_small(void *ptr, arena_bin_info_t *bin_info, bool zero); #ifdef JEMALLOC_JET -typedef void (arena_redzone_corruption_t)(void *, size_t, bool, size_t, - uint8_t); -extern arena_redzone_corruption_t *arena_redzone_corruption; typedef void (arena_dalloc_junk_small_t)(void *, arena_bin_info_t *); extern arena_dalloc_junk_small_t *arena_dalloc_junk_small; #else @@ -1113,8 +1081,7 @@ arena_ptr_small_binind_get(const void *ptr, size_t mapbits) assert(run_binind == actual_binind); bin_info = &arena_bin_info[actual_binind]; rpages = arena_miscelm_to_rpages(miscelm); - assert(((uintptr_t)ptr - ((uintptr_t)rpages + - (uintptr_t)bin_info->reg0_offset)) % bin_info->reg_interval + assert(((uintptr_t)ptr - (uintptr_t)rpages) % bin_info->reg_size == 0); } @@ -1142,18 +1109,16 @@ arena_run_regind(arena_run_t *run, arena_bin_info_t *bin_info, const void *ptr) * Freeing a pointer lower than region zero can cause assertion * failure. */ - assert((uintptr_t)ptr >= (uintptr_t)rpages + - (uintptr_t)bin_info->reg0_offset); + assert((uintptr_t)ptr >= (uintptr_t)rpages); /* * Avoid doing division with a variable divisor if possible. Using * actual division here can reduce allocator throughput by over 20%! */ - diff = (size_t)((uintptr_t)ptr - (uintptr_t)rpages - - bin_info->reg0_offset); + diff = (size_t)((uintptr_t)ptr - (uintptr_t)rpages); /* Rescale (factor powers of 2 out of the numerator and denominator). */ - interval = bin_info->reg_interval; + interval = bin_info->reg_size; shift = ffs_zu(interval) - 1; diff >>= shift; interval >>= shift; diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index c6aa5743..a8c476d9 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -423,7 +423,6 @@ extern bool opt_abort; extern const char *opt_junk; extern bool opt_junk_alloc; extern bool opt_junk_free; -extern bool opt_redzone; extern bool opt_utrace; extern bool opt_xmalloc; extern bool opt_zero; @@ -888,8 +887,6 @@ void *ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); void *ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero); size_t ivsalloc(tsdn_t *tsdn, const void *ptr, bool demote); -size_t u2rz(size_t usize); -size_t p2rz(tsdn_t *tsdn, const void *ptr); void idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool is_metadata, bool slow_path); void idalloc(tsd_t *tsd, void *ptr); @@ -1011,28 +1008,6 @@ ivsalloc(tsdn_t *tsdn, const void *ptr, bool demote) return (isalloc(tsdn, ptr, demote)); } -JEMALLOC_INLINE size_t -u2rz(size_t usize) -{ - size_t ret; - - if (usize <= SMALL_MAXCLASS) { - szind_t binind = size2index(usize); - ret = arena_bin_info[binind].redzone_size; - } else - ret = 0; - - return (ret); -} - -JEMALLOC_INLINE size_t -p2rz(tsdn_t *tsdn, const void *ptr) -{ - size_t usize = isalloc(tsdn, ptr, false); - - return (u2rz(usize)); -} - JEMALLOC_ALWAYS_INLINE void idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool is_metadata, bool slow_path) diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 5e5b0a78..7a38c91d 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -142,7 +142,7 @@ */ #undef JEMALLOC_DSS -/* Support memory filling (junk/zero/redzone). */ +/* Support memory filling (junk/zero). */ #undef JEMALLOC_FILL /* Support utrace(2)-based tracing. */ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 02377809..89933426 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -103,7 +103,6 @@ arena_ralloc arena_ralloc_junk_large arena_ralloc_no_move arena_rd_to_miscelm -arena_redzone_corruption arena_reset arena_run_regind arena_run_to_miscelm @@ -382,13 +381,11 @@ opt_prof_leak opt_prof_prefix opt_prof_thread_active_init opt_purge -opt_redzone opt_stats_print opt_tcache opt_utrace opt_xmalloc opt_zero -p2rz pages_boot pages_commit pages_decommit @@ -578,7 +575,6 @@ tsd_witnessesp_get tsdn_fetch tsdn_null tsdn_tsd -u2rz witness_assert_lockless witness_assert_not_owner witness_assert_owner diff --git a/src/arena.c b/src/arena.c index 607679d7..9b458abf 100644 --- a/src/arena.c +++ b/src/arena.c @@ -314,8 +314,8 @@ arena_run_reg_alloc(arena_run_t *run, arena_bin_info_t *bin_info) regind = (unsigned)bitmap_sfu(run->bitmap, &bin_info->bitmap_info); miscelm = arena_run_to_miscelm(run); rpages = arena_miscelm_to_rpages(miscelm); - ret = (void *)((uintptr_t)rpages + (uintptr_t)bin_info->reg0_offset + - (uintptr_t)(bin_info->reg_interval * regind)); + ret = (void *)((uintptr_t)rpages + (uintptr_t)(bin_info->reg_size * + regind)); run->nfree--; return (ret); } @@ -333,12 +333,10 @@ arena_run_reg_dalloc(arena_run_t *run, void *ptr) assert(run->nfree < bin_info->nregs); /* Freeing an interior pointer can cause assertion failure. */ assert(((uintptr_t)ptr - - ((uintptr_t)arena_miscelm_to_rpages(arena_run_to_miscelm(run)) + - (uintptr_t)bin_info->reg0_offset)) % - (uintptr_t)bin_info->reg_interval == 0); + (uintptr_t)arena_miscelm_to_rpages(arena_run_to_miscelm(run))) % + (uintptr_t)bin_info->reg_size == 0); assert((uintptr_t)ptr >= - (uintptr_t)arena_miscelm_to_rpages(arena_run_to_miscelm(run)) + - (uintptr_t)bin_info->reg0_offset); + (uintptr_t)arena_miscelm_to_rpages(arena_run_to_miscelm(run))); /* Freeing an unallocated pointer can cause assertion failure. */ assert(bitmap_get(run->bitmap, &bin_info->bitmap_info, regind)); @@ -2395,73 +2393,8 @@ void arena_alloc_junk_small(void *ptr, arena_bin_info_t *bin_info, bool zero) { - size_t redzone_size = bin_info->redzone_size; - - if (zero) { - memset((void *)((uintptr_t)ptr - redzone_size), - JEMALLOC_ALLOC_JUNK, redzone_size); - memset((void *)((uintptr_t)ptr + bin_info->reg_size), - JEMALLOC_ALLOC_JUNK, redzone_size); - } else { - memset((void *)((uintptr_t)ptr - redzone_size), - JEMALLOC_ALLOC_JUNK, bin_info->reg_interval); - } -} - -#ifdef JEMALLOC_JET -#undef arena_redzone_corruption -#define arena_redzone_corruption JEMALLOC_N(n_arena_redzone_corruption) -#endif -static void -arena_redzone_corruption(void *ptr, size_t usize, bool after, - size_t offset, uint8_t byte) -{ - - malloc_printf(": Corrupt redzone %zu byte%s %s %p " - "(size %zu), byte=%#x\n", offset, (offset == 1) ? "" : "s", - after ? "after" : "before", ptr, usize, byte); -} -#ifdef JEMALLOC_JET -#undef arena_redzone_corruption -#define arena_redzone_corruption JEMALLOC_N(arena_redzone_corruption) -arena_redzone_corruption_t *arena_redzone_corruption = - JEMALLOC_N(n_arena_redzone_corruption); -#endif - -static void -arena_redzones_validate(void *ptr, arena_bin_info_t *bin_info, bool reset) -{ - bool error = false; - - if (opt_junk_alloc) { - size_t size = bin_info->reg_size; - size_t redzone_size = bin_info->redzone_size; - size_t i; - - for (i = 1; i <= redzone_size; i++) { - uint8_t *byte = (uint8_t *)((uintptr_t)ptr - i); - if (*byte != JEMALLOC_ALLOC_JUNK) { - error = true; - arena_redzone_corruption(ptr, size, false, i, - *byte); - if (reset) - *byte = JEMALLOC_ALLOC_JUNK; - } - } - for (i = 0; i < redzone_size; i++) { - uint8_t *byte = (uint8_t *)((uintptr_t)ptr + size + i); - if (*byte != JEMALLOC_ALLOC_JUNK) { - error = true; - arena_redzone_corruption(ptr, size, true, i, - *byte); - if (reset) - *byte = JEMALLOC_ALLOC_JUNK; - } - } - } - - if (opt_abort && error) - abort(); + if (!zero) + memset(ptr, JEMALLOC_ALLOC_JUNK, bin_info->reg_size); } #ifdef JEMALLOC_JET @@ -2471,11 +2404,8 @@ arena_redzones_validate(void *ptr, arena_bin_info_t *bin_info, bool reset) void arena_dalloc_junk_small(void *ptr, arena_bin_info_t *bin_info) { - size_t redzone_size = bin_info->redzone_size; - arena_redzones_validate(ptr, bin_info, false); - memset((void *)((uintptr_t)ptr - redzone_size), JEMALLOC_FREE_JUNK, - bin_info->reg_interval); + memset(ptr, JEMALLOC_FREE_JUNK, bin_info->reg_size); } #ifdef JEMALLOC_JET #undef arena_dalloc_junk_small @@ -3559,43 +3489,16 @@ arena_new(tsdn_t *tsdn, unsigned ind) * *) bin_info->run_size <= arena_maxrun * *) bin_info->nregs <= RUN_MAXREGS * - * bin_info->nregs and bin_info->reg0_offset are also calculated here, since - * these settings are all interdependent. + * bin_info->nregs is also calculated here, since these settings are all + * interdependent. */ static void bin_info_run_size_calc(arena_bin_info_t *bin_info) { - size_t pad_size; size_t try_run_size, perfect_run_size, actual_run_size; uint32_t try_nregs, perfect_nregs, actual_nregs; - /* - * Determine redzone size based on minimum alignment and minimum - * redzone size. Add padding to the end of the run if it is needed to - * align the regions. The padding allows each redzone to be half the - * minimum alignment; without the padding, each redzone would have to - * be twice as large in order to maintain alignment. - */ - if (config_fill && unlikely(opt_redzone)) { - size_t align_min = ZU(1) << (ffs_zu(bin_info->reg_size) - 1); - if (align_min <= REDZONE_MINSIZE) { - bin_info->redzone_size = REDZONE_MINSIZE; - pad_size = 0; - } else { - bin_info->redzone_size = align_min >> 1; - pad_size = bin_info->redzone_size; - } - } else { - bin_info->redzone_size = 0; - pad_size = 0; - } - bin_info->reg_interval = bin_info->reg_size + - (bin_info->redzone_size << 1); - - /* - * Compute run size under ideal conditions (no redzones, no limit on run - * size). - */ + /* Compute smallest run size that is an integer multiple of reg_size. */ try_run_size = PAGE; try_nregs = (uint32_t)(try_run_size / bin_info->reg_size); do { @@ -3605,48 +3508,18 @@ bin_info_run_size_calc(arena_bin_info_t *bin_info) try_run_size += PAGE; try_nregs = (uint32_t)(try_run_size / bin_info->reg_size); } while (perfect_run_size != perfect_nregs * bin_info->reg_size); + assert(perfect_run_size <= arena_maxrun); assert(perfect_nregs <= RUN_MAXREGS); actual_run_size = perfect_run_size; - actual_nregs = (uint32_t)((actual_run_size - pad_size) / - bin_info->reg_interval); - - /* - * Redzones can require enough padding that not even a single region can - * fit within the number of pages that would normally be dedicated to a - * run for this size class. Increase the run size until at least one - * region fits. - */ - while (actual_nregs == 0) { - assert(config_fill && unlikely(opt_redzone)); - - actual_run_size += PAGE; - actual_nregs = (uint32_t)((actual_run_size - pad_size) / - bin_info->reg_interval); - } - - /* - * Make sure that the run will fit within an arena chunk. - */ - while (actual_run_size > arena_maxrun) { - actual_run_size -= PAGE; - actual_nregs = (uint32_t)((actual_run_size - pad_size) / - bin_info->reg_interval); - } - assert(actual_nregs > 0); - assert(actual_run_size == s2u(actual_run_size)); + actual_nregs = (uint32_t)((actual_run_size) / bin_info->reg_size); /* Copy final settings. */ bin_info->run_size = actual_run_size; bin_info->nregs = actual_nregs; - bin_info->reg0_offset = (uint32_t)(actual_run_size - (actual_nregs * - bin_info->reg_interval) - pad_size + bin_info->redzone_size); if (actual_run_size > small_maxrun) small_maxrun = actual_run_size; - - assert(bin_info->reg0_offset - bin_info->redzone_size + (bin_info->nregs - * bin_info->reg_interval) + pad_size == bin_info->run_size); } static void diff --git a/src/ctl.c b/src/ctl.c index f4c775db..908a2850 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -97,7 +97,6 @@ CTL_PROTO(opt_decay_time) CTL_PROTO(opt_stats_print) CTL_PROTO(opt_junk) CTL_PROTO(opt_zero) -CTL_PROTO(opt_redzone) CTL_PROTO(opt_utrace) CTL_PROTO(opt_xmalloc) CTL_PROTO(opt_tcache) @@ -272,7 +271,6 @@ static const ctl_named_node_t opt_node[] = { {NAME("stats_print"), CTL(opt_stats_print)}, {NAME("junk"), CTL(opt_junk)}, {NAME("zero"), CTL(opt_zero)}, - {NAME("redzone"), CTL(opt_redzone)}, {NAME("utrace"), CTL(opt_utrace)}, {NAME("xmalloc"), CTL(opt_xmalloc)}, {NAME("tcache"), CTL(opt_tcache)}, @@ -1279,7 +1277,6 @@ CTL_RO_NL_GEN(opt_lg_dirty_mult, opt_lg_dirty_mult, ssize_t) CTL_RO_NL_GEN(opt_decay_time, opt_decay_time, ssize_t) CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool) CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *) -CTL_RO_NL_CGEN(config_fill, opt_redzone, opt_redzone, bool) CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool) CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool) CTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool) diff --git a/src/jemalloc.c b/src/jemalloc.c index 4dd77e68..5be5961a 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -35,7 +35,6 @@ bool opt_junk_free = #endif ; -bool opt_redzone = false; bool opt_utrace = false; bool opt_xmalloc = false; bool opt_zero = false; @@ -1040,16 +1039,15 @@ malloc_conf_init(void) CONF_HANDLE_BOOL(opt_abort, "abort", true) /* - * Chunks always require at least one header page, - * as many as 2^(LG_SIZE_CLASS_GROUP+1) data pages, and - * possibly an additional page in the presence of - * redzones. In order to simplify options processing, - * use a conservative bound that accommodates all these + * Chunks always require at least one header page and as + * many as 2^(LG_SIZE_CLASS_GROUP+1) data pages. In + * order to simplify options processing, use a + * conservative bound that accommodates all these * constraints. */ CONF_HANDLE_SIZE_T(opt_lg_chunk, "lg_chunk", LG_PAGE + - LG_SIZE_CLASS_GROUP + (config_fill ? 2 : 1), - (sizeof(size_t) << 3) - 1, true) + LG_SIZE_CLASS_GROUP + 1, (sizeof(size_t) << 3) - 1, + true) if (strncmp("dss", k, klen) == 0) { int i; bool match = false; @@ -1124,7 +1122,6 @@ malloc_conf_init(void) } continue; } - CONF_HANDLE_BOOL(opt_redzone, "redzone", true) CONF_HANDLE_BOOL(opt_zero, "zero", true) } if (config_utrace) { diff --git a/src/stats.c b/src/stats.c index 16e5b1a3..0e1442ed 100644 --- a/src/stats.c +++ b/src/stats.c @@ -513,7 +513,6 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, OPT_WRITE_SSIZE_T_MUTABLE(decay_time, arenas.decay_time) OPT_WRITE_BOOL(stats_print) OPT_WRITE_CHAR_P(junk) - OPT_WRITE_BOOL(redzone) OPT_WRITE_BOOL(zero) OPT_WRITE_BOOL(utrace) OPT_WRITE_BOOL(xmalloc) diff --git a/test/unit/junk.c b/test/unit/junk.c index cb262ec1..f74e33f6 100644 --- a/test/unit/junk.c +++ b/test/unit/junk.c @@ -5,7 +5,7 @@ # define JEMALLOC_TEST_JUNK_OPT "junk:true" # endif const char *malloc_conf = - "abort:false,zero:false,redzone:true," JEMALLOC_TEST_JUNK_OPT; + "abort:false,zero:false," JEMALLOC_TEST_JUNK_OPT; #endif static arena_dalloc_junk_small_t *arena_dalloc_junk_small_orig; @@ -197,49 +197,6 @@ TEST_BEGIN(test_junk_large_ralloc_shrink) } TEST_END -static bool detected_redzone_corruption; - -static void -arena_redzone_corruption_replacement(void *ptr, size_t usize, bool after, - size_t offset, uint8_t byte) -{ - - detected_redzone_corruption = true; -} - -TEST_BEGIN(test_junk_redzone) -{ - char *s; - arena_redzone_corruption_t *arena_redzone_corruption_orig; - - test_skip_if(!config_fill); - test_skip_if(!opt_junk_alloc || !opt_junk_free); - - arena_redzone_corruption_orig = arena_redzone_corruption; - arena_redzone_corruption = arena_redzone_corruption_replacement; - - /* Test underflow. */ - detected_redzone_corruption = false; - s = (char *)mallocx(1, 0); - assert_ptr_not_null((void *)s, "Unexpected mallocx() failure"); - s[-1] = 0xbb; - dallocx(s, 0); - assert_true(detected_redzone_corruption, - "Did not detect redzone corruption"); - - /* Test overflow. */ - detected_redzone_corruption = false; - s = (char *)mallocx(1, 0); - assert_ptr_not_null((void *)s, "Unexpected mallocx() failure"); - s[sallocx(s, 0)] = 0xbb; - dallocx(s, 0); - assert_true(detected_redzone_corruption, - "Did not detect redzone corruption"); - - arena_redzone_corruption = arena_redzone_corruption_orig; -} -TEST_END - int main(void) { @@ -248,6 +205,5 @@ main(void) test_junk_small, test_junk_large, test_junk_huge, - test_junk_large_ralloc_shrink, - test_junk_redzone)); + test_junk_large_ralloc_shrink)); } diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 151e7ad0..79c5147c 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -168,7 +168,6 @@ TEST_BEGIN(test_mallctl_opt) TEST_MALLCTL_OPT(ssize_t, decay_time, always); TEST_MALLCTL_OPT(bool, stats_print, always); TEST_MALLCTL_OPT(const char *, junk, fill); - TEST_MALLCTL_OPT(bool, redzone, fill); TEST_MALLCTL_OPT(bool, zero, fill); TEST_MALLCTL_OPT(bool, utrace, utrace); TEST_MALLCTL_OPT(bool, xmalloc, xmalloc); diff --git a/test/unit/zero.c b/test/unit/zero.c index 80b8fe13..123f0e03 100644 --- a/test/unit/zero.c +++ b/test/unit/zero.c @@ -2,7 +2,7 @@ #ifdef JEMALLOC_FILL const char *malloc_conf = - "abort:false,junk:false,zero:true,redzone:false"; + "abort:false,junk:false,zero:true"; #endif static void -- GitLab From b683734b437209fb8a3a4520b04a649ab7aa56ea Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 6 Apr 2016 18:30:02 -0700 Subject: [PATCH 006/544] Implement BITMAP_INFO_INITIALIZER(nbits). This allows static initialization of bitmap_info_t structures. --- include/jemalloc/internal/bitmap.h | 86 ++++-- src/bitmap.c | 6 +- test/unit/bitmap.c | 405 +++++++++++++++++++++-------- 3 files changed, 366 insertions(+), 131 deletions(-) diff --git a/include/jemalloc/internal/bitmap.h b/include/jemalloc/internal/bitmap.h index 36f38b59..0d456e2d 100644 --- a/include/jemalloc/internal/bitmap.h +++ b/include/jemalloc/internal/bitmap.h @@ -12,7 +12,7 @@ typedef unsigned long bitmap_t; /* Number of bits per group. */ #define LG_BITMAP_GROUP_NBITS (LG_SIZEOF_BITMAP + 3) -#define BITMAP_GROUP_NBITS (ZU(1) << LG_BITMAP_GROUP_NBITS) +#define BITMAP_GROUP_NBITS (1U << LG_BITMAP_GROUP_NBITS) #define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1) /* @@ -21,12 +21,12 @@ typedef unsigned long bitmap_t; * use a tree instead. */ #if LG_BITMAP_MAXBITS - LG_BITMAP_GROUP_NBITS > 3 -# define USE_TREE +# define BITMAP_USE_TREE #endif /* Number of groups required to store a given number of bits. */ #define BITMAP_BITS2GROUPS(nbits) \ - ((nbits + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS) + (((nbits) + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS) /* * Number of groups required at a particular level for a given number of bits. @@ -40,6 +40,9 @@ typedef unsigned long bitmap_t; #define BITMAP_GROUPS_L3(nbits) \ BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ BITMAP_BITS2GROUPS((nbits))))) +#define BITMAP_GROUPS_L4(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))))) /* * Assuming the number of levels, number of groups required for a given number @@ -53,11 +56,13 @@ typedef unsigned long bitmap_t; (BITMAP_GROUPS_2_LEVEL(nbits) + BITMAP_GROUPS_L2(nbits)) #define BITMAP_GROUPS_4_LEVEL(nbits) \ (BITMAP_GROUPS_3_LEVEL(nbits) + BITMAP_GROUPS_L3(nbits)) +#define BITMAP_GROUPS_5_LEVEL(nbits) \ + (BITMAP_GROUPS_4_LEVEL(nbits) + BITMAP_GROUPS_L4(nbits)) /* * Maximum number of groups required to support LG_BITMAP_MAXBITS. */ -#ifdef USE_TREE +#ifdef BITMAP_USE_TREE #if LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS # define BITMAP_GROUPS_MAX BITMAP_GROUPS_1_LEVEL(BITMAP_MAXBITS) @@ -67,20 +72,63 @@ typedef unsigned long bitmap_t; # define BITMAP_GROUPS_MAX BITMAP_GROUPS_3_LEVEL(BITMAP_MAXBITS) #elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 4 # define BITMAP_GROUPS_MAX BITMAP_GROUPS_4_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 5 +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_5_LEVEL(BITMAP_MAXBITS) #else # error "Unsupported bitmap size" #endif -/* Maximum number of levels possible. */ -#define BITMAP_MAX_LEVELS \ - (LG_BITMAP_MAXBITS / LG_SIZEOF_BITMAP) \ - + !!(LG_BITMAP_MAXBITS % LG_SIZEOF_BITMAP) +/* + * Maximum number of levels possible. This could be statically computed based + * on LG_BITMAP_MAXBITS: + * + * #define BITMAP_MAX_LEVELS \ + * (LG_BITMAP_MAXBITS / LG_SIZEOF_BITMAP) \ + * + !!(LG_BITMAP_MAXBITS % LG_SIZEOF_BITMAP) + * + * However, that would not allow the generic BITMAP_INFO_INITIALIZER() macro, so + * instead hardcode BITMAP_MAX_LEVELS to the largest number supported by the + * various cascading macros. The only additional cost this incurs is some + * unused trailing entries in bitmap_info_t structures; the bitmaps themselves + * are not impacted. + */ +#define BITMAP_MAX_LEVELS 5 + +#define BITMAP_INFO_INITIALIZER(nbits) { \ + /* nbits. */ \ + nbits, \ + /* nlevels. */ \ + (BITMAP_GROUPS_L0(nbits) > BITMAP_GROUPS_L1(nbits)) + \ + (BITMAP_GROUPS_L1(nbits) > BITMAP_GROUPS_L2(nbits)) + \ + (BITMAP_GROUPS_L2(nbits) > BITMAP_GROUPS_L3(nbits)) + \ + (BITMAP_GROUPS_L3(nbits) > BITMAP_GROUPS_L4(nbits)) + 1, \ + /* levels. */ \ + { \ + {0}, \ + {BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) + \ + BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L3(nbits) + BITMAP_GROUPS_L2(nbits) + \ + BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L4(nbits) + BITMAP_GROUPS_L3(nbits) + \ + BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) \ + + BITMAP_GROUPS_L0(nbits)} \ + } \ +} + +#else /* BITMAP_USE_TREE */ -#else /* USE_TREE */ +#define BITMAP_GROUPS_MAX BITMAP_BITS2GROUPS(BITMAP_MAXBITS) -#define BITMAP_GROUPS_MAX BITMAP_BITS2GROUPS(BITMAP_MAXBITS) +#define BITMAP_INFO_INITIALIZER(nbits) { \ + /* nbits. */ \ + nbits, \ + /* ngroups. */ \ + BITMAP_BITS2GROUPS(nbits) \ +} -#endif /* USE_TREE */ +#endif /* BITMAP_USE_TREE */ #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ @@ -95,7 +143,7 @@ struct bitmap_info_s { /* Logical number of bits in bitmap (stored at bottom level). */ size_t nbits; -#ifdef USE_TREE +#ifdef BITMAP_USE_TREE /* Number of levels necessary for nbits. */ unsigned nlevels; @@ -104,10 +152,10 @@ struct bitmap_info_s { * bottom to top (e.g. the bottom level is stored in levels[0]). */ bitmap_level_t levels[BITMAP_MAX_LEVELS+1]; -#else /* USE_TREE */ +#else /* BITMAP_USE_TREE */ /* Number of groups necessary for nbits. */ size_t ngroups; -#endif /* USE_TREE */ +#endif /* BITMAP_USE_TREE */ }; #endif /* JEMALLOC_H_STRUCTS */ @@ -134,7 +182,7 @@ void bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); JEMALLOC_INLINE bool bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) { -#ifdef USE_TREE +#ifdef BITMAP_USE_TREE size_t rgoff = binfo->levels[binfo->nlevels].group_offset - 1; bitmap_t rg = bitmap[rgoff]; /* The bitmap is full iff the root group is 0. */ @@ -178,7 +226,7 @@ bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); *gp = g; assert(bitmap_get(bitmap, binfo, bit)); -#ifdef USE_TREE +#ifdef BITMAP_USE_TREE /* Propagate group state transitions up the tree. */ if (g == 0) { unsigned i; @@ -207,7 +255,7 @@ bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) assert(!bitmap_full(bitmap, binfo)); -#ifdef USE_TREE +#ifdef BITMAP_USE_TREE i = binfo->nlevels - 1; g = bitmap[binfo->levels[i].group_offset]; bit = ffs_lu(g) - 1; @@ -247,7 +295,7 @@ bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); *gp = g; assert(!bitmap_get(bitmap, binfo, bit)); -#ifdef USE_TREE +#ifdef BITMAP_USE_TREE /* Propagate group state transitions up the tree. */ if (propagate) { unsigned i; @@ -265,7 +313,7 @@ bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) break; } } -#endif /* USE_TREE */ +#endif /* BITMAP_USE_TREE */ } #endif diff --git a/src/bitmap.c b/src/bitmap.c index ac0f3b38..66554451 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -3,7 +3,7 @@ /******************************************************************************/ -#ifdef USE_TREE +#ifdef BITMAP_USE_TREE void bitmap_info_init(bitmap_info_t *binfo, size_t nbits) @@ -69,7 +69,7 @@ bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo) } } -#else /* USE_TREE */ +#else /* BITMAP_USE_TREE */ void bitmap_info_init(bitmap_info_t *binfo, size_t nbits) @@ -101,7 +101,7 @@ bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo) bitmap[binfo->ngroups - 1] >>= extra; } -#endif /* USE_TREE */ +#endif /* BITMAP_USE_TREE */ size_t bitmap_size(const bitmap_info_t *binfo) diff --git a/test/unit/bitmap.c b/test/unit/bitmap.c index a2dd5463..10d47c76 100644 --- a/test/unit/bitmap.c +++ b/test/unit/bitmap.c @@ -1,152 +1,338 @@ #include "test/jemalloc_test.h" +#define NBITS_TAB \ + NB( 1) \ + NB( 2) \ + NB( 3) \ + NB( 4) \ + NB( 5) \ + NB( 6) \ + NB( 7) \ + NB( 8) \ + NB( 9) \ + NB(10) \ + NB(11) \ + NB(12) \ + NB(13) \ + NB(14) \ + NB(15) \ + NB(16) \ + NB(17) \ + NB(18) \ + NB(19) \ + NB(20) \ + NB(21) \ + NB(22) \ + NB(23) \ + NB(24) \ + NB(25) \ + NB(26) \ + NB(27) \ + NB(28) \ + NB(29) \ + NB(30) \ + NB(31) \ + NB(32) \ + \ + NB(33) \ + NB(34) \ + NB(35) \ + NB(36) \ + NB(37) \ + NB(38) \ + NB(39) \ + NB(40) \ + NB(41) \ + NB(42) \ + NB(43) \ + NB(44) \ + NB(45) \ + NB(46) \ + NB(47) \ + NB(48) \ + NB(49) \ + NB(50) \ + NB(51) \ + NB(52) \ + NB(53) \ + NB(54) \ + NB(55) \ + NB(56) \ + NB(57) \ + NB(58) \ + NB(59) \ + NB(60) \ + NB(61) \ + NB(62) \ + NB(63) \ + NB(64) \ + NB(65) \ + \ + NB(126) \ + NB(127) \ + NB(128) \ + NB(129) \ + NB(130) \ + \ + NB(254) \ + NB(255) \ + NB(256) \ + NB(257) \ + NB(258) \ + \ + NB(510) \ + NB(511) \ + NB(512) \ + NB(513) \ + NB(514) \ + \ + NB(1024) \ + NB(2048) \ + NB(4096) \ + NB(8192) \ + NB(16384) \ + +static void +test_bitmap_initializer_body(const bitmap_info_t *binfo, size_t nbits) +{ + bitmap_info_t binfo_dyn; + bitmap_info_init(&binfo_dyn, nbits); + + assert_zu_eq(bitmap_size(binfo), bitmap_size(&binfo_dyn), + "Unexpected difference between static and dynamic initialization, " + "nbits=%zu", nbits); + assert_zu_eq(binfo->nbits, binfo_dyn.nbits, + "Unexpected difference between static and dynamic initialization, " + "nbits=%zu", nbits); +#ifdef BITMAP_USE_TREE + assert_u_eq(binfo->nlevels, binfo_dyn.nlevels, + "Unexpected difference between static and dynamic initialization, " + "nbits=%zu", nbits); + { + unsigned i; + + for (i = 0; i < binfo->nlevels; i++) { + assert_zu_eq(binfo->levels[i].group_offset, + binfo_dyn.levels[i].group_offset, + "Unexpected difference between static and dynamic " + "initialization, nbits=%zu, level=%u", nbits, i); + } + } +#else + assert_zu_eq(binfo->ngroups, binfo_dyn.ngroups, + "Unexpected difference between static and dynamic initialization"); +#endif +} + +TEST_BEGIN(test_bitmap_initializer) +{ + +#define NB(nbits) { \ + if (nbits <= BITMAP_MAXBITS) { \ + bitmap_info_t binfo = \ + BITMAP_INFO_INITIALIZER(nbits); \ + test_bitmap_initializer_body(&binfo, nbits); \ + } \ + } + NBITS_TAB +#undef NB +} +TEST_END + +static size_t +test_bitmap_size_body(const bitmap_info_t *binfo, size_t nbits, + size_t prev_size) +{ + size_t size = bitmap_size(binfo); + assert_zu_ge(size, (nbits >> 3), + "Bitmap size is smaller than expected"); + assert_zu_ge(size, prev_size, "Bitmap size is smaller than expected"); + return (size); +} + TEST_BEGIN(test_bitmap_size) { - size_t i, prev_size; + size_t nbits, prev_size; prev_size = 0; - for (i = 1; i <= BITMAP_MAXBITS; i++) { + for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) { bitmap_info_t binfo; - size_t size; - - bitmap_info_init(&binfo, i); - size = bitmap_size(&binfo); - assert_true(size >= prev_size, - "Bitmap size is smaller than expected"); - prev_size = size; + bitmap_info_init(&binfo, nbits); + prev_size = test_bitmap_size_body(&binfo, nbits, prev_size); + } +#define NB(nbits) { \ + bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \ + prev_size = test_bitmap_size_body(&binfo, nbits, \ + prev_size); \ } + prev_size = 0; + NBITS_TAB +#undef NB } TEST_END -TEST_BEGIN(test_bitmap_init) +static void +test_bitmap_init_body(const bitmap_info_t *binfo, size_t nbits) { size_t i; + bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo)); + assert_ptr_not_null(bitmap, "Unexpected malloc() failure"); + bitmap_init(bitmap, binfo); + + for (i = 0; i < nbits; i++) { + assert_false(bitmap_get(bitmap, binfo, i), + "Bit should be unset"); + } + free(bitmap); +} - for (i = 1; i <= BITMAP_MAXBITS; i++) { +TEST_BEGIN(test_bitmap_init) +{ + size_t nbits; + + for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) { bitmap_info_t binfo; - bitmap_info_init(&binfo, i); - { - size_t j; - bitmap_t *bitmap = (bitmap_t *)malloc( - bitmap_size(&binfo)); - bitmap_init(bitmap, &binfo); - - for (j = 0; j < i; j++) { - assert_false(bitmap_get(bitmap, &binfo, j), - "Bit should be unset"); - } - free(bitmap); - } + bitmap_info_init(&binfo, nbits); + test_bitmap_init_body(&binfo, nbits); + } +#define NB(nbits) { \ + bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \ + test_bitmap_init_body(&binfo, nbits); \ } + NBITS_TAB +#undef NB } TEST_END -TEST_BEGIN(test_bitmap_set) +static void +test_bitmap_set_body(const bitmap_info_t *binfo, size_t nbits) { size_t i; + bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo)); + assert_ptr_not_null(bitmap, "Unexpected malloc() failure"); + bitmap_init(bitmap, binfo); + + for (i = 0; i < nbits; i++) + bitmap_set(bitmap, binfo, i); + assert_true(bitmap_full(bitmap, binfo), "All bits should be set"); + free(bitmap); +} + +TEST_BEGIN(test_bitmap_set) +{ + size_t nbits; - for (i = 1; i <= BITMAP_MAXBITS; i++) { + for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) { bitmap_info_t binfo; - bitmap_info_init(&binfo, i); - { - size_t j; - bitmap_t *bitmap = (bitmap_t *)malloc( - bitmap_size(&binfo)); - bitmap_init(bitmap, &binfo); - - for (j = 0; j < i; j++) - bitmap_set(bitmap, &binfo, j); - assert_true(bitmap_full(bitmap, &binfo), - "All bits should be set"); - free(bitmap); - } + bitmap_info_init(&binfo, nbits); + test_bitmap_set_body(&binfo, nbits); + } +#define NB(nbits) { \ + bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \ + test_bitmap_set_body(&binfo, nbits); \ } + NBITS_TAB +#undef NB } TEST_END -TEST_BEGIN(test_bitmap_unset) +static void +test_bitmap_unset_body(const bitmap_info_t *binfo, size_t nbits) { size_t i; + bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo)); + assert_ptr_not_null(bitmap, "Unexpected malloc() failure"); + bitmap_init(bitmap, binfo); + + for (i = 0; i < nbits; i++) + bitmap_set(bitmap, binfo, i); + assert_true(bitmap_full(bitmap, binfo), "All bits should be set"); + for (i = 0; i < nbits; i++) + bitmap_unset(bitmap, binfo, i); + for (i = 0; i < nbits; i++) + bitmap_set(bitmap, binfo, i); + assert_true(bitmap_full(bitmap, binfo), "All bits should be set"); + free(bitmap); +} - for (i = 1; i <= BITMAP_MAXBITS; i++) { +TEST_BEGIN(test_bitmap_unset) +{ + size_t nbits; + + for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) { bitmap_info_t binfo; - bitmap_info_init(&binfo, i); - { - size_t j; - bitmap_t *bitmap = (bitmap_t *)malloc( - bitmap_size(&binfo)); - bitmap_init(bitmap, &binfo); - - for (j = 0; j < i; j++) - bitmap_set(bitmap, &binfo, j); - assert_true(bitmap_full(bitmap, &binfo), - "All bits should be set"); - for (j = 0; j < i; j++) - bitmap_unset(bitmap, &binfo, j); - for (j = 0; j < i; j++) - bitmap_set(bitmap, &binfo, j); - assert_true(bitmap_full(bitmap, &binfo), - "All bits should be set"); - free(bitmap); - } + bitmap_info_init(&binfo, nbits); + test_bitmap_unset_body(&binfo, nbits); } +#define NB(nbits) { \ + bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \ + test_bitmap_unset_body(&binfo, nbits); \ + } + NBITS_TAB +#undef NB } TEST_END -TEST_BEGIN(test_bitmap_sfu) +static void +test_bitmap_sfu_body(const bitmap_info_t *binfo, size_t nbits) { size_t i; + bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo)); + assert_ptr_not_null(bitmap, "Unexpected malloc() failure"); + bitmap_init(bitmap, binfo); + + /* Iteratively set bits starting at the beginning. */ + for (i = 0; i < nbits; i++) { + assert_zd_eq(bitmap_sfu(bitmap, binfo), i, + "First unset bit should be just after previous first unset " + "bit"); + } + assert_true(bitmap_full(bitmap, binfo), "All bits should be set"); + + /* + * Iteratively unset bits starting at the end, and verify that + * bitmap_sfu() reaches the unset bits. + */ + for (i = nbits - 1; i < nbits; i--) { /* (nbits..0] */ + bitmap_unset(bitmap, binfo, i); + assert_zd_eq(bitmap_sfu(bitmap, binfo), i, + "First unset bit should the bit previously unset"); + bitmap_unset(bitmap, binfo, i); + } + assert_false(bitmap_get(bitmap, binfo, 0), "Bit should be unset"); + + /* + * Iteratively set bits starting at the beginning, and verify that + * bitmap_sfu() looks past them. + */ + for (i = 1; i < nbits; i++) { + bitmap_set(bitmap, binfo, i - 1); + assert_zd_eq(bitmap_sfu(bitmap, binfo), i, + "First unset bit should be just after the bit previously " + "set"); + bitmap_unset(bitmap, binfo, i); + } + assert_zd_eq(bitmap_sfu(bitmap, binfo), nbits - 1, + "First unset bit should be the last bit"); + assert_true(bitmap_full(bitmap, binfo), "All bits should be set"); + free(bitmap); +} - for (i = 1; i <= BITMAP_MAXBITS; i++) { +TEST_BEGIN(test_bitmap_sfu) +{ + size_t nbits; + + for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) { bitmap_info_t binfo; - bitmap_info_init(&binfo, i); - { - size_t j; - bitmap_t *bitmap = (bitmap_t *)malloc( - bitmap_size(&binfo)); - bitmap_init(bitmap, &binfo); - - /* Iteratively set bits starting at the beginning. */ - for (j = 0; j < i; j++) { - assert_zd_eq(bitmap_sfu(bitmap, &binfo), j, - "First unset bit should be just after " - "previous first unset bit"); - } - assert_true(bitmap_full(bitmap, &binfo), - "All bits should be set"); - - /* - * Iteratively unset bits starting at the end, and - * verify that bitmap_sfu() reaches the unset bits. - */ - for (j = i - 1; j < i; j--) { /* (i..0] */ - bitmap_unset(bitmap, &binfo, j); - assert_zd_eq(bitmap_sfu(bitmap, &binfo), j, - "First unset bit should the bit previously " - "unset"); - bitmap_unset(bitmap, &binfo, j); - } - assert_false(bitmap_get(bitmap, &binfo, 0), - "Bit should be unset"); - - /* - * Iteratively set bits starting at the beginning, and - * verify that bitmap_sfu() looks past them. - */ - for (j = 1; j < i; j++) { - bitmap_set(bitmap, &binfo, j - 1); - assert_zd_eq(bitmap_sfu(bitmap, &binfo), j, - "First unset bit should be just after the " - "bit previously set"); - bitmap_unset(bitmap, &binfo, j); - } - assert_zd_eq(bitmap_sfu(bitmap, &binfo), i - 1, - "First unset bit should be the last bit"); - assert_true(bitmap_full(bitmap, &binfo), - "All bits should be set"); - free(bitmap); - } + bitmap_info_init(&binfo, nbits); + test_bitmap_sfu_body(&binfo, nbits); + } +#define NB(nbits) { \ + bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \ + test_bitmap_sfu_body(&binfo, nbits); \ } + NBITS_TAB +#undef NB } TEST_END @@ -155,6 +341,7 @@ main(void) { return (test( + test_bitmap_initializer, test_bitmap_size, test_bitmap_init, test_bitmap_set, -- GitLab From 627372b459479bf8908470ba25e832c4a9a420db Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 7 Apr 2016 08:04:12 -0400 Subject: [PATCH 007/544] Initialize arena_bin_info at compile time rather than at boot time. This resolves #370. --- include/jemalloc/internal/arena.h | 15 +-- include/jemalloc/internal/size_classes.sh | 63 ++++++++++-- src/arena.c | 112 +++++++--------------- src/jemalloc.c | 4 +- test/unit/junk.c | 2 +- 5 files changed, 100 insertions(+), 96 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 6e71b5f6..866b12fe 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -470,7 +470,7 @@ extern const char *purge_mode_names[]; extern ssize_t opt_lg_dirty_mult; extern ssize_t opt_decay_time; -extern arena_bin_info_t arena_bin_info[NBINS]; +extern const arena_bin_info_t arena_bin_info[NBINS]; extern size_t map_bias; /* Number of arena chunk header pages. */ extern size_t map_misc_offset; @@ -511,13 +511,13 @@ void arena_maybe_purge(tsdn_t *tsdn, arena_t *arena); void arena_reset(tsd_t *tsd, arena_t *arena); void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_bin_t *tbin, szind_t binind, uint64_t prof_accumbytes); -void arena_alloc_junk_small(void *ptr, arena_bin_info_t *bin_info, +void arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, bool zero); #ifdef JEMALLOC_JET -typedef void (arena_dalloc_junk_small_t)(void *, arena_bin_info_t *); +typedef void (arena_dalloc_junk_small_t)(void *, const arena_bin_info_t *); extern arena_dalloc_junk_small_t *arena_dalloc_junk_small; #else -void arena_dalloc_junk_small(void *ptr, arena_bin_info_t *bin_info); +void arena_dalloc_junk_small(void *ptr, const arena_bin_info_t *bin_info); #endif void *arena_malloc_large(tsdn_t *tsdn, arena_t *arena, szind_t ind, bool zero); @@ -634,7 +634,7 @@ bool arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes); bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes); szind_t arena_ptr_small_binind_get(const void *ptr, size_t mapbits); szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin); -size_t arena_run_regind(arena_run_t *run, arena_bin_info_t *bin_info, +size_t arena_run_regind(arena_run_t *run, const arena_bin_info_t *bin_info, const void *ptr); prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr); void arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, @@ -1058,7 +1058,7 @@ arena_ptr_small_binind_get(const void *ptr, size_t mapbits) const arena_run_t *run; arena_bin_t *bin; szind_t run_binind, actual_binind; - arena_bin_info_t *bin_info; + const arena_bin_info_t *bin_info; const arena_chunk_map_misc_t *miscelm; const void *rpages; @@ -1099,7 +1099,8 @@ arena_bin_index(arena_t *arena, arena_bin_t *bin) } JEMALLOC_INLINE size_t -arena_run_regind(arena_run_t *run, arena_bin_info_t *bin_info, const void *ptr) +arena_run_regind(arena_run_t *run, const arena_bin_info_t *bin_info, + const void *ptr) { size_t diff, interval, shift, regind; arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(run); diff --git a/include/jemalloc/internal/size_classes.sh b/include/jemalloc/internal/size_classes.sh index 2b0ca29a..c9b84718 100755 --- a/include/jemalloc/internal/size_classes.sh +++ b/include/jemalloc/internal/size_classes.sh @@ -40,6 +40,36 @@ lg() { done } +run_size() { + lg_p=$1 + lg_grp=$2 + lg_delta=$3 + ndelta=$4 + + pow2 ${lg_p}; p=${pow2_result} + + pow2 ${lg_grp}; grp=${pow2_result} + pow2 ${lg_delta}; delta=${pow2_result} + reg_size=$((${grp} + ${delta}*${ndelta})) + + # Compute smallest run size that is an integer multiple of reg_size. + try_run_size=${p} + try_nregs=$((${try_run_size} / ${reg_size})) + perfect=0 + while [ ${perfect} -eq 0 ] ; do + perfect_run_size=${try_run_size} + perfect_nregs=${try_nregs} + + try_run_size=$((${try_run_size} + ${p})) + try_nregs=$((${try_run_size} / ${reg_size})) + if [ ${perfect_run_size} -eq $((${perfect_nregs} * ${reg_size})) ] ; then + perfect=1 + fi + done + + run_size_pgs=$((${perfect_run_size} / ${p})) +} + size_class() { index=$1 lg_grp=$2 @@ -65,8 +95,10 @@ size_class() { if [ ${lg_size} -lt $((${lg_p} + ${lg_g})) ] ; then bin="yes" + run_size ${lg_p} ${lg_grp} ${lg_delta} ${ndelta}; pgs=${run_size_pgs} else bin="no" + pgs=0 fi if [ ${lg_size} -lt ${lg_kmax} \ -o ${lg_size} -eq ${lg_kmax} -a ${rem} = "no" ] ; then @@ -74,14 +106,15 @@ size_class() { else lg_delta_lookup="no" fi - printf ' SC(%3d, %6d, %8d, %6d, %3s, %2s) \\\n' ${index} ${lg_grp} ${lg_delta} ${ndelta} ${bin} ${lg_delta_lookup} + printf ' SC(%3d, %6d, %8d, %6d, %3s, %3d, %2s) \\\n' ${index} ${lg_grp} ${lg_delta} ${ndelta} ${bin} ${pgs} ${lg_delta_lookup} # Defined upon return: - # - lg_delta_lookup (${lg_delta} or "no") # - bin ("yes" or "no") + # - pgs + # - lg_delta_lookup (${lg_delta} or "no") } sep_line() { - echo " \\" + echo " \\" } size_classes() { @@ -95,12 +128,13 @@ size_classes() { pow2 ${lg_g}; g=${pow2_result} echo "#define SIZE_CLASSES \\" - echo " /* index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup */ \\" + echo " /* index, lg_grp, lg_delta, ndelta, bin, pgs, lg_delta_lookup */ \\" ntbins=0 nlbins=0 lg_tiny_maxclass='"NA"' nbins=0 + slab_maxpgs=0 # Tiny size classes. ndelta=0 @@ -114,6 +148,9 @@ size_classes() { fi if [ ${bin} != "no" ] ; then nbins=$((${index} + 1)) + if [ ${pgs} -gt ${slab_maxpgs} ] ; then + slab_maxpgs=${pgs} + fi fi ntbins=$((${ntbins} + 1)) lg_tiny_maxclass=${lg_grp} # Final written value is correct. @@ -133,11 +170,17 @@ size_classes() { index=$((${index} + 1)) lg_grp=$((${lg_grp} + 1)) lg_delta=$((${lg_delta} + 1)) + if [ ${pgs} -gt ${slab_maxpgs} ] ; then + slab_maxpgs=${pgs} + fi fi while [ ${ndelta} -lt ${g} ] ; do size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax} index=$((${index} + 1)) ndelta=$((${ndelta} + 1)) + if [ ${pgs} -gt ${slab_maxpgs} ] ; then + slab_maxpgs=${pgs} + fi done # All remaining groups. @@ -161,6 +204,9 @@ size_classes() { nbins=$((${index} + 1)) # Final written value is correct: small_maxclass="((((size_t)1) << ${lg_grp}) + (((size_t)${ndelta}) << ${lg_delta}))" + if [ ${pgs} -gt ${slab_maxpgs} ] ; then + slab_maxpgs=${pgs} + fi if [ ${lg_g} -gt 0 ] ; then lg_large_minclass=$((${lg_grp} + 1)) else @@ -186,6 +232,7 @@ size_classes() { # - lg_tiny_maxclass # - lookup_maxclass # - small_maxclass + # - slab_maxpgs # - lg_large_minclass # - huge_maxclass } @@ -200,14 +247,14 @@ cat <> LG_PAGE]) + if (size <= (ZU(SLAB_MAXPGS) << LG_PAGE) && small_run_tab[size >> + LG_PAGE]) return (size); /* @@ -121,12 +133,12 @@ run_quantize_ceil_compute_hard(size_t size) large_pad) + 1) + large_pad); } else large_run_size_next = SIZE_T_MAX; - if (size >= small_maxrun) + if ((size >> LG_PAGE) >= ZU(SLAB_MAXPGS)) return (large_run_size_next); while (true) { size += PAGE; - assert(size <= small_maxrun); + assert(size <= (ZU(SLAB_MAXPGS) << LG_PAGE)); if (small_run_tab[size >> LG_PAGE]) { if (large_run_size_next < size) return (large_run_size_next); @@ -301,7 +313,7 @@ arena_chunk_cache_maybe_remove(arena_t *arena, extent_node_t *node, bool dirty) } JEMALLOC_INLINE_C void * -arena_run_reg_alloc(arena_run_t *run, arena_bin_info_t *bin_info) +arena_run_reg_alloc(arena_run_t *run, const arena_bin_info_t *bin_info) { void *ret; size_t regind; @@ -327,7 +339,7 @@ arena_run_reg_dalloc(arena_run_t *run, void *ptr) size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; size_t mapbits = arena_mapbits_get(chunk, pageind); szind_t binind = arena_ptr_small_binind_get(ptr, mapbits); - arena_bin_info_t *bin_info = &arena_bin_info[binind]; + const arena_bin_info_t *bin_info = &arena_bin_info[binind]; size_t regind = arena_run_regind(run, bin_info, ptr); assert(run->nfree < bin_info->nregs); @@ -1822,7 +1834,7 @@ arena_achunk_prof_reset(tsd_t *tsd, arena_t *arena, arena_chunk_t *chunk) /* Skip small run. */ size_t binind = arena_mapbits_binind_get(chunk, pageind); - arena_bin_info_t *bin_info = + const arena_bin_info_t *bin_info = &arena_bin_info[binind]; npages = bin_info->run_size >> LG_PAGE; } @@ -2045,7 +2057,7 @@ arena_run_size_get(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, assert(size == PAGE || arena_mapbits_large_size_get(chunk, run_ind+(size>>LG_PAGE)-1) == 0); } else { - arena_bin_info_t *bin_info = &arena_bin_info[run->binind]; + const arena_bin_info_t *bin_info = &arena_bin_info[run->binind]; size = bin_info->run_size; } @@ -2241,7 +2253,7 @@ arena_bin_nonfull_run_get(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin) { arena_run_t *run; szind_t binind; - arena_bin_info_t *bin_info; + const arena_bin_info_t *bin_info; /* Look for a usable run. */ run = arena_bin_nonfull_run_tryget(bin); @@ -2291,7 +2303,7 @@ static void * arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin) { szind_t binind; - arena_bin_info_t *bin_info; + const arena_bin_info_t *bin_info; arena_run_t *run; binind = arena_bin_index(arena, bin); @@ -2390,7 +2402,7 @@ arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_bin_t *tbin, } void -arena_alloc_junk_small(void *ptr, arena_bin_info_t *bin_info, bool zero) +arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, bool zero) { if (!zero) @@ -2402,7 +2414,7 @@ arena_alloc_junk_small(void *ptr, arena_bin_info_t *bin_info, bool zero) #define arena_dalloc_junk_small JEMALLOC_N(n_arena_dalloc_junk_small) #endif void -arena_dalloc_junk_small(void *ptr, arena_bin_info_t *bin_info) +arena_dalloc_junk_small(void *ptr, const arena_bin_info_t *bin_info) { memset(ptr, JEMALLOC_FREE_JUNK, bin_info->reg_size); @@ -2706,7 +2718,7 @@ arena_dissociate_bin_run(arena_chunk_t *chunk, arena_run_t *run, else { szind_t binind = arena_bin_index(extent_node_arena_get( &chunk->node), bin); - arena_bin_info_t *bin_info = &arena_bin_info[binind]; + const arena_bin_info_t *bin_info = &arena_bin_info[binind]; /* * The following block's conditional is necessary because if the @@ -2768,7 +2780,7 @@ arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, size_t pageind, rpages_ind; arena_run_t *run; arena_bin_t *bin; - arena_bin_info_t *bin_info; + const arena_bin_info_t *bin_info; szind_t binind; pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; @@ -3483,81 +3495,24 @@ arena_new(tsdn_t *tsdn, unsigned ind) return (arena); } -/* - * Calculate bin_info->run_size such that it meets the following constraints: - * - * *) bin_info->run_size <= arena_maxrun - * *) bin_info->nregs <= RUN_MAXREGS - * - * bin_info->nregs is also calculated here, since these settings are all - * interdependent. - */ -static void -bin_info_run_size_calc(arena_bin_info_t *bin_info) -{ - size_t try_run_size, perfect_run_size, actual_run_size; - uint32_t try_nregs, perfect_nregs, actual_nregs; - - /* Compute smallest run size that is an integer multiple of reg_size. */ - try_run_size = PAGE; - try_nregs = (uint32_t)(try_run_size / bin_info->reg_size); - do { - perfect_run_size = try_run_size; - perfect_nregs = try_nregs; - - try_run_size += PAGE; - try_nregs = (uint32_t)(try_run_size / bin_info->reg_size); - } while (perfect_run_size != perfect_nregs * bin_info->reg_size); - assert(perfect_run_size <= arena_maxrun); - assert(perfect_nregs <= RUN_MAXREGS); - - actual_run_size = perfect_run_size; - actual_nregs = (uint32_t)((actual_run_size) / bin_info->reg_size); - - /* Copy final settings. */ - bin_info->run_size = actual_run_size; - bin_info->nregs = actual_nregs; - - if (actual_run_size > small_maxrun) - small_maxrun = actual_run_size; -} - -static void -bin_info_init(void) -{ - arena_bin_info_t *bin_info; - -#define BIN_INFO_INIT_bin_yes(index, size) \ - bin_info = &arena_bin_info[index]; \ - bin_info->reg_size = size; \ - bin_info_run_size_calc(bin_info); \ - bitmap_info_init(&bin_info->bitmap_info, bin_info->nregs); -#define BIN_INFO_INIT_bin_no(index, size) -#define SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \ - BIN_INFO_INIT_bin_##bin(index, (ZU(1)<> - LG_PAGE)); + small_run_tab = (bool *)base_alloc(NULL, sizeof(bool) * SLAB_MAXPGS); if (small_run_tab == NULL) return (true); #define TAB_INIT_bin_yes(index, size) { \ - arena_bin_info_t *bin_info = &arena_bin_info[index]; \ + const arena_bin_info_t *bin_info = \ + &arena_bin_info[index]; \ small_run_tab[bin_info->run_size >> LG_PAGE] = true; \ } #define TAB_INIT_bin_no(index, size) -#define SC(index, lg_grp, lg_delta, ndelta, bin, lg_delta_lookup) \ +#define SC(index, lg_grp, lg_delta, ndelta, bin, run_size, \ + lg_delta_lookup) \ TAB_INIT_bin_##bin(index, (ZU(1)< Date: Sun, 17 Apr 2016 16:16:11 -0700 Subject: [PATCH 008/544] Implement pz2ind(), pind2sz(), and psz2u(). These compute size classes and indices similarly to size2index(), index2size() and s2u(), respectively, but using the subset of size classes that are multiples of the page size. Note that pszind_t and szind_t are not interchangeable. --- .../jemalloc/internal/jemalloc_internal.h.in | 80 ++++++++++++++-- include/jemalloc/internal/private_symbols.txt | 3 + include/jemalloc/internal/size_classes.sh | 43 ++++++++- src/arena.c | 5 +- src/jemalloc.c | 4 +- test/unit/size_classes.c | 94 ++++++++++++++++--- 6 files changed, 203 insertions(+), 26 deletions(-) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index a8c476d9..224ceddc 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -178,6 +178,9 @@ static const bool config_cache_oblivious = #include "jemalloc/internal/jemalloc_internal_macros.h" +/* Page size index type. */ +typedef unsigned pszind_t; + /* Size class index type. */ typedef unsigned szind_t; @@ -525,6 +528,9 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/huge.h" #ifndef JEMALLOC_ENABLE_INLINE +pszind_t psz2ind(size_t psz); +size_t pind2sz(pszind_t pind); +size_t psz2u(size_t psz); szind_t size2index_compute(size_t size); szind_t size2index_lookup(size_t size); szind_t size2index(size_t size); @@ -545,10 +551,74 @@ ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) +JEMALLOC_INLINE pszind_t +psz2ind(size_t psz) +{ + + if (unlikely(psz > HUGE_MAXCLASS)) + return (NPSIZES); + { + pszind_t x = lg_floor((psz<<1)-1); + pszind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_PAGE) ? 0 : x - + (LG_SIZE_CLASS_GROUP + LG_PAGE); + pszind_t grp = shift << LG_SIZE_CLASS_GROUP; + + pszind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? + LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1; + + size_t delta_inverse_mask = ZI(-1) << lg_delta; + pszind_t mod = ((((psz-1) & delta_inverse_mask) >> lg_delta)) & + ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); + + pszind_t ind = grp + mod; + return (ind); + } +} + +JEMALLOC_INLINE size_t +pind2sz(pszind_t pind) +{ + + { + size_t grp = pind >> LG_SIZE_CLASS_GROUP; + size_t mod = pind & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); + + size_t grp_size_mask = ~((!!grp)-1); + size_t grp_size = ((ZU(1) << (LG_PAGE + + (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask; + + size_t shift = (grp == 0) ? 1 : grp; + size_t lg_delta = shift + (LG_PAGE-1); + size_t mod_size = (mod+1) << lg_delta; + + size_t sz = grp_size + mod_size; + return (sz); + } +} + +JEMALLOC_INLINE size_t +psz2u(size_t psz) +{ + + if (unlikely(psz > HUGE_MAXCLASS)) + return (0); + { + size_t x = lg_floor((psz<<1)-1); + size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? + LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1; + size_t delta = ZU(1) << lg_delta; + size_t delta_mask = delta - 1; + size_t usize = (psz + delta_mask) & ~delta_mask; + return (usize); + } +} + JEMALLOC_INLINE szind_t size2index_compute(size_t size) { + if (unlikely(size > HUGE_MAXCLASS)) + return (NSIZES); #if (NTBINS != 0) if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { szind_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; @@ -557,9 +627,7 @@ size2index_compute(size_t size) } #endif { - szind_t x = unlikely(ZI(size) < 0) ? ((size<<1) ? - (ZU(1)<<(LG_SIZEOF_PTR+3)) : ((ZU(1)<<(LG_SIZEOF_PTR+3))-1)) - : lg_floor((size<<1)-1); + szind_t x = lg_floor((size<<1)-1); szind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM) ? 0 : x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM); szind_t grp = shift << LG_SIZE_CLASS_GROUP; @@ -645,6 +713,8 @@ JEMALLOC_ALWAYS_INLINE size_t s2u_compute(size_t size) { + if (unlikely(size > HUGE_MAXCLASS)) + return (0); #if (NTBINS > 0) if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { size_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; @@ -654,9 +724,7 @@ s2u_compute(size_t size) } #endif { - size_t x = unlikely(ZI(size) < 0) ? ((size<<1) ? - (ZU(1)<<(LG_SIZEOF_PTR+3)) : ((ZU(1)<<(LG_SIZEOF_PTR+3))-1)) - : lg_floor((size<<1)-1); + size_t x = lg_floor((size<<1)-1); size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; size_t delta = ZU(1) << lg_delta; diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 89933426..cbafc2b1 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -393,6 +393,7 @@ pages_map pages_purge pages_trim pages_unmap +pind2sz pow2_ceil_u32 pow2_ceil_u64 pow2_ceil_zu @@ -446,6 +447,8 @@ prof_thread_active_init_set prof_thread_active_set prof_thread_name_get prof_thread_name_set +psz2ind +psz2u purge_mode_names register_zone rtree_child_read diff --git a/include/jemalloc/internal/size_classes.sh b/include/jemalloc/internal/size_classes.sh index c9b84718..ecee1a0a 100755 --- a/include/jemalloc/internal/size_classes.sh +++ b/include/jemalloc/internal/size_classes.sh @@ -78,6 +78,21 @@ size_class() { lg_p=$5 lg_kmax=$6 + if [ ${lg_delta} -ge ${lg_p} ] ; then + psz="yes" + else + pow2 ${lg_p}; p=${pow2_result} + pow2 ${lg_grp}; grp=${pow2_result} + pow2 ${lg_delta}; delta=${pow2_result} + sz=$((${grp} + ${delta} * ${ndelta})) + npgs=$((${sz} / ${p})) + if [ ${sz} -eq $((${npgs} * ${p})) ] ; then + psz="yes" + else + psz="no" + fi + fi + lg ${ndelta}; lg_ndelta=${lg_result}; pow2 ${lg_ndelta} if [ ${pow2_result} -lt ${ndelta} ] ; then rem="yes" @@ -106,15 +121,16 @@ size_class() { else lg_delta_lookup="no" fi - printf ' SC(%3d, %6d, %8d, %6d, %3s, %3d, %2s) \\\n' ${index} ${lg_grp} ${lg_delta} ${ndelta} ${bin} ${pgs} ${lg_delta_lookup} + printf ' SC(%3d, %6d, %8d, %6d, %3s, %3s, %3d, %2s) \\\n' ${index} ${lg_grp} ${lg_delta} ${ndelta} ${psz} ${bin} ${pgs} ${lg_delta_lookup} # Defined upon return: + # - psz ("yes" or "no") # - bin ("yes" or "no") # - pgs # - lg_delta_lookup (${lg_delta} or "no") } sep_line() { - echo " \\" + echo " \\" } size_classes() { @@ -128,12 +144,13 @@ size_classes() { pow2 ${lg_g}; g=${pow2_result} echo "#define SIZE_CLASSES \\" - echo " /* index, lg_grp, lg_delta, ndelta, bin, pgs, lg_delta_lookup */ \\" + echo " /* index, lg_grp, lg_delta, ndelta, psz, bin, pgs, lg_delta_lookup */ \\" ntbins=0 nlbins=0 lg_tiny_maxclass='"NA"' nbins=0 + npsizes=0 slab_maxpgs=0 # Tiny size classes. @@ -146,6 +163,9 @@ size_classes() { if [ ${lg_delta_lookup} != "no" ] ; then nlbins=$((${index} + 1)) fi + if [ ${psz} = "yes" ] ; then + npsizes=$((${npsizes} + 1)) + fi if [ ${bin} != "no" ] ; then nbins=$((${index} + 1)) if [ ${pgs} -gt ${slab_maxpgs} ] ; then @@ -170,6 +190,9 @@ size_classes() { index=$((${index} + 1)) lg_grp=$((${lg_grp} + 1)) lg_delta=$((${lg_delta} + 1)) + if [ ${psz} = "yes" ] ; then + npsizes=$((${npsizes} + 1)) + fi if [ ${pgs} -gt ${slab_maxpgs} ] ; then slab_maxpgs=${pgs} fi @@ -178,6 +201,9 @@ size_classes() { size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax} index=$((${index} + 1)) ndelta=$((${ndelta} + 1)) + if [ ${psz} = "yes" ] ; then + npsizes=$((${npsizes} + 1)) + fi if [ ${pgs} -gt ${slab_maxpgs} ] ; then slab_maxpgs=${pgs} fi @@ -200,6 +226,9 @@ size_classes() { # Final written value is correct: lookup_maxclass="((((size_t)1) << ${lg_grp}) + (((size_t)${ndelta}) << ${lg_delta}))" fi + if [ ${psz} = "yes" ] ; then + npsizes=$((${npsizes} + 1)) + fi if [ ${bin} != "no" ] ; then nbins=$((${index} + 1)) # Final written value is correct: @@ -229,6 +258,7 @@ size_classes() { # - nlbins # - nbins # - nsizes + # - npsizes # - lg_tiny_maxclass # - lookup_maxclass # - small_maxclass @@ -247,12 +277,13 @@ cat <run_size >> LG_PAGE] = true; \ } #define TAB_INIT_bin_no(index, size) -#define SC(index, lg_grp, lg_delta, ndelta, bin, run_size, \ +#define SC(index, lg_grp, lg_delta, ndelta, psz, bin, run_size, \ lg_delta_lookup) \ TAB_INIT_bin_##bin(index, (ZU(1)<" + " size_class=%zu --> pind=%u --> size_class=%zu", pind, + size_class, psz2ind(size_class), + pind2sz(psz2ind(size_class))); + assert_zu_eq(size_class, pind2sz(psz2ind(size_class)), + "pind2sz() does not reverse psz2ind(): pind=%u -->" + " size_class=%zu --> pind=%u --> size_class=%zu", pind, + size_class, psz2ind(size_class), + pind2sz(psz2ind(size_class))); + + assert_u_eq(pind+1, psz2ind(size_class+1), + "Next size_class does not round up properly"); + + assert_zu_eq(size_class, (pind > 0) ? + psz2u(pind2sz(pind-1)+1) : psz2u(1), + "psz2u() does not round up to size class"); + assert_zu_eq(size_class, psz2u(size_class-1), + "psz2u() does not round up to size class"); + assert_zu_eq(size_class, psz2u(size_class), + "psz2u() does not compute same size class"); + assert_zu_eq(psz2u(size_class+1), pind2sz(pind+1), + "psz2u() does not round up to next size class"); + } + + assert_u_eq(pind, psz2ind(pind2sz(pind)), + "psz2ind() does not reverse pind2sz()"); + assert_zu_eq(max_size_class, pind2sz(psz2ind(max_size_class)), + "pind2sz() does not reverse psz2ind()"); + + assert_zu_eq(size_class, psz2u(pind2sz(pind-1)+1), + "psz2u() does not round up to size class"); + assert_zu_eq(size_class, psz2u(size_class-1), + "psz2u() does not round up to size class"); + assert_zu_eq(size_class, psz2u(size_class), + "psz2u() does not compute same size class"); +} +TEST_END + TEST_BEGIN(test_overflow) { size_t max_size_class; max_size_class = get_max_size_class(); - assert_u_ge(size2index(max_size_class+1), NSIZES, - "size2index() should return >= NSIZES on overflow"); - assert_u_ge(size2index(ZU(PTRDIFF_MAX)+1), NSIZES, - "size2index() should return >= NSIZES on overflow"); - assert_u_ge(size2index(SIZE_T_MAX), NSIZES, - "size2index() should return >= NSIZES on overflow"); - - assert_zu_gt(s2u(max_size_class+1), HUGE_MAXCLASS, - "s2u() should return > HUGE_MAXCLASS for unsupported size"); - assert_zu_gt(s2u(ZU(PTRDIFF_MAX)+1), HUGE_MAXCLASS, - "s2u() should return > HUGE_MAXCLASS for unsupported size"); + assert_u_eq(size2index(max_size_class+1), NSIZES, + "size2index() should return NSIZES on overflow"); + assert_u_eq(size2index(ZU(PTRDIFF_MAX)+1), NSIZES, + "size2index() should return NSIZES on overflow"); + assert_u_eq(size2index(SIZE_T_MAX), NSIZES, + "size2index() should return NSIZES on overflow"); + + assert_zu_eq(s2u(max_size_class+1), 0, + "s2u() should return 0 for unsupported size"); + assert_zu_eq(s2u(ZU(PTRDIFF_MAX)+1), 0, + "s2u() should return 0 for unsupported size"); assert_zu_eq(s2u(SIZE_T_MAX), 0, "s2u() should return 0 on overflow"); + + assert_u_eq(psz2ind(max_size_class+1), NPSIZES, + "psz2ind() should return NPSIZES on overflow"); + assert_u_eq(psz2ind(ZU(PTRDIFF_MAX)+1), NPSIZES, + "psz2ind() should return NPSIZES on overflow"); + assert_u_eq(psz2ind(SIZE_T_MAX), NPSIZES, + "psz2ind() should return NPSIZES on overflow"); + + assert_zu_eq(psz2u(max_size_class+1), 0, + "psz2u() should return 0 for unsupported size"); + assert_zu_eq(psz2u(ZU(PTRDIFF_MAX)+1), 0, + "psz2u() should return 0 for unsupported size"); + assert_zu_eq(psz2u(SIZE_T_MAX), 0, + "psz2u() should return 0 on overflow"); } TEST_END @@ -108,5 +179,6 @@ main(void) return (test( test_size_classes, + test_psize_classes, test_overflow)); } -- GitLab From 7bb00ae9d656b3d3ea9a01777cf1a13ab97f2430 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 8 Apr 2016 14:17:57 -0700 Subject: [PATCH 009/544] Refactor runs_avail. Use pszind_t size classes rather than szind_t size classes, and always reserve space for NPSIZES elements. This removes unused heaps that are not multiples of the page size, and adds (currently) unused heaps for all huge size classes, with the immediate benefit that the size of arena_t allocations is constant (no longer dependent on chunk size). --- include/jemalloc/internal/arena.h | 9 +-- .../jemalloc/internal/jemalloc_internal.h.in | 27 +++++++- include/jemalloc/internal/private_symbols.txt | 3 +- include/jemalloc/internal/size_classes.sh | 15 +++-- src/arena.c | 61 +++++++------------ src/jemalloc.c | 17 +++++- test/unit/run_quantize.c | 2 +- 7 files changed, 81 insertions(+), 53 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 866b12fe..bb65c7a9 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -441,10 +441,12 @@ struct arena_s { arena_bin_t bins[NBINS]; /* - * Quantized address-ordered heaps of this arena's available runs. The - * heaps are used for first-best-fit run allocation. + * Size-segregated address-ordered heaps of this arena's available runs, + * used for first-best-fit run allocation. Runs are quantized, i.e. + * they reside in the last heap which corresponds to a size class less + * than or equal to the run size. */ - arena_run_heap_t runs_avail[1]; /* Dynamically sized. */ + arena_run_heap_t runs_avail[NPSIZES]; }; /* Used in conjunction with tsd for fast arena-related context lookup. */ @@ -476,7 +478,6 @@ extern size_t map_bias; /* Number of arena chunk header pages. */ extern size_t map_misc_offset; extern size_t arena_maxrun; /* Max run size for arenas. */ extern size_t large_maxclass; /* Max large size class. */ -extern size_t run_quantize_max; /* Max run_quantize_*() input. */ extern unsigned nlclasses; /* Number of large size classes. */ extern unsigned nhclasses; /* Number of huge size classes. */ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 224ceddc..eabb9ce3 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -443,11 +443,16 @@ extern unsigned narenas_auto; */ extern arena_t **arenas; +/* + * pind2sz_tab encodes the same information as could be computed by + * pind2sz_compute(). + */ +extern size_t const pind2sz_tab[NPSIZES]; /* * index2size_tab encodes the same information as could be computed (at * unacceptable cost in some code paths) by index2size_compute(). */ -extern size_t const index2size_tab[NSIZES+1]; +extern size_t const index2size_tab[NSIZES]; /* * size2index_tab is a compact lookup table that rounds request sizes up to * size classes. In order to reduce cache footprint, the table is compressed, @@ -529,6 +534,8 @@ void jemalloc_postfork_child(void); #ifndef JEMALLOC_ENABLE_INLINE pszind_t psz2ind(size_t psz); +size_t pind2sz_compute(pszind_t pind); +size_t pind2sz_lookup(pszind_t pind); size_t pind2sz(pszind_t pind); size_t psz2u(size_t psz); szind_t size2index_compute(size_t size); @@ -576,7 +583,7 @@ psz2ind(size_t psz) } JEMALLOC_INLINE size_t -pind2sz(pszind_t pind) +pind2sz_compute(pszind_t pind) { { @@ -596,6 +603,22 @@ pind2sz(pszind_t pind) } } +JEMALLOC_INLINE size_t +pind2sz_lookup(pszind_t pind) +{ + size_t ret = (size_t)pind2sz_tab[pind]; + assert(ret == pind2sz_compute(pind)); + return (ret); +} + +JEMALLOC_INLINE size_t +pind2sz(pszind_t pind) +{ + + assert(pind < NPSIZES); + return (pind2sz_lookup(pind)); +} + JEMALLOC_INLINE size_t psz2u(size_t psz) { diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index cbafc2b1..e046c3b1 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -394,6 +394,8 @@ pages_purge pages_trim pages_unmap pind2sz +pind2sz_compute +pind2sz_lookup pow2_ceil_u32 pow2_ceil_u64 pow2_ceil_zu @@ -468,7 +470,6 @@ rtree_val_read rtree_val_write run_quantize_ceil run_quantize_floor -run_quantize_max s2u s2u_compute s2u_lookup diff --git a/include/jemalloc/internal/size_classes.sh b/include/jemalloc/internal/size_classes.sh index ecee1a0a..d1b1db1e 100755 --- a/include/jemalloc/internal/size_classes.sh +++ b/include/jemalloc/internal/size_classes.sh @@ -40,6 +40,16 @@ lg() { done } +reg_size_compute() { + lg_grp=$1 + lg_delta=$2 + ndelta=$3 + + pow2 ${lg_grp}; grp=${pow2_result} + pow2 ${lg_delta}; delta=${pow2_result} + reg_size=$((${grp} + ${delta}*${ndelta})) +} + run_size() { lg_p=$1 lg_grp=$2 @@ -47,10 +57,7 @@ run_size() { ndelta=$4 pow2 ${lg_p}; p=${pow2_result} - - pow2 ${lg_grp}; grp=${pow2_result} - pow2 ${lg_delta}; delta=${pow2_result} - reg_size=$((${grp} + ${delta}*${ndelta})) + reg_size_compute ${lg_grp} ${lg_delta} ${ndelta} # Compute smallest run size that is an integer multiple of reg_size. try_run_size=${p} diff --git a/src/arena.c b/src/arena.c index ff119ba6..a0fd2ce6 100644 --- a/src/arena.c +++ b/src/arena.c @@ -34,14 +34,11 @@ size_t map_bias; size_t map_misc_offset; size_t arena_maxrun; /* Max run size for arenas. */ size_t large_maxclass; /* Max large size class. */ -size_t run_quantize_max; /* Max run_quantize_*() input. */ static bool *small_run_tab; /* Valid small run page multiples. */ static size_t *run_quantize_floor_tab; /* run_quantize_floor() memoization. */ static size_t *run_quantize_ceil_tab; /* run_quantize_ceil() memoization. */ unsigned nlclasses; /* Number of large size classes. */ unsigned nhclasses; /* Number of huge size classes. */ -static szind_t runs_avail_bias; /* Size index for first runs_avail tree. */ -static szind_t runs_avail_nclasses; /* Number of runs_avail trees. */ /******************************************************************************/ /* @@ -177,7 +174,7 @@ run_quantize_floor(size_t size) size_t ret; assert(size > 0); - assert(size <= run_quantize_max); + assert(size <= HUGE_MAXCLASS); assert((size & PAGE_MASK) == 0); ret = run_quantize_floor_tab[(size >> LG_PAGE) - 1]; @@ -200,7 +197,7 @@ run_quantize_ceil(size_t size) size_t ret; assert(size > 0); - assert(size <= run_quantize_max); + assert(size <= HUGE_MAXCLASS); assert((size & PAGE_MASK) == 0); ret = run_quantize_ceil_tab[(size >> LG_PAGE) - 1]; @@ -213,25 +210,15 @@ run_quantize_ceil(size_t size) run_quantize_t *run_quantize_ceil = JEMALLOC_N(n_run_quantize_ceil); #endif -static arena_run_heap_t * -arena_runs_avail_get(arena_t *arena, szind_t ind) -{ - - assert(ind >= runs_avail_bias); - assert(ind - runs_avail_bias < runs_avail_nclasses); - - return (&arena->runs_avail[ind - runs_avail_bias]); -} - static void arena_avail_insert(arena_t *arena, arena_chunk_t *chunk, size_t pageind, size_t npages) { - szind_t ind = size2index(run_quantize_floor(arena_miscelm_size_get( + pszind_t pind = psz2ind(run_quantize_floor(arena_miscelm_size_get( arena_miscelm_get_const(chunk, pageind)))); assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >> LG_PAGE)); - arena_run_heap_insert(arena_runs_avail_get(arena, ind), + arena_run_heap_insert(&arena->runs_avail[pind], arena_miscelm_get_mutable(chunk, pageind)); } @@ -239,11 +226,11 @@ static void arena_avail_remove(arena_t *arena, arena_chunk_t *chunk, size_t pageind, size_t npages) { - szind_t ind = size2index(run_quantize_floor(arena_miscelm_size_get( + pszind_t pind = psz2ind(run_quantize_floor(arena_miscelm_size_get( arena_miscelm_get_const(chunk, pageind)))); assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >> LG_PAGE)); - arena_run_heap_remove(arena_runs_avail_get(arena, ind), + arena_run_heap_remove(&arena->runs_avail[pind], arena_miscelm_get_mutable(chunk, pageind)); } @@ -1088,12 +1075,13 @@ arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, void *chunk, static arena_run_t * arena_run_first_best_fit(arena_t *arena, size_t size) { - szind_t ind, i; + pszind_t pind, i; - ind = size2index(run_quantize_ceil(size)); - for (i = ind; i < runs_avail_nclasses + runs_avail_bias; i++) { + pind = psz2ind(run_quantize_ceil(size)); + + for (i = pind; pind2sz(i) <= large_maxclass; i++) { arena_chunk_map_misc_t *miscelm = arena_run_heap_first( - arena_runs_avail_get(arena, i)); + &arena->runs_avail[i]); if (miscelm != NULL) return (&miscelm->run); } @@ -1946,7 +1934,8 @@ arena_reset(tsd_t *tsd, arena_t *arena) assert(!arena->purging); arena->nactive = 0; - for(i = 0; i < runs_avail_nclasses; i++) + for (i = 0; i < sizeof(arena->runs_avail) / sizeof(arena_run_heap_t); + i++) arena_run_heap_new(&arena->runs_avail[i]); malloc_mutex_unlock(tsd_tsdn(tsd), &arena->lock); @@ -3388,23 +3377,19 @@ arena_t * arena_new(tsdn_t *tsdn, unsigned ind) { arena_t *arena; - size_t arena_size; unsigned i; - /* Compute arena size to incorporate sufficient runs_avail elements. */ - arena_size = offsetof(arena_t, runs_avail) + (sizeof(arena_run_heap_t) * - runs_avail_nclasses); /* * Allocate arena, arena->lstats, and arena->hstats contiguously, mainly * because there is no way to clean up if base_alloc() OOMs. */ if (config_stats) { arena = (arena_t *)base_alloc(tsdn, - CACHELINE_CEILING(arena_size) + QUANTUM_CEILING(nlclasses * - sizeof(malloc_large_stats_t) + nhclasses) * - sizeof(malloc_huge_stats_t)); + CACHELINE_CEILING(sizeof(arena_t)) + + QUANTUM_CEILING((nlclasses * sizeof(malloc_large_stats_t)) + + (nhclasses * sizeof(malloc_huge_stats_t)))); } else - arena = (arena_t *)base_alloc(tsdn, arena_size); + arena = (arena_t *)base_alloc(tsdn, sizeof(arena_t)); if (arena == NULL) return (NULL); @@ -3416,11 +3401,11 @@ arena_new(tsdn_t *tsdn, unsigned ind) if (config_stats) { memset(&arena->stats, 0, sizeof(arena_stats_t)); arena->stats.lstats = (malloc_large_stats_t *)((uintptr_t)arena - + CACHELINE_CEILING(arena_size)); + + CACHELINE_CEILING(sizeof(arena_t))); memset(arena->stats.lstats, 0, nlclasses * sizeof(malloc_large_stats_t)); arena->stats.hstats = (malloc_huge_stats_t *)((uintptr_t)arena - + CACHELINE_CEILING(arena_size) + + + CACHELINE_CEILING(sizeof(arena_t)) + QUANTUM_CEILING(nlclasses * sizeof(malloc_large_stats_t))); memset(arena->stats.hstats, 0, nhclasses * sizeof(malloc_huge_stats_t)); @@ -3454,8 +3439,10 @@ arena_new(tsdn_t *tsdn, unsigned ind) arena->nactive = 0; arena->ndirty = 0; - for(i = 0; i < runs_avail_nclasses; i++) + for (i = 0; i < sizeof(arena->runs_avail) / sizeof(arena_run_heap_t); + i++) arena_run_heap_new(&arena->runs_avail[i]); + qr_new(&arena->runs_dirty, rd_link); qr_new(&arena->chunks_cache, cc_link); @@ -3526,6 +3513,7 @@ small_run_size_init(void) static bool run_quantize_init(void) { + size_t run_quantize_max; unsigned i; run_quantize_max = chunksize + large_pad; @@ -3604,9 +3592,6 @@ arena_boot(void) if (run_quantize_init()) return (true); - runs_avail_bias = size2index(PAGE); - runs_avail_nclasses = size2index(run_quantize_max)+1 - runs_avail_bias; - return (false); } diff --git a/src/jemalloc.c b/src/jemalloc.c index b907d9e5..849e9418 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -78,14 +78,25 @@ enum { }; static uint8_t malloc_slow_flags; -/* Last entry for overflow detection only. */ JEMALLOC_ALIGNED(CACHELINE) -const size_t index2size_tab[NSIZES+1] = { +const size_t pind2sz_tab[NPSIZES] = { +#define PSZ_yes(lg_grp, ndelta, lg_delta) \ + (((ZU(1)<> LG_PAGE; i++) { + for (i = 1; i <= large_maxclass >> LG_PAGE; i++) { size_t run_size, floor, ceil; run_size = i << LG_PAGE; -- GitLab From 3aea827f5e7d07ce156476bba8a843640969de51 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 8 Apr 2016 14:16:19 -0700 Subject: [PATCH 010/544] Simplify run quantization. --- include/jemalloc/internal/arena.h | 2 +- include/jemalloc/internal/size_classes.sh | 16 -- src/arena.c | 179 ++++------------------ src/jemalloc.c | 3 +- 4 files changed, 31 insertions(+), 169 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index bb65c7a9..11863fc7 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -569,7 +569,7 @@ unsigned arena_nthreads_get(arena_t *arena, bool internal); void arena_nthreads_inc(arena_t *arena, bool internal); void arena_nthreads_dec(arena_t *arena, bool internal); arena_t *arena_new(tsdn_t *tsdn, unsigned ind); -bool arena_boot(void); +void arena_boot(void); void arena_prefork0(tsdn_t *tsdn, arena_t *arena); void arena_prefork1(tsdn_t *tsdn, arena_t *arena); void arena_prefork2(tsdn_t *tsdn, arena_t *arena); diff --git a/include/jemalloc/internal/size_classes.sh b/include/jemalloc/internal/size_classes.sh index d1b1db1e..440953ad 100755 --- a/include/jemalloc/internal/size_classes.sh +++ b/include/jemalloc/internal/size_classes.sh @@ -158,7 +158,6 @@ size_classes() { lg_tiny_maxclass='"NA"' nbins=0 npsizes=0 - slab_maxpgs=0 # Tiny size classes. ndelta=0 @@ -175,9 +174,6 @@ size_classes() { fi if [ ${bin} != "no" ] ; then nbins=$((${index} + 1)) - if [ ${pgs} -gt ${slab_maxpgs} ] ; then - slab_maxpgs=${pgs} - fi fi ntbins=$((${ntbins} + 1)) lg_tiny_maxclass=${lg_grp} # Final written value is correct. @@ -200,9 +196,6 @@ size_classes() { if [ ${psz} = "yes" ] ; then npsizes=$((${npsizes} + 1)) fi - if [ ${pgs} -gt ${slab_maxpgs} ] ; then - slab_maxpgs=${pgs} - fi fi while [ ${ndelta} -lt ${g} ] ; do size_class ${index} ${lg_grp} ${lg_delta} ${ndelta} ${lg_p} ${lg_kmax} @@ -211,9 +204,6 @@ size_classes() { if [ ${psz} = "yes" ] ; then npsizes=$((${npsizes} + 1)) fi - if [ ${pgs} -gt ${slab_maxpgs} ] ; then - slab_maxpgs=${pgs} - fi done # All remaining groups. @@ -240,9 +230,6 @@ size_classes() { nbins=$((${index} + 1)) # Final written value is correct: small_maxclass="((((size_t)1) << ${lg_grp}) + (((size_t)${ndelta}) << ${lg_delta}))" - if [ ${pgs} -gt ${slab_maxpgs} ] ; then - slab_maxpgs=${pgs} - fi if [ ${lg_g} -gt 0 ] ; then lg_large_minclass=$((${lg_grp} + 1)) else @@ -269,7 +256,6 @@ size_classes() { # - lg_tiny_maxclass # - lookup_maxclass # - small_maxclass - # - slab_maxpgs # - lg_large_minclass # - huge_maxclass } @@ -303,7 +289,6 @@ cat <> - LG_PAGE]) - return (size); - - /* - * Round down to the nearest run size that can actually be requested - * during normal large allocation. Add large_pad so that cache index - * randomization can offset the allocation from the page boundary. - */ - qsize = index2size(size2index(size - large_pad + 1) - 1) + large_pad; - if (qsize <= SMALL_MAXCLASS + large_pad) - return (run_quantize_floor_compute(size - large_pad)); - assert(qsize <= size); - return (qsize); -} - -static size_t -run_quantize_ceil_compute_hard(size_t size) -{ - size_t large_run_size_next; - - assert(size != 0); - assert(size == PAGE_CEILING(size)); - - /* - * Return the next quantized size greater than the input size. - * Quantized sizes comprise the union of run sizes that back small - * region runs, and run sizes that back large regions with no explicit - * alignment constraints. - */ - - if (size > SMALL_MAXCLASS) { - large_run_size_next = PAGE_CEILING(index2size(size2index(size - - large_pad) + 1) + large_pad); - } else - large_run_size_next = SIZE_T_MAX; - if ((size >> LG_PAGE) >= ZU(SLAB_MAXPGS)) - return (large_run_size_next); - - while (true) { - size += PAGE; - assert(size <= (ZU(SLAB_MAXPGS) << LG_PAGE)); - if (small_run_tab[size >> LG_PAGE]) { - if (large_run_size_next < size) - return (large_run_size_next); - return (size); - } - } -} - -static size_t -run_quantize_ceil_compute(size_t size) -{ - size_t qsize = run_quantize_floor_compute(size); - - if (qsize < size) { - /* - * Skip a quantization that may have an adequately large run, - * because under-sized runs may be mixed in. This only happens - * when an unusual size is requested, i.e. for aligned - * allocation, and is just one of several places where linear - * search would potentially find sufficiently aligned available - * memory somewhere lower. - */ - qsize = run_quantize_ceil_compute_hard(qsize); - } - return (qsize); -} - #ifdef JEMALLOC_JET #undef run_quantize_floor #define run_quantize_floor JEMALLOC_N(n_run_quantize_floor) @@ -172,13 +91,27 @@ static size_t run_quantize_floor(size_t size) { size_t ret; + pszind_t pind; assert(size > 0); assert(size <= HUGE_MAXCLASS); assert((size & PAGE_MASK) == 0); - ret = run_quantize_floor_tab[(size >> LG_PAGE) - 1]; - assert(ret == run_quantize_floor_compute(size)); + assert(size != 0); + assert(size == PAGE_CEILING(size)); + + pind = psz2ind(size - large_pad + 1); + if (pind == 0) { + /* + * Avoid underflow. This short-circuit would also do the right + * thing for all sizes in the range for which there are + * PAGE-spaced size classes, but it's simplest to just handle + * the one case that would cause erroneous results. + */ + return (size); + } + ret = pind2sz(pind - 1) + large_pad; + assert(ret <= size); return (ret); } #ifdef JEMALLOC_JET @@ -200,8 +133,18 @@ run_quantize_ceil(size_t size) assert(size <= HUGE_MAXCLASS); assert((size & PAGE_MASK) == 0); - ret = run_quantize_ceil_tab[(size >> LG_PAGE) - 1]; - assert(ret == run_quantize_ceil_compute(size)); + ret = run_quantize_floor(size); + if (ret < size) { + /* + * Skip a quantization that may have an adequately large run, + * because under-sized runs may be mixed in. This only happens + * when an unusual size is requested, i.e. for aligned + * allocation, and is just one of several places where linear + * search would potentially find sufficiently aligned available + * memory somewhere lower. + */ + ret = pind2sz(psz2ind(ret - large_pad + 1)) + large_pad; + } return (ret); } #ifdef JEMALLOC_JET @@ -3483,64 +3426,7 @@ arena_new(tsdn_t *tsdn, unsigned ind) return (arena); } -static bool -small_run_size_init(void) -{ - - assert(SLAB_MAXPGS != 0); - - small_run_tab = (bool *)base_alloc(NULL, sizeof(bool) * SLAB_MAXPGS); - if (small_run_tab == NULL) - return (true); - -#define TAB_INIT_bin_yes(index, size) { \ - const arena_bin_info_t *bin_info = \ - &arena_bin_info[index]; \ - small_run_tab[bin_info->run_size >> LG_PAGE] = true; \ - } -#define TAB_INIT_bin_no(index, size) -#define SC(index, lg_grp, lg_delta, ndelta, psz, bin, run_size, \ - lg_delta_lookup) \ - TAB_INIT_bin_##bin(index, (ZU(1)<> LG_PAGE)); - if (run_quantize_floor_tab == NULL) - return (true); - - run_quantize_ceil_tab = (size_t *)base_alloc(NULL, sizeof(size_t) * - (run_quantize_max >> LG_PAGE)); - if (run_quantize_ceil_tab == NULL) - return (true); - - for (i = 1; i <= run_quantize_max >> LG_PAGE; i++) { - size_t run_size = i << LG_PAGE; - - run_quantize_floor_tab[i-1] = - run_quantize_floor_compute(run_size); - run_quantize_ceil_tab[i-1] = - run_quantize_ceil_compute(run_size); - } - - return (false); -} - -bool +void arena_boot(void) { unsigned i; @@ -3586,13 +3472,6 @@ arena_boot(void) assert(large_maxclass > 0); nlclasses = size2index(large_maxclass) - size2index(SMALL_MAXCLASS); nhclasses = NSIZES - nlclasses - NBINS; - - if (small_run_size_init()) - return (true); - if (run_quantize_init()) - return (true); - - return (false); } void diff --git a/src/jemalloc.c b/src/jemalloc.c index 849e9418..929f3b87 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1234,8 +1234,7 @@ malloc_init_hard_a0_locked() return (true); if (config_prof) prof_boot1(); - if (arena_boot()) - return (true); + arena_boot(); if (config_tcache && tcache_boot(TSDN_NULL)) return (true); if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS)) -- GitLab From a7a6f5bc96500d4821d72cdfafe731d564460890 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 23 Mar 2016 21:09:28 -0700 Subject: [PATCH 011/544] Rename extent_node_t to extent_t. --- include/jemalloc/internal/arena.h | 80 ++++---- include/jemalloc/internal/chunk.h | 11 +- include/jemalloc/internal/extent.h | 169 ++++++++-------- .../jemalloc/internal/jemalloc_internal.h.in | 18 +- include/jemalloc/internal/private_symbols.txt | 41 ++-- include/jemalloc/internal/rtree.h | 18 +- include/jemalloc/internal/witness.h | 2 +- src/arena.c | 175 ++++++++-------- src/base.c | 74 +++---- src/chunk.c | 188 +++++++++--------- src/extent.c | 20 +- src/huge.c | 147 +++++++------- src/tcache.c | 9 +- test/unit/rtree.c | 25 +-- 14 files changed, 491 insertions(+), 486 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 11863fc7..93d0a327 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -177,11 +177,11 @@ typedef ph(arena_chunk_map_misc_t) arena_run_heap_t; /* Arena chunk header. */ struct arena_chunk_s { /* - * A pointer to the arena that owns the chunk is stored within the node. - * This field as a whole is used by chunks_rtree to support both - * ivsalloc() and core-based debugging. + * A pointer to the arena that owns the chunk is stored within the + * extent structure. This field as a whole is used by chunks_rtree to + * support both ivsalloc() and core-based debugging. */ - extent_node_t node; + extent_t extent; /* * Map of pages within chunk that keeps track of free/large/small. The @@ -303,7 +303,7 @@ struct arena_s { /* Extant arena chunks. */ - ql_head(extent_node_t) achunks; + ql_head(extent_t) achunks; /* * In order to avoid rapid chunk allocation/deallocation when an arena @@ -345,25 +345,25 @@ struct arena_s { * /-- arena ---\ * | | * | | - * |------------| /- chunk -\ - * ...->|chunks_cache|<--------------------------->| /----\ |<--... - * |------------| | |node| | - * | | | | | | - * | | /- run -\ /- run -\ | | | | - * | | | | | | | | | | - * | | | | | | | | | | - * |------------| |-------| |-------| | |----| | - * ...->|runs_dirty |<-->|rd |<-->|rd |<---->|rd |<----... - * |------------| |-------| |-------| | |----| | - * | | | | | | | | | | - * | | | | | | | \----/ | - * | | \-------/ \-------/ | | - * | | | | - * | | | | - * \------------/ \---------/ + * |------------| /-- chunk --\ + * ...->|chunks_cache|<--------------------------->| /------\ |<--... + * |------------| | |extent| | + * | | | | | | + * | | /- run -\ /- run -\ | | | | + * | | | | | | | | | | + * | | | | | | | | | | + * |------------| |-------| |-------| | |------| | + * ...->|runs_dirty |<-->|rd |<-->|rd |<---->|rd |<----... + * |------------| |-------| |-------| | |------| | + * | | | | | | | | | | + * | | | | | | | \------/ | + * | | \-------/ \-------/ | | + * | | | | + * | | | | + * \------------/ \-----------/ */ arena_runs_dirty_link_t runs_dirty; - extent_node_t chunks_cache; + extent_t chunks_cache; /* * Approximate time in seconds from the creation of a set of unused @@ -413,16 +413,16 @@ struct arena_s { size_t decay_backlog[SMOOTHSTEP_NSTEPS]; /* Extant huge allocations. */ - ql_head(extent_node_t) huge; + ql_head(extent_t) huge; /* Synchronizes all huge allocation/update/deallocation. */ malloc_mutex_t huge_mtx; /* * Trees of chunks that were previously allocated (trees differ only in - * node ordering). These are used when allocating chunks, in an attempt - * to re-use address space. Depending on function, different tree - * orderings are needed, which is why there are two trees with the same - * contents. + * extent ordering). These are used when allocating chunks, in an + * attempt to re-use address space. Depending on function, different + * tree orderings are needed, which is why there are two trees with the + * same contents. */ extent_tree_t chunks_szad_cached; extent_tree_t chunks_ad_cached; @@ -430,9 +430,9 @@ struct arena_s { extent_tree_t chunks_ad_retained; malloc_mutex_t chunks_mtx; - /* Cache of nodes that were allocated via base_alloc(). */ - ql_head(extent_node_t) node_cache; - malloc_mutex_t node_cache_mtx; + /* Cache of extent structures that were allocated via base_alloc(). */ + ql_head(extent_t) extent_cache; + malloc_mutex_t extent_cache_mtx; /* User-configurable chunk hook functions. */ chunk_hooks_t chunk_hooks; @@ -486,12 +486,12 @@ typedef size_t (run_quantize_t)(size_t); extern run_quantize_t *run_quantize_floor; extern run_quantize_t *run_quantize_ceil; #endif -void arena_chunk_cache_maybe_insert(arena_t *arena, extent_node_t *node, +void arena_chunk_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache); -void arena_chunk_cache_maybe_remove(arena_t *arena, extent_node_t *node, +void arena_chunk_cache_maybe_remove(arena_t *arena, extent_t *extent, bool cache); -extent_node_t *arena_node_alloc(tsdn_t *tsdn, arena_t *arena); -void arena_node_dalloc(tsdn_t *tsdn, arena_t *arena, extent_node_t *node); +extent_t *arena_extent_alloc(tsdn_t *tsdn, arena_t *arena); +void arena_extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent); void *arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero); void arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, void *chunk, @@ -1066,7 +1066,7 @@ arena_ptr_small_binind_get(const void *ptr, size_t mapbits) assert(binind != BININD_INVALID); assert(binind < NBINS); chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - arena = extent_node_arena_get(&chunk->node); + arena = extent_arena_get(&chunk->extent); pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; actual_mapbits = arena_mapbits_get(chunk, pageind); assert(mapbits == actual_mapbits); @@ -1317,7 +1317,7 @@ arena_aalloc(const void *ptr) chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); if (likely(chunk != ptr)) - return (extent_node_arena_get(&chunk->node)); + return (extent_arena_get(&chunk->extent)); else return (huge_aalloc(ptr)); } @@ -1395,7 +1395,7 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path) binind, slow_path); } else { arena_dalloc_small(tsdn, - extent_node_arena_get(&chunk->node), chunk, + extent_arena_get(&chunk->extent), chunk, ptr, pageind); } } else { @@ -1411,7 +1411,7 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path) size - large_pad, slow_path); } else { arena_dalloc_large(tsdn, - extent_node_arena_get(&chunk->node), chunk, + extent_arena_get(&chunk->extent), chunk, ptr); } } @@ -1455,7 +1455,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; arena_dalloc_small(tsdn, - extent_node_arena_get(&chunk->node), chunk, + extent_arena_get(&chunk->extent), chunk, ptr, pageind); } } else { @@ -1467,7 +1467,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, size, slow_path); } else { arena_dalloc_large(tsdn, - extent_node_arena_get(&chunk->node), chunk, + extent_arena_get(&chunk->extent), chunk, ptr); } } diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index c9fd4ecb..4666a649 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -52,13 +52,12 @@ chunk_hooks_t chunk_hooks_get(tsdn_t *tsdn, arena_t *arena); chunk_hooks_t chunk_hooks_set(tsdn_t *tsdn, arena_t *arena, const chunk_hooks_t *chunk_hooks); -bool chunk_register(tsdn_t *tsdn, const void *chunk, - const extent_node_t *node); -void chunk_deregister(const void *chunk, const extent_node_t *node); +bool chunk_register(tsdn_t *tsdn, const void *chunk, const extent_t *extent); +void chunk_deregister(const void *chunk, const extent_t *extent); void *chunk_alloc_base(size_t size); void *chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, - bool *zero, bool dalloc_node); + bool *zero, bool dalloc_extent); void *chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit); @@ -80,11 +79,11 @@ void chunk_postfork_child(tsdn_t *tsdn); #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE -extent_node_t *chunk_lookup(const void *chunk, bool dependent); +extent_t *chunk_lookup(const void *chunk, bool dependent); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_CHUNK_C_)) -JEMALLOC_INLINE extent_node_t * +JEMALLOC_INLINE extent_t * chunk_lookup(const void *ptr, bool dependent) { diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 49d76a57..acc67f00 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -1,237 +1,236 @@ /******************************************************************************/ #ifdef JEMALLOC_H_TYPES -typedef struct extent_node_s extent_node_t; +typedef struct extent_s extent_t; #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ #ifdef JEMALLOC_H_STRUCTS -/* Tree of extents. Use accessor functions for en_* fields. */ -struct extent_node_s { +/* Extent (span of pages). Use accessor functions for e_* fields. */ +struct extent_s { /* Arena from which this extent came, if any. */ - arena_t *en_arena; + arena_t *e_arena; - /* Pointer to the extent that this tree node is responsible for. */ - void *en_addr; + /* Pointer to the extent that this structure is responsible for. */ + void *e_addr; /* Total region size. */ - size_t en_size; + size_t e_size; /* * The zeroed flag is used by chunk recycling code to track whether * memory is zero-filled. */ - bool en_zeroed; + bool e_zeroed; /* * True if physical memory is committed to the extent, whether * explicitly or implicitly as on a system that overcommits and * satisfies physical memory needs on demand via soft page faults. */ - bool en_committed; + bool e_committed; /* * The achunk flag is used to validate that huge allocation lookups * don't return arena chunks. */ - bool en_achunk; + bool e_achunk; /* Profile counters, used for huge objects. */ - prof_tctx_t *en_prof_tctx; + prof_tctx_t *e_prof_tctx; /* Linkage for arena's runs_dirty and chunks_cache rings. */ arena_runs_dirty_link_t rd; - qr(extent_node_t) cc_link; + qr(extent_t) cc_link; union { /* Linkage for the size/address-ordered tree. */ - rb_node(extent_node_t) szad_link; + rb_node(extent_t) szad_link; /* Linkage for arena's achunks, huge, and node_cache lists. */ - ql_elm(extent_node_t) ql_link; + ql_elm(extent_t) ql_link; }; /* Linkage for the address-ordered tree. */ - rb_node(extent_node_t) ad_link; + rb_node(extent_t) ad_link; }; -typedef rb_tree(extent_node_t) extent_tree_t; +typedef rb_tree(extent_t) extent_tree_t; #endif /* JEMALLOC_H_STRUCTS */ /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS -rb_proto(, extent_tree_szad_, extent_tree_t, extent_node_t) +rb_proto(, extent_tree_szad_, extent_tree_t, extent_t) -rb_proto(, extent_tree_ad_, extent_tree_t, extent_node_t) +rb_proto(, extent_tree_ad_, extent_tree_t, extent_t) #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE -arena_t *extent_node_arena_get(const extent_node_t *node); -void *extent_node_addr_get(const extent_node_t *node); -size_t extent_node_size_get(const extent_node_t *node); -bool extent_node_zeroed_get(const extent_node_t *node); -bool extent_node_committed_get(const extent_node_t *node); -bool extent_node_achunk_get(const extent_node_t *node); -prof_tctx_t *extent_node_prof_tctx_get(const extent_node_t *node); -void extent_node_arena_set(extent_node_t *node, arena_t *arena); -void extent_node_addr_set(extent_node_t *node, void *addr); -void extent_node_size_set(extent_node_t *node, size_t size); -void extent_node_zeroed_set(extent_node_t *node, bool zeroed); -void extent_node_committed_set(extent_node_t *node, bool committed); -void extent_node_achunk_set(extent_node_t *node, bool achunk); -void extent_node_prof_tctx_set(extent_node_t *node, prof_tctx_t *tctx); -void extent_node_init(extent_node_t *node, arena_t *arena, void *addr, +arena_t *extent_arena_get(const extent_t *extent); +void *extent_addr_get(const extent_t *extent); +size_t extent_size_get(const extent_t *extent); +bool extent_zeroed_get(const extent_t *extent); +bool extent_committed_get(const extent_t *extent); +bool extent_achunk_get(const extent_t *extent); +prof_tctx_t *extent_prof_tctx_get(const extent_t *extent); +void extent_arena_set(extent_t *extent, arena_t *arena); +void extent_addr_set(extent_t *extent, void *addr); +void extent_size_set(extent_t *extent, size_t size); +void extent_zeroed_set(extent_t *extent, bool zeroed); +void extent_committed_set(extent_t *extent, bool committed); +void extent_achunk_set(extent_t *extent, bool achunk); +void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx); +void extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, bool zeroed, bool committed); -void extent_node_dirty_linkage_init(extent_node_t *node); -void extent_node_dirty_insert(extent_node_t *node, - arena_runs_dirty_link_t *runs_dirty, extent_node_t *chunks_dirty); -void extent_node_dirty_remove(extent_node_t *node); +void extent_dirty_linkage_init(extent_t *extent); +void extent_dirty_insert(extent_t *extent, + arena_runs_dirty_link_t *runs_dirty, extent_t *chunks_dirty); +void extent_dirty_remove(extent_t *extent); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_)) JEMALLOC_INLINE arena_t * -extent_node_arena_get(const extent_node_t *node) +extent_arena_get(const extent_t *extent) { - return (node->en_arena); + return (extent->e_arena); } JEMALLOC_INLINE void * -extent_node_addr_get(const extent_node_t *node) +extent_addr_get(const extent_t *extent) { - return (node->en_addr); + return (extent->e_addr); } JEMALLOC_INLINE size_t -extent_node_size_get(const extent_node_t *node) +extent_size_get(const extent_t *extent) { - return (node->en_size); + return (extent->e_size); } JEMALLOC_INLINE bool -extent_node_zeroed_get(const extent_node_t *node) +extent_zeroed_get(const extent_t *extent) { - return (node->en_zeroed); + return (extent->e_zeroed); } JEMALLOC_INLINE bool -extent_node_committed_get(const extent_node_t *node) +extent_committed_get(const extent_t *extent) { - assert(!node->en_achunk); - return (node->en_committed); + assert(!extent->e_achunk); + return (extent->e_committed); } JEMALLOC_INLINE bool -extent_node_achunk_get(const extent_node_t *node) +extent_achunk_get(const extent_t *extent) { - return (node->en_achunk); + return (extent->e_achunk); } JEMALLOC_INLINE prof_tctx_t * -extent_node_prof_tctx_get(const extent_node_t *node) +extent_prof_tctx_get(const extent_t *extent) { - return (node->en_prof_tctx); + return (extent->e_prof_tctx); } JEMALLOC_INLINE void -extent_node_arena_set(extent_node_t *node, arena_t *arena) +extent_arena_set(extent_t *extent, arena_t *arena) { - node->en_arena = arena; + extent->e_arena = arena; } JEMALLOC_INLINE void -extent_node_addr_set(extent_node_t *node, void *addr) +extent_addr_set(extent_t *extent, void *addr) { - node->en_addr = addr; + extent->e_addr = addr; } JEMALLOC_INLINE void -extent_node_size_set(extent_node_t *node, size_t size) +extent_size_set(extent_t *extent, size_t size) { - node->en_size = size; + extent->e_size = size; } JEMALLOC_INLINE void -extent_node_zeroed_set(extent_node_t *node, bool zeroed) +extent_zeroed_set(extent_t *extent, bool zeroed) { - node->en_zeroed = zeroed; + extent->e_zeroed = zeroed; } JEMALLOC_INLINE void -extent_node_committed_set(extent_node_t *node, bool committed) +extent_committed_set(extent_t *extent, bool committed) { - node->en_committed = committed; + extent->e_committed = committed; } JEMALLOC_INLINE void -extent_node_achunk_set(extent_node_t *node, bool achunk) +extent_achunk_set(extent_t *extent, bool achunk) { - node->en_achunk = achunk; + extent->e_achunk = achunk; } JEMALLOC_INLINE void -extent_node_prof_tctx_set(extent_node_t *node, prof_tctx_t *tctx) +extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) { - node->en_prof_tctx = tctx; + extent->e_prof_tctx = tctx; } JEMALLOC_INLINE void -extent_node_init(extent_node_t *node, arena_t *arena, void *addr, size_t size, +extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, bool zeroed, bool committed) { - extent_node_arena_set(node, arena); - extent_node_addr_set(node, addr); - extent_node_size_set(node, size); - extent_node_zeroed_set(node, zeroed); - extent_node_committed_set(node, committed); - extent_node_achunk_set(node, false); + extent_arena_set(extent, arena); + extent_addr_set(extent, addr); + extent_size_set(extent, size); + extent_zeroed_set(extent, zeroed); + extent_committed_set(extent, committed); + extent_achunk_set(extent, false); if (config_prof) - extent_node_prof_tctx_set(node, NULL); + extent_prof_tctx_set(extent, NULL); } JEMALLOC_INLINE void -extent_node_dirty_linkage_init(extent_node_t *node) +extent_dirty_linkage_init(extent_t *extent) { - qr_new(&node->rd, rd_link); - qr_new(node, cc_link); + qr_new(&extent->rd, rd_link); + qr_new(extent, cc_link); } JEMALLOC_INLINE void -extent_node_dirty_insert(extent_node_t *node, - arena_runs_dirty_link_t *runs_dirty, extent_node_t *chunks_dirty) +extent_dirty_insert(extent_t *extent, + arena_runs_dirty_link_t *runs_dirty, extent_t *chunks_dirty) { - qr_meld(runs_dirty, &node->rd, rd_link); - qr_meld(chunks_dirty, node, cc_link); + qr_meld(runs_dirty, &extent->rd, rd_link); + qr_meld(chunks_dirty, extent, cc_link); } JEMALLOC_INLINE void -extent_node_dirty_remove(extent_node_t *node) +extent_dirty_remove(extent_t *extent) { - qr_remove(&node->rd, rd_link); - qr_remove(node, cc_link); + qr_remove(&extent->rd, rd_link); + qr_remove(extent, cc_link); } - #endif #endif /* JEMALLOC_H_INLINES */ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index eabb9ce3..e487db14 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -966,6 +966,7 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) #include "jemalloc/internal/hash.h" #ifndef JEMALLOC_ENABLE_INLINE +extent_t *iealloc(const void *ptr); arena_t *iaalloc(const void *ptr); size_t isalloc(tsdn_t *tsdn, const void *ptr, bool demote); void *iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, @@ -995,6 +996,13 @@ bool ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) +JEMALLOC_ALWAYS_INLINE extent_t * +iealloc(const void *ptr) +{ + + return (chunk_lookup(ptr, true)); +} + JEMALLOC_ALWAYS_INLINE arena_t * iaalloc(const void *ptr) { @@ -1086,15 +1094,15 @@ ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero) JEMALLOC_ALWAYS_INLINE size_t ivsalloc(tsdn_t *tsdn, const void *ptr, bool demote) { - extent_node_t *node; + extent_t *extent; /* Return 0 if ptr is not within a chunk managed by jemalloc. */ - node = chunk_lookup(ptr, false); - if (node == NULL) + extent = chunk_lookup(ptr, false); + if (extent == NULL) return (0); /* Only arena chunks should be looked up via interior pointers. */ - assert(extent_node_addr_get(node) == ptr || - extent_node_achunk_get(node)); + assert(extent_addr_get(extent) == ptr || + extent_achunk_get(extent)); return (isalloc(tsdn, ptr, demote)); } diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index e046c3b1..61b29b9d 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -35,6 +35,8 @@ arena_decay_time_get arena_decay_time_set arena_dss_prec_get arena_dss_prec_set +arena_extent_alloc +arena_extent_dalloc arena_get arena_ichoose arena_init @@ -78,8 +80,6 @@ arena_miscelm_get_mutable arena_miscelm_to_pageind arena_miscelm_to_rpages arena_new -arena_node_alloc -arena_node_dalloc arena_nthreads_dec arena_nthreads_get arena_nthreads_inc @@ -204,24 +204,22 @@ ctl_postfork_parent ctl_prefork decay_ticker_get dss_prec_names -extent_node_achunk_get -extent_node_achunk_set -extent_node_addr_get -extent_node_addr_set -extent_node_arena_get -extent_node_arena_set -extent_node_committed_get -extent_node_committed_set -extent_node_dirty_insert -extent_node_dirty_linkage_init -extent_node_dirty_remove -extent_node_init -extent_node_prof_tctx_get -extent_node_prof_tctx_set -extent_node_size_get -extent_node_size_set -extent_node_zeroed_get -extent_node_zeroed_set +extent_achunk_get +extent_achunk_set +extent_addr_get +extent_addr_set +extent_arena_get +extent_arena_set +extent_committed_get +extent_committed_set +extent_dirty_insert +extent_dirty_linkage_init +extent_dirty_remove +extent_init +extent_prof_tctx_get +extent_prof_tctx_set +extent_size_get +extent_size_set extent_tree_ad_destroy extent_tree_ad_destroy_recurse extent_tree_ad_empty @@ -260,6 +258,8 @@ extent_tree_szad_reverse_iter extent_tree_szad_reverse_iter_recurse extent_tree_szad_reverse_iter_start extent_tree_szad_search +extent_zeroed_get +extent_zeroed_set ffs_llu ffs_lu ffs_u @@ -294,6 +294,7 @@ iallocztm iarena_cleanup idalloc idalloctm +iealloc index2size index2size_compute index2size_lookup diff --git a/include/jemalloc/internal/rtree.h b/include/jemalloc/internal/rtree.h index 8d0c584d..45e49b74 100644 --- a/include/jemalloc/internal/rtree.h +++ b/include/jemalloc/internal/rtree.h @@ -39,7 +39,7 @@ struct rtree_node_elm_s { union { void *pun; rtree_node_elm_t *child; - extent_node_t *val; + extent_t *val; }; }; @@ -116,17 +116,17 @@ rtree_node_elm_t *rtree_child_tryread(rtree_node_elm_t *elm, bool dependent); rtree_node_elm_t *rtree_child_read(rtree_t *rtree, rtree_node_elm_t *elm, unsigned level, bool dependent); -extent_node_t *rtree_val_read(rtree_t *rtree, rtree_node_elm_t *elm, +extent_t *rtree_val_read(rtree_t *rtree, rtree_node_elm_t *elm, bool dependent); void rtree_val_write(rtree_t *rtree, rtree_node_elm_t *elm, - const extent_node_t *val); + const extent_t *val); rtree_node_elm_t *rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent); rtree_node_elm_t *rtree_subtree_read(rtree_t *rtree, unsigned level, bool dependent); -extent_node_t *rtree_get(rtree_t *rtree, uintptr_t key, bool dependent); -bool rtree_set(rtree_t *rtree, uintptr_t key, const extent_node_t *val); +extent_t *rtree_get(rtree_t *rtree, uintptr_t key, bool dependent); +bool rtree_set(rtree_t *rtree, uintptr_t key, const extent_t *val); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_RTREE_C_)) @@ -186,7 +186,7 @@ rtree_child_read(rtree_t *rtree, rtree_node_elm_t *elm, unsigned level, return (child); } -JEMALLOC_ALWAYS_INLINE extent_node_t * +JEMALLOC_ALWAYS_INLINE extent_t * rtree_val_read(rtree_t *rtree, rtree_node_elm_t *elm, bool dependent) { @@ -209,7 +209,7 @@ rtree_val_read(rtree_t *rtree, rtree_node_elm_t *elm, bool dependent) } JEMALLOC_INLINE void -rtree_val_write(rtree_t *rtree, rtree_node_elm_t *elm, const extent_node_t *val) +rtree_val_write(rtree_t *rtree, rtree_node_elm_t *elm, const extent_t *val) { atomic_write_p(&elm->pun, val); @@ -240,7 +240,7 @@ rtree_subtree_read(rtree_t *rtree, unsigned level, bool dependent) return (subtree); } -JEMALLOC_ALWAYS_INLINE extent_node_t * +JEMALLOC_ALWAYS_INLINE extent_t * rtree_get(rtree_t *rtree, uintptr_t key, bool dependent) { uintptr_t subkey; @@ -332,7 +332,7 @@ rtree_get(rtree_t *rtree, uintptr_t key, bool dependent) } JEMALLOC_INLINE bool -rtree_set(rtree_t *rtree, uintptr_t key, const extent_node_t *val) +rtree_set(rtree_t *rtree, uintptr_t key, const extent_t *val) { uintptr_t subkey; unsigned i, start_level; diff --git a/include/jemalloc/internal/witness.h b/include/jemalloc/internal/witness.h index d78dca2d..c68c9694 100644 --- a/include/jemalloc/internal/witness.h +++ b/include/jemalloc/internal/witness.h @@ -24,7 +24,7 @@ typedef int witness_comp_t (const witness_t *, const witness_t *); #define WITNESS_RANK_ARENA 8U #define WITNESS_RANK_ARENA_CHUNKS 9U -#define WITNESS_RANK_ARENA_NODE_CACHE 10 +#define WITNESS_RANK_ARENA_EXTENT_CACHE 10 #define WITNESS_RANK_BASE 11U diff --git a/src/arena.c b/src/arena.c index 06a69856..b59f7f1b 100644 --- a/src/arena.c +++ b/src/arena.c @@ -214,32 +214,32 @@ arena_run_dirty_remove(arena_t *arena, arena_chunk_t *chunk, size_t pageind, } static size_t -arena_chunk_dirty_npages(const extent_node_t *node) +arena_chunk_dirty_npages(const extent_t *extent) { - return (extent_node_size_get(node) >> LG_PAGE); + return (extent_size_get(extent) >> LG_PAGE); } void -arena_chunk_cache_maybe_insert(arena_t *arena, extent_node_t *node, bool cache) +arena_chunk_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache) { if (cache) { - extent_node_dirty_linkage_init(node); - extent_node_dirty_insert(node, &arena->runs_dirty, + extent_dirty_linkage_init(extent); + extent_dirty_insert(extent, &arena->runs_dirty, &arena->chunks_cache); - arena->ndirty += arena_chunk_dirty_npages(node); + arena->ndirty += arena_chunk_dirty_npages(extent); } } void -arena_chunk_cache_maybe_remove(arena_t *arena, extent_node_t *node, bool dirty) +arena_chunk_cache_maybe_remove(arena_t *arena, extent_t *extent, bool dirty) { if (dirty) { - extent_node_dirty_remove(node); - assert(arena->ndirty >= arena_chunk_dirty_npages(node)); - arena->ndirty -= arena_chunk_dirty_npages(node); + extent_dirty_remove(extent); + assert(arena->ndirty >= arena_chunk_dirty_npages(extent)); + arena->ndirty -= arena_chunk_dirty_npages(extent); } } @@ -516,14 +516,14 @@ arena_chunk_register(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, { /* - * The extent node notion of "committed" doesn't directly apply to - * arena chunks. Arbitrarily mark them as committed. The commit state - * of runs is tracked individually, and upon chunk deallocation the - * entire chunk is in a consistent commit state. + * The extent notion of "committed" doesn't directly apply to arena + * chunks. Arbitrarily mark them as committed. The commit state of + * runs is tracked individually, and upon chunk deallocation the entire + * chunk is in a consistent commit state. */ - extent_node_init(&chunk->node, arena, chunk, chunksize, zero, true); - extent_node_achunk_set(&chunk->node, true); - return (chunk_register(tsdn, chunk, &chunk->node)); + extent_init(&chunk->extent, arena, chunk, chunksize, zero, true); + extent_achunk_set(&chunk->extent, true); + return (chunk_register(tsdn, chunk, &chunk->extent)); } static arena_chunk_t * @@ -648,8 +648,8 @@ arena_chunk_alloc(tsdn_t *tsdn, arena_t *arena) return (NULL); } - ql_elm_new(&chunk->node, ql_link); - ql_tail_insert(&arena->achunks, &chunk->node, ql_link); + ql_elm_new(&chunk->extent, ql_link); + ql_tail_insert(&arena->achunks, &chunk->extent, ql_link); arena_avail_insert(arena, chunk, map_bias, chunk_npages-map_bias); return (chunk); @@ -661,7 +661,7 @@ arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk) bool committed; chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; - chunk_deregister(chunk, &chunk->node); + chunk_deregister(chunk, &chunk->extent); committed = (arena_mapbits_decommitted_get(chunk, map_bias) == 0); if (!committed) { @@ -718,7 +718,7 @@ arena_chunk_dalloc(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk) /* Remove run from runs_avail, so that the arena does not use it. */ arena_avail_remove(arena, chunk, map_bias, chunk_npages-map_bias); - ql_remove(&arena->achunks, &chunk->node, ql_link); + ql_remove(&arena->achunks, &chunk->extent, ql_link); spare = arena->spare; arena->spare = chunk; if (spare != NULL) @@ -805,30 +805,30 @@ arena_huge_ralloc_stats_update_undo(arena_t *arena, size_t oldsize, arena_huge_malloc_stats_update_undo(arena, usize); } -extent_node_t * -arena_node_alloc(tsdn_t *tsdn, arena_t *arena) +extent_t * +arena_extent_alloc(tsdn_t *tsdn, arena_t *arena) { - extent_node_t *node; + extent_t *extent; - malloc_mutex_lock(tsdn, &arena->node_cache_mtx); - node = ql_last(&arena->node_cache, ql_link); - if (node == NULL) { - malloc_mutex_unlock(tsdn, &arena->node_cache_mtx); - return (base_alloc(tsdn, sizeof(extent_node_t))); + malloc_mutex_lock(tsdn, &arena->extent_cache_mtx); + extent = ql_last(&arena->extent_cache, ql_link); + if (extent == NULL) { + malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); + return (base_alloc(tsdn, sizeof(extent_t))); } - ql_tail_remove(&arena->node_cache, extent_node_t, ql_link); - malloc_mutex_unlock(tsdn, &arena->node_cache_mtx); - return (node); + ql_tail_remove(&arena->extent_cache, extent_t, ql_link); + malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); + return (extent); } void -arena_node_dalloc(tsdn_t *tsdn, arena_t *arena, extent_node_t *node) +arena_extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { - malloc_mutex_lock(tsdn, &arena->node_cache_mtx); - ql_elm_new(node, ql_link); - ql_tail_insert(&arena->node_cache, node, ql_link); - malloc_mutex_unlock(tsdn, &arena->node_cache_mtx); + malloc_mutex_lock(tsdn, &arena->extent_cache_mtx); + ql_elm_new(extent, ql_link); + ql_tail_insert(&arena->extent_cache, extent, ql_link); + malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); } static void * @@ -1424,7 +1424,7 @@ arena_dirty_count(arena_t *arena) { size_t ndirty = 0; arena_runs_dirty_link_t *rdelm; - extent_node_t *chunkselm; + extent_t *chunkselm; for (rdelm = qr_next(&arena->runs_dirty, rd_link), chunkselm = qr_next(&arena->chunks_cache, cc_link); @@ -1432,7 +1432,7 @@ arena_dirty_count(arena_t *arena) size_t npages; if (rdelm == &chunkselm->rd) { - npages = extent_node_size_get(chunkselm) >> LG_PAGE; + npages = extent_size_get(chunkselm) >> LG_PAGE; chunkselm = qr_next(chunkselm, cc_link); } else { arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE( @@ -1456,10 +1456,10 @@ arena_dirty_count(arena_t *arena) static size_t arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, size_t ndirty_limit, arena_runs_dirty_link_t *purge_runs_sentinel, - extent_node_t *purge_chunks_sentinel) + extent_t *purge_chunks_sentinel) { arena_runs_dirty_link_t *rdelm, *rdelm_next; - extent_node_t *chunkselm; + extent_t *chunkselm; size_t nstashed = 0; /* Stash runs/chunks according to ndirty_limit. */ @@ -1470,11 +1470,11 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, rdelm_next = qr_next(rdelm, rd_link); if (rdelm == &chunkselm->rd) { - extent_node_t *chunkselm_next; + extent_t *chunkselm_next; bool zero; UNUSED void *chunk; - npages = extent_node_size_get(chunkselm) >> LG_PAGE; + npages = extent_size_get(chunkselm) >> LG_PAGE; if (opt_purge == purge_mode_decay && arena->ndirty - (nstashed + npages) < ndirty_limit) break; @@ -1482,18 +1482,18 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunkselm_next = qr_next(chunkselm, cc_link); /* * Allocate. chunkselm remains valid due to the - * dalloc_node=false argument to chunk_alloc_cache(). + * dalloc_extent=false argument to chunk_alloc_cache(). */ zero = false; chunk = chunk_alloc_cache(tsdn, arena, chunk_hooks, - extent_node_addr_get(chunkselm), - extent_node_size_get(chunkselm), chunksize, &zero, + extent_addr_get(chunkselm), + extent_size_get(chunkselm), chunksize, &zero, false); - assert(chunk == extent_node_addr_get(chunkselm)); - assert(zero == extent_node_zeroed_get(chunkselm)); - extent_node_dirty_insert(chunkselm, purge_runs_sentinel, + assert(chunk == extent_addr_get(chunkselm)); + assert(zero == extent_zeroed_get(chunkselm)); + extent_dirty_insert(chunkselm, purge_runs_sentinel, purge_chunks_sentinel); - assert(npages == (extent_node_size_get(chunkselm) >> + assert(npages == (extent_size_get(chunkselm) >> LG_PAGE)); chunkselm = chunkselm_next; } else { @@ -1546,11 +1546,11 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, static size_t arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, arena_runs_dirty_link_t *purge_runs_sentinel, - extent_node_t *purge_chunks_sentinel) + extent_t *purge_chunks_sentinel) { size_t npurged, nmadvise; arena_runs_dirty_link_t *rdelm; - extent_node_t *chunkselm; + extent_t *chunkselm; if (config_stats) nmadvise = 0; @@ -1571,7 +1571,7 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, * decommitted, or purged, depending on chunk * deallocation policy. */ - size_t size = extent_node_size_get(chunkselm); + size_t size = extent_size_get(chunkselm); npages = size >> LG_PAGE; chunkselm = qr_next(chunkselm, cc_link); } else { @@ -1639,10 +1639,10 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, static void arena_unstash_purged(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, arena_runs_dirty_link_t *purge_runs_sentinel, - extent_node_t *purge_chunks_sentinel) + extent_t *purge_chunks_sentinel) { arena_runs_dirty_link_t *rdelm, *rdelm_next; - extent_node_t *chunkselm; + extent_t *chunkselm; /* Deallocate chunks/runs. */ for (rdelm = qr_next(purge_runs_sentinel, rd_link), @@ -1650,14 +1650,13 @@ arena_unstash_purged(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, rdelm != purge_runs_sentinel; rdelm = rdelm_next) { rdelm_next = qr_next(rdelm, rd_link); if (rdelm == &chunkselm->rd) { - extent_node_t *chunkselm_next = qr_next(chunkselm, - cc_link); - void *addr = extent_node_addr_get(chunkselm); - size_t size = extent_node_size_get(chunkselm); - bool zeroed = extent_node_zeroed_get(chunkselm); - bool committed = extent_node_committed_get(chunkselm); - extent_node_dirty_remove(chunkselm); - arena_node_dalloc(tsdn, arena, chunkselm); + extent_t *chunkselm_next = qr_next(chunkselm, cc_link); + void *addr = extent_addr_get(chunkselm); + size_t size = extent_size_get(chunkselm); + bool zeroed = extent_zeroed_get(chunkselm); + bool committed = extent_committed_get(chunkselm); + extent_dirty_remove(chunkselm); + arena_extent_dalloc(tsdn, arena, chunkselm); chunkselm = chunkselm_next; chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, addr, size, zeroed, committed); @@ -1692,7 +1691,7 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) chunk_hooks_t chunk_hooks = chunk_hooks_get(tsdn, arena); size_t npurge, npurged; arena_runs_dirty_link_t purge_runs_sentinel; - extent_node_t purge_chunks_sentinel; + extent_t purge_chunks_sentinel; arena->purging = true; @@ -1708,7 +1707,7 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) arena->lg_dirty_mult) < arena->ndirty || ndirty_limit == 0); qr_new(&purge_runs_sentinel, rd_link); - extent_node_dirty_linkage_init(&purge_chunks_sentinel); + extent_dirty_linkage_init(&purge_chunks_sentinel); npurge = arena_stash_dirty(tsdn, arena, &chunk_hooks, ndirty_limit, &purge_runs_sentinel, &purge_chunks_sentinel); @@ -1783,7 +1782,7 @@ void arena_reset(tsd_t *tsd, arena_t *arena) { unsigned i; - extent_node_t *node; + extent_t *extent; /* * Locking in this function is unintuitive. The caller guarantees that @@ -1801,9 +1800,9 @@ arena_reset(tsd_t *tsd, arena_t *arena) /* Remove large allocations from prof sample set. */ if (config_prof && opt_prof) { - ql_foreach(node, &arena->achunks, ql_link) { + ql_foreach(extent, &arena->achunks, ql_link) { arena_achunk_prof_reset(tsd, arena, - extent_node_addr_get(node)); + extent_addr_get(extent)); } } @@ -1815,9 +1814,9 @@ arena_reset(tsd_t *tsd, arena_t *arena) /* Huge allocations. */ malloc_mutex_lock(tsd_tsdn(tsd), &arena->huge_mtx); - for (node = ql_last(&arena->huge, ql_link); node != NULL; node = + for (extent = ql_last(&arena->huge, ql_link); extent != NULL; extent = ql_last(&arena->huge, ql_link)) { - void *ptr = extent_node_addr_get(node); + void *ptr = extent_addr_get(extent); size_t usize; malloc_mutex_unlock(tsd_tsdn(tsd), &arena->huge_mtx); @@ -1854,18 +1853,18 @@ arena_reset(tsd_t *tsd, arena_t *arena) * chains directly correspond. */ qr_new(&arena->runs_dirty, rd_link); - for (node = qr_next(&arena->chunks_cache, cc_link); - node != &arena->chunks_cache; node = qr_next(node, cc_link)) { - qr_new(&node->rd, rd_link); - qr_meld(&arena->runs_dirty, &node->rd, rd_link); + for (extent = qr_next(&arena->chunks_cache, cc_link); + extent != &arena->chunks_cache; extent = qr_next(extent, cc_link)) { + qr_new(&extent->rd, rd_link); + qr_meld(&arena->runs_dirty, &extent->rd, rd_link); } /* Arena chunks. */ - for (node = ql_last(&arena->achunks, ql_link); node != NULL; node = - ql_last(&arena->achunks, ql_link)) { - ql_remove(&arena->achunks, node, ql_link); + for (extent = ql_last(&arena->achunks, ql_link); extent != NULL; extent + = ql_last(&arena->achunks, ql_link)) { + ql_remove(&arena->achunks, extent, ql_link); arena_chunk_discard(tsd_tsdn(tsd), arena, - extent_node_addr_get(node)); + extent_addr_get(extent)); } /* Spare. */ @@ -2649,8 +2648,8 @@ arena_dissociate_bin_run(arena_chunk_t *chunk, arena_run_t *run, if (run == bin->runcur) bin->runcur = NULL; else { - szind_t binind = arena_bin_index(extent_node_arena_get( - &chunk->node), bin); + szind_t binind = arena_bin_index(extent_arena_get( + &chunk->extent), bin); const arena_bin_info_t *bin_info = &arena_bin_info[binind]; /* @@ -3018,7 +3017,7 @@ arena_ralloc_large(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t usize_min, } chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - arena = extent_node_arena_get(&chunk->node); + arena = extent_arena_get(&chunk->extent); if (oldsize < usize_max) { bool ret = arena_ralloc_large_grow(tsdn, arena, chunk, ptr, @@ -3080,7 +3079,7 @@ arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, } chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - arena_decay_tick(tsdn, extent_node_arena_get(&chunk->node)); + arena_decay_tick(tsdn, extent_arena_get(&chunk->extent)); return (false); } else { return (huge_ralloc_no_move(tsdn, ptr, oldsize, usize_min, @@ -3404,9 +3403,9 @@ arena_new(tsdn_t *tsdn, unsigned ind) if (malloc_mutex_init(&arena->chunks_mtx, "arena_chunks", WITNESS_RANK_ARENA_CHUNKS)) return (NULL); - ql_new(&arena->node_cache); - if (malloc_mutex_init(&arena->node_cache_mtx, "arena_node_cache", - WITNESS_RANK_ARENA_NODE_CACHE)) + ql_new(&arena->extent_cache); + if (malloc_mutex_init(&arena->extent_cache_mtx, "arena_extent_cache", + WITNESS_RANK_ARENA_EXTENT_CACHE)) return (NULL); arena->chunk_hooks = chunk_hooks_default; @@ -3492,7 +3491,7 @@ void arena_prefork2(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_prefork(tsdn, &arena->node_cache_mtx); + malloc_mutex_prefork(tsdn, &arena->extent_cache_mtx); } void @@ -3513,7 +3512,7 @@ arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) malloc_mutex_postfork_parent(tsdn, &arena->huge_mtx); for (i = 0; i < NBINS; i++) malloc_mutex_postfork_parent(tsdn, &arena->bins[i].lock); - malloc_mutex_postfork_parent(tsdn, &arena->node_cache_mtx); + malloc_mutex_postfork_parent(tsdn, &arena->extent_cache_mtx); malloc_mutex_postfork_parent(tsdn, &arena->chunks_mtx); malloc_mutex_postfork_parent(tsdn, &arena->lock); } @@ -3526,7 +3525,7 @@ arena_postfork_child(tsdn_t *tsdn, arena_t *arena) malloc_mutex_postfork_child(tsdn, &arena->huge_mtx); for (i = 0; i < NBINS; i++) malloc_mutex_postfork_child(tsdn, &arena->bins[i].lock); - malloc_mutex_postfork_child(tsdn, &arena->node_cache_mtx); + malloc_mutex_postfork_child(tsdn, &arena->extent_cache_mtx); malloc_mutex_postfork_child(tsdn, &arena->chunks_mtx); malloc_mutex_postfork_child(tsdn, &arena->lock); } diff --git a/src/base.c b/src/base.c index 1b0bf697..a9ab279e 100644 --- a/src/base.c +++ b/src/base.c @@ -6,59 +6,59 @@ static malloc_mutex_t base_mtx; static extent_tree_t base_avail_szad; -static extent_node_t *base_nodes; +static extent_t *base_extents; static size_t base_allocated; static size_t base_resident; static size_t base_mapped; /******************************************************************************/ -static extent_node_t * -base_node_try_alloc(tsdn_t *tsdn) +static extent_t * +base_extent_try_alloc(tsdn_t *tsdn) { - extent_node_t *node; + extent_t *extent; malloc_mutex_assert_owner(tsdn, &base_mtx); - if (base_nodes == NULL) + if (base_extents == NULL) return (NULL); - node = base_nodes; - base_nodes = *(extent_node_t **)node; - return (node); + extent = base_extents; + base_extents = *(extent_t **)extent; + return (extent); } static void -base_node_dalloc(tsdn_t *tsdn, extent_node_t *node) +base_extent_dalloc(tsdn_t *tsdn, extent_t *extent) { malloc_mutex_assert_owner(tsdn, &base_mtx); - *(extent_node_t **)node = base_nodes; - base_nodes = node; + *(extent_t **)extent = base_extents; + base_extents = extent; } -static extent_node_t * +static extent_t * base_chunk_alloc(tsdn_t *tsdn, size_t minsize) { - extent_node_t *node; + extent_t *extent; size_t csize, nsize; void *addr; malloc_mutex_assert_owner(tsdn, &base_mtx); assert(minsize != 0); - node = base_node_try_alloc(tsdn); - /* Allocate enough space to also carve a node out if necessary. */ - nsize = (node == NULL) ? CACHELINE_CEILING(sizeof(extent_node_t)) : 0; + extent = base_extent_try_alloc(tsdn); + /* Allocate enough space to also carve an extent out if necessary. */ + nsize = (extent == NULL) ? CACHELINE_CEILING(sizeof(extent_t)) : 0; csize = CHUNK_CEILING(minsize + nsize); addr = chunk_alloc_base(csize); if (addr == NULL) { - if (node != NULL) - base_node_dalloc(tsdn, node); + if (extent != NULL) + base_extent_dalloc(tsdn, extent); return (NULL); } base_mapped += csize; - if (node == NULL) { - node = (extent_node_t *)addr; + if (extent == NULL) { + extent = (extent_t *)addr; addr = (void *)((uintptr_t)addr + nsize); csize -= nsize; if (config_stats) { @@ -66,8 +66,8 @@ base_chunk_alloc(tsdn_t *tsdn, size_t minsize) base_resident += PAGE_CEILING(nsize); } } - extent_node_init(node, NULL, addr, csize, true, true); - return (node); + extent_init(extent, NULL, addr, csize, true, true); + return (extent); } /* @@ -80,8 +80,8 @@ base_alloc(tsdn_t *tsdn, size_t size) { void *ret; size_t csize, usize; - extent_node_t *node; - extent_node_t key; + extent_t *extent; + extent_t key; /* * Round size up to nearest multiple of the cacheline size, so that @@ -90,28 +90,28 @@ base_alloc(tsdn_t *tsdn, size_t size) csize = CACHELINE_CEILING(size); usize = s2u(csize); - extent_node_init(&key, NULL, NULL, usize, false, false); + extent_init(&key, NULL, NULL, usize, false, false); malloc_mutex_lock(tsdn, &base_mtx); - node = extent_tree_szad_nsearch(&base_avail_szad, &key); - if (node != NULL) { + extent = extent_tree_szad_nsearch(&base_avail_szad, &key); + if (extent != NULL) { /* Use existing space. */ - extent_tree_szad_remove(&base_avail_szad, node); + extent_tree_szad_remove(&base_avail_szad, extent); } else { /* Try to allocate more space. */ - node = base_chunk_alloc(tsdn, csize); + extent = base_chunk_alloc(tsdn, csize); } - if (node == NULL) { + if (extent == NULL) { ret = NULL; goto label_return; } - ret = extent_node_addr_get(node); - if (extent_node_size_get(node) > csize) { - extent_node_addr_set(node, (void *)((uintptr_t)ret + csize)); - extent_node_size_set(node, extent_node_size_get(node) - csize); - extent_tree_szad_insert(&base_avail_szad, node); + ret = extent_addr_get(extent); + if (extent_size_get(extent) > csize) { + extent_addr_set(extent, (void *)((uintptr_t)ret + csize)); + extent_size_set(extent, extent_size_get(extent) - csize); + extent_tree_szad_insert(&base_avail_szad, extent); } else - base_node_dalloc(tsdn, node); + base_extent_dalloc(tsdn, extent); if (config_stats) { base_allocated += csize; /* @@ -147,7 +147,7 @@ base_boot(void) if (malloc_mutex_init(&base_mtx, "base", WITNESS_RANK_BASE)) return (true); extent_tree_szad_new(&base_avail_szad); - base_nodes = NULL; + base_extents = NULL; return (false); } diff --git a/src/chunk.c b/src/chunk.c index 7af7bb91..d3a600a5 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -141,15 +141,15 @@ chunk_hooks_assure_initialized(tsdn_t *tsdn, arena_t *arena, } bool -chunk_register(tsdn_t *tsdn, const void *chunk, const extent_node_t *node) +chunk_register(tsdn_t *tsdn, const void *chunk, const extent_t *extent) { - assert(extent_node_addr_get(node) == chunk); + assert(extent_addr_get(extent) == chunk); - if (rtree_set(&chunks_rtree, (uintptr_t)chunk, node)) + if (rtree_set(&chunks_rtree, (uintptr_t)chunk, extent)) return (true); if (config_prof && opt_prof) { - size_t size = extent_node_size_get(node); + size_t size = extent_size_get(extent); size_t nadd = (size == 0) ? 1 : size / chunksize; size_t cur = atomic_add_z(&curchunks, nadd); size_t high = atomic_read_z(&highchunks); @@ -168,14 +168,14 @@ chunk_register(tsdn_t *tsdn, const void *chunk, const extent_node_t *node) } void -chunk_deregister(const void *chunk, const extent_node_t *node) +chunk_deregister(const void *chunk, const extent_t *extent) { bool err; err = rtree_set(&chunks_rtree, (uintptr_t)chunk, NULL); assert(!err); if (config_prof && opt_prof) { - size_t size = extent_node_size_get(node); + size_t size = extent_size_get(extent); size_t nsub = (size == 0) ? 1 : size / chunksize; assert(atomic_read_z(&curchunks) >= nsub); atomic_sub_z(&curchunks, nsub); @@ -186,15 +186,15 @@ chunk_deregister(const void *chunk, const extent_node_t *node) * Do first-best-fit chunk selection, i.e. select the lowest chunk that best * fits. */ -static extent_node_t * +static extent_t * chunk_first_best_fit(arena_t *arena, extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, size_t size) { - extent_node_t key; + extent_t key; assert(size == CHUNK_CEILING(size)); - extent_node_init(&key, arena, NULL, size, false, false); + extent_init(&key, arena, NULL, size, false, false); return (extent_tree_szad_nsearch(chunks_szad, &key)); } @@ -202,20 +202,20 @@ static void * chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, bool cache, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit, - bool dalloc_node) + bool dalloc_extent) { void *ret; - extent_node_t *node; + extent_t *extent; size_t alloc_size, leadsize, trailsize; bool zeroed, committed; assert(new_addr == NULL || alignment == chunksize); /* - * Cached chunks use the node linkage embedded in their headers, in - * which case dalloc_node is true, and new_addr is non-NULL because + * Cached chunks use the extent linkage embedded in their headers, in + * which case dalloc_extent is true, and new_addr is non-NULL because * we're operating on a specific chunk. */ - assert(dalloc_node || new_addr != NULL); + assert(dalloc_extent || new_addr != NULL); alloc_size = CHUNK_CEILING(s2u(size + alignment - chunksize)); /* Beware size_t wrap-around. */ @@ -224,56 +224,55 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, malloc_mutex_lock(tsdn, &arena->chunks_mtx); chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); if (new_addr != NULL) { - extent_node_t key; - extent_node_init(&key, arena, new_addr, alloc_size, false, - false); - node = extent_tree_ad_search(chunks_ad, &key); + extent_t key; + extent_init(&key, arena, new_addr, alloc_size, false, false); + extent = extent_tree_ad_search(chunks_ad, &key); } else { - node = chunk_first_best_fit(arena, chunks_szad, chunks_ad, + extent = chunk_first_best_fit(arena, chunks_szad, chunks_ad, alloc_size); } - if (node == NULL || (new_addr != NULL && extent_node_size_get(node) < + if (extent == NULL || (new_addr != NULL && extent_size_get(extent) < size)) { malloc_mutex_unlock(tsdn, &arena->chunks_mtx); return (NULL); } - leadsize = ALIGNMENT_CEILING((uintptr_t)extent_node_addr_get(node), - alignment) - (uintptr_t)extent_node_addr_get(node); + leadsize = ALIGNMENT_CEILING((uintptr_t)extent_addr_get(extent), + alignment) - (uintptr_t)extent_addr_get(extent); assert(new_addr == NULL || leadsize == 0); - assert(extent_node_size_get(node) >= leadsize + size); - trailsize = extent_node_size_get(node) - leadsize - size; - ret = (void *)((uintptr_t)extent_node_addr_get(node) + leadsize); - zeroed = extent_node_zeroed_get(node); + assert(extent_size_get(extent) >= leadsize + size); + trailsize = extent_size_get(extent) - leadsize - size; + ret = (void *)((uintptr_t)extent_addr_get(extent) + leadsize); + zeroed = extent_zeroed_get(extent); if (zeroed) *zero = true; - committed = extent_node_committed_get(node); + committed = extent_committed_get(extent); if (committed) *commit = true; /* Split the lead. */ if (leadsize != 0 && - chunk_hooks->split(extent_node_addr_get(node), - extent_node_size_get(node), leadsize, size, false, arena->ind)) { + chunk_hooks->split(extent_addr_get(extent), + extent_size_get(extent), leadsize, size, false, arena->ind)) { malloc_mutex_unlock(tsdn, &arena->chunks_mtx); return (NULL); } - /* Remove node from the tree. */ - extent_tree_szad_remove(chunks_szad, node); - extent_tree_ad_remove(chunks_ad, node); - arena_chunk_cache_maybe_remove(arena, node, cache); + /* Remove extent from the tree. */ + extent_tree_szad_remove(chunks_szad, extent); + extent_tree_ad_remove(chunks_ad, extent); + arena_chunk_cache_maybe_remove(arena, extent, cache); if (leadsize != 0) { /* Insert the leading space as a smaller chunk. */ - extent_node_size_set(node, leadsize); - extent_tree_szad_insert(chunks_szad, node); - extent_tree_ad_insert(chunks_ad, node); - arena_chunk_cache_maybe_insert(arena, node, cache); - node = NULL; + extent_size_set(extent, leadsize); + extent_tree_szad_insert(chunks_szad, extent); + extent_tree_ad_insert(chunks_ad, extent); + arena_chunk_cache_maybe_insert(arena, extent, cache); + extent = NULL; } if (trailsize != 0) { /* Split the trail. */ if (chunk_hooks->split(ret, size + trailsize, size, trailsize, false, arena->ind)) { - if (dalloc_node && node != NULL) - arena_node_dalloc(tsdn, arena, node); + if (dalloc_extent && extent != NULL) + arena_extent_dalloc(tsdn, arena, extent); malloc_mutex_unlock(tsdn, &arena->chunks_mtx); chunk_record(tsdn, arena, chunk_hooks, chunks_szad, chunks_ad, cache, ret, size + trailsize, zeroed, @@ -281,9 +280,9 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, return (NULL); } /* Insert the trailing space as a smaller chunk. */ - if (node == NULL) { - node = arena_node_alloc(tsdn, arena); - if (node == NULL) { + if (extent == NULL) { + extent = arena_extent_alloc(tsdn, arena); + if (extent == NULL) { malloc_mutex_unlock(tsdn, &arena->chunks_mtx); chunk_record(tsdn, arena, chunk_hooks, chunks_szad, chunks_ad, cache, ret, size + @@ -291,12 +290,12 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, return (NULL); } } - extent_node_init(node, arena, (void *)((uintptr_t)(ret) + size), + extent_init(extent, arena, (void *)((uintptr_t)(ret) + size), trailsize, zeroed, committed); - extent_tree_szad_insert(chunks_szad, node); - extent_tree_ad_insert(chunks_ad, node); - arena_chunk_cache_maybe_insert(arena, node, cache); - node = NULL; + extent_tree_szad_insert(chunks_szad, extent); + extent_tree_ad_insert(chunks_ad, extent); + arena_chunk_cache_maybe_insert(arena, extent, cache); + extent = NULL; } if (!committed && chunk_hooks->commit(ret, size, 0, size, arena->ind)) { malloc_mutex_unlock(tsdn, &arena->chunks_mtx); @@ -306,9 +305,9 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } malloc_mutex_unlock(tsdn, &arena->chunks_mtx); - assert(dalloc_node || node != NULL); - if (dalloc_node && node != NULL) - arena_node_dalloc(tsdn, arena, node); + assert(dalloc_extent || extent != NULL); + if (dalloc_extent && extent != NULL) + arena_extent_dalloc(tsdn, arena, extent); if (*zero) { if (!zeroed) memset(ret, 0, size); @@ -381,7 +380,8 @@ chunk_alloc_base(size_t size) void * chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - void *new_addr, size_t size, size_t alignment, bool *zero, bool dalloc_node) + void *new_addr, size_t size, size_t alignment, bool *zero, + bool dalloc_extent) { void *ret; bool commit; @@ -394,7 +394,7 @@ chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, commit = true; ret = chunk_recycle(tsdn, arena, chunk_hooks, &arena->chunks_szad_cached, &arena->chunks_ad_cached, true, - new_addr, size, alignment, zero, &commit, dalloc_node); + new_addr, size, alignment, zero, &commit, dalloc_extent); if (ret == NULL) return (NULL); assert(commit); @@ -480,40 +480,39 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool zeroed, bool committed) { bool unzeroed; - extent_node_t *node, *prev; - extent_node_t key; + extent_t *extent, *prev; + extent_t key; assert(!cache || !zeroed); unzeroed = cache || !zeroed; malloc_mutex_lock(tsdn, &arena->chunks_mtx); chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); - extent_node_init(&key, arena, (void *)((uintptr_t)chunk + size), 0, - false, false); - node = extent_tree_ad_nsearch(chunks_ad, &key); + extent_init(&key, arena, (void *)((uintptr_t)chunk + size), 0, false, + false); + extent = extent_tree_ad_nsearch(chunks_ad, &key); /* Try to coalesce forward. */ - if (node != NULL && extent_node_addr_get(node) == - extent_node_addr_get(&key) && extent_node_committed_get(node) == - committed && !chunk_hooks->merge(chunk, size, - extent_node_addr_get(node), extent_node_size_get(node), false, - arena->ind)) { + if (extent != NULL && extent_addr_get(extent) == extent_addr_get(&key) + && extent_committed_get(extent) == committed && + !chunk_hooks->merge(chunk, size, extent_addr_get(extent), + extent_size_get(extent), false, arena->ind)) { /* * Coalesce chunk with the following address range. This does * not change the position within chunks_ad, so only * remove/insert from/into chunks_szad. */ - extent_tree_szad_remove(chunks_szad, node); - arena_chunk_cache_maybe_remove(arena, node, cache); - extent_node_addr_set(node, chunk); - extent_node_size_set(node, size + extent_node_size_get(node)); - extent_node_zeroed_set(node, extent_node_zeroed_get(node) && + extent_tree_szad_remove(chunks_szad, extent); + arena_chunk_cache_maybe_remove(arena, extent, cache); + extent_addr_set(extent, chunk); + extent_size_set(extent, size + extent_size_get(extent)); + extent_zeroed_set(extent, extent_zeroed_get(extent) && !unzeroed); - extent_tree_szad_insert(chunks_szad, node); - arena_chunk_cache_maybe_insert(arena, node, cache); + extent_tree_szad_insert(chunks_szad, extent); + arena_chunk_cache_maybe_insert(arena, extent, cache); } else { - /* Coalescing forward failed, so insert a new node. */ - node = arena_node_alloc(tsdn, arena); - if (node == NULL) { + /* Coalescing forward failed, so insert a new extent. */ + extent = arena_extent_alloc(tsdn, arena); + if (extent == NULL) { /* * Node allocation failed, which is an exceedingly * unlikely failure. Leak chunk after making sure its @@ -526,39 +525,38 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } goto label_return; } - extent_node_init(node, arena, chunk, size, !unzeroed, + extent_init(extent, arena, chunk, size, !unzeroed, committed); - extent_tree_ad_insert(chunks_ad, node); - extent_tree_szad_insert(chunks_szad, node); - arena_chunk_cache_maybe_insert(arena, node, cache); + extent_tree_ad_insert(chunks_ad, extent); + extent_tree_szad_insert(chunks_szad, extent); + arena_chunk_cache_maybe_insert(arena, extent, cache); } /* Try to coalesce backward. */ - prev = extent_tree_ad_prev(chunks_ad, node); - if (prev != NULL && (void *)((uintptr_t)extent_node_addr_get(prev) + - extent_node_size_get(prev)) == chunk && - extent_node_committed_get(prev) == committed && - !chunk_hooks->merge(extent_node_addr_get(prev), - extent_node_size_get(prev), chunk, size, false, arena->ind)) { + prev = extent_tree_ad_prev(chunks_ad, extent); + if (prev != NULL && (void *)((uintptr_t)extent_addr_get(prev) + + extent_size_get(prev)) == chunk && extent_committed_get(prev) == + committed && !chunk_hooks->merge(extent_addr_get(prev), + extent_size_get(prev), chunk, size, false, arena->ind)) { /* * Coalesce chunk with the previous address range. This does * not change the position within chunks_ad, so only - * remove/insert node from/into chunks_szad. + * remove/insert extent from/into chunks_szad. */ extent_tree_szad_remove(chunks_szad, prev); extent_tree_ad_remove(chunks_ad, prev); arena_chunk_cache_maybe_remove(arena, prev, cache); - extent_tree_szad_remove(chunks_szad, node); - arena_chunk_cache_maybe_remove(arena, node, cache); - extent_node_addr_set(node, extent_node_addr_get(prev)); - extent_node_size_set(node, extent_node_size_get(prev) + - extent_node_size_get(node)); - extent_node_zeroed_set(node, extent_node_zeroed_get(prev) && - extent_node_zeroed_get(node)); - extent_tree_szad_insert(chunks_szad, node); - arena_chunk_cache_maybe_insert(arena, node, cache); - - arena_node_dalloc(tsdn, arena, prev); + extent_tree_szad_remove(chunks_szad, extent); + arena_chunk_cache_maybe_remove(arena, extent, cache); + extent_addr_set(extent, extent_addr_get(prev)); + extent_size_set(extent, extent_size_get(prev) + + extent_size_get(extent)); + extent_zeroed_set(extent, extent_zeroed_get(prev) && + extent_zeroed_get(extent)); + extent_tree_szad_insert(chunks_szad, extent); + arena_chunk_cache_maybe_insert(arena, extent, cache); + + arena_extent_dalloc(tsdn, arena, prev); } label_return: diff --git a/src/extent.c b/src/extent.c index 9f5146e5..8d24d6d6 100644 --- a/src/extent.c +++ b/src/extent.c @@ -15,11 +15,11 @@ extent_quantize(size_t size) } JEMALLOC_INLINE_C int -extent_szad_comp(const extent_node_t *a, const extent_node_t *b) +extent_szad_comp(const extent_t *a, const extent_t *b) { int ret; - size_t a_qsize = extent_quantize(extent_node_size_get(a)); - size_t b_qsize = extent_quantize(extent_node_size_get(b)); + size_t a_qsize = extent_quantize(extent_size_get(a)); + size_t b_qsize = extent_quantize(extent_size_get(b)); /* * Compare based on quantized size rather than size, in order to sort @@ -27,8 +27,8 @@ extent_szad_comp(const extent_node_t *a, const extent_node_t *b) */ ret = (a_qsize > b_qsize) - (a_qsize < b_qsize); if (ret == 0) { - uintptr_t a_addr = (uintptr_t)extent_node_addr_get(a); - uintptr_t b_addr = (uintptr_t)extent_node_addr_get(b); + uintptr_t a_addr = (uintptr_t)extent_addr_get(a); + uintptr_t b_addr = (uintptr_t)extent_addr_get(b); ret = (a_addr > b_addr) - (a_addr < b_addr); } @@ -37,17 +37,17 @@ extent_szad_comp(const extent_node_t *a, const extent_node_t *b) } /* Generate red-black tree functions. */ -rb_gen(, extent_tree_szad_, extent_tree_t, extent_node_t, szad_link, +rb_gen(, extent_tree_szad_, extent_tree_t, extent_t, szad_link, extent_szad_comp) JEMALLOC_INLINE_C int -extent_ad_comp(const extent_node_t *a, const extent_node_t *b) +extent_ad_comp(const extent_t *a, const extent_t *b) { - uintptr_t a_addr = (uintptr_t)extent_node_addr_get(a); - uintptr_t b_addr = (uintptr_t)extent_node_addr_get(b); + uintptr_t a_addr = (uintptr_t)extent_addr_get(a); + uintptr_t b_addr = (uintptr_t)extent_addr_get(b); return ((a_addr > b_addr) - (a_addr < b_addr)); } /* Generate red-black tree functions. */ -rb_gen(, extent_tree_ad_, extent_tree_t, extent_node_t, ad_link, extent_ad_comp) +rb_gen(, extent_tree_ad_, extent_tree_t, extent_t, ad_link, extent_ad_comp) diff --git a/src/huge.c b/src/huge.c index b1ff918a..c30e78de 100644 --- a/src/huge.c +++ b/src/huge.c @@ -3,40 +3,40 @@ /******************************************************************************/ -static extent_node_t * -huge_node_get(const void *ptr) +static extent_t * +huge_extent_get(const void *ptr) { - extent_node_t *node; + extent_t *extent; - node = chunk_lookup(ptr, true); - assert(!extent_node_achunk_get(node)); + extent = chunk_lookup(ptr, true); + assert(!extent_achunk_get(extent)); - return (node); + return (extent); } static bool -huge_node_set(tsdn_t *tsdn, const void *ptr, extent_node_t *node) +huge_extent_set(tsdn_t *tsdn, const void *ptr, extent_t *extent) { - assert(extent_node_addr_get(node) == ptr); - assert(!extent_node_achunk_get(node)); - return (chunk_register(tsdn, ptr, node)); + assert(extent_addr_get(extent) == ptr); + assert(!extent_achunk_get(extent)); + return (chunk_register(tsdn, ptr, extent)); } static void -huge_node_reset(tsdn_t *tsdn, const void *ptr, extent_node_t *node) +huge_extent_reset(tsdn_t *tsdn, const void *ptr, extent_t *extent) { bool err; - err = huge_node_set(tsdn, ptr, node); + err = huge_extent_set(tsdn, ptr, extent); assert(!err); } static void -huge_node_unset(const void *ptr, const extent_node_t *node) +huge_extent_unset(const void *ptr, const extent_t *extent) { - chunk_deregister(ptr, node); + chunk_deregister(ptr, extent); } void * @@ -54,7 +54,7 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, { void *ret; size_t ausize; - extent_node_t *node; + extent_t *extent; bool is_zeroed; /* Allocate one or more contiguous chunks for this request. */ @@ -66,10 +66,10 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, return (NULL); assert(ausize >= chunksize); - /* Allocate an extent node with which to track the chunk. */ - node = ipallocztm(tsdn, CACHELINE_CEILING(sizeof(extent_node_t)), + /* Allocate an extent with which to track the chunk. */ + extent = ipallocztm(tsdn, CACHELINE_CEILING(sizeof(extent_t)), CACHELINE, false, NULL, true, arena_ichoose(tsdn, arena)); - if (node == NULL) + if (extent == NULL) return (NULL); /* @@ -81,22 +81,22 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, arena = arena_choose(tsdn_tsd(tsdn), arena); if (unlikely(arena == NULL) || (ret = arena_chunk_alloc_huge(tsdn, arena, usize, alignment, &is_zeroed)) == NULL) { - idalloctm(tsdn, node, NULL, true, true); + idalloctm(tsdn, extent, NULL, true, true); return (NULL); } - extent_node_init(node, arena, ret, usize, is_zeroed, true); + extent_init(extent, arena, ret, usize, is_zeroed, true); - if (huge_node_set(tsdn, ret, node)) { + if (huge_extent_set(tsdn, ret, extent)) { arena_chunk_dalloc_huge(tsdn, arena, ret, usize); - idalloctm(tsdn, node, NULL, true, true); + idalloctm(tsdn, extent, NULL, true, true); return (NULL); } - /* Insert node into huge. */ + /* Insert extent into huge. */ malloc_mutex_lock(tsdn, &arena->huge_mtx); - ql_elm_new(node, ql_link); - ql_tail_insert(&arena->huge, node, ql_link); + ql_elm_new(extent, ql_link); + ql_tail_insert(&arena->huge, extent, ql_link); malloc_mutex_unlock(tsdn, &arena->huge_mtx); if (zero || (config_fill && unlikely(opt_zero))) { @@ -137,7 +137,7 @@ huge_ralloc_no_move_similar(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t usize_min, size_t usize_max, bool zero) { size_t usize, usize_next; - extent_node_t *node; + extent_t *extent; arena_t *arena; chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; bool pre_zeroed, post_zeroed; @@ -150,9 +150,9 @@ huge_ralloc_no_move_similar(tsdn_t *tsdn, void *ptr, size_t oldsize, if (oldsize == usize) return; - node = huge_node_get(ptr); - arena = extent_node_arena_get(node); - pre_zeroed = extent_node_zeroed_get(node); + extent = huge_extent_get(ptr); + arena = extent_arena_get(extent); + pre_zeroed = extent_zeroed_get(extent); /* Fill if necessary (shrinking). */ if (oldsize > usize) { @@ -171,12 +171,12 @@ huge_ralloc_no_move_similar(tsdn_t *tsdn, void *ptr, size_t oldsize, malloc_mutex_lock(tsdn, &arena->huge_mtx); /* Update the size of the huge allocation. */ - huge_node_unset(ptr, node); - assert(extent_node_size_get(node) != usize); - extent_node_size_set(node, usize); - huge_node_reset(tsdn, ptr, node); + assert(extent_size_get(extent) != usize); + huge_extent_unset(ptr, extent); + extent_size_set(extent, usize); + huge_extent_reset(tsdn, ptr, extent); /* Update zeroed. */ - extent_node_zeroed_set(node, post_zeroed); + extent_zeroed_set(extent, post_zeroed); malloc_mutex_unlock(tsdn, &arena->huge_mtx); arena_chunk_ralloc_huge_similar(tsdn, arena, ptr, oldsize, usize); @@ -199,15 +199,15 @@ static bool huge_ralloc_no_move_shrink(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t usize) { - extent_node_t *node; + extent_t *extent; arena_t *arena; chunk_hooks_t chunk_hooks; size_t cdiff; bool pre_zeroed, post_zeroed; - node = huge_node_get(ptr); - arena = extent_node_arena_get(node); - pre_zeroed = extent_node_zeroed_get(node); + extent = huge_extent_get(ptr); + arena = extent_arena_get(extent); + pre_zeroed = extent_zeroed_get(extent); chunk_hooks = chunk_hooks_get(tsdn, arena); assert(oldsize > usize); @@ -235,11 +235,11 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, void *ptr, size_t oldsize, malloc_mutex_lock(tsdn, &arena->huge_mtx); /* Update the size of the huge allocation. */ - huge_node_unset(ptr, node); - extent_node_size_set(node, usize); - huge_node_reset(tsdn, ptr, node); + huge_extent_unset(ptr, extent); + extent_size_set(extent, usize); + huge_extent_reset(tsdn, ptr, extent); /* Update zeroed. */ - extent_node_zeroed_set(node, post_zeroed); + extent_zeroed_set(extent, post_zeroed); malloc_mutex_unlock(tsdn, &arena->huge_mtx); /* Zap the excess chunks. */ @@ -250,15 +250,16 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, void *ptr, size_t oldsize, static bool huge_ralloc_no_move_expand(tsdn_t *tsdn, void *ptr, size_t oldsize, - size_t usize, bool zero) { - extent_node_t *node; + size_t usize, bool zero) +{ + extent_t *extent; arena_t *arena; bool is_zeroed_subchunk, is_zeroed_chunk; - node = huge_node_get(ptr); - arena = extent_node_arena_get(node); + extent = huge_extent_get(ptr); + arena = extent_arena_get(extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); - is_zeroed_subchunk = extent_node_zeroed_get(node); + is_zeroed_subchunk = extent_zeroed_get(extent); malloc_mutex_unlock(tsdn, &arena->huge_mtx); /* @@ -273,9 +274,9 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, void *ptr, size_t oldsize, malloc_mutex_lock(tsdn, &arena->huge_mtx); /* Update the size of the huge allocation. */ - huge_node_unset(ptr, node); - extent_node_size_set(node, usize); - huge_node_reset(tsdn, ptr, node); + huge_extent_unset(ptr, extent); + extent_size_set(extent, usize); + huge_extent_reset(tsdn, ptr, extent); malloc_mutex_unlock(tsdn, &arena->huge_mtx); if (zero || (config_fill && unlikely(opt_zero))) { @@ -390,21 +391,21 @@ huge_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, void huge_dalloc(tsdn_t *tsdn, void *ptr) { - extent_node_t *node; + extent_t *extent; arena_t *arena; - node = huge_node_get(ptr); - arena = extent_node_arena_get(node); - huge_node_unset(ptr, node); + extent = huge_extent_get(ptr); + arena = extent_arena_get(extent); + huge_extent_unset(ptr, extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); - ql_remove(&arena->huge, node, ql_link); + ql_remove(&arena->huge, extent, ql_link); malloc_mutex_unlock(tsdn, &arena->huge_mtx); - huge_dalloc_junk(tsdn, extent_node_addr_get(node), - extent_node_size_get(node)); - arena_chunk_dalloc_huge(tsdn, extent_node_arena_get(node), - extent_node_addr_get(node), extent_node_size_get(node)); - idalloctm(tsdn, node, NULL, true, true); + huge_dalloc_junk(tsdn, extent_addr_get(extent), + extent_size_get(extent)); + arena_chunk_dalloc_huge(tsdn, extent_arena_get(extent), + extent_addr_get(extent), extent_size_get(extent)); + idalloctm(tsdn, extent, NULL, true, true); arena_decay_tick(tsdn, arena); } @@ -413,20 +414,20 @@ arena_t * huge_aalloc(const void *ptr) { - return (extent_node_arena_get(huge_node_get(ptr))); + return (extent_arena_get(huge_extent_get(ptr))); } size_t huge_salloc(tsdn_t *tsdn, const void *ptr) { size_t size; - extent_node_t *node; + extent_t *extent; arena_t *arena; - node = huge_node_get(ptr); - arena = extent_node_arena_get(node); + extent = huge_extent_get(ptr); + arena = extent_arena_get(extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); - size = extent_node_size_get(node); + size = extent_size_get(extent); malloc_mutex_unlock(tsdn, &arena->huge_mtx); return (size); @@ -436,13 +437,13 @@ prof_tctx_t * huge_prof_tctx_get(tsdn_t *tsdn, const void *ptr) { prof_tctx_t *tctx; - extent_node_t *node; + extent_t *extent; arena_t *arena; - node = huge_node_get(ptr); - arena = extent_node_arena_get(node); + extent = huge_extent_get(ptr); + arena = extent_arena_get(extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); - tctx = extent_node_prof_tctx_get(node); + tctx = extent_prof_tctx_get(extent); malloc_mutex_unlock(tsdn, &arena->huge_mtx); return (tctx); @@ -451,13 +452,13 @@ huge_prof_tctx_get(tsdn_t *tsdn, const void *ptr) void huge_prof_tctx_set(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx) { - extent_node_t *node; + extent_t *extent; arena_t *arena; - node = huge_node_get(ptr); - arena = extent_node_arena_get(node); + extent = huge_extent_get(ptr); + arena = extent_arena_get(extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); - extent_node_prof_tctx_set(node, tctx); + extent_prof_tctx_set(extent, tctx); malloc_mutex_unlock(tsdn, &arena->huge_mtx); } diff --git a/src/tcache.c b/src/tcache.c index 175759c7..c4a99006 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -103,7 +103,7 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, /* Lock the arena bin associated with the first object. */ arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE( *(tbin->avail - 1)); - arena_t *bin_arena = extent_node_arena_get(&chunk->node); + arena_t *bin_arena = extent_arena_get(&chunk->extent); arena_bin_t *bin = &bin_arena->bins[binind]; if (config_prof && bin_arena == arena) { @@ -126,7 +126,7 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, ptr = *(tbin->avail - 1 - i); assert(ptr != NULL); chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (extent_node_arena_get(&chunk->node) == bin_arena) { + if (extent_arena_get(&chunk->extent) == bin_arena) { size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; arena_chunk_map_bits_t *bitselm = @@ -185,7 +185,7 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, /* Lock the arena associated with the first object. */ arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE( *(tbin->avail - 1)); - arena_t *locked_arena = extent_node_arena_get(&chunk->node); + arena_t *locked_arena = extent_arena_get(&chunk->extent); UNUSED bool idump; if (config_prof) @@ -211,8 +211,7 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, ptr = *(tbin->avail - 1 - i); assert(ptr != NULL); chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (extent_node_arena_get(&chunk->node) == - locked_arena) { + if (extent_arena_get(&chunk->extent) == locked_arena) { arena_dalloc_large_junked_locked(tsd_tsdn(tsd), locked_arena, chunk, ptr); } else { diff --git a/test/unit/rtree.c b/test/unit/rtree.c index b54b3e86..30b1c541 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -32,21 +32,22 @@ TEST_END TEST_BEGIN(test_rtree_extrema) { unsigned i; - extent_node_t node_a, node_b; + extent_t extent_a, extent_b; for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) { rtree_t rtree; assert_false(rtree_new(&rtree, i, node_alloc, node_dalloc), "Unexpected rtree_new() failure"); - assert_false(rtree_set(&rtree, 0, &node_a), + assert_false(rtree_set(&rtree, 0, &extent_a), "Unexpected rtree_set() failure"); - assert_ptr_eq(rtree_get(&rtree, 0, true), &node_a, + assert_ptr_eq(rtree_get(&rtree, 0, true), &extent_a, "rtree_get() should return previously set value"); - assert_false(rtree_set(&rtree, ~((uintptr_t)0), &node_b), + assert_false(rtree_set(&rtree, ~((uintptr_t)0), &extent_b), "Unexpected rtree_set() failure"); - assert_ptr_eq(rtree_get(&rtree, ~((uintptr_t)0), true), &node_b, + assert_ptr_eq(rtree_get(&rtree, ~((uintptr_t)0), true), + &extent_b, "rtree_get() should return previously set value"); rtree_delete(&rtree); @@ -61,18 +62,18 @@ TEST_BEGIN(test_rtree_bits) for (i = 1; i < (sizeof(uintptr_t) << 3); i++) { uintptr_t keys[] = {0, 1, (((uintptr_t)1) << (sizeof(uintptr_t)*8-i)) - 1}; - extent_node_t node; + extent_t extent; rtree_t rtree; assert_false(rtree_new(&rtree, i, node_alloc, node_dalloc), "Unexpected rtree_new() failure"); for (j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) { - assert_false(rtree_set(&rtree, keys[j], &node), + assert_false(rtree_set(&rtree, keys[j], &extent), "Unexpected rtree_set() failure"); for (k = 0; k < sizeof(keys)/sizeof(uintptr_t); k++) { assert_ptr_eq(rtree_get(&rtree, keys[k], true), - &node, "rtree_get() should return " + &extent, "rtree_get() should return " "previously set value and ignore " "insignificant key bits; i=%u, j=%u, k=%u, " "set key=%#"FMTxPTR", get key=%#"FMTxPTR, i, @@ -101,7 +102,7 @@ TEST_BEGIN(test_rtree_random) sfmt = init_gen_rand(SEED); for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) { uintptr_t keys[NSET]; - extent_node_t node; + extent_t extent; unsigned j; rtree_t rtree; @@ -110,13 +111,13 @@ TEST_BEGIN(test_rtree_random) for (j = 0; j < NSET; j++) { keys[j] = (uintptr_t)gen_rand64(sfmt); - assert_false(rtree_set(&rtree, keys[j], &node), + assert_false(rtree_set(&rtree, keys[j], &extent), "Unexpected rtree_set() failure"); - assert_ptr_eq(rtree_get(&rtree, keys[j], true), &node, + assert_ptr_eq(rtree_get(&rtree, keys[j], true), &extent, "rtree_get() should return previously set value"); } for (j = 0; j < NSET; j++) { - assert_ptr_eq(rtree_get(&rtree, keys[j], true), &node, + assert_ptr_eq(rtree_get(&rtree, keys[j], true), &extent, "rtree_get() should return previously set value"); } -- GitLab From f4a58847d3de70b359e57b57b59f4825afdb58c6 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 30 May 2016 10:45:38 -0700 Subject: [PATCH 012/544] Remove obsolete reference to Valgrind and quarantine. --- doc/jemalloc.xml.in | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index eddc88c1..e3c97bd8 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -1517,9 +1517,7 @@ malloc_conf = "xmalloc:true";]]> of the arena's discarded/cached allocations may accessed afterward. As part of this requirement, all thread caches which were used to allocate/deallocate in conjunction with the arena must be flushed - beforehand. This interface cannot be used if running inside Valgrind, - nor if the quarantine size is - non-zero. + beforehand. -- GitLab From 2d2b4e98c947f9fcaf4a9fd2215b685057e89212 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 28 Mar 2016 03:06:35 -0700 Subject: [PATCH 013/544] Add element acquire/release capabilities to rtree. This makes it possible to acquire short-term "ownership" of rtree elements so that it is possible to read an extent pointer *and* read the extent's contents with a guarantee that the element will not be modified until the ownership is released. This is intended as a mechanism for resolving rtree read/write races rather than as a way to lock extents. --- include/jemalloc/internal/chunk.h | 2 +- include/jemalloc/internal/private_symbols.txt | 14 +- include/jemalloc/internal/rtree.h | 235 ++++++++++++------ src/chunk.c | 12 +- src/rtree.c | 23 +- test/unit/rtree.c | 153 +++++++++--- 6 files changed, 303 insertions(+), 136 deletions(-) diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index 4666a649..9e5502ac 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -87,7 +87,7 @@ JEMALLOC_INLINE extent_t * chunk_lookup(const void *ptr, bool dependent) { - return (rtree_get(&chunks_rtree, (uintptr_t)ptr, dependent)); + return (rtree_read(&chunks_rtree, (uintptr_t)ptr, dependent)); } #endif diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 61b29b9d..478bc2ab 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -457,18 +457,24 @@ register_zone rtree_child_read rtree_child_read_hard rtree_child_tryread +rtree_clear rtree_delete -rtree_get rtree_new rtree_node_valid -rtree_set +rtree_elm_acquire +rtree_elm_lookup +rtree_elm_read +rtree_elm_read_acquired +rtree_elm_release +rtree_elm_write +rtree_elm_write_acquired +rtree_read rtree_start_level rtree_subkey rtree_subtree_read rtree_subtree_read_hard rtree_subtree_tryread -rtree_val_read -rtree_val_write +rtree_write run_quantize_ceil run_quantize_floor s2u diff --git a/include/jemalloc/internal/rtree.h b/include/jemalloc/internal/rtree.h index 45e49b74..59a7ab3c 100644 --- a/include/jemalloc/internal/rtree.h +++ b/include/jemalloc/internal/rtree.h @@ -6,7 +6,7 @@ */ #ifdef JEMALLOC_H_TYPES -typedef struct rtree_node_elm_s rtree_node_elm_t; +typedef struct rtree_elm_s rtree_elm_t; typedef struct rtree_level_s rtree_level_t; typedef struct rtree_s rtree_t; @@ -21,25 +21,24 @@ typedef struct rtree_s rtree_t; ((1U << (LG_SIZEOF_PTR+3)) / RTREE_BITS_PER_LEVEL) /* Used for two-stage lock-free node initialization. */ -#define RTREE_NODE_INITIALIZING ((rtree_node_elm_t *)0x1) +#define RTREE_NODE_INITIALIZING ((rtree_elm_t *)0x1) /* * The node allocation callback function's argument is the number of contiguous - * rtree_node_elm_t structures to allocate, and the resulting memory must be - * zeroed. + * rtree_elm_t structures to allocate, and the resulting memory must be zeroed. */ -typedef rtree_node_elm_t *(rtree_node_alloc_t)(size_t); -typedef void (rtree_node_dalloc_t)(rtree_node_elm_t *); +typedef rtree_elm_t *(rtree_node_alloc_t)(size_t); +typedef void (rtree_node_dalloc_t)(rtree_elm_t *); #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ #ifdef JEMALLOC_H_STRUCTS -struct rtree_node_elm_s { +struct rtree_elm_s { union { - void *pun; - rtree_node_elm_t *child; - extent_t *val; + void *pun; + rtree_elm_t *child; + extent_t *extent; }; }; @@ -60,15 +59,15 @@ struct rtree_level_s { * * levels[1] : [ | 0x00000001**** | 0x00000002**** | ... ] * - * levels[2] : [val(0x000000000000) | val(0x000000000001) | ...] + * levels[2] : [extent(0x000000000000) | extent(0x000000000001) | ...] * * This has practical implications on x64, which currently uses only the * lower 47 bits of virtual address space in userland, thus leaving * subtrees[0] unused and avoiding a level of tree traversal. */ union { - void *subtree_pun; - rtree_node_elm_t *subtree; + void *subtree_pun; + rtree_elm_t *subtree; }; /* Number of key bits distinguished by this level. */ unsigned bits; @@ -98,10 +97,9 @@ struct rtree_s { bool rtree_new(rtree_t *rtree, unsigned bits, rtree_node_alloc_t *alloc, rtree_node_dalloc_t *dalloc); void rtree_delete(rtree_t *rtree); -rtree_node_elm_t *rtree_subtree_read_hard(rtree_t *rtree, +rtree_elm_t *rtree_subtree_read_hard(rtree_t *rtree, unsigned level); +rtree_elm_t *rtree_child_read_hard(rtree_t *rtree, rtree_elm_t *elm, unsigned level); -rtree_node_elm_t *rtree_child_read_hard(rtree_t *rtree, - rtree_node_elm_t *elm, unsigned level); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ @@ -111,22 +109,27 @@ rtree_node_elm_t *rtree_child_read_hard(rtree_t *rtree, unsigned rtree_start_level(rtree_t *rtree, uintptr_t key); uintptr_t rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level); -bool rtree_node_valid(rtree_node_elm_t *node); -rtree_node_elm_t *rtree_child_tryread(rtree_node_elm_t *elm, - bool dependent); -rtree_node_elm_t *rtree_child_read(rtree_t *rtree, rtree_node_elm_t *elm, +bool rtree_node_valid(rtree_elm_t *node); +rtree_elm_t *rtree_child_tryread(rtree_elm_t *elm, bool dependent); +rtree_elm_t *rtree_child_read(rtree_t *rtree, rtree_elm_t *elm, unsigned level, bool dependent); -extent_t *rtree_val_read(rtree_t *rtree, rtree_node_elm_t *elm, - bool dependent); -void rtree_val_write(rtree_t *rtree, rtree_node_elm_t *elm, - const extent_t *val); -rtree_node_elm_t *rtree_subtree_tryread(rtree_t *rtree, unsigned level, +extent_t *rtree_elm_read(rtree_elm_t *elm, bool dependent); +void rtree_elm_write(rtree_elm_t *elm, const extent_t *extent); +rtree_elm_t *rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent); -rtree_node_elm_t *rtree_subtree_read(rtree_t *rtree, unsigned level, +rtree_elm_t *rtree_subtree_read(rtree_t *rtree, unsigned level, bool dependent); - -extent_t *rtree_get(rtree_t *rtree, uintptr_t key, bool dependent); -bool rtree_set(rtree_t *rtree, uintptr_t key, const extent_t *val); +rtree_elm_t *rtree_elm_lookup(rtree_t *rtree, uintptr_t key, + bool dependent, bool init_missing); + +bool rtree_write(rtree_t *rtree, uintptr_t key, const extent_t *extent); +extent_t *rtree_read(rtree_t *rtree, uintptr_t key, bool dependent); +rtree_elm_t *rtree_elm_acquire(rtree_t *rtree, uintptr_t key, + bool dependent, bool init_missing); +extent_t *rtree_elm_read_acquired(rtree_elm_t *elm); +void rtree_elm_write_acquired(rtree_elm_t *elm, const extent_t *extent); +void rtree_elm_release(rtree_elm_t *elm); +void rtree_clear(rtree_t *rtree, uintptr_t key); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_RTREE_C_)) @@ -154,18 +157,18 @@ rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level) } JEMALLOC_ALWAYS_INLINE bool -rtree_node_valid(rtree_node_elm_t *node) +rtree_node_valid(rtree_elm_t *node) { return ((uintptr_t)node > (uintptr_t)RTREE_NODE_INITIALIZING); } -JEMALLOC_ALWAYS_INLINE rtree_node_elm_t * -rtree_child_tryread(rtree_node_elm_t *elm, bool dependent) +JEMALLOC_ALWAYS_INLINE rtree_elm_t * +rtree_child_tryread(rtree_elm_t *elm, bool dependent) { - rtree_node_elm_t *child; + rtree_elm_t *child; - /* Double-checked read (first read may be stale. */ + /* Double-checked read (first read may be stale). */ child = elm->child; if (!dependent && !rtree_node_valid(child)) child = atomic_read_p(&elm->pun); @@ -173,11 +176,11 @@ rtree_child_tryread(rtree_node_elm_t *elm, bool dependent) return (child); } -JEMALLOC_ALWAYS_INLINE rtree_node_elm_t * -rtree_child_read(rtree_t *rtree, rtree_node_elm_t *elm, unsigned level, +JEMALLOC_ALWAYS_INLINE rtree_elm_t * +rtree_child_read(rtree_t *rtree, rtree_elm_t *elm, unsigned level, bool dependent) { - rtree_node_elm_t *child; + rtree_elm_t *child; child = rtree_child_tryread(elm, dependent); if (!dependent && unlikely(!rtree_node_valid(child))) @@ -187,40 +190,46 @@ rtree_child_read(rtree_t *rtree, rtree_node_elm_t *elm, unsigned level, } JEMALLOC_ALWAYS_INLINE extent_t * -rtree_val_read(rtree_t *rtree, rtree_node_elm_t *elm, bool dependent) +rtree_elm_read(rtree_elm_t *elm, bool dependent) { + extent_t *extent; if (dependent) { /* - * Reading a val on behalf of a pointer to a valid allocation is - * guaranteed to be a clean read even without synchronization, - * because the rtree update became visible in memory before the - * pointer came into existence. + * Reading a value on behalf of a pointer to a valid allocation + * is guaranteed to be a clean read even without + * synchronization, because the rtree update became visible in + * memory before the pointer came into existence. */ - return (elm->val); + extent = elm->extent; } else { /* * An arbitrary read, e.g. on behalf of ivsalloc(), may not be * dependent on a previous rtree write, which means a stale read * could result if synchronization were omitted here. */ - return (atomic_read_p(&elm->pun)); + extent = (extent_t *)atomic_read_p(&elm->pun); } + + /* Mask the lock bit. */ + extent = (extent_t *)((uintptr_t)extent & ~((uintptr_t)0x1)); + + return (extent); } JEMALLOC_INLINE void -rtree_val_write(rtree_t *rtree, rtree_node_elm_t *elm, const extent_t *val) +rtree_elm_write(rtree_elm_t *elm, const extent_t *extent) { - atomic_write_p(&elm->pun, val); + atomic_write_p(&elm->pun, extent); } -JEMALLOC_ALWAYS_INLINE rtree_node_elm_t * +JEMALLOC_ALWAYS_INLINE rtree_elm_t * rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent) { - rtree_node_elm_t *subtree; + rtree_elm_t *subtree; - /* Double-checked read (first read may be stale. */ + /* Double-checked read (first read may be stale). */ subtree = rtree->levels[level].subtree; if (!dependent && unlikely(!rtree_node_valid(subtree))) subtree = atomic_read_p(&rtree->levels[level].subtree_pun); @@ -228,10 +237,10 @@ rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent) return (subtree); } -JEMALLOC_ALWAYS_INLINE rtree_node_elm_t * +JEMALLOC_ALWAYS_INLINE rtree_elm_t * rtree_subtree_read(rtree_t *rtree, unsigned level, bool dependent) { - rtree_node_elm_t *subtree; + rtree_elm_t *subtree; subtree = rtree_subtree_tryread(rtree, level, dependent); if (!dependent && unlikely(!rtree_node_valid(subtree))) @@ -240,16 +249,20 @@ rtree_subtree_read(rtree_t *rtree, unsigned level, bool dependent) return (subtree); } -JEMALLOC_ALWAYS_INLINE extent_t * -rtree_get(rtree_t *rtree, uintptr_t key, bool dependent) +JEMALLOC_ALWAYS_INLINE rtree_elm_t * +rtree_elm_lookup(rtree_t *rtree, uintptr_t key, bool dependent, + bool init_missing) { uintptr_t subkey; unsigned start_level; - rtree_node_elm_t *node; + rtree_elm_t *node; + + assert(!dependent || !init_missing); start_level = rtree_start_level(rtree, key); - node = rtree_subtree_tryread(rtree, start_level, dependent); + node = init_missing ? rtree_subtree_read(rtree, start_level, dependent) + : rtree_subtree_tryread(rtree, start_level, dependent); #define RTREE_GET_BIAS (RTREE_HEIGHT_MAX - rtree->height) switch (start_level + RTREE_GET_BIAS) { #define RTREE_GET_SUBTREE(level) \ @@ -259,7 +272,9 @@ rtree_get(rtree_t *rtree, uintptr_t key, bool dependent) return (NULL); \ subkey = rtree_subkey(rtree, key, level - \ RTREE_GET_BIAS); \ - node = rtree_child_tryread(&node[subkey], dependent); \ + node = init_missing ? rtree_child_read(rtree, \ + &node[subkey], level - RTREE_GET_BIAS, dependent) : \ + rtree_child_tryread(&node[subkey], dependent); \ /* Fall through. */ #define RTREE_GET_LEAF(level) \ case level: \ @@ -272,8 +287,7 @@ rtree_get(rtree_t *rtree, uintptr_t key, bool dependent) * node is a leaf, so it contains values rather than \ * child pointers. \ */ \ - return (rtree_val_read(rtree, &node[subkey], \ - dependent)); + return (&node[subkey]); #if RTREE_HEIGHT_MAX > 1 RTREE_GET_SUBTREE(0) #endif @@ -332,33 +346,94 @@ rtree_get(rtree_t *rtree, uintptr_t key, bool dependent) } JEMALLOC_INLINE bool -rtree_set(rtree_t *rtree, uintptr_t key, const extent_t *val) +rtree_write(rtree_t *rtree, uintptr_t key, const extent_t *extent) { - uintptr_t subkey; - unsigned i, start_level; - rtree_node_elm_t *node, *child; + rtree_elm_t *elm; - start_level = rtree_start_level(rtree, key); + assert(extent != NULL); /* Use rtree_clear() for this case. */ + assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); - node = rtree_subtree_read(rtree, start_level, false); - if (node == NULL) + elm = rtree_elm_lookup(rtree, key, false, true); + if (elm == NULL) return (true); - for (i = start_level; /**/; i++, node = child) { - subkey = rtree_subkey(rtree, key, i); - if (i == rtree->height - 1) { - /* - * node is a leaf, so it contains values rather than - * child pointers. - */ - rtree_val_write(rtree, &node[subkey], val); - return (false); - } - assert(i + 1 < rtree->height); - child = rtree_child_read(rtree, &node[subkey], i, false); - if (child == NULL) - return (true); + assert(rtree_elm_read(elm, false) == NULL); + rtree_elm_write(elm, extent); + + return (false); +} + +JEMALLOC_ALWAYS_INLINE extent_t * +rtree_read(rtree_t *rtree, uintptr_t key, bool dependent) +{ + rtree_elm_t *elm; + + elm = rtree_elm_lookup(rtree, key, dependent, false); + if (elm == NULL) + return (NULL); + + return (rtree_elm_read(elm, dependent)); +} + +JEMALLOC_INLINE rtree_elm_t * +rtree_elm_acquire(rtree_t *rtree, uintptr_t key, bool dependent, + bool init_missing) +{ + rtree_elm_t *elm; + + elm = rtree_elm_lookup(rtree, key, dependent, init_missing); + if (!dependent && elm == NULL) + return (NULL); + { + extent_t *extent; + void *s; + + do { + extent = rtree_elm_read(elm, false); + /* The least significant bit serves as a lock. */ + s = (void *)((uintptr_t)extent | (uintptr_t)0x1); + } while (atomic_cas_p(&elm->pun, (void *)extent, s)); } - not_reached(); + + return (elm); +} + +JEMALLOC_INLINE extent_t * +rtree_elm_read_acquired(rtree_elm_t *elm) +{ + extent_t *extent; + + assert(((uintptr_t)elm->pun & (uintptr_t)0x1) == (uintptr_t)0x1); + extent = (extent_t *)((uintptr_t)elm->pun & ~((uintptr_t)0x1)); + assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); + + return (extent); +} + +JEMALLOC_INLINE void +rtree_elm_write_acquired(rtree_elm_t *elm, const extent_t *extent) +{ + + assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); + assert(((uintptr_t)elm->pun & (uintptr_t)0x1) == (uintptr_t)0x1); + elm->pun = (void *)((uintptr_t)extent | (uintptr_t)0x1); + assert(rtree_elm_read_acquired(elm) == extent); +} + +JEMALLOC_INLINE void +rtree_elm_release(rtree_elm_t *elm) +{ + + rtree_elm_write(elm, rtree_elm_read_acquired(elm)); +} + +JEMALLOC_INLINE void +rtree_clear(rtree_t *rtree, uintptr_t key) +{ + rtree_elm_t *elm; + + elm = rtree_elm_acquire(rtree, key, true, false); + rtree_elm_write_acquired(elm, NULL); + rtree_elm_release(elm); } #endif diff --git a/src/chunk.c b/src/chunk.c index d3a600a5..31b86456 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -146,7 +146,7 @@ chunk_register(tsdn_t *tsdn, const void *chunk, const extent_t *extent) assert(extent_addr_get(extent) == chunk); - if (rtree_set(&chunks_rtree, (uintptr_t)chunk, extent)) + if (rtree_write(&chunks_rtree, (uintptr_t)chunk, extent)) return (true); if (config_prof && opt_prof) { size_t size = extent_size_get(extent); @@ -170,10 +170,8 @@ chunk_register(tsdn_t *tsdn, const void *chunk, const extent_t *extent) void chunk_deregister(const void *chunk, const extent_t *extent) { - bool err; - err = rtree_set(&chunks_rtree, (uintptr_t)chunk, NULL); - assert(!err); + rtree_clear(&chunks_rtree, (uintptr_t)chunk); if (config_prof && opt_prof) { size_t size = extent_size_get(extent); size_t nsub = (size == 0) ? 1 : size / chunksize; @@ -684,12 +682,12 @@ chunk_merge_default(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b, return (false); } -static rtree_node_elm_t * +static rtree_elm_t * chunks_rtree_node_alloc(size_t nelms) { - return ((rtree_node_elm_t *)base_alloc(tsdn_fetch(), nelms * - sizeof(rtree_node_elm_t))); + return ((rtree_elm_t *)base_alloc(tsdn_fetch(), nelms * + sizeof(rtree_elm_t))); } bool diff --git a/src/rtree.c b/src/rtree.c index 3166b45f..71c69c41 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -8,7 +8,10 @@ hmin(unsigned ha, unsigned hb) return (ha < hb ? ha : hb); } -/* Only the most significant bits of keys passed to rtree_[gs]et() are used. */ +/* + * Only the most significant bits of keys passed to rtree_{read,write}() are + * used. + */ bool rtree_new(rtree_t *rtree, unsigned bits, rtree_node_alloc_t *alloc, rtree_node_dalloc_t *dalloc) @@ -62,7 +65,7 @@ rtree_new(rtree_t *rtree, unsigned bits, rtree_node_alloc_t *alloc, } static void -rtree_delete_subtree(rtree_t *rtree, rtree_node_elm_t *node, unsigned level) +rtree_delete_subtree(rtree_t *rtree, rtree_elm_t *node, unsigned level) { if (level + 1 < rtree->height) { @@ -70,7 +73,7 @@ rtree_delete_subtree(rtree_t *rtree, rtree_node_elm_t *node, unsigned level) nchildren = ZU(1) << rtree->levels[level].bits; for (i = 0; i < nchildren; i++) { - rtree_node_elm_t *child = node[i].child; + rtree_elm_t *child = node[i].child; if (child != NULL) rtree_delete_subtree(rtree, child, level + 1); } @@ -84,16 +87,16 @@ rtree_delete(rtree_t *rtree) unsigned i; for (i = 0; i < rtree->height; i++) { - rtree_node_elm_t *subtree = rtree->levels[i].subtree; + rtree_elm_t *subtree = rtree->levels[i].subtree; if (subtree != NULL) rtree_delete_subtree(rtree, subtree, i); } } -static rtree_node_elm_t * -rtree_node_init(rtree_t *rtree, unsigned level, rtree_node_elm_t **elmp) +static rtree_elm_t * +rtree_node_init(rtree_t *rtree, unsigned level, rtree_elm_t **elmp) { - rtree_node_elm_t *node; + rtree_elm_t *node; if (atomic_cas_p((void **)elmp, NULL, RTREE_NODE_INITIALIZING)) { /* @@ -114,15 +117,15 @@ rtree_node_init(rtree_t *rtree, unsigned level, rtree_node_elm_t **elmp) return (node); } -rtree_node_elm_t * +rtree_elm_t * rtree_subtree_read_hard(rtree_t *rtree, unsigned level) { return (rtree_node_init(rtree, level, &rtree->levels[level].subtree)); } -rtree_node_elm_t * -rtree_child_read_hard(rtree_t *rtree, rtree_node_elm_t *elm, unsigned level) +rtree_elm_t * +rtree_child_read_hard(rtree_t *rtree, rtree_elm_t *elm, unsigned level) { return (rtree_node_init(rtree, level, &elm->child)); diff --git a/test/unit/rtree.c b/test/unit/rtree.c index 30b1c541..671e2c8a 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -1,20 +1,24 @@ #include "test/jemalloc_test.h" -static rtree_node_elm_t * +static rtree_elm_t * node_alloc(size_t nelms) { + rtree_elm_t *node; - return ((rtree_node_elm_t *)calloc(nelms, sizeof(rtree_node_elm_t))); + node = (rtree_elm_t *)calloc(nelms, sizeof(rtree_elm_t)); + assert_ptr_not_null(node, "Unexpected calloc() failure"); + + return (node); } static void -node_dalloc(rtree_node_elm_t *node) +node_dalloc(rtree_elm_t *node) { free(node); } -TEST_BEGIN(test_rtree_get_empty) +TEST_BEGIN(test_rtree_read_empty) { unsigned i; @@ -22,13 +26,89 @@ TEST_BEGIN(test_rtree_get_empty) rtree_t rtree; assert_false(rtree_new(&rtree, i, node_alloc, node_dalloc), "Unexpected rtree_new() failure"); - assert_ptr_null(rtree_get(&rtree, 0, false), - "rtree_get() should return NULL for empty tree"); + assert_ptr_null(rtree_read(&rtree, 0, false), + "rtree_read() should return NULL for empty tree"); rtree_delete(&rtree); } } TEST_END +#define NTHREADS 8 +#define MAX_NBITS 18 +#define NITERS 1000 +#define SEED 42 + +typedef struct { + unsigned nbits; + rtree_t rtree; + uint32_t seed; +} thd_start_arg_t; + +static void * +thd_start(void *varg) +{ + thd_start_arg_t *arg = (thd_start_arg_t *)varg; + sfmt_t *sfmt; + extent_t *extent; + unsigned i; + + sfmt = init_gen_rand(arg->seed); + extent = (extent_t *)malloc(sizeof(extent)); + assert_ptr_not_null(extent, "Unexpected malloc() failure"); + + for (i = 0; i < NITERS; i++) { + uintptr_t key = (uintptr_t)gen_rand64(sfmt); + if (i % 2 == 0) { + rtree_elm_t *elm; + + elm = rtree_elm_acquire(&arg->rtree, key, false, true); + assert_ptr_not_null(elm, + "Unexpected rtree_elm_acquire() failure"); + rtree_elm_write_acquired(elm, extent); + rtree_elm_release(elm); + + elm = rtree_elm_acquire(&arg->rtree, key, true, false); + assert_ptr_not_null(elm, + "Unexpected rtree_elm_acquire() failure"); + rtree_elm_read_acquired(elm); + rtree_elm_release(elm); + } else + rtree_read(&arg->rtree, key, false); + } + + free(extent); + fini_gen_rand(sfmt); + return (NULL); +} + +TEST_BEGIN(test_rtree_concurrent) +{ + thd_start_arg_t arg; + thd_t thds[NTHREADS]; + sfmt_t *sfmt; + unsigned i, j; + + sfmt = init_gen_rand(SEED); + for (i = 1; i < MAX_NBITS; i++) { + arg.nbits = i; + assert_false(rtree_new(&arg.rtree, arg.nbits, node_alloc, + node_dalloc), "Unexpected rtree_new() failure"); + arg.seed = gen_rand32(sfmt); + for (j = 0; j < NTHREADS; j++) + thd_create(&thds[j], thd_start, (void *)&arg); + for (j = 0; j < NTHREADS; j++) + thd_join(thds[j], NULL); + rtree_delete(&arg.rtree); + } + fini_gen_rand(sfmt); +} +TEST_END + +#undef NTHREADS +#undef MAX_NBITS +#undef NITERS +#undef SEED + TEST_BEGIN(test_rtree_extrema) { unsigned i; @@ -39,16 +119,16 @@ TEST_BEGIN(test_rtree_extrema) assert_false(rtree_new(&rtree, i, node_alloc, node_dalloc), "Unexpected rtree_new() failure"); - assert_false(rtree_set(&rtree, 0, &extent_a), - "Unexpected rtree_set() failure"); - assert_ptr_eq(rtree_get(&rtree, 0, true), &extent_a, - "rtree_get() should return previously set value"); + assert_false(rtree_write(&rtree, 0, &extent_a), + "Unexpected rtree_write() failure, i=%u", i); + assert_ptr_eq(rtree_read(&rtree, 0, true), &extent_a, + "rtree_read() should return previously set value, i=%u", i); - assert_false(rtree_set(&rtree, ~((uintptr_t)0), &extent_b), - "Unexpected rtree_set() failure"); - assert_ptr_eq(rtree_get(&rtree, ~((uintptr_t)0), true), + assert_false(rtree_write(&rtree, ~((uintptr_t)0), &extent_b), + "Unexpected rtree_write() failure, i=%u", i); + assert_ptr_eq(rtree_read(&rtree, ~((uintptr_t)0), true), &extent_b, - "rtree_get() should return previously set value"); + "rtree_read() should return previously set value, i=%u", i); rtree_delete(&rtree); } @@ -69,22 +149,21 @@ TEST_BEGIN(test_rtree_bits) "Unexpected rtree_new() failure"); for (j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) { - assert_false(rtree_set(&rtree, keys[j], &extent), - "Unexpected rtree_set() failure"); + assert_false(rtree_write(&rtree, keys[j], &extent), + "Unexpected rtree_write() failure"); for (k = 0; k < sizeof(keys)/sizeof(uintptr_t); k++) { - assert_ptr_eq(rtree_get(&rtree, keys[k], true), - &extent, "rtree_get() should return " + assert_ptr_eq(rtree_read(&rtree, keys[k], true), + &extent, "rtree_read() should return " "previously set value and ignore " "insignificant key bits; i=%u, j=%u, k=%u, " "set key=%#"FMTxPTR", get key=%#"FMTxPTR, i, j, k, keys[j], keys[k]); } - assert_ptr_null(rtree_get(&rtree, + assert_ptr_null(rtree_read(&rtree, (((uintptr_t)1) << (sizeof(uintptr_t)*8-i)), false), "Only leftmost rtree leaf should be set; " "i=%u, j=%u", i, j); - assert_false(rtree_set(&rtree, keys[j], NULL), - "Unexpected rtree_set() failure"); + rtree_clear(&rtree, keys[j]); } rtree_delete(&rtree); @@ -105,31 +184,36 @@ TEST_BEGIN(test_rtree_random) extent_t extent; unsigned j; rtree_t rtree; + rtree_elm_t *elm; assert_false(rtree_new(&rtree, i, node_alloc, node_dalloc), "Unexpected rtree_new() failure"); for (j = 0; j < NSET; j++) { keys[j] = (uintptr_t)gen_rand64(sfmt); - assert_false(rtree_set(&rtree, keys[j], &extent), - "Unexpected rtree_set() failure"); - assert_ptr_eq(rtree_get(&rtree, keys[j], true), &extent, - "rtree_get() should return previously set value"); + elm = rtree_elm_acquire(&rtree, keys[j], false, true); + assert_ptr_not_null(elm, + "Unexpected rtree_elm_acquire() failure"); + rtree_elm_write_acquired(elm, &extent); + rtree_elm_release(elm); + assert_ptr_eq(rtree_read(&rtree, keys[j], true), + &extent, + "rtree_read() should return previously set value"); } for (j = 0; j < NSET; j++) { - assert_ptr_eq(rtree_get(&rtree, keys[j], true), &extent, - "rtree_get() should return previously set value"); + assert_ptr_eq(rtree_read(&rtree, keys[j], true), + &extent, "rtree_read() should return previously " + "set value, j=%u", j); } for (j = 0; j < NSET; j++) { - assert_false(rtree_set(&rtree, keys[j], NULL), - "Unexpected rtree_set() failure"); - assert_ptr_null(rtree_get(&rtree, keys[j], true), - "rtree_get() should return previously set value"); + rtree_clear(&rtree, keys[j]); + assert_ptr_null(rtree_read(&rtree, keys[j], true), + "rtree_read() should return previously set value"); } for (j = 0; j < NSET; j++) { - assert_ptr_null(rtree_get(&rtree, keys[j], true), - "rtree_get() should return previously set value"); + assert_ptr_null(rtree_read(&rtree, keys[j], true), + "rtree_read() should return previously set value"); } rtree_delete(&rtree); @@ -145,7 +229,8 @@ main(void) { return (test( - test_rtree_get_empty, + test_rtree_read_empty, + test_rtree_concurrent, test_rtree_extrema, test_rtree_bits, test_rtree_random)); -- GitLab From db72272bef91fa1b4709e89168aede0f01206d55 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 23 Mar 2016 20:29:33 -0700 Subject: [PATCH 014/544] Use rtree-based chunk lookups rather than pointer bit twiddling. Look up chunk metadata via the radix tree, rather than using CHUNK_ADDR2BASE(). Propagate pointer's containing extent. Minimize extent lookups by doing a single lookup (e.g. in free()) and propagating the pointer's extent into nearly all the functions that may need it. --- include/jemalloc/internal/arena.h | 133 +++++----- include/jemalloc/internal/chunk.h | 2 + include/jemalloc/internal/huge.h | 22 +- .../jemalloc/internal/jemalloc_internal.h.in | 124 +++++---- include/jemalloc/internal/private_symbols.txt | 2 +- include/jemalloc/internal/prof.h | 81 +++--- include/jemalloc/internal/tcache.h | 2 +- src/arena.c | 245 ++++++++++-------- src/chunk.c | 9 + src/ckh.c | 10 +- src/huge.c | 149 ++++------- src/jemalloc.c | 210 ++++++++------- src/prof.c | 32 ++- src/tcache.c | 31 ++- 14 files changed, 548 insertions(+), 504 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 93d0a327..d441aaf5 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -526,13 +526,13 @@ void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero); void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero, tcache_t *tcache); -void arena_prof_promoted(tsdn_t *tsdn, const void *ptr, size_t size); +void arena_prof_promoted(tsdn_t *tsdn, const extent_t *extent, + const void *ptr, size_t size); void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, - arena_chunk_t *chunk, void *ptr, arena_chunk_map_bits_t *bitselm); -void arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - void *ptr, size_t pageind, arena_chunk_map_bits_t *bitselm); + arena_chunk_t *chunk, extent_t *extent, void *ptr, + arena_chunk_map_bits_t *bitselm); void arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - void *ptr, size_t pageind); + extent_t *extent, void *ptr, size_t pageind); #ifdef JEMALLOC_JET typedef void (arena_dalloc_junk_large_t)(void *, size_t); extern arena_dalloc_junk_large_t *arena_dalloc_junk_large; @@ -540,17 +540,17 @@ extern arena_dalloc_junk_large_t *arena_dalloc_junk_large; void arena_dalloc_junk_large(void *ptr, size_t usize); #endif void arena_dalloc_large_junked_locked(tsdn_t *tsdn, arena_t *arena, - arena_chunk_t *chunk, void *ptr); + arena_chunk_t *chunk, extent_t *extent, void *ptr); void arena_dalloc_large(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - void *ptr); + extent_t *extent, void *ptr); #ifdef JEMALLOC_JET typedef void (arena_ralloc_junk_large_t)(void *, size_t, size_t); extern arena_ralloc_junk_large_t *arena_ralloc_junk_large; #endif -bool arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, - size_t size, size_t extra, bool zero); -void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, - size_t size, size_t alignment, bool zero, tcache_t *tcache); +bool arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, + size_t oldsize, size_t size, size_t extra, bool zero); +void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, + size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache); dss_prec_t arena_dss_prec_get(tsdn_t *tsdn, arena_t *arena); bool arena_dss_prec_set(tsdn_t *tsdn, arena_t *arena, dss_prec_t dss_prec); ssize_t arena_lg_dirty_mult_default_get(void); @@ -637,20 +637,23 @@ szind_t arena_ptr_small_binind_get(const void *ptr, size_t mapbits); szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin); size_t arena_run_regind(arena_run_t *run, const arena_bin_info_t *bin_info, const void *ptr); -prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr); -void arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, - prof_tctx_t *tctx); -void arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, size_t usize, - const void *old_ptr, prof_tctx_t *old_tctx); +prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, + const void *ptr); +void arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize, prof_tctx_t *tctx); +void arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize, const void *old_ptr, prof_tctx_t *old_tctx); void arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks); void arena_decay_tick(tsdn_t *tsdn, arena_t *arena); void *arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, tcache_t *tcache, bool slow_path); arena_t *arena_aalloc(const void *ptr); -size_t arena_salloc(tsdn_t *tsdn, const void *ptr, bool demote); -void arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path); -void arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - bool slow_path); +size_t arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr, + bool demote); +void arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, + tcache_t *tcache, bool slow_path); +void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, + tcache_t *tcache, bool slow_path); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) @@ -1042,7 +1045,9 @@ arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) return (ret); } } +# endif /* JEMALLOC_ARENA_INLINE_A */ +# ifdef JEMALLOC_ARENA_INLINE_B JEMALLOC_ALWAYS_INLINE szind_t arena_ptr_small_binind_get(const void *ptr, size_t mapbits) { @@ -1051,6 +1056,7 @@ arena_ptr_small_binind_get(const void *ptr, size_t mapbits) binind = (mapbits & CHUNK_MAP_BININD_MASK) >> CHUNK_MAP_BININD_SHIFT; if (config_debug) { + const extent_t *extent; arena_chunk_t *chunk; arena_t *arena; size_t pageind; @@ -1065,8 +1071,9 @@ arena_ptr_small_binind_get(const void *ptr, size_t mapbits) assert(binind != BININD_INVALID); assert(binind < NBINS); - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - arena = extent_arena_get(&chunk->extent); + extent = iealloc(ptr); + chunk = (arena_chunk_t *)extent_addr_get(extent); + arena = extent_arena_get(extent); pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; actual_mapbits = arena_mapbits_get(chunk, pageind); assert(mapbits == actual_mapbits); @@ -1088,9 +1095,7 @@ arena_ptr_small_binind_get(const void *ptr, size_t mapbits) return (binind); } -# endif /* JEMALLOC_ARENA_INLINE_A */ -# ifdef JEMALLOC_ARENA_INLINE_B JEMALLOC_INLINE szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin) { @@ -1172,16 +1177,15 @@ arena_run_regind(arena_run_t *run, const arena_bin_info_t *bin_info, } JEMALLOC_INLINE prof_tctx_t * -arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr) +arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { prof_tctx_t *ret; - arena_chunk_t *chunk; cassert(config_prof); assert(ptr != NULL); - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (likely(chunk != ptr)) { + if (likely(extent_achunk_get(extent))) { + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; size_t mapbits = arena_mapbits_get(chunk, pageind); assert((mapbits & CHUNK_MAP_ALLOCATED) != 0); @@ -1193,22 +1197,21 @@ arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr) ret = atomic_read_p(&elm->prof_tctx_pun); } } else - ret = huge_prof_tctx_get(tsdn, ptr); + ret = huge_prof_tctx_get(tsdn, extent, ptr); return (ret); } JEMALLOC_INLINE void -arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, - prof_tctx_t *tctx) +arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize, prof_tctx_t *tctx) { - arena_chunk_t *chunk; cassert(config_prof); assert(ptr != NULL); - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (likely(chunk != ptr)) { + if (likely(extent_achunk_get(extent))) { + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; assert(arena_mapbits_allocated_get(chunk, pageind) != 0); @@ -1231,12 +1234,12 @@ arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, assert(arena_mapbits_large_get(chunk, pageind) == 0); } } else - huge_prof_tctx_set(tsdn, ptr, tctx); + huge_prof_tctx_set(tsdn, extent, ptr, tctx); } JEMALLOC_INLINE void -arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, size_t usize, - const void *old_ptr, prof_tctx_t *old_tctx) +arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize, const void *old_ptr, prof_tctx_t *old_tctx) { cassert(config_prof); @@ -1244,7 +1247,7 @@ arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, size_t usize, if (unlikely(usize > SMALL_MAXCLASS || (ptr == old_ptr && (uintptr_t)old_tctx > (uintptr_t)1U))) { - arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); if (likely(chunk != ptr)) { size_t pageind; arena_chunk_map_misc_t *elm; @@ -1259,7 +1262,7 @@ arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, size_t usize, atomic_write_p(&elm->prof_tctx_pun, (prof_tctx_t *)(uintptr_t)1U); } else - huge_prof_tctx_reset(tsdn, ptr); + huge_prof_tctx_reset(tsdn, extent, ptr); } } @@ -1313,28 +1316,24 @@ arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, JEMALLOC_ALWAYS_INLINE arena_t * arena_aalloc(const void *ptr) { - arena_chunk_t *chunk; - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (likely(chunk != ptr)) - return (extent_arena_get(&chunk->extent)); - else - return (huge_aalloc(ptr)); + return (extent_arena_get(iealloc(ptr))); } /* Return the size of the allocation pointed to by ptr. */ JEMALLOC_ALWAYS_INLINE size_t -arena_salloc(tsdn_t *tsdn, const void *ptr, bool demote) +arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr, bool demote) { size_t ret; - arena_chunk_t *chunk; size_t pageind; szind_t binind; assert(ptr != NULL); - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (likely(chunk != ptr)) { + if (likely(extent_achunk_get(extent))) { + const arena_chunk_t *chunk = + (const arena_chunk_t *)extent_addr_get(extent); + pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; assert(arena_mapbits_allocated_get(chunk, pageind) != 0); binind = arena_mapbits_binind_get(chunk, pageind); @@ -1367,22 +1366,23 @@ arena_salloc(tsdn_t *tsdn, const void *ptr, bool demote) ret = index2size(binind); } } else - ret = huge_salloc(tsdn, ptr); + ret = huge_salloc(tsdn, extent, ptr); return (ret); } JEMALLOC_ALWAYS_INLINE void -arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path) +arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, + bool slow_path) { - arena_chunk_t *chunk; size_t pageind, mapbits; assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (likely(chunk != ptr)) { + if (likely(extent_achunk_get(extent))) { + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; mapbits = arena_mapbits_get(chunk, pageind); assert(arena_mapbits_allocated_get(chunk, pageind) != 0); @@ -1395,7 +1395,7 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path) binind, slow_path); } else { arena_dalloc_small(tsdn, - extent_arena_get(&chunk->extent), chunk, + extent_arena_get(extent), chunk, extent, ptr, pageind); } } else { @@ -1411,24 +1411,24 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path) size - large_pad, slow_path); } else { arena_dalloc_large(tsdn, - extent_arena_get(&chunk->extent), chunk, + extent_arena_get(extent), chunk, extent, ptr); } } } else - huge_dalloc(tsdn, ptr); + huge_dalloc(tsdn, extent, ptr); } JEMALLOC_ALWAYS_INLINE void -arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - bool slow_path) +arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, + tcache_t *tcache, bool slow_path) { - arena_chunk_t *chunk; assert(!tsdn_null(tsdn) || tcache == NULL); - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (likely(chunk != ptr)) { + if (likely(extent_achunk_get(extent))) { + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + if (config_prof && opt_prof) { size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; @@ -1443,7 +1443,8 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, pageind) - large_pad; } } - assert(s2u(size) == s2u(arena_salloc(tsdn, ptr, false))); + assert(s2u(size) == s2u(arena_salloc(tsdn, extent, ptr, + false))); if (likely(size <= SMALL_MAXCLASS)) { /* Small allocation. */ @@ -1455,7 +1456,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; arena_dalloc_small(tsdn, - extent_arena_get(&chunk->extent), chunk, + extent_arena_get(extent), chunk, extent, ptr, pageind); } } else { @@ -1467,12 +1468,12 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, size, slow_path); } else { arena_dalloc_large(tsdn, - extent_arena_get(&chunk->extent), chunk, + extent_arena_get(extent), chunk, extent, ptr); } } } else - huge_dalloc(tsdn, ptr); + huge_dalloc(tsdn, extent, ptr); } # endif /* JEMALLOC_ARENA_INLINE_B */ #endif diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index 9e5502ac..c13f2171 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -54,6 +54,8 @@ chunk_hooks_t chunk_hooks_set(tsdn_t *tsdn, arena_t *arena, bool chunk_register(tsdn_t *tsdn, const void *chunk, const extent_t *extent); void chunk_deregister(const void *chunk, const extent_t *extent); +void chunk_reregister(tsdn_t *tsdn, const void *chunk, + const extent_t *extent); void *chunk_alloc_base(size_t size); void *chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, diff --git a/include/jemalloc/internal/huge.h b/include/jemalloc/internal/huge.h index 8b501e5a..a385a202 100644 --- a/include/jemalloc/internal/huge.h +++ b/include/jemalloc/internal/huge.h @@ -12,20 +12,22 @@ void *huge_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero); void *huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero); -bool huge_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, - size_t usize_min, size_t usize_max, bool zero); -void *huge_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, - size_t usize, size_t alignment, bool zero, tcache_t *tcache); +bool huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, + size_t oldsize, size_t usize_min, size_t usize_max, bool zero); +void *huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, + size_t oldsize, size_t usize, size_t alignment, bool zero, + tcache_t *tcache); #ifdef JEMALLOC_JET typedef void (huge_dalloc_junk_t)(tsdn_t *, void *, size_t); extern huge_dalloc_junk_t *huge_dalloc_junk; #endif -void huge_dalloc(tsdn_t *tsdn, void *ptr); -arena_t *huge_aalloc(const void *ptr); -size_t huge_salloc(tsdn_t *tsdn, const void *ptr); -prof_tctx_t *huge_prof_tctx_get(tsdn_t *tsdn, const void *ptr); -void huge_prof_tctx_set(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx); -void huge_prof_tctx_reset(tsdn_t *tsdn, const void *ptr); +void huge_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr); +size_t huge_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr); +prof_tctx_t *huge_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, + const void *ptr); +void huge_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, + prof_tctx_t *tctx); +void huge_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index e487db14..1fc9d3d7 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -959,6 +959,20 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) #define JEMALLOC_ARENA_INLINE_A #include "jemalloc/internal/arena.h" #undef JEMALLOC_ARENA_INLINE_A + +#ifndef JEMALLOC_ENABLE_INLINE +extent_t *iealloc(const void *ptr); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) +JEMALLOC_ALWAYS_INLINE extent_t * +iealloc(const void *ptr) +{ + + return (chunk_lookup(ptr, true)); +} +#endif + #include "jemalloc/internal/tcache.h" #define JEMALLOC_ARENA_INLINE_B #include "jemalloc/internal/arena.h" @@ -968,7 +982,8 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) #ifndef JEMALLOC_ENABLE_INLINE extent_t *iealloc(const void *ptr); arena_t *iaalloc(const void *ptr); -size_t isalloc(tsdn_t *tsdn, const void *ptr, bool demote); +size_t isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr, + bool demote); void *iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, bool is_metadata, arena_t *arena, bool slow_path); void *ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, @@ -979,30 +994,23 @@ void *ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); void *ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero); size_t ivsalloc(tsdn_t *tsdn, const void *ptr, bool demote); -void idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool is_metadata, - bool slow_path); -void idalloc(tsd_t *tsd, void *ptr); -void isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - bool slow_path); -void *iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, - size_t extra, size_t alignment, bool zero, tcache_t *tcache, - arena_t *arena); -void *iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, - size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); -void *iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, - size_t alignment, bool zero); -bool ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, - size_t extra, size_t alignment, bool zero); +void idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, + bool is_metadata, bool slow_path); +void idalloc(tsd_t *tsd, extent_t *extent, void *ptr); +void isdalloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, + tcache_t *tcache, bool slow_path); +void *iralloct_realign(tsdn_t *tsdn, extent_t *extent, void *ptr, + size_t oldsize, size_t size, size_t extra, size_t alignment, bool zero, + tcache_t *tcache, arena_t *arena); +void *iralloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, + size_t size, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); +void *iralloc(tsd_t *tsd, extent_t *extent, void *ptr, size_t oldsize, + size_t size, size_t alignment, bool zero); +bool ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, + size_t size, size_t extra, size_t alignment, bool zero); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) -JEMALLOC_ALWAYS_INLINE extent_t * -iealloc(const void *ptr) -{ - - return (chunk_lookup(ptr, true)); -} - JEMALLOC_ALWAYS_INLINE arena_t * iaalloc(const void *ptr) { @@ -1016,17 +1024,18 @@ iaalloc(const void *ptr) * Typical usage: * tsdn_t *tsdn = [...] * void *ptr = [...] - * size_t sz = isalloc(tsdn, ptr, config_prof); + * extent_t *extent = iealloc(ptr); + * size_t sz = isalloc(tsdn, extent, ptr, config_prof); */ JEMALLOC_ALWAYS_INLINE size_t -isalloc(tsdn_t *tsdn, const void *ptr, bool demote) +isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr, bool demote) { assert(ptr != NULL); /* Demotion only makes sense if config_prof is true. */ assert(config_prof || !demote); - return (arena_salloc(tsdn, ptr, demote)); + return (arena_salloc(tsdn, extent, ptr, demote)); } JEMALLOC_ALWAYS_INLINE void * @@ -1041,8 +1050,8 @@ iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, ret = arena_malloc(tsdn, arena, size, ind, zero, tcache, slow_path); if (config_stats && is_metadata && likely(ret != NULL)) { - arena_metadata_allocated_add(iaalloc(ret), - isalloc(tsdn, ret, config_prof)); + arena_metadata_allocated_add(iaalloc(ret), isalloc(tsdn, + iealloc(ret), ret, config_prof)); } return (ret); } @@ -1069,8 +1078,8 @@ ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, ret = arena_palloc(tsdn, arena, usize, alignment, zero, tcache); assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret); if (config_stats && is_metadata && likely(ret != NULL)) { - arena_metadata_allocated_add(iaalloc(ret), isalloc(tsdn, ret, - config_prof)); + arena_metadata_allocated_add(iaalloc(ret), isalloc(tsdn, + iealloc(ret), ret, config_prof)); } return (ret); } @@ -1104,43 +1113,45 @@ ivsalloc(tsdn_t *tsdn, const void *ptr, bool demote) assert(extent_addr_get(extent) == ptr || extent_achunk_get(extent)); - return (isalloc(tsdn, ptr, demote)); + return (isalloc(tsdn, extent, ptr, demote)); } JEMALLOC_ALWAYS_INLINE void -idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool is_metadata, - bool slow_path) +idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, + bool is_metadata, bool slow_path) { assert(ptr != NULL); assert(!is_metadata || tcache == NULL); assert(!is_metadata || iaalloc(ptr)->ind < narenas_auto); if (config_stats && is_metadata) { - arena_metadata_allocated_sub(iaalloc(ptr), isalloc(tsdn, ptr, - config_prof)); + arena_metadata_allocated_sub(iaalloc(ptr), isalloc(tsdn, extent, + ptr, config_prof)); } - arena_dalloc(tsdn, ptr, tcache, slow_path); + arena_dalloc(tsdn, extent, ptr, tcache, slow_path); } JEMALLOC_ALWAYS_INLINE void -idalloc(tsd_t *tsd, void *ptr) +idalloc(tsd_t *tsd, extent_t *extent, void *ptr) { - idalloctm(tsd_tsdn(tsd), ptr, tcache_get(tsd, false), false, true); + idalloctm(tsd_tsdn(tsd), extent, ptr, tcache_get(tsd, false), false, + true); } JEMALLOC_ALWAYS_INLINE void -isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - bool slow_path) +isdalloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, + tcache_t *tcache, bool slow_path) { - arena_sdalloc(tsdn, ptr, size, tcache, slow_path); + arena_sdalloc(tsdn, extent, ptr, size, tcache, slow_path); } JEMALLOC_ALWAYS_INLINE void * -iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, - size_t extra, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) +iralloct_realign(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, + size_t size, size_t extra, size_t alignment, bool zero, tcache_t *tcache, + arena_t *arena) { void *p; size_t usize, copysize; @@ -1166,13 +1177,13 @@ iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, */ copysize = (size < oldsize) ? size : oldsize; memcpy(p, ptr, copysize); - isdalloct(tsdn, ptr, oldsize, tcache, true); + isdalloct(tsdn, extent, ptr, oldsize, tcache, true); return (p); } JEMALLOC_ALWAYS_INLINE void * -iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment, - bool zero, tcache_t *tcache, arena_t *arena) +iralloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, + size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) { assert(ptr != NULL); @@ -1184,26 +1195,26 @@ iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment, * Existing object alignment is inadequate; allocate new space * and copy. */ - return (iralloct_realign(tsdn, ptr, oldsize, size, 0, alignment, - zero, tcache, arena)); + return (iralloct_realign(tsdn, extent, ptr, oldsize, size, 0, + alignment, zero, tcache, arena)); } - return (arena_ralloc(tsdn, arena, ptr, oldsize, size, alignment, zero, - tcache)); + return (arena_ralloc(tsdn, arena, extent, ptr, oldsize, size, alignment, + zero, tcache)); } JEMALLOC_ALWAYS_INLINE void * -iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment, - bool zero) +iralloc(tsd_t *tsd, extent_t *extent, void *ptr, size_t oldsize, size_t size, + size_t alignment, bool zero) { - return (iralloct(tsd_tsdn(tsd), ptr, oldsize, size, alignment, zero, - tcache_get(tsd, true), NULL)); + return (iralloct(tsd_tsdn(tsd), extent, ptr, oldsize, size, alignment, + zero, tcache_get(tsd, true), NULL)); } JEMALLOC_ALWAYS_INLINE bool -ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, - size_t alignment, bool zero) +ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, + size_t extra, size_t alignment, bool zero) { assert(ptr != NULL); @@ -1215,7 +1226,8 @@ ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, return (true); } - return (arena_ralloc_no_move(tsdn, ptr, oldsize, size, extra, zero)); + return (arena_ralloc_no_move(tsdn, extent, ptr, oldsize, size, extra, + zero)); } #endif diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 478bc2ab..5f4a4b0b 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -181,6 +181,7 @@ chunk_postfork_parent chunk_prefork chunk_purge_wrapper chunk_register +chunk_reregister chunks_rtree chunksize chunksize_mask @@ -277,7 +278,6 @@ hash_rotl_64 hash_x64_128 hash_x86_128 hash_x86_32 -huge_aalloc huge_dalloc huge_dalloc_junk huge_malloc diff --git a/include/jemalloc/internal/prof.h b/include/jemalloc/internal/prof.h index 691e153d..81f02d11 100644 --- a/include/jemalloc/internal/prof.h +++ b/include/jemalloc/internal/prof.h @@ -281,8 +281,8 @@ extern uint64_t prof_interval; extern size_t lg_prof_sample; void prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated); -void prof_malloc_sample_object(tsdn_t *tsdn, const void *ptr, size_t usize, - prof_tctx_t *tctx); +void prof_malloc_sample_object(tsdn_t *tsdn, extent_t *extent, + const void *ptr, size_t usize, prof_tctx_t *tctx); void prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_tctx_t *tctx); void bt_init(prof_bt_t *bt, void **vec); void prof_backtrace(prof_bt_t *bt); @@ -330,21 +330,23 @@ void prof_sample_threshold_update(prof_tdata_t *tdata); bool prof_active_get_unlocked(void); bool prof_gdump_get_unlocked(void); prof_tdata_t *prof_tdata_get(tsd_t *tsd, bool create); -prof_tctx_t *prof_tctx_get(tsdn_t *tsdn, const void *ptr); -void prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, - prof_tctx_t *tctx); -void prof_tctx_reset(tsdn_t *tsdn, const void *ptr, size_t usize, - const void *old_ptr, prof_tctx_t *tctx); +prof_tctx_t *prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, + const void *ptr); +void prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize, prof_tctx_t *tctx); +void prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize, const void *old_ptr, prof_tctx_t *tctx); bool prof_sample_accum_update(tsd_t *tsd, size_t usize, bool commit, prof_tdata_t **tdata_out); prof_tctx_t *prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update); -void prof_malloc(tsdn_t *tsdn, const void *ptr, size_t usize, - prof_tctx_t *tctx); -void prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, - prof_tctx_t *tctx, bool prof_active, bool updated, const void *old_ptr, - size_t old_usize, prof_tctx_t *old_tctx); -void prof_free(tsd_t *tsd, const void *ptr, size_t usize); +void prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize, prof_tctx_t *tctx); +void prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, + size_t usize, prof_tctx_t *tctx, bool prof_active, bool updated, + const void *old_ptr, size_t old_usize, prof_tctx_t *old_tctx); +void prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, + size_t usize); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PROF_C_)) @@ -398,34 +400,35 @@ prof_tdata_get(tsd_t *tsd, bool create) } JEMALLOC_ALWAYS_INLINE prof_tctx_t * -prof_tctx_get(tsdn_t *tsdn, const void *ptr) +prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { cassert(config_prof); assert(ptr != NULL); - return (arena_prof_tctx_get(tsdn, ptr)); + return (arena_prof_tctx_get(tsdn, extent, ptr)); } JEMALLOC_ALWAYS_INLINE void -prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, prof_tctx_t *tctx) +prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, + prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); - arena_prof_tctx_set(tsdn, ptr, usize, tctx); + arena_prof_tctx_set(tsdn, extent, ptr, usize, tctx); } JEMALLOC_ALWAYS_INLINE void -prof_tctx_reset(tsdn_t *tsdn, const void *ptr, size_t usize, const void *old_ptr, - prof_tctx_t *old_tctx) +prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, + const void *old_ptr, prof_tctx_t *old_tctx) { cassert(config_prof); assert(ptr != NULL); - arena_prof_tctx_reset(tsdn, ptr, usize, old_ptr, old_tctx); + arena_prof_tctx_reset(tsdn, extent, ptr, usize, old_ptr, old_tctx); } JEMALLOC_ALWAYS_INLINE bool @@ -480,23 +483,26 @@ prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update) } JEMALLOC_ALWAYS_INLINE void -prof_malloc(tsdn_t *tsdn, const void *ptr, size_t usize, prof_tctx_t *tctx) +prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, + prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); - assert(usize == isalloc(tsdn, ptr, true)); + assert(usize == isalloc(tsdn, extent, ptr, true)); if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) - prof_malloc_sample_object(tsdn, ptr, usize, tctx); - else - prof_tctx_set(tsdn, ptr, usize, (prof_tctx_t *)(uintptr_t)1U); + prof_malloc_sample_object(tsdn, extent, ptr, usize, tctx); + else { + prof_tctx_set(tsdn, extent, ptr, usize, + (prof_tctx_t *)(uintptr_t)1U); + } } JEMALLOC_ALWAYS_INLINE void -prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, prof_tctx_t *tctx, - bool prof_active, bool updated, const void *old_ptr, size_t old_usize, - prof_tctx_t *old_tctx) +prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, + prof_tctx_t *tctx, bool prof_active, bool updated, const void *old_ptr, + size_t old_usize, prof_tctx_t *old_tctx) { bool sampled, old_sampled; @@ -504,7 +510,7 @@ prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, prof_tctx_t *tctx, assert(ptr != NULL || (uintptr_t)tctx <= (uintptr_t)1U); if (prof_active && !updated && ptr != NULL) { - assert(usize == isalloc(tsd_tsdn(tsd), ptr, true)); + assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr, true)); if (prof_sample_accum_update(tsd, usize, true, NULL)) { /* * Don't sample. The usize passed to prof_alloc_prep() @@ -520,22 +526,25 @@ prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, prof_tctx_t *tctx, sampled = ((uintptr_t)tctx > (uintptr_t)1U); old_sampled = ((uintptr_t)old_tctx > (uintptr_t)1U); - if (unlikely(sampled)) - prof_malloc_sample_object(tsd_tsdn(tsd), ptr, usize, tctx); - else - prof_tctx_reset(tsd_tsdn(tsd), ptr, usize, old_ptr, old_tctx); + if (unlikely(sampled)) { + prof_malloc_sample_object(tsd_tsdn(tsd), extent, ptr, usize, + tctx); + } else { + prof_tctx_reset(tsd_tsdn(tsd), extent, ptr, usize, old_ptr, + old_tctx); + } if (unlikely(old_sampled)) prof_free_sampled_object(tsd, old_usize, old_tctx); } JEMALLOC_ALWAYS_INLINE void -prof_free(tsd_t *tsd, const void *ptr, size_t usize) +prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, size_t usize) { - prof_tctx_t *tctx = prof_tctx_get(tsd_tsdn(tsd), ptr); + prof_tctx_t *tctx = prof_tctx_get(tsd_tsdn(tsd), extent, ptr); cassert(config_prof); - assert(usize == isalloc(tsd_tsdn(tsd), ptr, true)); + assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr, true)); if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) prof_free_sampled_object(tsd, usize, tctx); diff --git a/include/jemalloc/internal/tcache.h b/include/jemalloc/internal/tcache.h index 70883b1a..d6d27506 100644 --- a/include/jemalloc/internal/tcache.h +++ b/include/jemalloc/internal/tcache.h @@ -371,7 +371,7 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, if (config_prof && usize == LARGE_MINCLASS) { arena_chunk_t *chunk = - (arena_chunk_t *)CHUNK_ADDR2BASE(ret); + (arena_chunk_t *)extent_addr_get(iealloc(ret)); size_t pageind = (((uintptr_t)ret - (uintptr_t)chunk) >> LG_PAGE); arena_mapbits_large_binind_set(chunk, pageind, diff --git a/src/arena.c b/src/arena.c index b59f7f1b..3abbc623 100644 --- a/src/arena.c +++ b/src/arena.c @@ -45,10 +45,10 @@ unsigned nhclasses; /* Number of huge size classes. */ static void arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit); -static void arena_run_dalloc(tsdn_t *tsdn, arena_t *arena, arena_run_t *run, - bool dirty, bool cleaned, bool decommitted); +static void arena_run_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + arena_run_t *run, bool dirty, bool cleaned, bool decommitted); static void arena_dalloc_bin_run(tsdn_t *tsdn, arena_t *arena, - arena_chunk_t *chunk, arena_run_t *run, arena_bin_t *bin); + arena_chunk_t *chunk, extent_t *extent, arena_run_t *run, arena_bin_t *bin); static void arena_bin_lower_run(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, arena_bin_t *bin); @@ -264,9 +264,9 @@ arena_run_reg_alloc(arena_run_t *run, const arena_bin_info_t *bin_info) } JEMALLOC_INLINE_C void -arena_run_reg_dalloc(arena_run_t *run, void *ptr) +arena_run_reg_dalloc(arena_run_t *run, extent_t *extent, void *ptr) { - arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run); + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; size_t mapbits = arena_mapbits_get(chunk, pageind); szind_t binind = arena_ptr_small_binind_get(ptr, mapbits); @@ -375,15 +375,15 @@ arena_run_split_remove(arena_t *arena, arena_chunk_t *chunk, size_t run_ind, } static bool -arena_run_split_large_helper(arena_t *arena, arena_run_t *run, size_t size, - bool remove, bool zero) +arena_run_split_large_helper(arena_t *arena, extent_t *extent, arena_run_t *run, + size_t size, bool remove, bool zero) { arena_chunk_t *chunk; arena_chunk_map_misc_t *miscelm; size_t flag_dirty, flag_decommitted, run_ind, need_pages; size_t flag_unzeroed_mask; - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run); + chunk = (arena_chunk_t *)extent_addr_get(extent); miscelm = arena_run_to_miscelm(run); run_ind = arena_miscelm_to_pageind(miscelm); flag_dirty = arena_mapbits_dirty_get(chunk, run_ind); @@ -439,22 +439,26 @@ arena_run_split_large_helper(arena_t *arena, arena_run_t *run, size_t size, } static bool -arena_run_split_large(arena_t *arena, arena_run_t *run, size_t size, bool zero) +arena_run_split_large(arena_t *arena, extent_t *extent, arena_run_t *run, + size_t size, bool zero) { - return (arena_run_split_large_helper(arena, run, size, true, zero)); + return (arena_run_split_large_helper(arena, extent, run, size, true, + zero)); } static bool -arena_run_init_large(arena_t *arena, arena_run_t *run, size_t size, bool zero) +arena_run_init_large(arena_t *arena, extent_t *extent, arena_run_t *run, + size_t size, bool zero) { - return (arena_run_split_large_helper(arena, run, size, false, zero)); + return (arena_run_split_large_helper(arena, extent, run, size, false, + zero)); } static bool -arena_run_split_small(arena_t *arena, arena_run_t *run, size_t size, - szind_t binind) +arena_run_split_small(arena_t *arena, extent_t *extent, arena_run_t *run, + size_t size, szind_t binind) { arena_chunk_t *chunk; arena_chunk_map_misc_t *miscelm; @@ -462,7 +466,7 @@ arena_run_split_small(arena_t *arena, arena_run_t *run, size_t size, assert(binind != BININD_INVALID); - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run); + chunk = (arena_chunk_t *)extent_addr_get(extent); miscelm = arena_run_to_miscelm(run); run_ind = arena_miscelm_to_pageind(miscelm); flag_dirty = arena_mapbits_dirty_get(chunk, run_ind); @@ -1037,7 +1041,7 @@ arena_run_alloc_large_helper(arena_t *arena, size_t size, bool zero) { arena_run_t *run = arena_run_first_best_fit(arena, s2u(size)); if (run != NULL) { - if (arena_run_split_large(arena, run, size, zero)) + if (arena_run_split_large(arena, iealloc(run), run, size, zero)) run = NULL; } return (run); @@ -1063,7 +1067,7 @@ arena_run_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t size, bool zero) chunk = arena_chunk_alloc(tsdn, arena); if (chunk != NULL) { run = &arena_miscelm_get_mutable(chunk, map_bias)->run; - if (arena_run_split_large(arena, run, size, zero)) + if (arena_run_split_large(arena, iealloc(run), run, size, zero)) run = NULL; return (run); } @@ -1081,7 +1085,8 @@ arena_run_alloc_small_helper(arena_t *arena, size_t size, szind_t binind) { arena_run_t *run = arena_run_first_best_fit(arena, size); if (run != NULL) { - if (arena_run_split_small(arena, run, size, binind)) + if (arena_run_split_small(arena, iealloc(run), run, size, + binind)) run = NULL; } return (run); @@ -1108,7 +1113,8 @@ arena_run_alloc_small(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t binind) chunk = arena_chunk_alloc(tsdn, arena); if (chunk != NULL) { run = &arena_miscelm_get_mutable(chunk, map_bias)->run; - if (arena_run_split_small(arena, run, size, binind)) + if (arena_run_split_small(arena, iealloc(run), run, size, + binind)) run = NULL; return (run); } @@ -1435,8 +1441,9 @@ arena_dirty_count(arena_t *arena) npages = extent_size_get(chunkselm) >> LG_PAGE; chunkselm = qr_next(chunkselm, cc_link); } else { - arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE( - rdelm); + extent_t *extent = iealloc(rdelm); + arena_chunk_t *chunk = + (arena_chunk_t *)extent_addr_get(extent); arena_chunk_map_misc_t *miscelm = arena_rd_to_miscelm(rdelm); size_t pageind = arena_miscelm_to_pageind(miscelm); @@ -1497,8 +1504,9 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, LG_PAGE)); chunkselm = chunkselm_next; } else { + extent_t *extent = iealloc(rdelm); arena_chunk_t *chunk = - (arena_chunk_t *)CHUNK_ADDR2BASE(rdelm); + (arena_chunk_t *)extent_addr_get(extent); arena_chunk_map_misc_t *miscelm = arena_rd_to_miscelm(rdelm); size_t pageind = arena_miscelm_to_pageind(miscelm); @@ -1523,7 +1531,8 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, arena_chunk_alloc(tsdn, arena); /* Temporarily allocate the free dirty run. */ - arena_run_split_large(arena, run, run_size, false); + arena_run_split_large(arena, extent, run, run_size, + false); /* Stash. */ if (false) qr_new(rdelm, rd_link); /* Redundant. */ @@ -1577,8 +1586,9 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } else { size_t pageind, run_size, flag_unzeroed, flags, i; bool decommitted; + extent_t *extent = iealloc(rdelm); arena_chunk_t *chunk = - (arena_chunk_t *)CHUNK_ADDR2BASE(rdelm); + (arena_chunk_t *)extent_addr_get(extent); arena_chunk_map_misc_t *miscelm = arena_rd_to_miscelm(rdelm); pageind = arena_miscelm_to_pageind(miscelm); @@ -1661,8 +1671,9 @@ arena_unstash_purged(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, addr, size, zeroed, committed); } else { + extent_t *extent = iealloc(rdelm); arena_chunk_t *chunk = - (arena_chunk_t *)CHUNK_ADDR2BASE(rdelm); + (arena_chunk_t *)extent_addr_get(extent); arena_chunk_map_misc_t *miscelm = arena_rd_to_miscelm(rdelm); size_t pageind = arena_miscelm_to_pageind(miscelm); @@ -1670,7 +1681,7 @@ arena_unstash_purged(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, pageind) != 0); arena_run_t *run = &miscelm->run; qr_remove(rdelm, rd_link); - arena_run_dalloc(tsdn, arena, run, false, true, + arena_run_dalloc(tsdn, arena, extent, run, false, true, decommitted); } } @@ -1755,10 +1766,10 @@ arena_achunk_prof_reset(tsd_t *tsd, arena_t *arena, arena_chunk_t *chunk) if (arena_mapbits_large_get(chunk, pageind) != 0) { void *ptr = (void *)((uintptr_t)chunk + (pageind << LG_PAGE)); - size_t usize = isalloc(tsd_tsdn(tsd), ptr, - config_prof); + size_t usize = isalloc(tsd_tsdn(tsd), + &chunk->extent, ptr, config_prof); - prof_free(tsd, ptr, usize); + prof_free(tsd, &chunk->extent, ptr, usize); npages = arena_mapbits_large_size_get(chunk, pageind) >> LG_PAGE; } else { @@ -1820,12 +1831,14 @@ arena_reset(tsd_t *tsd, arena_t *arena) size_t usize; malloc_mutex_unlock(tsd_tsdn(tsd), &arena->huge_mtx); - if (config_stats || (config_prof && opt_prof)) - usize = isalloc(tsd_tsdn(tsd), ptr, config_prof); + if (config_stats || (config_prof && opt_prof)) { + usize = isalloc(tsd_tsdn(tsd), extent, ptr, + config_prof); + } /* Remove huge allocation from prof sample set. */ if (config_prof && opt_prof) - prof_free(tsd, ptr, usize); - huge_dalloc(tsd_tsdn(tsd), ptr); + prof_free(tsd, extent, ptr, usize); + huge_dalloc(tsd_tsdn(tsd), extent, ptr); malloc_mutex_lock(tsd_tsdn(tsd), &arena->huge_mtx); /* Cancel out unwanted effects on stats. */ if (config_stats) @@ -1997,14 +2010,14 @@ arena_run_size_get(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, } static void -arena_run_dalloc(tsdn_t *tsdn, arena_t *arena, arena_run_t *run, bool dirty, - bool cleaned, bool decommitted) +arena_run_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + arena_run_t *run, bool dirty, bool cleaned, bool decommitted) { arena_chunk_t *chunk; arena_chunk_map_misc_t *miscelm; size_t size, run_ind, run_pages, flag_dirty, flag_decommitted; - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run); + chunk = (arena_chunk_t *)extent_addr_get(extent); miscelm = arena_run_to_miscelm(run); run_ind = arena_miscelm_to_pageind(miscelm); assert(run_ind >= map_bias); @@ -2074,7 +2087,7 @@ arena_run_dalloc(tsdn_t *tsdn, arena_t *arena, arena_run_t *run, bool dirty, static void arena_run_trim_head(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - arena_run_t *run, size_t oldsize, size_t newsize) + extent_t *extent, arena_run_t *run, size_t oldsize, size_t newsize) { arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(run); size_t pageind = arena_miscelm_to_pageind(miscelm); @@ -2109,13 +2122,14 @@ arena_run_trim_head(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, flag_dirty | (flag_unzeroed_mask & arena_mapbits_unzeroed_get(chunk, pageind+head_npages))); - arena_run_dalloc(tsdn, arena, run, false, false, (flag_decommitted != - 0)); + arena_run_dalloc(tsdn, arena, extent, run, false, false, + (flag_decommitted != 0)); } static void arena_run_trim_tail(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - arena_run_t *run, size_t oldsize, size_t newsize, bool dirty) + extent_t *extent, arena_run_t *run, size_t oldsize, size_t newsize, + bool dirty) { arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(run); size_t pageind = arena_miscelm_to_pageind(miscelm); @@ -2154,8 +2168,8 @@ arena_run_trim_tail(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, tail_miscelm = arena_miscelm_get_mutable(chunk, pageind + head_npages); tail_run = &tail_miscelm->run; - arena_run_dalloc(tsdn, arena, tail_run, dirty, false, (flag_decommitted - != 0)); + arena_run_dalloc(tsdn, arena, extent, tail_run, dirty, false, + (flag_decommitted != 0)); } static void @@ -2251,6 +2265,7 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin) assert(bin->runcur->nfree > 0); ret = arena_run_reg_alloc(bin->runcur, bin_info); if (run != NULL) { + extent_t *extent; arena_chunk_t *chunk; /* @@ -2261,10 +2276,11 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin) * arena_bin_lower_run() must be called, as if a region * were just deallocated from the run. */ - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run); + extent = iealloc(run); + chunk = (arena_chunk_t *)extent_addr_get(extent); if (run->nfree == bin_info->nregs) { - arena_dalloc_bin_run(tsdn, arena, chunk, run, - bin); + arena_dalloc_bin_run(tsdn, arena, chunk, extent, + run, bin); } else arena_bin_lower_run(arena, chunk, run, bin); } @@ -2499,6 +2515,7 @@ arena_palloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, void *ret; size_t alloc_size, leadsize, trailsize; arena_run_t *run; + extent_t *extent; arena_chunk_t *chunk; arena_chunk_map_misc_t *miscelm; void *rpages; @@ -2520,7 +2537,8 @@ arena_palloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, malloc_mutex_unlock(tsdn, &arena->lock); return (NULL); } - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(run); + extent = iealloc(run); + chunk = (arena_chunk_t *)extent_addr_get(extent); miscelm = arena_run_to_miscelm(run); rpages = arena_miscelm_to_rpages(miscelm); @@ -2531,20 +2549,22 @@ arena_palloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, if (leadsize != 0) { arena_chunk_map_misc_t *head_miscelm = miscelm; arena_run_t *head_run = run; + extent_t *head_extent = extent; miscelm = arena_miscelm_get_mutable(chunk, arena_miscelm_to_pageind(head_miscelm) + (leadsize >> LG_PAGE)); run = &miscelm->run; + extent = iealloc(run); - arena_run_trim_head(tsdn, arena, chunk, head_run, alloc_size, - alloc_size - leadsize); + arena_run_trim_head(tsdn, arena, chunk, head_extent, head_run, + alloc_size, alloc_size - leadsize); } if (trailsize != 0) { - arena_run_trim_tail(tsdn, arena, chunk, run, usize + large_pad + - trailsize, usize + large_pad, false); + arena_run_trim_tail(tsdn, arena, chunk, extent, run, usize + + large_pad + trailsize, usize + large_pad, false); } - if (arena_run_init_large(arena, run, usize + large_pad, zero)) { + if (arena_run_init_large(arena, extent, run, usize + large_pad, zero)) { size_t run_ind = arena_miscelm_to_pageind(arena_run_to_miscelm(run)); bool dirty = (arena_mapbits_dirty_get(chunk, run_ind) != 0); @@ -2552,7 +2572,8 @@ arena_palloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, run_ind) != 0); assert(decommitted); /* Cause of OOM. */ - arena_run_dalloc(tsdn, arena, run, dirty, false, decommitted); + arena_run_dalloc(tsdn, arena, extent, run, dirty, false, + decommitted); malloc_mutex_unlock(tsdn, &arena->lock); return (NULL); } @@ -2616,7 +2637,8 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, } void -arena_prof_promoted(tsdn_t *tsdn, const void *ptr, size_t size) +arena_prof_promoted(tsdn_t *tsdn, const extent_t *extent, const void *ptr, + size_t size) { arena_chunk_t *chunk; size_t pageind; @@ -2624,32 +2646,30 @@ arena_prof_promoted(tsdn_t *tsdn, const void *ptr, size_t size) cassert(config_prof); assert(ptr != NULL); - assert(CHUNK_ADDR2BASE(ptr) != ptr); - assert(isalloc(tsdn, ptr, false) == LARGE_MINCLASS); - assert(isalloc(tsdn, ptr, true) == LARGE_MINCLASS); + assert(extent_addr_get(extent) != ptr); + assert(isalloc(tsdn, extent, ptr, false) == LARGE_MINCLASS); + assert(isalloc(tsdn, extent, ptr, true) == LARGE_MINCLASS); assert(size <= SMALL_MAXCLASS); - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + chunk = (arena_chunk_t *)extent_addr_get(extent); pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; binind = size2index(size); assert(binind < NBINS); arena_mapbits_large_binind_set(chunk, pageind, binind); - assert(isalloc(tsdn, ptr, false) == LARGE_MINCLASS); - assert(isalloc(tsdn, ptr, true) == size); + assert(isalloc(tsdn, extent, ptr, false) == LARGE_MINCLASS); + assert(isalloc(tsdn, extent, ptr, true) == size); } static void -arena_dissociate_bin_run(arena_chunk_t *chunk, arena_run_t *run, - arena_bin_t *bin) +arena_dissociate_bin_run(extent_t *extent, arena_run_t *run, arena_bin_t *bin) { /* Dissociate run from bin. */ if (run == bin->runcur) bin->runcur = NULL; else { - szind_t binind = arena_bin_index(extent_arena_get( - &chunk->extent), bin); + szind_t binind = arena_bin_index(extent_arena_get(extent), bin); const arena_bin_info_t *bin_info = &arena_bin_info[binind]; /* @@ -2668,7 +2688,7 @@ arena_dissociate_bin_run(arena_chunk_t *chunk, arena_run_t *run, static void arena_dalloc_bin_run(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - arena_run_t *run, arena_bin_t *bin) + extent_t *extent, arena_run_t *run, arena_bin_t *bin) { assert(run != bin->runcur); @@ -2676,7 +2696,7 @@ arena_dalloc_bin_run(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, malloc_mutex_unlock(tsdn, &bin->lock); /******************************/ malloc_mutex_lock(tsdn, &arena->lock); - arena_run_dalloc(tsdn, arena, run, true, false, false); + arena_run_dalloc(tsdn, arena, extent, run, true, false, false); malloc_mutex_unlock(tsdn, &arena->lock); /****************************/ malloc_mutex_lock(tsdn, &bin->lock); @@ -2707,7 +2727,7 @@ arena_bin_lower_run(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, static void arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - void *ptr, arena_chunk_map_bits_t *bitselm, bool junked) + extent_t *extent, void *ptr, arena_chunk_map_bits_t *bitselm, bool junked) { size_t pageind, rpages_ind; arena_run_t *run; @@ -2725,10 +2745,10 @@ arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, if (!junked && config_fill && unlikely(opt_junk_free)) arena_dalloc_junk_small(ptr, bin_info); - arena_run_reg_dalloc(run, ptr); + arena_run_reg_dalloc(run, extent, ptr); if (run->nfree == bin_info->nregs) { - arena_dissociate_bin_run(chunk, run, bin); - arena_dalloc_bin_run(tsdn, arena, chunk, run, bin); + arena_dissociate_bin_run(extent, run, bin); + arena_dalloc_bin_run(tsdn, arena, chunk, extent, run, bin); } else if (run->nfree == 1 && run != bin->runcur) arena_bin_lower_run(arena, chunk, run, bin); @@ -2740,15 +2760,17 @@ arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, - arena_chunk_t *chunk, void *ptr, arena_chunk_map_bits_t *bitselm) + arena_chunk_t *chunk, extent_t *extent, void *ptr, + arena_chunk_map_bits_t *bitselm) { - arena_dalloc_bin_locked_impl(tsdn, arena, chunk, ptr, bitselm, true); + arena_dalloc_bin_locked_impl(tsdn, arena, chunk, extent, ptr, bitselm, + true); } -void -arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, void *ptr, - size_t pageind, arena_chunk_map_bits_t *bitselm) +static void +arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, + extent_t *extent, void *ptr, size_t pageind, arena_chunk_map_bits_t *bitselm) { arena_run_t *run; arena_bin_t *bin; @@ -2758,13 +2780,14 @@ arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, void *ptr, run = &arena_miscelm_get_mutable(chunk, rpages_ind)->run; bin = &arena->bins[run->binind]; malloc_mutex_lock(tsdn, &bin->lock); - arena_dalloc_bin_locked_impl(tsdn, arena, chunk, ptr, bitselm, false); + arena_dalloc_bin_locked_impl(tsdn, arena, chunk, extent, ptr, bitselm, + false); malloc_mutex_unlock(tsdn, &bin->lock); } void arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - void *ptr, size_t pageind) + extent_t *extent, void *ptr, size_t pageind) { arena_chunk_map_bits_t *bitselm; @@ -2774,7 +2797,7 @@ arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, pageind)) != BININD_INVALID); } bitselm = arena_bitselm_get_mutable(chunk, pageind); - arena_dalloc_bin(tsdn, arena, chunk, ptr, pageind, bitselm); + arena_dalloc_bin(tsdn, arena, chunk, extent, ptr, pageind, bitselm); arena_decay_tick(tsdn, arena); } @@ -2798,7 +2821,7 @@ arena_dalloc_junk_large_t *arena_dalloc_junk_large = static void arena_dalloc_large_locked_impl(tsdn_t *tsdn, arena_t *arena, - arena_chunk_t *chunk, void *ptr, bool junked) + arena_chunk_t *chunk, extent_t *extent, void *ptr, bool junked) { size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; arena_chunk_map_misc_t *miscelm = arena_miscelm_get_mutable(chunk, @@ -2821,31 +2844,31 @@ arena_dalloc_large_locked_impl(tsdn_t *tsdn, arena_t *arena, } } - arena_run_dalloc(tsdn, arena, run, true, false, false); + arena_run_dalloc(tsdn, arena, extent, run, true, false, false); } void arena_dalloc_large_junked_locked(tsdn_t *tsdn, arena_t *arena, - arena_chunk_t *chunk, void *ptr) + arena_chunk_t *chunk, extent_t *extent, void *ptr) { - arena_dalloc_large_locked_impl(tsdn, arena, chunk, ptr, true); + arena_dalloc_large_locked_impl(tsdn, arena, chunk, extent, ptr, true); } void arena_dalloc_large(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - void *ptr) + extent_t *extent, void *ptr) { malloc_mutex_lock(tsdn, &arena->lock); - arena_dalloc_large_locked_impl(tsdn, arena, chunk, ptr, false); + arena_dalloc_large_locked_impl(tsdn, arena, chunk, extent, ptr, false); malloc_mutex_unlock(tsdn, &arena->lock); arena_decay_tick(tsdn, arena); } static void arena_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - void *ptr, size_t oldsize, size_t size) + extent_t *extent, void *ptr, size_t oldsize, size_t size) { size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; arena_chunk_map_misc_t *miscelm = arena_miscelm_get_mutable(chunk, @@ -2859,8 +2882,8 @@ arena_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, * allocations. */ malloc_mutex_lock(tsdn, &arena->lock); - arena_run_trim_tail(tsdn, arena, chunk, run, oldsize + large_pad, size + - large_pad, true); + arena_run_trim_tail(tsdn, arena, chunk, extent, run, oldsize + + large_pad, size + large_pad, true); if (config_stats) { szind_t oldindex = size2index(oldsize) - NBINS; szind_t index = size2index(size) - NBINS; @@ -2916,7 +2939,8 @@ arena_ralloc_large_grow(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, goto label_fail; run = &arena_miscelm_get_mutable(chunk, pageind+npages)->run; - if (arena_run_split_large(arena, run, splitsize, zero)) + if (arena_run_split_large(arena, iealloc(run), run, splitsize, + zero)) goto label_fail; if (config_cache_oblivious && zero) { @@ -3005,8 +3029,8 @@ arena_ralloc_junk_large_t *arena_ralloc_junk_large = * always fail if growing an object, and the following run is already in use. */ static bool -arena_ralloc_large(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t usize_min, - size_t usize_max, bool zero) +arena_ralloc_large(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, + size_t usize_min, size_t usize_max, bool zero) { arena_chunk_t *chunk; arena_t *arena; @@ -3016,8 +3040,8 @@ arena_ralloc_large(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t usize_min, return (false); } - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - arena = extent_arena_get(&chunk->extent); + chunk = (arena_chunk_t *)extent_addr_get(extent); + arena = extent_arena_get(extent); if (oldsize < usize_max) { bool ret = arena_ralloc_large_grow(tsdn, arena, chunk, ptr, @@ -3026,10 +3050,12 @@ arena_ralloc_large(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t usize_min, if (unlikely(opt_junk_alloc)) { memset((void *)((uintptr_t)ptr + oldsize), JEMALLOC_ALLOC_JUNK, - isalloc(tsdn, ptr, config_prof) - oldsize); + isalloc(tsdn, extent, ptr, config_prof) - + oldsize); } else if (unlikely(opt_zero)) { memset((void *)((uintptr_t)ptr + oldsize), 0, - isalloc(tsdn, ptr, config_prof) - oldsize); + isalloc(tsdn, extent, ptr, config_prof) - + oldsize); } } return (ret); @@ -3038,13 +3064,14 @@ arena_ralloc_large(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t usize_min, assert(oldsize > usize_max); /* Fill before shrinking in order avoid a race. */ arena_ralloc_junk_large(ptr, oldsize, usize_max); - arena_ralloc_large_shrink(tsdn, arena, chunk, ptr, oldsize, usize_max); + arena_ralloc_large_shrink(tsdn, arena, chunk, extent, ptr, oldsize, + usize_max); return (false); } bool -arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, - size_t extra, bool zero) +arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, + size_t size, size_t extra, bool zero) { size_t usize_min, usize_max; @@ -3057,8 +3084,6 @@ arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, usize_min = s2u(size); usize_max = s2u(size + extra); if (likely(oldsize <= large_maxclass && usize_min <= large_maxclass)) { - arena_chunk_t *chunk; - /* * Avoid moving the allocation if the size class can be left the * same. @@ -3073,17 +3098,16 @@ arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, } else { if (usize_max <= SMALL_MAXCLASS) return (true); - if (arena_ralloc_large(tsdn, ptr, oldsize, usize_min, - usize_max, zero)) + if (arena_ralloc_large(tsdn, extent, ptr, oldsize, + usize_min, usize_max, zero)) return (true); } - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - arena_decay_tick(tsdn, extent_arena_get(&chunk->extent)); + arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } else { - return (huge_ralloc_no_move(tsdn, ptr, oldsize, usize_min, - usize_max, zero)); + return (huge_ralloc_no_move(tsdn, extent, ptr, oldsize, + usize_min, usize_max, zero)); } } @@ -3102,8 +3126,8 @@ arena_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, } void * -arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, - size_t size, size_t alignment, bool zero, tcache_t *tcache) +arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, + size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache) { void *ret; size_t usize; @@ -3116,7 +3140,8 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, size_t copysize; /* Try to avoid moving the allocation. */ - if (!arena_ralloc_no_move(tsdn, ptr, oldsize, usize, 0, zero)) + if (!arena_ralloc_no_move(tsdn, extent, ptr, oldsize, usize, 0, + zero)) return (ptr); /* @@ -3136,10 +3161,10 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, copysize = (usize < oldsize) ? usize : oldsize; memcpy(ret, ptr, copysize); - isdalloct(tsdn, ptr, oldsize, tcache, true); + isdalloct(tsdn, extent, ptr, oldsize, tcache, true); } else { - ret = huge_ralloc(tsdn, arena, ptr, oldsize, usize, alignment, - zero, tcache); + ret = huge_ralloc(tsdn, arena, extent, ptr, oldsize, usize, + alignment, zero, tcache); } return (ret); } diff --git a/src/chunk.c b/src/chunk.c index 31b86456..e35bb30a 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -180,6 +180,15 @@ chunk_deregister(const void *chunk, const extent_t *extent) } } +void +chunk_reregister(tsdn_t *tsdn, const void *chunk, const extent_t *extent) +{ + bool err; + + err = chunk_register(tsdn, chunk, extent); + assert(!err); +} + /* * Do first-best-fit chunk selection, i.e. select the lowest chunk that best * fits. diff --git a/src/ckh.c b/src/ckh.c index 747c1c86..3135ee74 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -283,12 +283,12 @@ ckh_grow(tsdn_t *tsdn, ckh_t *ckh) ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; if (!ckh_rebuild(ckh, tab)) { - idalloctm(tsdn, tab, NULL, true, true); + idalloctm(tsdn, iealloc(tab), tab, NULL, true, true); break; } /* Rebuilding failed, so back out partially rebuilt table. */ - idalloctm(tsdn, ckh->tab, NULL, true, true); + idalloctm(tsdn, iealloc(ckh->tab), ckh->tab, NULL, true, true); ckh->tab = tab; ckh->lg_curbuckets = lg_prevbuckets; } @@ -330,7 +330,7 @@ ckh_shrink(tsdn_t *tsdn, ckh_t *ckh) ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; if (!ckh_rebuild(ckh, tab)) { - idalloctm(tsdn, tab, NULL, true, true); + idalloctm(tsdn, iealloc(tab), tab, NULL, true, true); #ifdef CKH_COUNT ckh->nshrinks++; #endif @@ -338,7 +338,7 @@ ckh_shrink(tsdn_t *tsdn, ckh_t *ckh) } /* Rebuilding failed, so back out partially rebuilt table. */ - idalloctm(tsdn, ckh->tab, NULL, true, true); + idalloctm(tsdn, iealloc(ckh->tab), ckh->tab, NULL, true, true); ckh->tab = tab; ckh->lg_curbuckets = lg_prevbuckets; #ifdef CKH_COUNT @@ -421,7 +421,7 @@ ckh_delete(tsdn_t *tsdn, ckh_t *ckh) (unsigned long long)ckh->nrelocs); #endif - idalloctm(tsdn, ckh->tab, NULL, true, true); + idalloctm(tsdn, iealloc(ckh->tab), ckh->tab, NULL, true, true); if (config_debug) memset(ckh, JEMALLOC_FREE_JUNK, sizeof(ckh_t)); } diff --git a/src/huge.c b/src/huge.c index c30e78de..e42ea9c1 100644 --- a/src/huge.c +++ b/src/huge.c @@ -3,42 +3,6 @@ /******************************************************************************/ -static extent_t * -huge_extent_get(const void *ptr) -{ - extent_t *extent; - - extent = chunk_lookup(ptr, true); - assert(!extent_achunk_get(extent)); - - return (extent); -} - -static bool -huge_extent_set(tsdn_t *tsdn, const void *ptr, extent_t *extent) -{ - - assert(extent_addr_get(extent) == ptr); - assert(!extent_achunk_get(extent)); - return (chunk_register(tsdn, ptr, extent)); -} - -static void -huge_extent_reset(tsdn_t *tsdn, const void *ptr, extent_t *extent) -{ - bool err; - - err = huge_extent_set(tsdn, ptr, extent); - assert(!err); -} - -static void -huge_extent_unset(const void *ptr, const extent_t *extent) -{ - - chunk_deregister(ptr, extent); -} - void * huge_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero) { @@ -81,15 +45,15 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, arena = arena_choose(tsdn_tsd(tsdn), arena); if (unlikely(arena == NULL) || (ret = arena_chunk_alloc_huge(tsdn, arena, usize, alignment, &is_zeroed)) == NULL) { - idalloctm(tsdn, extent, NULL, true, true); + idalloctm(tsdn, iealloc(extent), extent, NULL, true, true); return (NULL); } extent_init(extent, arena, ret, usize, is_zeroed, true); - if (huge_extent_set(tsdn, ret, extent)) { + if (chunk_register(tsdn, ret, extent)) { arena_chunk_dalloc_huge(tsdn, arena, ret, usize); - idalloctm(tsdn, extent, NULL, true, true); + idalloctm(tsdn, iealloc(extent), extent, NULL, true, true); return (NULL); } @@ -133,11 +97,10 @@ huge_dalloc_junk_t *huge_dalloc_junk = JEMALLOC_N(huge_dalloc_junk_impl); #endif static void -huge_ralloc_no_move_similar(tsdn_t *tsdn, void *ptr, size_t oldsize, - size_t usize_min, size_t usize_max, bool zero) +huge_ralloc_no_move_similar(tsdn_t *tsdn, extent_t *extent, void *ptr, + size_t oldsize, size_t usize_min, size_t usize_max, bool zero) { size_t usize, usize_next; - extent_t *extent; arena_t *arena; chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; bool pre_zeroed, post_zeroed; @@ -150,7 +113,6 @@ huge_ralloc_no_move_similar(tsdn_t *tsdn, void *ptr, size_t oldsize, if (oldsize == usize) return; - extent = huge_extent_get(ptr); arena = extent_arena_get(extent); pre_zeroed = extent_zeroed_get(extent); @@ -169,15 +131,15 @@ huge_ralloc_no_move_similar(tsdn_t *tsdn, void *ptr, size_t oldsize, } else post_zeroed = pre_zeroed; - malloc_mutex_lock(tsdn, &arena->huge_mtx); /* Update the size of the huge allocation. */ assert(extent_size_get(extent) != usize); - huge_extent_unset(ptr, extent); + chunk_deregister(tsdn, ptr, extent); + malloc_mutex_lock(tsdn, &arena->huge_mtx); extent_size_set(extent, usize); - huge_extent_reset(tsdn, ptr, extent); + malloc_mutex_unlock(tsdn, &arena->huge_mtx); + chunk_reregister(tsdn, ptr, extent); /* Update zeroed. */ extent_zeroed_set(extent, post_zeroed); - malloc_mutex_unlock(tsdn, &arena->huge_mtx); arena_chunk_ralloc_huge_similar(tsdn, arena, ptr, oldsize, usize); @@ -196,16 +158,14 @@ huge_ralloc_no_move_similar(tsdn_t *tsdn, void *ptr, size_t oldsize, } static bool -huge_ralloc_no_move_shrink(tsdn_t *tsdn, void *ptr, size_t oldsize, - size_t usize) +huge_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, void *ptr, + size_t oldsize, size_t usize) { - extent_t *extent; arena_t *arena; chunk_hooks_t chunk_hooks; size_t cdiff; bool pre_zeroed, post_zeroed; - extent = huge_extent_get(ptr); arena = extent_arena_get(extent); pre_zeroed = extent_zeroed_get(extent); chunk_hooks = chunk_hooks_get(tsdn, arena); @@ -233,14 +193,14 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, void *ptr, size_t oldsize, } else post_zeroed = pre_zeroed; - malloc_mutex_lock(tsdn, &arena->huge_mtx); /* Update the size of the huge allocation. */ - huge_extent_unset(ptr, extent); + chunk_deregister(ptr, extent); + malloc_mutex_lock(tsdn, &arena->huge_mtx); extent_size_set(extent, usize); - huge_extent_reset(tsdn, ptr, extent); /* Update zeroed. */ extent_zeroed_set(extent, post_zeroed); malloc_mutex_unlock(tsdn, &arena->huge_mtx); + chunk_reregister(tsdn, ptr, extent); /* Zap the excess chunks. */ arena_chunk_ralloc_huge_shrink(tsdn, arena, ptr, oldsize, usize); @@ -249,14 +209,12 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, void *ptr, size_t oldsize, } static bool -huge_ralloc_no_move_expand(tsdn_t *tsdn, void *ptr, size_t oldsize, - size_t usize, bool zero) +huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, void *ptr, + size_t oldsize, size_t usize, bool zero) { - extent_t *extent; arena_t *arena; bool is_zeroed_subchunk, is_zeroed_chunk; - extent = huge_extent_get(ptr); arena = extent_arena_get(extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); is_zeroed_subchunk = extent_zeroed_get(extent); @@ -272,12 +230,12 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, void *ptr, size_t oldsize, &is_zeroed_chunk)) return (true); - malloc_mutex_lock(tsdn, &arena->huge_mtx); /* Update the size of the huge allocation. */ - huge_extent_unset(ptr, extent); + chunk_deregister(ptr, extent); + malloc_mutex_lock(tsdn, &arena->huge_mtx); extent_size_set(extent, usize); - huge_extent_reset(tsdn, ptr, extent); malloc_mutex_unlock(tsdn, &arena->huge_mtx); + chunk_reregister(tsdn, ptr, extent); if (zero || (config_fill && unlikely(opt_zero))) { if (!is_zeroed_subchunk) { @@ -298,8 +256,8 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, void *ptr, size_t oldsize, } bool -huge_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t usize_min, - size_t usize_max, bool zero) +huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, + size_t usize_min, size_t usize_max, bool zero) { assert(s2u(oldsize) == oldsize); @@ -312,16 +270,16 @@ huge_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t usize_min, if (CHUNK_CEILING(usize_max) > CHUNK_CEILING(oldsize)) { /* Attempt to expand the allocation in-place. */ - if (!huge_ralloc_no_move_expand(tsdn, ptr, oldsize, usize_max, - zero)) { - arena_decay_tick(tsdn, huge_aalloc(ptr)); + if (!huge_ralloc_no_move_expand(tsdn, extent, ptr, oldsize, + usize_max, zero)) { + arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } /* Try again, this time with usize_min. */ if (usize_min < usize_max && CHUNK_CEILING(usize_min) > CHUNK_CEILING(oldsize) && huge_ralloc_no_move_expand(tsdn, - ptr, oldsize, usize_min, zero)) { - arena_decay_tick(tsdn, huge_aalloc(ptr)); + extent, ptr, oldsize, usize_min, zero)) { + arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } } @@ -332,17 +290,17 @@ huge_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t usize_min, */ if (CHUNK_CEILING(oldsize) >= CHUNK_CEILING(usize_min) && CHUNK_CEILING(oldsize) <= CHUNK_CEILING(usize_max)) { - huge_ralloc_no_move_similar(tsdn, ptr, oldsize, usize_min, - usize_max, zero); - arena_decay_tick(tsdn, huge_aalloc(ptr)); + huge_ralloc_no_move_similar(tsdn, extent, ptr, oldsize, + usize_min, usize_max, zero); + arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } /* Attempt to shrink the allocation in-place. */ if (CHUNK_CEILING(oldsize) > CHUNK_CEILING(usize_max)) { - if (!huge_ralloc_no_move_shrink(tsdn, ptr, oldsize, + if (!huge_ralloc_no_move_shrink(tsdn, extent, ptr, oldsize, usize_max)) { - arena_decay_tick(tsdn, huge_aalloc(ptr)); + arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } } @@ -360,8 +318,8 @@ huge_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, } void * -huge_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, - size_t usize, size_t alignment, bool zero, tcache_t *tcache) +huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, + size_t oldsize, size_t usize, size_t alignment, bool zero, tcache_t *tcache) { void *ret; size_t copysize; @@ -370,7 +328,8 @@ huge_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, assert(usize > 0 && usize <= HUGE_MAXCLASS); /* Try to avoid moving the allocation. */ - if (!huge_ralloc_no_move(tsdn, ptr, oldsize, usize, usize, zero)) + if (!huge_ralloc_no_move(tsdn, extent, ptr, oldsize, usize, usize, + zero)) return (ptr); /* @@ -384,19 +343,17 @@ huge_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, copysize = (usize < oldsize) ? usize : oldsize; memcpy(ret, ptr, copysize); - isdalloct(tsdn, ptr, oldsize, tcache, true); + isdalloct(tsdn, extent, ptr, oldsize, tcache, true); return (ret); } void -huge_dalloc(tsdn_t *tsdn, void *ptr) +huge_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr) { - extent_t *extent; arena_t *arena; - extent = huge_extent_get(ptr); arena = extent_arena_get(extent); - huge_extent_unset(ptr, extent); + chunk_deregister(ptr, extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); ql_remove(&arena->huge, extent, ql_link); malloc_mutex_unlock(tsdn, &arena->huge_mtx); @@ -405,26 +362,17 @@ huge_dalloc(tsdn_t *tsdn, void *ptr) extent_size_get(extent)); arena_chunk_dalloc_huge(tsdn, extent_arena_get(extent), extent_addr_get(extent), extent_size_get(extent)); - idalloctm(tsdn, extent, NULL, true, true); + idalloctm(tsdn, iealloc(extent), extent, NULL, true, true); arena_decay_tick(tsdn, arena); } -arena_t * -huge_aalloc(const void *ptr) -{ - - return (extent_arena_get(huge_extent_get(ptr))); -} - size_t -huge_salloc(tsdn_t *tsdn, const void *ptr) +huge_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { size_t size; - extent_t *extent; arena_t *arena; - extent = huge_extent_get(ptr); arena = extent_arena_get(extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); size = extent_size_get(extent); @@ -434,13 +382,13 @@ huge_salloc(tsdn_t *tsdn, const void *ptr) } prof_tctx_t * -huge_prof_tctx_get(tsdn_t *tsdn, const void *ptr) +huge_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { prof_tctx_t *tctx; - extent_t *extent; arena_t *arena; - extent = huge_extent_get(ptr); + assert(extent == iealloc(ptr)); + arena = extent_arena_get(extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); tctx = extent_prof_tctx_get(extent); @@ -450,12 +398,13 @@ huge_prof_tctx_get(tsdn_t *tsdn, const void *ptr) } void -huge_prof_tctx_set(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx) +huge_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, + prof_tctx_t *tctx) { - extent_t *extent; arena_t *arena; - extent = huge_extent_get(ptr); + assert(extent == iealloc(ptr)); + arena = extent_arena_get(extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); extent_prof_tctx_set(extent, tctx); @@ -463,8 +412,8 @@ huge_prof_tctx_set(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx) } void -huge_prof_tctx_reset(tsdn_t *tsdn, const void *ptr) +huge_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr) { - huge_prof_tctx_set(tsdn, ptr, (prof_tctx_t *)(uintptr_t)1U); + huge_prof_tctx_set(tsdn, extent, ptr, (prof_tctx_t *)(uintptr_t)1U); } diff --git a/src/jemalloc.c b/src/jemalloc.c index 929f3b87..67a3b564 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -308,10 +308,10 @@ a0ialloc(size_t size, bool zero, bool is_metadata) } static void -a0idalloc(void *ptr, bool is_metadata) +a0idalloc(extent_t *extent, void *ptr, bool is_metadata) { - idalloctm(TSDN_NULL, ptr, false, is_metadata, true); + idalloctm(TSDN_NULL, extent, ptr, false, is_metadata, true); } void * @@ -325,7 +325,7 @@ void a0dalloc(void *ptr) { - a0idalloc(ptr, true); + a0idalloc(iealloc(ptr), ptr, true); } /* @@ -365,7 +365,7 @@ bootstrap_free(void *ptr) if (unlikely(ptr == NULL)) return; - a0idalloc(ptr, false); + a0idalloc(iealloc(ptr), ptr, false); } static void @@ -1401,7 +1401,7 @@ ialloc_prof_sample(tsd_t *tsd, size_t usize, szind_t ind, bool zero, p = ialloc(tsd, LARGE_MINCLASS, ind_large, zero, slow_path); if (p == NULL) return (NULL); - arena_prof_promoted(tsd_tsdn(tsd), p, usize); + arena_prof_promoted(tsd_tsdn(tsd), iealloc(p), p, usize); } else p = ialloc(tsd, usize, ind, zero, slow_path); @@ -1423,7 +1423,7 @@ ialloc_prof(tsd_t *tsd, size_t usize, szind_t ind, bool zero, bool slow_path) prof_alloc_rollback(tsd, tctx, true); return (NULL); } - prof_malloc(tsd_tsdn(tsd), p, usize, tctx); + prof_malloc(tsd_tsdn(tsd), iealloc(p), p, usize, tctx); return (p); } @@ -1482,7 +1482,7 @@ ialloc_post_check(void *ret, tsdn_t *tsdn, size_t usize, const char *func, set_errno(ENOMEM); } if (config_stats && likely(ret != NULL)) { - assert(usize == isalloc(tsdn, ret, config_prof)); + assert(usize == isalloc(tsdn, iealloc(ret), ret, config_prof)); *tsd_thread_allocatedp_get(tsdn_tsd(tsdn)) += usize; } witness_assert_lockless(tsdn); @@ -1525,7 +1525,7 @@ imemalign_prof_sample(tsd_t *tsd, size_t alignment, size_t usize, p = ipalloc(tsd, LARGE_MINCLASS, alignment, false); if (p == NULL) return (NULL); - arena_prof_promoted(tsd_tsdn(tsd), p, usize); + arena_prof_promoted(tsd_tsdn(tsd), iealloc(p), p, usize); } else p = ipalloc(tsd, usize, alignment, false); @@ -1547,7 +1547,7 @@ imemalign_prof(tsd_t *tsd, size_t alignment, size_t usize) prof_alloc_rollback(tsd, tctx, true); return (NULL); } - prof_malloc(tsd_tsdn(tsd), p, usize, tctx); + prof_malloc(tsd_tsdn(tsd), iealloc(p), p, usize, tctx); return (p); } @@ -1604,7 +1604,8 @@ imemalign(void **memptr, size_t alignment, size_t size, size_t min_alignment) ret = 0; label_return: if (config_stats && likely(result != NULL)) { - assert(usize == isalloc(tsd_tsdn(tsd), result, config_prof)); + assert(usize == isalloc(tsd_tsdn(tsd), iealloc(result), result, + config_prof)); *tsd_thread_allocatedp_get(tsd) += usize; } UTRACE(0, size, result); @@ -1683,44 +1684,49 @@ je_calloc(size_t num, size_t size) } static void * -irealloc_prof_sample(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize, - prof_tctx_t *tctx) +irealloc_prof_sample(tsd_t *tsd, extent_t *extent, void *old_ptr, + size_t old_usize, size_t usize, prof_tctx_t *tctx) { void *p; if (tctx == NULL) return (NULL); if (usize <= SMALL_MAXCLASS) { - p = iralloc(tsd, old_ptr, old_usize, LARGE_MINCLASS, 0, false); + p = iralloc(tsd, extent, old_ptr, old_usize, LARGE_MINCLASS, 0, + false); if (p == NULL) return (NULL); - arena_prof_promoted(tsd_tsdn(tsd), p, usize); + arena_prof_promoted(tsd_tsdn(tsd), iealloc(p), p, usize); } else - p = iralloc(tsd, old_ptr, old_usize, usize, 0, false); + p = iralloc(tsd, extent, old_ptr, old_usize, usize, 0, false); return (p); } JEMALLOC_ALWAYS_INLINE_C void * -irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize) +irealloc_prof(tsd_t *tsd, extent_t *extent, void *old_ptr, size_t old_usize, + size_t usize) { void *p; + extent_t *e; bool prof_active; prof_tctx_t *old_tctx, *tctx; prof_active = prof_active_get_unlocked(); - old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr); + old_tctx = prof_tctx_get(tsd_tsdn(tsd), extent, old_ptr); tctx = prof_alloc_prep(tsd, usize, prof_active, true); - if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) - p = irealloc_prof_sample(tsd, old_ptr, old_usize, usize, tctx); - else - p = iralloc(tsd, old_ptr, old_usize, usize, 0, false); + if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { + p = irealloc_prof_sample(tsd, extent, old_ptr, old_usize, usize, + tctx); + } else + p = iralloc(tsd, extent, old_ptr, old_usize, usize, 0, false); if (unlikely(p == NULL)) { prof_alloc_rollback(tsd, tctx, true); return (NULL); } - prof_realloc(tsd, p, usize, tctx, prof_active, true, old_ptr, old_usize, - old_tctx); + e = (p == old_ptr) ? extent : iealloc(p); + prof_realloc(tsd, e, p, usize, tctx, prof_active, true, + old_ptr, old_usize, old_tctx); return (p); } @@ -1728,6 +1734,7 @@ irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize) JEMALLOC_INLINE_C void ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { + extent_t *extent; size_t usize; witness_assert_lockless(tsd_tsdn(tsd)); @@ -1735,22 +1742,24 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); + extent = iealloc(ptr); if (config_prof && opt_prof) { - usize = isalloc(tsd_tsdn(tsd), ptr, config_prof); - prof_free(tsd, ptr, usize); + usize = isalloc(tsd_tsdn(tsd), extent, ptr, config_prof); + prof_free(tsd, extent, ptr, usize); } else if (config_stats) - usize = isalloc(tsd_tsdn(tsd), ptr, config_prof); + usize = isalloc(tsd_tsdn(tsd), extent, ptr, config_prof); if (config_stats) *tsd_thread_deallocatedp_get(tsd) += usize; if (likely(!slow_path)) - idalloctm(tsd_tsdn(tsd), ptr, tcache, false, false); + idalloctm(tsd_tsdn(tsd), extent, ptr, tcache, false, false); else - idalloctm(tsd_tsdn(tsd), ptr, tcache, false, true); + idalloctm(tsd_tsdn(tsd), extent, ptr, tcache, false, true); } JEMALLOC_INLINE_C void -isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) +isfree(tsd_t *tsd, extent_t *extent, void *ptr, size_t usize, tcache_t *tcache, + bool slow_path) { witness_assert_lockless(tsd_tsdn(tsd)); @@ -1759,14 +1768,14 @@ isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) assert(malloc_initialized() || IS_INITIALIZER); if (config_prof && opt_prof) - prof_free(tsd, ptr, usize); + prof_free(tsd, extent, ptr, usize); if (config_stats) *tsd_thread_deallocatedp_get(tsd) += usize; if (likely(!slow_path)) - isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, false); + isdalloct(tsd_tsdn(tsd), extent, ptr, usize, tcache, false); else - isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, true); + isdalloct(tsd_tsdn(tsd), extent, ptr, usize, tcache, true); } JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN @@ -1794,22 +1803,26 @@ je_realloc(void *ptr, size_t size) if (likely(ptr != NULL)) { tsd_t *tsd; + extent_t *extent; assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); - old_usize = isalloc(tsd_tsdn(tsd), ptr, config_prof); + extent = iealloc(ptr); + old_usize = isalloc(tsd_tsdn(tsd), extent, ptr, config_prof); if (config_prof && opt_prof) { usize = s2u(size); ret = unlikely(usize == 0 || usize > HUGE_MAXCLASS) ? - NULL : irealloc_prof(tsd, ptr, old_usize, usize); + NULL : irealloc_prof(tsd, extent, ptr, old_usize, + usize); } else { if (config_stats) usize = s2u(size); - ret = iralloc(tsd, ptr, old_usize, size, 0, false); + ret = iralloc(tsd, extent, ptr, old_usize, size, 0, + false); } tsdn = tsd_tsdn(tsd); } else { @@ -1832,7 +1845,7 @@ je_realloc(void *ptr, size_t size) if (config_stats && likely(ret != NULL)) { tsd_t *tsd; - assert(usize == isalloc(tsdn, ret, config_prof)); + assert(usize == isalloc(tsdn, iealloc(ret), ret, config_prof)); tsd = tsdn_tsd(tsdn); *tsd_thread_allocatedp_get(tsd) += usize; *tsd_thread_deallocatedp_get(tsd) += old_usize; @@ -1986,11 +1999,10 @@ imallocx_prof_sample(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, tcache, arena, slow_path); if (p == NULL) return (NULL); - arena_prof_promoted(tsdn, p, usize); - } else { + arena_prof_promoted(tsdn, iealloc(p), p, usize); + } else p = imallocx_flags(tsdn, usize, alignment, zero, tcache, arena, slow_path); - } return (p); } @@ -2021,7 +2033,7 @@ imallocx_prof(tsd_t *tsd, size_t size, int flags, size_t *usize, bool slow_path) prof_alloc_rollback(tsd, tctx, true); return (NULL); } - prof_malloc(tsd_tsdn(tsd), p, *usize, tctx); + prof_malloc(tsd_tsdn(tsd), iealloc(p), p, *usize, tctx); assert(alignment == 0 || ((uintptr_t)p & (alignment - 1)) == ZU(0)); return (p); @@ -2109,46 +2121,47 @@ je_mallocx(size_t size, int flags) } static void * -irallocx_prof_sample(tsdn_t *tsdn, void *old_ptr, size_t old_usize, - size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena, - prof_tctx_t *tctx) +irallocx_prof_sample(tsdn_t *tsdn, extent_t *extent, void *old_ptr, + size_t old_usize, size_t usize, size_t alignment, bool zero, + tcache_t *tcache, arena_t *arena, prof_tctx_t *tctx) { void *p; if (tctx == NULL) return (NULL); if (usize <= SMALL_MAXCLASS) { - p = iralloct(tsdn, old_ptr, old_usize, LARGE_MINCLASS, + p = iralloct(tsdn, extent, old_ptr, old_usize, LARGE_MINCLASS, alignment, zero, tcache, arena); if (p == NULL) return (NULL); - arena_prof_promoted(tsdn, p, usize); + arena_prof_promoted(tsdn, iealloc(p), p, usize); } else { - p = iralloct(tsdn, old_ptr, old_usize, usize, alignment, zero, - tcache, arena); + p = iralloct(tsdn, extent, old_ptr, old_usize, usize, alignment, + zero, tcache, arena); } return (p); } JEMALLOC_ALWAYS_INLINE_C void * -irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size, - size_t alignment, size_t *usize, bool zero, tcache_t *tcache, +irallocx_prof(tsd_t *tsd, extent_t *extent, void *old_ptr, size_t old_usize, + size_t size, size_t alignment, size_t *usize, bool zero, tcache_t *tcache, arena_t *arena) { void *p; + extent_t *e; bool prof_active; prof_tctx_t *old_tctx, *tctx; prof_active = prof_active_get_unlocked(); - old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr); + old_tctx = prof_tctx_get(tsd_tsdn(tsd), extent, old_ptr); tctx = prof_alloc_prep(tsd, *usize, prof_active, true); if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { - p = irallocx_prof_sample(tsd_tsdn(tsd), old_ptr, old_usize, - *usize, alignment, zero, tcache, arena, tctx); + p = irallocx_prof_sample(tsd_tsdn(tsd), extent, old_ptr, + old_usize, *usize, alignment, zero, tcache, arena, tctx); } else { - p = iralloct(tsd_tsdn(tsd), old_ptr, old_usize, size, alignment, - zero, tcache, arena); + p = iralloct(tsd_tsdn(tsd), extent, old_ptr, old_usize, size, + alignment, zero, tcache, arena); } if (unlikely(p == NULL)) { prof_alloc_rollback(tsd, tctx, true); @@ -2164,9 +2177,11 @@ irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size, * be the same as the current usize because of in-place large * reallocation. Therefore, query the actual value of usize. */ - *usize = isalloc(tsd_tsdn(tsd), p, config_prof); - } - prof_realloc(tsd, p, *usize, tctx, prof_active, true, old_ptr, + e = extent; + *usize = isalloc(tsd_tsdn(tsd), e, p, config_prof); + } else + e = iealloc(p); + prof_realloc(tsd, e, p, *usize, tctx, prof_active, true, old_ptr, old_usize, old_tctx); return (p); @@ -2179,6 +2194,7 @@ je_rallocx(void *ptr, size_t size, int flags) { void *p; tsd_t *tsd; + extent_t *extent; size_t usize; size_t old_usize; size_t alignment = MALLOCX_ALIGN_GET(flags); @@ -2191,6 +2207,7 @@ je_rallocx(void *ptr, size_t size, int flags) assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); + extent = iealloc(ptr); if (unlikely((flags & MALLOCX_ARENA_MASK) != 0)) { unsigned arena_ind = MALLOCX_ARENA_GET(flags); @@ -2208,23 +2225,25 @@ je_rallocx(void *ptr, size_t size, int flags) } else tcache = tcache_get(tsd, true); - old_usize = isalloc(tsd_tsdn(tsd), ptr, config_prof); + old_usize = isalloc(tsd_tsdn(tsd), extent, ptr, config_prof); if (config_prof && opt_prof) { usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment); if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) goto label_oom; - p = irallocx_prof(tsd, ptr, old_usize, size, alignment, &usize, - zero, tcache, arena); + p = irallocx_prof(tsd, extent, ptr, old_usize, size, alignment, + &usize, zero, tcache, arena); if (unlikely(p == NULL)) goto label_oom; } else { - p = iralloct(tsd_tsdn(tsd), ptr, old_usize, size, alignment, - zero, tcache, arena); + p = iralloct(tsd_tsdn(tsd), extent, ptr, old_usize, size, + alignment, zero, tcache, arena); if (unlikely(p == NULL)) goto label_oom; - if (config_stats) - usize = isalloc(tsd_tsdn(tsd), p, config_prof); + if (config_stats) { + usize = isalloc(tsd_tsdn(tsd), iealloc(p), p, + config_prof); + } } assert(alignment == 0 || ((uintptr_t)p & (alignment - 1)) == ZU(0)); @@ -2246,42 +2265,43 @@ label_oom: } JEMALLOC_ALWAYS_INLINE_C size_t -ixallocx_helper(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size, - size_t extra, size_t alignment, bool zero) +ixallocx_helper(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t old_usize, + size_t size, size_t extra, size_t alignment, bool zero) { size_t usize; - if (ixalloc(tsdn, ptr, old_usize, size, extra, alignment, zero)) + if (ixalloc(tsdn, extent, ptr, old_usize, size, extra, alignment, zero)) return (old_usize); - usize = isalloc(tsdn, ptr, config_prof); + usize = isalloc(tsdn, extent, ptr, config_prof); return (usize); } static size_t -ixallocx_prof_sample(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size, - size_t extra, size_t alignment, bool zero, prof_tctx_t *tctx) +ixallocx_prof_sample(tsdn_t *tsdn, extent_t *extent, void *ptr, + size_t old_usize, size_t size, size_t extra, size_t alignment, bool zero, + prof_tctx_t *tctx) { size_t usize; if (tctx == NULL) return (old_usize); - usize = ixallocx_helper(tsdn, ptr, old_usize, size, extra, alignment, - zero); + usize = ixallocx_helper(tsdn, extent, ptr, old_usize, size, extra, + alignment, zero); return (usize); } JEMALLOC_ALWAYS_INLINE_C size_t -ixallocx_prof(tsd_t *tsd, void *ptr, size_t old_usize, size_t size, - size_t extra, size_t alignment, bool zero) +ixallocx_prof(tsd_t *tsd, extent_t *extent, void *ptr, size_t old_usize, + size_t size, size_t extra, size_t alignment, bool zero) { size_t usize_max, usize; bool prof_active; prof_tctx_t *old_tctx, *tctx; prof_active = prof_active_get_unlocked(); - old_tctx = prof_tctx_get(tsd_tsdn(tsd), ptr); + old_tctx = prof_tctx_get(tsd_tsdn(tsd), extent, ptr); /* * usize isn't knowable before ixalloc() returns when extra is non-zero. * Therefore, compute its maximum possible value and use that in @@ -2306,18 +2326,18 @@ ixallocx_prof(tsd_t *tsd, void *ptr, size_t old_usize, size_t size, tctx = prof_alloc_prep(tsd, usize_max, prof_active, false); if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { - usize = ixallocx_prof_sample(tsd_tsdn(tsd), ptr, old_usize, - size, extra, alignment, zero, tctx); + usize = ixallocx_prof_sample(tsd_tsdn(tsd), extent, ptr, + old_usize, size, extra, alignment, zero, tctx); } else { - usize = ixallocx_helper(tsd_tsdn(tsd), ptr, old_usize, size, - extra, alignment, zero); + usize = ixallocx_helper(tsd_tsdn(tsd), extent, ptr, old_usize, + size, extra, alignment, zero); } if (usize == old_usize) { prof_alloc_rollback(tsd, tctx, false); return (usize); } - prof_realloc(tsd, ptr, usize, tctx, prof_active, false, ptr, old_usize, - old_tctx); + prof_realloc(tsd, extent, ptr, usize, tctx, prof_active, false, ptr, + old_usize, old_tctx); return (usize); } @@ -2326,6 +2346,7 @@ JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW je_xallocx(void *ptr, size_t size, size_t extra, int flags) { tsd_t *tsd; + extent_t *extent; size_t usize, old_usize; size_t alignment = MALLOCX_ALIGN_GET(flags); bool zero = flags & MALLOCX_ZERO; @@ -2336,8 +2357,9 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); + extent = iealloc(ptr); - old_usize = isalloc(tsd_tsdn(tsd), ptr, config_prof); + old_usize = isalloc(tsd_tsdn(tsd), extent, ptr, config_prof); /* * The API explicitly absolves itself of protecting against (size + @@ -2356,11 +2378,11 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) extra = HUGE_MAXCLASS - size; if (config_prof && opt_prof) { - usize = ixallocx_prof(tsd, ptr, old_usize, size, extra, + usize = ixallocx_prof(tsd, extent, ptr, old_usize, size, extra, alignment, zero); } else { - usize = ixallocx_helper(tsd_tsdn(tsd), ptr, old_usize, size, - extra, alignment, zero); + usize = ixallocx_helper(tsd_tsdn(tsd), extent, ptr, old_usize, + size, extra, alignment, zero); } if (unlikely(usize == old_usize)) goto label_not_resized; @@ -2390,7 +2412,7 @@ je_sallocx(const void *ptr, int flags) if (config_ivsalloc) usize = ivsalloc(tsdn, ptr, config_prof); else - usize = isalloc(tsdn, ptr, config_prof); + usize = isalloc(tsdn, iealloc(ptr), ptr, config_prof); witness_assert_lockless(tsdn); return (usize); @@ -2442,14 +2464,16 @@ JEMALLOC_EXPORT void JEMALLOC_NOTHROW je_sdallocx(void *ptr, size_t size, int flags) { tsd_t *tsd; - tcache_t *tcache; + extent_t *extent; size_t usize; + tcache_t *tcache; assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); + extent = iealloc(ptr); usize = inallocx(tsd_tsdn(tsd), size, flags); - assert(usize == isalloc(tsd_tsdn(tsd), ptr, config_prof)); + assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr, config_prof)); witness_assert_lockless(tsd_tsdn(tsd)); if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { @@ -2462,9 +2486,9 @@ je_sdallocx(void *ptr, size_t size, int flags) UTRACE(ptr, 0, 0); if (likely(!malloc_slow)) - isfree(tsd, ptr, usize, tcache, false); + isfree(tsd, extent, ptr, usize, tcache, false); else - isfree(tsd, ptr, usize, tcache, true); + isfree(tsd, extent, ptr, usize, tcache, true); witness_assert_lockless(tsd_tsdn(tsd)); } @@ -2566,8 +2590,10 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) if (config_ivsalloc) ret = ivsalloc(tsdn, ptr, config_prof); - else - ret = (ptr == NULL) ? 0 : isalloc(tsdn, ptr, config_prof); + else { + ret = (ptr == NULL) ? 0 : isalloc(tsdn, iealloc(ptr), ptr, + config_prof); + } witness_assert_lockless(tsdn); return (ret); diff --git a/src/prof.c b/src/prof.c index c1f58d46..121dcd91 100644 --- a/src/prof.c +++ b/src/prof.c @@ -223,11 +223,11 @@ prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated) } void -prof_malloc_sample_object(tsdn_t *tsdn, const void *ptr, size_t usize, - prof_tctx_t *tctx) +prof_malloc_sample_object(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize, prof_tctx_t *tctx) { - prof_tctx_set(tsdn, ptr, usize, tctx); + prof_tctx_set(tsdn, extent, ptr, usize, tctx); malloc_mutex_lock(tsdn, tctx->tdata->lock); tctx->cnts.curobjs++; @@ -596,7 +596,7 @@ prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self, prof_gctx_t *gctx, prof_leave(tsd, tdata_self); /* Destroy gctx. */ malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock); - idalloctm(tsd_tsdn(tsd), gctx, NULL, true, true); + idalloctm(tsd_tsdn(tsd), iealloc(gctx), gctx, NULL, true, true); } else { /* * Compensate for increment in prof_tctx_destroy() or @@ -707,7 +707,7 @@ prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) prof_tdata_destroy(tsd_tsdn(tsd), tdata, false); if (destroy_tctx) - idalloctm(tsd_tsdn(tsd), tctx, NULL, true, true); + idalloctm(tsd_tsdn(tsd), iealloc(tctx), tctx, NULL, true, true); } static bool @@ -736,7 +736,8 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, if (ckh_insert(tsd_tsdn(tsd), &bt2gctx, btkey.v, gctx.v)) { /* OOM. */ prof_leave(tsd, tdata); - idalloctm(tsd_tsdn(tsd), gctx.v, NULL, true, true); + idalloctm(tsd_tsdn(tsd), iealloc(gctx.v), gctx.v, NULL, + true, true); return (true); } new_gctx = true; @@ -816,7 +817,8 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) if (error) { if (new_gctx) prof_gctx_try_destroy(tsd, tdata, gctx, tdata); - idalloctm(tsd_tsdn(tsd), ret.v, NULL, true, true); + idalloctm(tsd_tsdn(tsd), iealloc(ret.v), ret.v, NULL, + true, true); return (NULL); } malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock); @@ -1238,7 +1240,8 @@ prof_gctx_finish(tsd_t *tsd, prof_gctx_tree_t *gctxs) to_destroy); tctx_tree_remove(&gctx->tctxs, to_destroy); - idalloctm(tsd_tsdn(tsd), to_destroy, + idalloctm(tsd_tsdn(tsd), + iealloc(to_destroy), to_destroy, NULL, true, true); } else next = NULL; @@ -1815,7 +1818,7 @@ prof_tdata_init_impl(tsdn_t *tsdn, uint64_t thr_uid, uint64_t thr_discrim, if (ckh_new(tsdn, &tdata->bt2tctx, PROF_CKH_MINITEMS, prof_bt_hash, prof_bt_keycomp)) { - idalloctm(tsdn, tdata, NULL, true, true); + idalloctm(tsdn, iealloc(tdata), tdata, NULL, true, true); return (NULL); } @@ -1878,10 +1881,12 @@ prof_tdata_destroy_locked(tsdn_t *tsdn, prof_tdata_t *tdata, assert(prof_tdata_should_destroy_unlocked(tdata, even_if_attached)); - if (tdata->thread_name != NULL) - idalloctm(tsdn, tdata->thread_name, NULL, true, true); + if (tdata->thread_name != NULL) { + idalloctm(tsdn, iealloc(tdata->thread_name), tdata->thread_name, + NULL, true, true); + } ckh_delete(tsdn, &tdata->bt2tctx); - idalloctm(tsdn, tdata, NULL, true, true); + idalloctm(tsdn, iealloc(tdata), tdata, NULL, true, true); } static void @@ -2075,7 +2080,8 @@ prof_thread_name_set(tsd_t *tsd, const char *thread_name) return (EAGAIN); if (tdata->thread_name != NULL) { - idalloctm(tsd_tsdn(tsd), tdata->thread_name, NULL, true, true); + idalloctm(tsd_tsdn(tsd), iealloc(tdata->thread_name), + tdata->thread_name, NULL, true, true); tdata->thread_name = NULL; } if (strlen(s) > 0) diff --git a/src/tcache.c b/src/tcache.c index c4a99006..c02f0f0c 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -27,7 +27,7 @@ size_t tcache_salloc(tsdn_t *tsdn, const void *ptr) { - return (arena_salloc(tsdn, ptr, false)); + return (arena_salloc(tsdn, iealloc(ptr), ptr, false)); } void @@ -101,9 +101,8 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, assert(arena != NULL); for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) { /* Lock the arena bin associated with the first object. */ - arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE( - *(tbin->avail - 1)); - arena_t *bin_arena = extent_arena_get(&chunk->extent); + extent_t *extent = iealloc(*(tbin->avail - 1)); + arena_t *bin_arena = extent_arena_get(extent); arena_bin_t *bin = &bin_arena->bins[binind]; if (config_prof && bin_arena == arena) { @@ -125,14 +124,17 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, for (i = 0; i < nflush; i++) { ptr = *(tbin->avail - 1 - i); assert(ptr != NULL); - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (extent_arena_get(&chunk->extent) == bin_arena) { + + extent = iealloc(ptr); + if (extent_arena_get(extent) == bin_arena) { + arena_chunk_t *chunk = + (arena_chunk_t *)extent_addr_get(extent); size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; arena_chunk_map_bits_t *bitselm = arena_bitselm_get_mutable(chunk, pageind); arena_dalloc_bin_junked_locked(tsd_tsdn(tsd), - bin_arena, chunk, ptr, bitselm); + bin_arena, chunk, extent, ptr, bitselm); } else { /* * This object was allocated via a different @@ -183,9 +185,8 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, assert(arena != NULL); for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) { /* Lock the arena associated with the first object. */ - arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE( - *(tbin->avail - 1)); - arena_t *locked_arena = extent_arena_get(&chunk->extent); + extent_t *extent = iealloc(*(tbin->avail - 1)); + arena_t *locked_arena = extent_arena_get(extent); UNUSED bool idump; if (config_prof) @@ -210,10 +211,12 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, for (i = 0; i < nflush; i++) { ptr = *(tbin->avail - 1 - i); assert(ptr != NULL); - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (extent_arena_get(&chunk->extent) == locked_arena) { + extent = iealloc(ptr); + if (extent_arena_get(extent) == locked_arena) { + arena_chunk_t *chunk = + (arena_chunk_t *)extent_addr_get(extent); arena_dalloc_large_junked_locked(tsd_tsdn(tsd), - locked_arena, chunk, ptr); + locked_arena, chunk, extent, ptr); } else { /* * This object was allocated via a different @@ -391,7 +394,7 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache) arena_prof_accum(tsd_tsdn(tsd), arena, tcache->prof_accumbytes)) prof_idump(tsd_tsdn(tsd)); - idalloctm(tsd_tsdn(tsd), tcache, NULL, true, true); + idalloctm(tsd_tsdn(tsd), iealloc(tcache), tcache, NULL, true, true); } void -- GitLab From 8c9be3e83732883e852d43bca2cf7724c465f93e Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 16 Apr 2016 00:36:11 -0700 Subject: [PATCH 015/544] Refactor rtree to always use base_alloc() for node allocation. --- include/jemalloc/internal/arena.h | 18 +-- include/jemalloc/internal/chunk.h | 9 +- .../jemalloc/internal/jemalloc_internal.h.in | 31 +++-- include/jemalloc/internal/private_symbols.txt | 2 + include/jemalloc/internal/rtree.h | 75 ++++++----- include/jemalloc/internal/tcache.h | 4 +- src/arena.c | 59 +++++---- src/chunk.c | 17 +-- src/ckh.c | 12 +- src/huge.c | 18 +-- src/jemalloc.c | 56 +++++---- src/prof.c | 30 ++--- src/rtree.c | 71 ++++++++--- src/tcache.c | 13 +- test/unit/rtree.c | 117 ++++++++++++------ 15 files changed, 315 insertions(+), 217 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index d441aaf5..ff3e01d8 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -633,7 +633,8 @@ size_t arena_metadata_allocated_get(arena_t *arena); bool arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes); bool arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes); bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes); -szind_t arena_ptr_small_binind_get(const void *ptr, size_t mapbits); +szind_t arena_ptr_small_binind_get(tsdn_t *tsdn, const void *ptr, + size_t mapbits); szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin); size_t arena_run_regind(arena_run_t *run, const arena_bin_info_t *bin_info, const void *ptr); @@ -647,7 +648,7 @@ void arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks); void arena_decay_tick(tsdn_t *tsdn, arena_t *arena); void *arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, tcache_t *tcache, bool slow_path); -arena_t *arena_aalloc(const void *ptr); +arena_t *arena_aalloc(tsdn_t *tsdn, const void *ptr); size_t arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr, bool demote); void arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, @@ -1049,7 +1050,7 @@ arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) # ifdef JEMALLOC_ARENA_INLINE_B JEMALLOC_ALWAYS_INLINE szind_t -arena_ptr_small_binind_get(const void *ptr, size_t mapbits) +arena_ptr_small_binind_get(tsdn_t *tsdn, const void *ptr, size_t mapbits) { szind_t binind; @@ -1071,7 +1072,7 @@ arena_ptr_small_binind_get(const void *ptr, size_t mapbits) assert(binind != BININD_INVALID); assert(binind < NBINS); - extent = iealloc(ptr); + extent = iealloc(tsdn, ptr); chunk = (arena_chunk_t *)extent_addr_get(extent); arena = extent_arena_get(extent); pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; @@ -1314,10 +1315,10 @@ arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, } JEMALLOC_ALWAYS_INLINE arena_t * -arena_aalloc(const void *ptr) +arena_aalloc(tsdn_t *tsdn, const void *ptr) { - return (extent_arena_get(iealloc(ptr))); + return (extent_arena_get(iealloc(tsdn, ptr))); } /* Return the size of the allocation pointed to by ptr. */ @@ -1361,7 +1362,7 @@ arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr, bool demote) * object). */ assert(arena_mapbits_large_get(chunk, pageind) != 0 || - arena_ptr_small_binind_get(ptr, + arena_ptr_small_binind_get(tsdn, ptr, arena_mapbits_get(chunk, pageind)) == binind); ret = index2size(binind); } @@ -1389,7 +1390,8 @@ arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, if (likely((mapbits & CHUNK_MAP_LARGE) == 0)) { /* Small allocation. */ if (likely(tcache != NULL)) { - szind_t binind = arena_ptr_small_binind_get(ptr, + szind_t binind = + arena_ptr_small_binind_get(tsdn, ptr, mapbits); tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, binind, slow_path); diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index c13f2171..be56c2bd 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -53,7 +53,8 @@ chunk_hooks_t chunk_hooks_set(tsdn_t *tsdn, arena_t *arena, const chunk_hooks_t *chunk_hooks); bool chunk_register(tsdn_t *tsdn, const void *chunk, const extent_t *extent); -void chunk_deregister(const void *chunk, const extent_t *extent); +void chunk_deregister(tsdn_t *tsdn, const void *chunk, + const extent_t *extent); void chunk_reregister(tsdn_t *tsdn, const void *chunk, const extent_t *extent); void *chunk_alloc_base(size_t size); @@ -81,15 +82,15 @@ void chunk_postfork_child(tsdn_t *tsdn); #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE -extent_t *chunk_lookup(const void *chunk, bool dependent); +extent_t *chunk_lookup(tsdn_t *tsdn, const void *chunk, bool dependent); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_CHUNK_C_)) JEMALLOC_INLINE extent_t * -chunk_lookup(const void *ptr, bool dependent) +chunk_lookup(tsdn_t *tsdn, const void *ptr, bool dependent) { - return (rtree_read(&chunks_rtree, (uintptr_t)ptr, dependent)); + return (rtree_read(tsdn, &chunks_rtree, (uintptr_t)ptr, dependent)); } #endif diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 1fc9d3d7..d1306e17 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -961,15 +961,15 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) #undef JEMALLOC_ARENA_INLINE_A #ifndef JEMALLOC_ENABLE_INLINE -extent_t *iealloc(const void *ptr); +extent_t *iealloc(tsdn_t *tsdn, const void *ptr); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) JEMALLOC_ALWAYS_INLINE extent_t * -iealloc(const void *ptr) +iealloc(tsdn_t *tsdn, const void *ptr) { - return (chunk_lookup(ptr, true)); + return (chunk_lookup(tsdn, ptr, true)); } #endif @@ -980,8 +980,7 @@ iealloc(const void *ptr) #include "jemalloc/internal/hash.h" #ifndef JEMALLOC_ENABLE_INLINE -extent_t *iealloc(const void *ptr); -arena_t *iaalloc(const void *ptr); +arena_t *iaalloc(tsdn_t *tsdn, const void *ptr); size_t isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr, bool demote); void *iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, @@ -1012,19 +1011,19 @@ bool ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) JEMALLOC_ALWAYS_INLINE arena_t * -iaalloc(const void *ptr) +iaalloc(tsdn_t *tsdn, const void *ptr) { assert(ptr != NULL); - return (arena_aalloc(ptr)); + return (arena_aalloc(tsdn, ptr)); } /* * Typical usage: * tsdn_t *tsdn = [...] * void *ptr = [...] - * extent_t *extent = iealloc(ptr); + * extent_t *extent = iealloc(tsdn, ptr); * size_t sz = isalloc(tsdn, extent, ptr, config_prof); */ JEMALLOC_ALWAYS_INLINE size_t @@ -1050,8 +1049,8 @@ iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, ret = arena_malloc(tsdn, arena, size, ind, zero, tcache, slow_path); if (config_stats && is_metadata && likely(ret != NULL)) { - arena_metadata_allocated_add(iaalloc(ret), isalloc(tsdn, - iealloc(ret), ret, config_prof)); + arena_metadata_allocated_add(iaalloc(tsdn, ret), isalloc(tsdn, + iealloc(tsdn, ret), ret, config_prof)); } return (ret); } @@ -1078,8 +1077,8 @@ ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, ret = arena_palloc(tsdn, arena, usize, alignment, zero, tcache); assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret); if (config_stats && is_metadata && likely(ret != NULL)) { - arena_metadata_allocated_add(iaalloc(ret), isalloc(tsdn, - iealloc(ret), ret, config_prof)); + arena_metadata_allocated_add(iaalloc(tsdn, ret), isalloc(tsdn, + iealloc(tsdn, ret), ret, config_prof)); } return (ret); } @@ -1106,7 +1105,7 @@ ivsalloc(tsdn_t *tsdn, const void *ptr, bool demote) extent_t *extent; /* Return 0 if ptr is not within a chunk managed by jemalloc. */ - extent = chunk_lookup(ptr, false); + extent = chunk_lookup(tsdn, ptr, false); if (extent == NULL) return (0); /* Only arena chunks should be looked up via interior pointers. */ @@ -1123,10 +1122,10 @@ idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, assert(ptr != NULL); assert(!is_metadata || tcache == NULL); - assert(!is_metadata || iaalloc(ptr)->ind < narenas_auto); + assert(!is_metadata || iaalloc(tsdn, ptr)->ind < narenas_auto); if (config_stats && is_metadata) { - arena_metadata_allocated_sub(iaalloc(ptr), isalloc(tsdn, extent, - ptr, config_prof)); + arena_metadata_allocated_sub(iaalloc(tsdn, ptr), isalloc(tsdn, + extent, ptr, config_prof)); } arena_dalloc(tsdn, extent, ptr, tcache, slow_path); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 5f4a4b0b..42c730c6 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -460,6 +460,8 @@ rtree_child_tryread rtree_clear rtree_delete rtree_new +rtree_node_alloc +rtree_node_dalloc rtree_node_valid rtree_elm_acquire rtree_elm_lookup diff --git a/include/jemalloc/internal/rtree.h b/include/jemalloc/internal/rtree.h index 59a7ab3c..dbea434c 100644 --- a/include/jemalloc/internal/rtree.h +++ b/include/jemalloc/internal/rtree.h @@ -23,13 +23,6 @@ typedef struct rtree_s rtree_t; /* Used for two-stage lock-free node initialization. */ #define RTREE_NODE_INITIALIZING ((rtree_elm_t *)0x1) -/* - * The node allocation callback function's argument is the number of contiguous - * rtree_elm_t structures to allocate, and the resulting memory must be zeroed. - */ -typedef rtree_elm_t *(rtree_node_alloc_t)(size_t); -typedef void (rtree_node_dalloc_t)(rtree_elm_t *); - #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ #ifdef JEMALLOC_H_STRUCTS @@ -79,8 +72,6 @@ struct rtree_level_s { }; struct rtree_s { - rtree_node_alloc_t *alloc; - rtree_node_dalloc_t *dalloc; unsigned height; /* * Precomputed table used to convert from the number of leading 0 key @@ -94,12 +85,18 @@ struct rtree_s { /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS -bool rtree_new(rtree_t *rtree, unsigned bits, rtree_node_alloc_t *alloc, - rtree_node_dalloc_t *dalloc); -void rtree_delete(rtree_t *rtree); -rtree_elm_t *rtree_subtree_read_hard(rtree_t *rtree, unsigned level); -rtree_elm_t *rtree_child_read_hard(rtree_t *rtree, rtree_elm_t *elm, +bool rtree_new(rtree_t *rtree, unsigned bits); +#ifdef JEMALLOC_JET +typedef rtree_elm_t *(rtree_node_alloc_t)(tsdn_t *, rtree_t *, size_t); +extern rtree_node_alloc_t *rtree_node_alloc; +typedef void (rtree_node_dalloc_t)(tsdn_t *, rtree_t *, rtree_elm_t *); +extern rtree_node_dalloc_t *rtree_node_dalloc; +void rtree_delete(tsdn_t *tsdn, rtree_t *rtree); +#endif +rtree_elm_t *rtree_subtree_read_hard(tsdn_t *tsdn, rtree_t *rtree, unsigned level); +rtree_elm_t *rtree_child_read_hard(tsdn_t *tsdn, rtree_t *rtree, + rtree_elm_t *elm, unsigned level); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ @@ -111,25 +108,27 @@ uintptr_t rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level); bool rtree_node_valid(rtree_elm_t *node); rtree_elm_t *rtree_child_tryread(rtree_elm_t *elm, bool dependent); -rtree_elm_t *rtree_child_read(rtree_t *rtree, rtree_elm_t *elm, +rtree_elm_t *rtree_child_read(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level, bool dependent); extent_t *rtree_elm_read(rtree_elm_t *elm, bool dependent); void rtree_elm_write(rtree_elm_t *elm, const extent_t *extent); rtree_elm_t *rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent); -rtree_elm_t *rtree_subtree_read(rtree_t *rtree, unsigned level, - bool dependent); -rtree_elm_t *rtree_elm_lookup(rtree_t *rtree, uintptr_t key, +rtree_elm_t *rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, + unsigned level, bool dependent); +rtree_elm_t *rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, bool dependent, bool init_missing); -bool rtree_write(rtree_t *rtree, uintptr_t key, const extent_t *extent); -extent_t *rtree_read(rtree_t *rtree, uintptr_t key, bool dependent); -rtree_elm_t *rtree_elm_acquire(rtree_t *rtree, uintptr_t key, +bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, + const extent_t *extent); +extent_t *rtree_read(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, + bool dependent); +rtree_elm_t *rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, bool dependent, bool init_missing); extent_t *rtree_elm_read_acquired(rtree_elm_t *elm); void rtree_elm_write_acquired(rtree_elm_t *elm, const extent_t *extent); void rtree_elm_release(rtree_elm_t *elm); -void rtree_clear(rtree_t *rtree, uintptr_t key); +void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_RTREE_C_)) @@ -177,14 +176,14 @@ rtree_child_tryread(rtree_elm_t *elm, bool dependent) } JEMALLOC_ALWAYS_INLINE rtree_elm_t * -rtree_child_read(rtree_t *rtree, rtree_elm_t *elm, unsigned level, +rtree_child_read(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level, bool dependent) { rtree_elm_t *child; child = rtree_child_tryread(elm, dependent); if (!dependent && unlikely(!rtree_node_valid(child))) - child = rtree_child_read_hard(rtree, elm, level); + child = rtree_child_read_hard(tsdn, rtree, elm, level); assert(!dependent || child != NULL); return (child); } @@ -238,19 +237,19 @@ rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent) } JEMALLOC_ALWAYS_INLINE rtree_elm_t * -rtree_subtree_read(rtree_t *rtree, unsigned level, bool dependent) +rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, unsigned level, bool dependent) { rtree_elm_t *subtree; subtree = rtree_subtree_tryread(rtree, level, dependent); if (!dependent && unlikely(!rtree_node_valid(subtree))) - subtree = rtree_subtree_read_hard(rtree, level); + subtree = rtree_subtree_read_hard(tsdn, rtree, level); assert(!dependent || subtree != NULL); return (subtree); } JEMALLOC_ALWAYS_INLINE rtree_elm_t * -rtree_elm_lookup(rtree_t *rtree, uintptr_t key, bool dependent, +rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, bool dependent, bool init_missing) { uintptr_t subkey; @@ -261,8 +260,8 @@ rtree_elm_lookup(rtree_t *rtree, uintptr_t key, bool dependent, start_level = rtree_start_level(rtree, key); - node = init_missing ? rtree_subtree_read(rtree, start_level, dependent) - : rtree_subtree_tryread(rtree, start_level, dependent); + node = init_missing ? rtree_subtree_read(tsdn, rtree, start_level, + dependent) : rtree_subtree_tryread(rtree, start_level, dependent); #define RTREE_GET_BIAS (RTREE_HEIGHT_MAX - rtree->height) switch (start_level + RTREE_GET_BIAS) { #define RTREE_GET_SUBTREE(level) \ @@ -272,7 +271,7 @@ rtree_elm_lookup(rtree_t *rtree, uintptr_t key, bool dependent, return (NULL); \ subkey = rtree_subkey(rtree, key, level - \ RTREE_GET_BIAS); \ - node = init_missing ? rtree_child_read(rtree, \ + node = init_missing ? rtree_child_read(tsdn, rtree, \ &node[subkey], level - RTREE_GET_BIAS, dependent) : \ rtree_child_tryread(&node[subkey], dependent); \ /* Fall through. */ @@ -346,14 +345,14 @@ rtree_elm_lookup(rtree_t *rtree, uintptr_t key, bool dependent, } JEMALLOC_INLINE bool -rtree_write(rtree_t *rtree, uintptr_t key, const extent_t *extent) +rtree_write(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, const extent_t *extent) { rtree_elm_t *elm; assert(extent != NULL); /* Use rtree_clear() for this case. */ assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); - elm = rtree_elm_lookup(rtree, key, false, true); + elm = rtree_elm_lookup(tsdn, rtree, key, false, true); if (elm == NULL) return (true); assert(rtree_elm_read(elm, false) == NULL); @@ -363,11 +362,11 @@ rtree_write(rtree_t *rtree, uintptr_t key, const extent_t *extent) } JEMALLOC_ALWAYS_INLINE extent_t * -rtree_read(rtree_t *rtree, uintptr_t key, bool dependent) +rtree_read(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, bool dependent) { rtree_elm_t *elm; - elm = rtree_elm_lookup(rtree, key, dependent, false); + elm = rtree_elm_lookup(tsdn, rtree, key, dependent, false); if (elm == NULL) return (NULL); @@ -375,12 +374,12 @@ rtree_read(rtree_t *rtree, uintptr_t key, bool dependent) } JEMALLOC_INLINE rtree_elm_t * -rtree_elm_acquire(rtree_t *rtree, uintptr_t key, bool dependent, +rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, bool dependent, bool init_missing) { rtree_elm_t *elm; - elm = rtree_elm_lookup(rtree, key, dependent, init_missing); + elm = rtree_elm_lookup(tsdn, rtree, key, dependent, init_missing); if (!dependent && elm == NULL) return (NULL); { @@ -427,11 +426,11 @@ rtree_elm_release(rtree_elm_t *elm) } JEMALLOC_INLINE void -rtree_clear(rtree_t *rtree, uintptr_t key) +rtree_clear(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key) { rtree_elm_t *elm; - elm = rtree_elm_acquire(rtree, key, true, false); + elm = rtree_elm_acquire(tsdn, rtree, key, true, false); rtree_elm_write_acquired(elm, NULL); rtree_elm_release(elm); } diff --git a/include/jemalloc/internal/tcache.h b/include/jemalloc/internal/tcache.h index d6d27506..ee63a652 100644 --- a/include/jemalloc/internal/tcache.h +++ b/include/jemalloc/internal/tcache.h @@ -370,8 +370,8 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, } if (config_prof && usize == LARGE_MINCLASS) { - arena_chunk_t *chunk = - (arena_chunk_t *)extent_addr_get(iealloc(ret)); + arena_chunk_t *chunk =(arena_chunk_t *)extent_addr_get( + iealloc(tsd_tsdn(tsd), ret)); size_t pageind = (((uintptr_t)ret - (uintptr_t)chunk) >> LG_PAGE); arena_mapbits_large_binind_set(chunk, pageind, diff --git a/src/arena.c b/src/arena.c index 3abbc623..8a93fca0 100644 --- a/src/arena.c +++ b/src/arena.c @@ -264,12 +264,13 @@ arena_run_reg_alloc(arena_run_t *run, const arena_bin_info_t *bin_info) } JEMALLOC_INLINE_C void -arena_run_reg_dalloc(arena_run_t *run, extent_t *extent, void *ptr) +arena_run_reg_dalloc(tsdn_t *tsdn, arena_run_t *run, extent_t *extent, + void *ptr) { arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; size_t mapbits = arena_mapbits_get(chunk, pageind); - szind_t binind = arena_ptr_small_binind_get(ptr, mapbits); + szind_t binind = arena_ptr_small_binind_get(tsdn, ptr, mapbits); const arena_bin_info_t *bin_info = &arena_bin_info[binind]; size_t regind = arena_run_regind(run, bin_info, ptr); @@ -665,7 +666,7 @@ arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk) bool committed; chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; - chunk_deregister(chunk, &chunk->extent); + chunk_deregister(tsdn, chunk, &chunk->extent); committed = (arena_mapbits_decommitted_get(chunk, map_bias) == 0); if (!committed) { @@ -1037,11 +1038,13 @@ arena_run_first_best_fit(arena_t *arena, size_t size) } static arena_run_t * -arena_run_alloc_large_helper(arena_t *arena, size_t size, bool zero) +arena_run_alloc_large_helper(tsdn_t *tsdn, arena_t *arena, size_t size, + bool zero) { arena_run_t *run = arena_run_first_best_fit(arena, s2u(size)); if (run != NULL) { - if (arena_run_split_large(arena, iealloc(run), run, size, zero)) + if (arena_run_split_large(arena, iealloc(tsdn, run), run, size, + zero)) run = NULL; } return (run); @@ -1057,7 +1060,7 @@ arena_run_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t size, bool zero) assert(size == PAGE_CEILING(size)); /* Search the arena's chunks for the lowest best fit. */ - run = arena_run_alloc_large_helper(arena, size, zero); + run = arena_run_alloc_large_helper(tsdn, arena, size, zero); if (run != NULL) return (run); @@ -1067,7 +1070,8 @@ arena_run_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t size, bool zero) chunk = arena_chunk_alloc(tsdn, arena); if (chunk != NULL) { run = &arena_miscelm_get_mutable(chunk, map_bias)->run; - if (arena_run_split_large(arena, iealloc(run), run, size, zero)) + if (arena_run_split_large(arena, iealloc(tsdn, run), run, size, + zero)) run = NULL; return (run); } @@ -1077,15 +1081,16 @@ arena_run_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t size, bool zero) * sufficient memory available while this one dropped arena->lock in * arena_chunk_alloc(), so search one more time. */ - return (arena_run_alloc_large_helper(arena, size, zero)); + return (arena_run_alloc_large_helper(tsdn, arena, size, zero)); } static arena_run_t * -arena_run_alloc_small_helper(arena_t *arena, size_t size, szind_t binind) +arena_run_alloc_small_helper(tsdn_t *tsdn, arena_t *arena, size_t size, + szind_t binind) { arena_run_t *run = arena_run_first_best_fit(arena, size); if (run != NULL) { - if (arena_run_split_small(arena, iealloc(run), run, size, + if (arena_run_split_small(arena, iealloc(tsdn, run), run, size, binind)) run = NULL; } @@ -1103,7 +1108,7 @@ arena_run_alloc_small(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t binind) assert(binind != BININD_INVALID); /* Search the arena's chunks for the lowest best fit. */ - run = arena_run_alloc_small_helper(arena, size, binind); + run = arena_run_alloc_small_helper(tsdn, arena, size, binind); if (run != NULL) return (run); @@ -1113,7 +1118,7 @@ arena_run_alloc_small(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t binind) chunk = arena_chunk_alloc(tsdn, arena); if (chunk != NULL) { run = &arena_miscelm_get_mutable(chunk, map_bias)->run; - if (arena_run_split_small(arena, iealloc(run), run, size, + if (arena_run_split_small(arena, iealloc(tsdn, run), run, size, binind)) run = NULL; return (run); @@ -1124,7 +1129,7 @@ arena_run_alloc_small(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t binind) * sufficient memory available while this one dropped arena->lock in * arena_chunk_alloc(), so search one more time. */ - return (arena_run_alloc_small_helper(arena, size, binind)); + return (arena_run_alloc_small_helper(tsdn, arena, size, binind)); } static bool @@ -1426,7 +1431,7 @@ arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) } static size_t -arena_dirty_count(arena_t *arena) +arena_dirty_count(tsdn_t *tsdn, arena_t *arena) { size_t ndirty = 0; arena_runs_dirty_link_t *rdelm; @@ -1441,7 +1446,7 @@ arena_dirty_count(arena_t *arena) npages = extent_size_get(chunkselm) >> LG_PAGE; chunkselm = qr_next(chunkselm, cc_link); } else { - extent_t *extent = iealloc(rdelm); + extent_t *extent = iealloc(tsdn, rdelm); arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); arena_chunk_map_misc_t *miscelm = @@ -1504,7 +1509,7 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, LG_PAGE)); chunkselm = chunkselm_next; } else { - extent_t *extent = iealloc(rdelm); + extent_t *extent = iealloc(tsdn, rdelm); arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); arena_chunk_map_misc_t *miscelm = @@ -1586,7 +1591,7 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } else { size_t pageind, run_size, flag_unzeroed, flags, i; bool decommitted; - extent_t *extent = iealloc(rdelm); + extent_t *extent = iealloc(tsdn, rdelm); arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); arena_chunk_map_misc_t *miscelm = @@ -1671,7 +1676,7 @@ arena_unstash_purged(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, addr, size, zeroed, committed); } else { - extent_t *extent = iealloc(rdelm); + extent_t *extent = iealloc(tsdn, rdelm); arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); arena_chunk_map_misc_t *miscelm = @@ -1711,7 +1716,7 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) * because overhead grows nonlinearly as memory usage increases. */ if (false && config_debug) { - size_t ndirty = arena_dirty_count(arena); + size_t ndirty = arena_dirty_count(tsdn, arena); assert(ndirty == arena->ndirty); } assert(opt_purge != purge_mode_ratio || (arena->nactive >> @@ -2276,7 +2281,7 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin) * arena_bin_lower_run() must be called, as if a region * were just deallocated from the run. */ - extent = iealloc(run); + extent = iealloc(tsdn, run); chunk = (arena_chunk_t *)extent_addr_get(extent); if (run->nfree == bin_info->nregs) { arena_dalloc_bin_run(tsdn, arena, chunk, extent, @@ -2537,7 +2542,7 @@ arena_palloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, malloc_mutex_unlock(tsdn, &arena->lock); return (NULL); } - extent = iealloc(run); + extent = iealloc(tsdn, run); chunk = (arena_chunk_t *)extent_addr_get(extent); miscelm = arena_run_to_miscelm(run); rpages = arena_miscelm_to_rpages(miscelm); @@ -2555,7 +2560,7 @@ arena_palloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, arena_miscelm_to_pageind(head_miscelm) + (leadsize >> LG_PAGE)); run = &miscelm->run; - extent = iealloc(run); + extent = iealloc(tsdn, run); arena_run_trim_head(tsdn, arena, chunk, head_extent, head_run, alloc_size, alloc_size - leadsize); @@ -2745,7 +2750,7 @@ arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, if (!junked && config_fill && unlikely(opt_junk_free)) arena_dalloc_junk_small(ptr, bin_info); - arena_run_reg_dalloc(run, extent, ptr); + arena_run_reg_dalloc(tsdn, run, extent, ptr); if (run->nfree == bin_info->nregs) { arena_dissociate_bin_run(extent, run, bin); arena_dalloc_bin_run(tsdn, arena, chunk, extent, run, bin); @@ -2793,8 +2798,8 @@ arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, if (config_debug) { /* arena_ptr_small_binind_get() does extra sanity checking. */ - assert(arena_ptr_small_binind_get(ptr, arena_mapbits_get(chunk, - pageind)) != BININD_INVALID); + assert(arena_ptr_small_binind_get(tsdn, ptr, + arena_mapbits_get(chunk, pageind)) != BININD_INVALID); } bitselm = arena_bitselm_get_mutable(chunk, pageind); arena_dalloc_bin(tsdn, arena, chunk, extent, ptr, pageind, bitselm); @@ -2939,8 +2944,8 @@ arena_ralloc_large_grow(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, goto label_fail; run = &arena_miscelm_get_mutable(chunk, pageind+npages)->run; - if (arena_run_split_large(arena, iealloc(run), run, splitsize, - zero)) + if (arena_run_split_large(arena, iealloc(tsdn, run), run, + splitsize, zero)) goto label_fail; if (config_cache_oblivious && zero) { diff --git a/src/chunk.c b/src/chunk.c index e35bb30a..4443368a 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -146,8 +146,9 @@ chunk_register(tsdn_t *tsdn, const void *chunk, const extent_t *extent) assert(extent_addr_get(extent) == chunk); - if (rtree_write(&chunks_rtree, (uintptr_t)chunk, extent)) + if (rtree_write(tsdn, &chunks_rtree, (uintptr_t)chunk, extent)) return (true); + if (config_prof && opt_prof) { size_t size = extent_size_get(extent); size_t nadd = (size == 0) ? 1 : size / chunksize; @@ -168,10 +169,10 @@ chunk_register(tsdn_t *tsdn, const void *chunk, const extent_t *extent) } void -chunk_deregister(const void *chunk, const extent_t *extent) +chunk_deregister(tsdn_t *tsdn, const void *chunk, const extent_t *extent) { - rtree_clear(&chunks_rtree, (uintptr_t)chunk); + rtree_clear(tsdn, &chunks_rtree, (uintptr_t)chunk); if (config_prof && opt_prof) { size_t size = extent_size_get(extent); size_t nsub = (size == 0) ? 1 : size / chunksize; @@ -691,14 +692,6 @@ chunk_merge_default(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b, return (false); } -static rtree_elm_t * -chunks_rtree_node_alloc(size_t nelms) -{ - - return ((rtree_elm_t *)base_alloc(tsdn_fetch(), nelms * - sizeof(rtree_elm_t))); -} - bool chunk_boot(void) { @@ -735,7 +728,7 @@ chunk_boot(void) if (have_dss && chunk_dss_boot()) return (true); if (rtree_new(&chunks_rtree, (unsigned)((ZU(1) << (LG_SIZEOF_PTR+3)) - - opt_lg_chunk), chunks_rtree_node_alloc, NULL)) + opt_lg_chunk))) return (true); return (false); diff --git a/src/ckh.c b/src/ckh.c index 3135ee74..2c120ac8 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -283,12 +283,14 @@ ckh_grow(tsdn_t *tsdn, ckh_t *ckh) ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; if (!ckh_rebuild(ckh, tab)) { - idalloctm(tsdn, iealloc(tab), tab, NULL, true, true); + idalloctm(tsdn, iealloc(tsdn, tab), tab, NULL, true, + true); break; } /* Rebuilding failed, so back out partially rebuilt table. */ - idalloctm(tsdn, iealloc(ckh->tab), ckh->tab, NULL, true, true); + idalloctm(tsdn, iealloc(tsdn, ckh->tab), ckh->tab, NULL, true, + true); ckh->tab = tab; ckh->lg_curbuckets = lg_prevbuckets; } @@ -330,7 +332,7 @@ ckh_shrink(tsdn_t *tsdn, ckh_t *ckh) ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; if (!ckh_rebuild(ckh, tab)) { - idalloctm(tsdn, iealloc(tab), tab, NULL, true, true); + idalloctm(tsdn, iealloc(tsdn, tab), tab, NULL, true, true); #ifdef CKH_COUNT ckh->nshrinks++; #endif @@ -338,7 +340,7 @@ ckh_shrink(tsdn_t *tsdn, ckh_t *ckh) } /* Rebuilding failed, so back out partially rebuilt table. */ - idalloctm(tsdn, iealloc(ckh->tab), ckh->tab, NULL, true, true); + idalloctm(tsdn, iealloc(tsdn, ckh->tab), ckh->tab, NULL, true, true); ckh->tab = tab; ckh->lg_curbuckets = lg_prevbuckets; #ifdef CKH_COUNT @@ -421,7 +423,7 @@ ckh_delete(tsdn_t *tsdn, ckh_t *ckh) (unsigned long long)ckh->nrelocs); #endif - idalloctm(tsdn, iealloc(ckh->tab), ckh->tab, NULL, true, true); + idalloctm(tsdn, iealloc(tsdn, ckh->tab), ckh->tab, NULL, true, true); if (config_debug) memset(ckh, JEMALLOC_FREE_JUNK, sizeof(ckh_t)); } diff --git a/src/huge.c b/src/huge.c index e42ea9c1..0b91c369 100644 --- a/src/huge.c +++ b/src/huge.c @@ -45,7 +45,8 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, arena = arena_choose(tsdn_tsd(tsdn), arena); if (unlikely(arena == NULL) || (ret = arena_chunk_alloc_huge(tsdn, arena, usize, alignment, &is_zeroed)) == NULL) { - idalloctm(tsdn, iealloc(extent), extent, NULL, true, true); + idalloctm(tsdn, iealloc(tsdn, extent), extent, NULL, true, + true); return (NULL); } @@ -53,7 +54,8 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, if (chunk_register(tsdn, ret, extent)) { arena_chunk_dalloc_huge(tsdn, arena, ret, usize); - idalloctm(tsdn, iealloc(extent), extent, NULL, true, true); + idalloctm(tsdn, iealloc(tsdn, extent), extent, NULL, true, + true); return (NULL); } @@ -194,7 +196,7 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, void *ptr, post_zeroed = pre_zeroed; /* Update the size of the huge allocation. */ - chunk_deregister(ptr, extent); + chunk_deregister(tsdn, ptr, extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); extent_size_set(extent, usize); /* Update zeroed. */ @@ -231,7 +233,7 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, void *ptr, return (true); /* Update the size of the huge allocation. */ - chunk_deregister(ptr, extent); + chunk_deregister(tsdn, ptr, extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); extent_size_set(extent, usize); malloc_mutex_unlock(tsdn, &arena->huge_mtx); @@ -353,7 +355,7 @@ huge_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr) arena_t *arena; arena = extent_arena_get(extent); - chunk_deregister(ptr, extent); + chunk_deregister(tsdn, ptr, extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); ql_remove(&arena->huge, extent, ql_link); malloc_mutex_unlock(tsdn, &arena->huge_mtx); @@ -362,7 +364,7 @@ huge_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr) extent_size_get(extent)); arena_chunk_dalloc_huge(tsdn, extent_arena_get(extent), extent_addr_get(extent), extent_size_get(extent)); - idalloctm(tsdn, iealloc(extent), extent, NULL, true, true); + idalloctm(tsdn, iealloc(tsdn, extent), extent, NULL, true, true); arena_decay_tick(tsdn, arena); } @@ -387,7 +389,7 @@ huge_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) prof_tctx_t *tctx; arena_t *arena; - assert(extent == iealloc(ptr)); + assert(extent == iealloc(tsdn, ptr)); arena = extent_arena_get(extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); @@ -403,7 +405,7 @@ huge_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, { arena_t *arena; - assert(extent == iealloc(ptr)); + assert(extent == iealloc(tsdn, ptr)); arena = extent_arena_get(extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); diff --git a/src/jemalloc.c b/src/jemalloc.c index 67a3b564..479d8319 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -325,7 +325,7 @@ void a0dalloc(void *ptr) { - a0idalloc(iealloc(ptr), ptr, true); + a0idalloc(iealloc(NULL, ptr), ptr, true); } /* @@ -365,7 +365,7 @@ bootstrap_free(void *ptr) if (unlikely(ptr == NULL)) return; - a0idalloc(iealloc(ptr), ptr, false); + a0idalloc(iealloc(NULL, ptr), ptr, false); } static void @@ -1401,7 +1401,8 @@ ialloc_prof_sample(tsd_t *tsd, size_t usize, szind_t ind, bool zero, p = ialloc(tsd, LARGE_MINCLASS, ind_large, zero, slow_path); if (p == NULL) return (NULL); - arena_prof_promoted(tsd_tsdn(tsd), iealloc(p), p, usize); + arena_prof_promoted(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, + usize); } else p = ialloc(tsd, usize, ind, zero, slow_path); @@ -1423,7 +1424,7 @@ ialloc_prof(tsd_t *tsd, size_t usize, szind_t ind, bool zero, bool slow_path) prof_alloc_rollback(tsd, tctx, true); return (NULL); } - prof_malloc(tsd_tsdn(tsd), iealloc(p), p, usize, tctx); + prof_malloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, usize, tctx); return (p); } @@ -1482,7 +1483,8 @@ ialloc_post_check(void *ret, tsdn_t *tsdn, size_t usize, const char *func, set_errno(ENOMEM); } if (config_stats && likely(ret != NULL)) { - assert(usize == isalloc(tsdn, iealloc(ret), ret, config_prof)); + assert(usize == isalloc(tsdn, iealloc(tsdn, ret), ret, + config_prof)); *tsd_thread_allocatedp_get(tsdn_tsd(tsdn)) += usize; } witness_assert_lockless(tsdn); @@ -1525,7 +1527,8 @@ imemalign_prof_sample(tsd_t *tsd, size_t alignment, size_t usize, p = ipalloc(tsd, LARGE_MINCLASS, alignment, false); if (p == NULL) return (NULL); - arena_prof_promoted(tsd_tsdn(tsd), iealloc(p), p, usize); + arena_prof_promoted(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, + usize); } else p = ipalloc(tsd, usize, alignment, false); @@ -1547,7 +1550,7 @@ imemalign_prof(tsd_t *tsd, size_t alignment, size_t usize) prof_alloc_rollback(tsd, tctx, true); return (NULL); } - prof_malloc(tsd_tsdn(tsd), iealloc(p), p, usize, tctx); + prof_malloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, usize, tctx); return (p); } @@ -1604,8 +1607,8 @@ imemalign(void **memptr, size_t alignment, size_t size, size_t min_alignment) ret = 0; label_return: if (config_stats && likely(result != NULL)) { - assert(usize == isalloc(tsd_tsdn(tsd), iealloc(result), result, - config_prof)); + assert(usize == isalloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), + result), result, config_prof)); *tsd_thread_allocatedp_get(tsd) += usize; } UTRACE(0, size, result); @@ -1696,7 +1699,8 @@ irealloc_prof_sample(tsd_t *tsd, extent_t *extent, void *old_ptr, false); if (p == NULL) return (NULL); - arena_prof_promoted(tsd_tsdn(tsd), iealloc(p), p, usize); + arena_prof_promoted(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, + usize); } else p = iralloc(tsd, extent, old_ptr, old_usize, usize, 0, false); @@ -1724,7 +1728,7 @@ irealloc_prof(tsd_t *tsd, extent_t *extent, void *old_ptr, size_t old_usize, prof_alloc_rollback(tsd, tctx, true); return (NULL); } - e = (p == old_ptr) ? extent : iealloc(p); + e = (p == old_ptr) ? extent : iealloc(tsd_tsdn(tsd), p); prof_realloc(tsd, e, p, usize, tctx, prof_active, true, old_ptr, old_usize, old_tctx); @@ -1742,7 +1746,7 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); - extent = iealloc(ptr); + extent = iealloc(tsd_tsdn(tsd), ptr); if (config_prof && opt_prof) { usize = isalloc(tsd_tsdn(tsd), extent, ptr, config_prof); prof_free(tsd, extent, ptr, usize); @@ -1810,9 +1814,8 @@ je_realloc(void *ptr, size_t size) witness_assert_lockless(tsd_tsdn(tsd)); - extent = iealloc(ptr); + extent = iealloc(tsd_tsdn(tsd), ptr); old_usize = isalloc(tsd_tsdn(tsd), extent, ptr, config_prof); - if (config_prof && opt_prof) { usize = s2u(size); ret = unlikely(usize == 0 || usize > HUGE_MAXCLASS) ? @@ -1845,7 +1848,8 @@ je_realloc(void *ptr, size_t size) if (config_stats && likely(ret != NULL)) { tsd_t *tsd; - assert(usize == isalloc(tsdn, iealloc(ret), ret, config_prof)); + assert(usize == isalloc(tsdn, iealloc(tsdn, ret), ret, + config_prof)); tsd = tsdn_tsd(tsdn); *tsd_thread_allocatedp_get(tsd) += usize; *tsd_thread_deallocatedp_get(tsd) += old_usize; @@ -1999,7 +2003,7 @@ imallocx_prof_sample(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, tcache, arena, slow_path); if (p == NULL) return (NULL); - arena_prof_promoted(tsdn, iealloc(p), p, usize); + arena_prof_promoted(tsdn, iealloc(tsdn, p), p, usize); } else p = imallocx_flags(tsdn, usize, alignment, zero, tcache, arena, slow_path); @@ -2033,7 +2037,7 @@ imallocx_prof(tsd_t *tsd, size_t size, int flags, size_t *usize, bool slow_path) prof_alloc_rollback(tsd, tctx, true); return (NULL); } - prof_malloc(tsd_tsdn(tsd), iealloc(p), p, *usize, tctx); + prof_malloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, *usize, tctx); assert(alignment == 0 || ((uintptr_t)p & (alignment - 1)) == ZU(0)); return (p); @@ -2134,7 +2138,7 @@ irallocx_prof_sample(tsdn_t *tsdn, extent_t *extent, void *old_ptr, alignment, zero, tcache, arena); if (p == NULL) return (NULL); - arena_prof_promoted(tsdn, iealloc(p), p, usize); + arena_prof_promoted(tsdn, iealloc(tsdn, p), p, usize); } else { p = iralloct(tsdn, extent, old_ptr, old_usize, usize, alignment, zero, tcache, arena); @@ -2180,7 +2184,7 @@ irallocx_prof(tsd_t *tsd, extent_t *extent, void *old_ptr, size_t old_usize, e = extent; *usize = isalloc(tsd_tsdn(tsd), e, p, config_prof); } else - e = iealloc(p); + e = iealloc(tsd_tsdn(tsd), p); prof_realloc(tsd, e, p, *usize, tctx, prof_active, true, old_ptr, old_usize, old_tctx); @@ -2207,7 +2211,7 @@ je_rallocx(void *ptr, size_t size, int flags) assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); - extent = iealloc(ptr); + extent = iealloc(tsd_tsdn(tsd), ptr); if (unlikely((flags & MALLOCX_ARENA_MASK) != 0)) { unsigned arena_ind = MALLOCX_ARENA_GET(flags); @@ -2241,8 +2245,8 @@ je_rallocx(void *ptr, size_t size, int flags) if (unlikely(p == NULL)) goto label_oom; if (config_stats) { - usize = isalloc(tsd_tsdn(tsd), iealloc(p), p, - config_prof); + usize = isalloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), + p), p, config_prof); } } assert(alignment == 0 || ((uintptr_t)p & (alignment - 1)) == ZU(0)); @@ -2357,7 +2361,7 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); - extent = iealloc(ptr); + extent = iealloc(tsd_tsdn(tsd), ptr); old_usize = isalloc(tsd_tsdn(tsd), extent, ptr, config_prof); @@ -2412,7 +2416,7 @@ je_sallocx(const void *ptr, int flags) if (config_ivsalloc) usize = ivsalloc(tsdn, ptr, config_prof); else - usize = isalloc(tsdn, iealloc(ptr), ptr, config_prof); + usize = isalloc(tsdn, iealloc(tsdn, ptr), ptr, config_prof); witness_assert_lockless(tsdn); return (usize); @@ -2471,7 +2475,7 @@ je_sdallocx(void *ptr, size_t size, int flags) assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); - extent = iealloc(ptr); + extent = iealloc(tsd_tsdn(tsd), ptr); usize = inallocx(tsd_tsdn(tsd), size, flags); assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr, config_prof)); @@ -2591,7 +2595,7 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) if (config_ivsalloc) ret = ivsalloc(tsdn, ptr, config_prof); else { - ret = (ptr == NULL) ? 0 : isalloc(tsdn, iealloc(ptr), ptr, + ret = (ptr == NULL) ? 0 : isalloc(tsdn, iealloc(tsdn, ptr), ptr, config_prof); } diff --git a/src/prof.c b/src/prof.c index 121dcd91..03979ca3 100644 --- a/src/prof.c +++ b/src/prof.c @@ -596,7 +596,8 @@ prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self, prof_gctx_t *gctx, prof_leave(tsd, tdata_self); /* Destroy gctx. */ malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock); - idalloctm(tsd_tsdn(tsd), iealloc(gctx), gctx, NULL, true, true); + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), gctx), gctx, + NULL, true, true); } else { /* * Compensate for increment in prof_tctx_destroy() or @@ -707,7 +708,8 @@ prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) prof_tdata_destroy(tsd_tsdn(tsd), tdata, false); if (destroy_tctx) - idalloctm(tsd_tsdn(tsd), iealloc(tctx), tctx, NULL, true, true); + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tctx), tctx, + NULL, true, true); } static bool @@ -736,8 +738,8 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, if (ckh_insert(tsd_tsdn(tsd), &bt2gctx, btkey.v, gctx.v)) { /* OOM. */ prof_leave(tsd, tdata); - idalloctm(tsd_tsdn(tsd), iealloc(gctx.v), gctx.v, NULL, - true, true); + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), gctx.v), + gctx.v, NULL, true, true); return (true); } new_gctx = true; @@ -817,8 +819,8 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) if (error) { if (new_gctx) prof_gctx_try_destroy(tsd, tdata, gctx, tdata); - idalloctm(tsd_tsdn(tsd), iealloc(ret.v), ret.v, NULL, - true, true); + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), ret.v), + ret.v, NULL, true, true); return (NULL); } malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock); @@ -1241,8 +1243,8 @@ prof_gctx_finish(tsd_t *tsd, prof_gctx_tree_t *gctxs) tctx_tree_remove(&gctx->tctxs, to_destroy); idalloctm(tsd_tsdn(tsd), - iealloc(to_destroy), to_destroy, - NULL, true, true); + iealloc(tsd_tsdn(tsd), to_destroy), + to_destroy, NULL, true, true); } else next = NULL; } while (next != NULL); @@ -1818,7 +1820,7 @@ prof_tdata_init_impl(tsdn_t *tsdn, uint64_t thr_uid, uint64_t thr_discrim, if (ckh_new(tsdn, &tdata->bt2tctx, PROF_CKH_MINITEMS, prof_bt_hash, prof_bt_keycomp)) { - idalloctm(tsdn, iealloc(tdata), tdata, NULL, true, true); + idalloctm(tsdn, iealloc(tsdn, tdata), tdata, NULL, true, true); return (NULL); } @@ -1882,11 +1884,11 @@ prof_tdata_destroy_locked(tsdn_t *tsdn, prof_tdata_t *tdata, assert(prof_tdata_should_destroy_unlocked(tdata, even_if_attached)); if (tdata->thread_name != NULL) { - idalloctm(tsdn, iealloc(tdata->thread_name), tdata->thread_name, - NULL, true, true); + idalloctm(tsdn, iealloc(tsdn, tdata->thread_name), + tdata->thread_name, NULL, true, true); } ckh_delete(tsdn, &tdata->bt2tctx); - idalloctm(tsdn, iealloc(tdata), tdata, NULL, true, true); + idalloctm(tsdn, iealloc(tsdn, tdata), tdata, NULL, true, true); } static void @@ -2080,8 +2082,8 @@ prof_thread_name_set(tsd_t *tsd, const char *thread_name) return (EAGAIN); if (tdata->thread_name != NULL) { - idalloctm(tsd_tsdn(tsd), iealloc(tdata->thread_name), - tdata->thread_name, NULL, true, true); + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), + tdata->thread_name), tdata->thread_name, NULL, true, true); tdata->thread_name = NULL; } if (strlen(s) > 0) diff --git a/src/rtree.c b/src/rtree.c index 71c69c41..c6b64cf4 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -13,8 +13,7 @@ hmin(unsigned ha, unsigned hb) * used. */ bool -rtree_new(rtree_t *rtree, unsigned bits, rtree_node_alloc_t *alloc, - rtree_node_dalloc_t *dalloc) +rtree_new(rtree_t *rtree, unsigned bits) { unsigned bits_in_leaf, height, i; @@ -32,8 +31,6 @@ rtree_new(rtree_t *rtree, unsigned bits, rtree_node_alloc_t *alloc, height = 1; assert((height-1) * RTREE_BITS_PER_LEVEL + bits_in_leaf == bits); - rtree->alloc = alloc; - rtree->dalloc = dalloc; rtree->height = height; /* Root level. */ @@ -64,8 +61,43 @@ rtree_new(rtree_t *rtree, unsigned bits, rtree_node_alloc_t *alloc, return (false); } +#ifdef JEMALLOC_JET +#undef rtree_node_alloc +#define rtree_node_alloc JEMALLOC_N(rtree_node_alloc_impl) +#endif +static rtree_elm_t * +rtree_node_alloc(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) +{ + + return ((rtree_elm_t *)base_alloc(tsdn, nelms * sizeof(rtree_elm_t))); +} +#ifdef JEMALLOC_JET +#undef rtree_node_alloc +#define rtree_node_alloc JEMALLOC_N(rtree_node_alloc) +rtree_node_alloc_t *rtree_node_alloc = JEMALLOC_N(rtree_node_alloc_impl); +#endif + +#ifdef JEMALLOC_JET +#undef rtree_node_dalloc +#define rtree_node_dalloc JEMALLOC_N(rtree_node_dalloc_impl) +#endif +UNUSED static void +rtree_node_dalloc(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) +{ + + /* Nodes are never deleted during normal operation. */ + not_reached(); +} +#ifdef JEMALLOC_JET +#undef rtree_node_dalloc +#define rtree_node_dalloc JEMALLOC_N(rtree_node_dalloc) +rtree_node_dalloc_t *rtree_node_dalloc = JEMALLOC_N(rtree_node_dalloc_impl); +#endif + +#ifdef JEMALLOC_JET static void -rtree_delete_subtree(rtree_t *rtree, rtree_elm_t *node, unsigned level) +rtree_delete_subtree(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node, + unsigned level) { if (level + 1 < rtree->height) { @@ -74,27 +106,31 @@ rtree_delete_subtree(rtree_t *rtree, rtree_elm_t *node, unsigned level) nchildren = ZU(1) << rtree->levels[level].bits; for (i = 0; i < nchildren; i++) { rtree_elm_t *child = node[i].child; - if (child != NULL) - rtree_delete_subtree(rtree, child, level + 1); + if (child != NULL) { + rtree_delete_subtree(tsdn, rtree, child, level + + 1); + } } } - rtree->dalloc(node); + rtree_node_dalloc(tsdn, rtree, node); } void -rtree_delete(rtree_t *rtree) +rtree_delete(tsdn_t *tsdn, rtree_t *rtree) { unsigned i; for (i = 0; i < rtree->height; i++) { rtree_elm_t *subtree = rtree->levels[i].subtree; if (subtree != NULL) - rtree_delete_subtree(rtree, subtree, i); + rtree_delete_subtree(tsdn, rtree, subtree, i); } } +#endif static rtree_elm_t * -rtree_node_init(rtree_t *rtree, unsigned level, rtree_elm_t **elmp) +rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level, + rtree_elm_t **elmp) { rtree_elm_t *node; @@ -108,7 +144,8 @@ rtree_node_init(rtree_t *rtree, unsigned level, rtree_elm_t **elmp) node = atomic_read_p((void **)elmp); } while (node == RTREE_NODE_INITIALIZING); } else { - node = rtree->alloc(ZU(1) << rtree->levels[level].bits); + node = rtree_node_alloc(tsdn, rtree, ZU(1) << + rtree->levels[level].bits); if (node == NULL) return (NULL); atomic_write_p((void **)elmp, node); @@ -118,15 +155,17 @@ rtree_node_init(rtree_t *rtree, unsigned level, rtree_elm_t **elmp) } rtree_elm_t * -rtree_subtree_read_hard(rtree_t *rtree, unsigned level) +rtree_subtree_read_hard(tsdn_t *tsdn, rtree_t *rtree, unsigned level) { - return (rtree_node_init(rtree, level, &rtree->levels[level].subtree)); + return (rtree_node_init(tsdn, rtree, level, + &rtree->levels[level].subtree)); } rtree_elm_t * -rtree_child_read_hard(rtree_t *rtree, rtree_elm_t *elm, unsigned level) +rtree_child_read_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, + unsigned level) { - return (rtree_node_init(rtree, level, &elm->child)); + return (rtree_node_init(tsdn, rtree, level, &elm->child)); } diff --git a/src/tcache.c b/src/tcache.c index c02f0f0c..8bd8df01 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -27,7 +27,7 @@ size_t tcache_salloc(tsdn_t *tsdn, const void *ptr) { - return (arena_salloc(tsdn, iealloc(ptr), ptr, false)); + return (arena_salloc(tsdn, iealloc(tsdn, ptr), ptr, false)); } void @@ -101,7 +101,7 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, assert(arena != NULL); for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) { /* Lock the arena bin associated with the first object. */ - extent_t *extent = iealloc(*(tbin->avail - 1)); + extent_t *extent = iealloc(tsd_tsdn(tsd), *(tbin->avail - 1)); arena_t *bin_arena = extent_arena_get(extent); arena_bin_t *bin = &bin_arena->bins[binind]; @@ -125,7 +125,7 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, ptr = *(tbin->avail - 1 - i); assert(ptr != NULL); - extent = iealloc(ptr); + extent = iealloc(tsd_tsdn(tsd), ptr); if (extent_arena_get(extent) == bin_arena) { arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); @@ -185,7 +185,7 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, assert(arena != NULL); for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) { /* Lock the arena associated with the first object. */ - extent_t *extent = iealloc(*(tbin->avail - 1)); + extent_t *extent = iealloc(tsd_tsdn(tsd), *(tbin->avail - 1)); arena_t *locked_arena = extent_arena_get(extent); UNUSED bool idump; @@ -211,7 +211,7 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, for (i = 0; i < nflush; i++) { ptr = *(tbin->avail - 1 - i); assert(ptr != NULL); - extent = iealloc(ptr); + extent = iealloc(tsd_tsdn(tsd), ptr); if (extent_arena_get(extent) == locked_arena) { arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); @@ -394,7 +394,8 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache) arena_prof_accum(tsd_tsdn(tsd), arena, tcache->prof_accumbytes)) prof_idump(tsd_tsdn(tsd)); - idalloctm(tsd_tsdn(tsd), iealloc(tcache), tcache, NULL, true, true); + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tcache), tcache, NULL, + true, true); } void diff --git a/test/unit/rtree.c b/test/unit/rtree.c index 671e2c8a..9c992e11 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -1,10 +1,18 @@ #include "test/jemalloc_test.h" +rtree_node_alloc_t *rtree_node_alloc_orig; +rtree_node_dalloc_t *rtree_node_dalloc_orig; + +rtree_t *test_rtree; + static rtree_elm_t * -node_alloc(size_t nelms) +rtree_node_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { rtree_elm_t *node; + if (rtree != test_rtree) + return rtree_node_alloc_orig(tsdn, rtree, nelms); + node = (rtree_elm_t *)calloc(nelms, sizeof(rtree_elm_t)); assert_ptr_not_null(node, "Unexpected calloc() failure"); @@ -12,23 +20,33 @@ node_alloc(size_t nelms) } static void -node_dalloc(rtree_elm_t *node) +rtree_node_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) { + if (rtree != test_rtree) { + rtree_node_dalloc_orig(tsdn, rtree, node); + return; + } + free(node); } TEST_BEGIN(test_rtree_read_empty) { + tsdn_t *tsdn; unsigned i; + tsdn = tsdn_fetch(); + for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) { rtree_t rtree; - assert_false(rtree_new(&rtree, i, node_alloc, node_dalloc), + test_rtree = &rtree; + assert_false(rtree_new(&rtree, i), "Unexpected rtree_new() failure"); - assert_ptr_null(rtree_read(&rtree, 0, false), + assert_ptr_null(rtree_read(tsdn, &rtree, 0, false), "rtree_read() should return NULL for empty tree"); - rtree_delete(&rtree); + rtree_delete(tsdn, &rtree); + test_rtree = NULL; } } TEST_END @@ -50,30 +68,34 @@ thd_start(void *varg) thd_start_arg_t *arg = (thd_start_arg_t *)varg; sfmt_t *sfmt; extent_t *extent; + tsdn_t *tsdn; unsigned i; sfmt = init_gen_rand(arg->seed); extent = (extent_t *)malloc(sizeof(extent)); assert_ptr_not_null(extent, "Unexpected malloc() failure"); + tsdn = tsdn_fetch(); for (i = 0; i < NITERS; i++) { uintptr_t key = (uintptr_t)gen_rand64(sfmt); if (i % 2 == 0) { rtree_elm_t *elm; - elm = rtree_elm_acquire(&arg->rtree, key, false, true); + elm = rtree_elm_acquire(tsdn, &arg->rtree, key, false, + true); assert_ptr_not_null(elm, "Unexpected rtree_elm_acquire() failure"); rtree_elm_write_acquired(elm, extent); rtree_elm_release(elm); - elm = rtree_elm_acquire(&arg->rtree, key, true, false); + elm = rtree_elm_acquire(tsdn, &arg->rtree, key, true, + false); assert_ptr_not_null(elm, "Unexpected rtree_elm_acquire() failure"); rtree_elm_read_acquired(elm); rtree_elm_release(elm); } else - rtree_read(&arg->rtree, key, false); + rtree_read(tsdn, &arg->rtree, key, false); } free(extent); @@ -86,19 +108,23 @@ TEST_BEGIN(test_rtree_concurrent) thd_start_arg_t arg; thd_t thds[NTHREADS]; sfmt_t *sfmt; + tsdn_t *tsdn; unsigned i, j; sfmt = init_gen_rand(SEED); + tsdn = tsdn_fetch(); for (i = 1; i < MAX_NBITS; i++) { arg.nbits = i; - assert_false(rtree_new(&arg.rtree, arg.nbits, node_alloc, - node_dalloc), "Unexpected rtree_new() failure"); + test_rtree = &arg.rtree; + assert_false(rtree_new(&arg.rtree, arg.nbits), + "Unexpected rtree_new() failure"); arg.seed = gen_rand32(sfmt); for (j = 0; j < NTHREADS; j++) thd_create(&thds[j], thd_start, (void *)&arg); for (j = 0; j < NTHREADS; j++) thd_join(thds[j], NULL); - rtree_delete(&arg.rtree); + rtree_delete(tsdn, &arg.rtree); + test_rtree = NULL; } fini_gen_rand(sfmt); } @@ -113,60 +139,70 @@ TEST_BEGIN(test_rtree_extrema) { unsigned i; extent_t extent_a, extent_b; + tsdn_t *tsdn; + + tsdn = tsdn_fetch(); for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) { rtree_t rtree; - assert_false(rtree_new(&rtree, i, node_alloc, node_dalloc), + test_rtree = &rtree; + assert_false(rtree_new(&rtree, i), "Unexpected rtree_new() failure"); - assert_false(rtree_write(&rtree, 0, &extent_a), + assert_false(rtree_write(tsdn, &rtree, 0, &extent_a), "Unexpected rtree_write() failure, i=%u", i); - assert_ptr_eq(rtree_read(&rtree, 0, true), &extent_a, + assert_ptr_eq(rtree_read(tsdn, &rtree, 0, true), &extent_a, "rtree_read() should return previously set value, i=%u", i); - assert_false(rtree_write(&rtree, ~((uintptr_t)0), &extent_b), - "Unexpected rtree_write() failure, i=%u", i); - assert_ptr_eq(rtree_read(&rtree, ~((uintptr_t)0), true), + assert_false(rtree_write(tsdn, &rtree, ~((uintptr_t)0), + &extent_b), "Unexpected rtree_write() failure, i=%u", i); + assert_ptr_eq(rtree_read(tsdn, &rtree, ~((uintptr_t)0), true), &extent_b, "rtree_read() should return previously set value, i=%u", i); - rtree_delete(&rtree); + rtree_delete(tsdn, &rtree); + test_rtree = NULL; } } TEST_END TEST_BEGIN(test_rtree_bits) { + tsdn_t *tsdn; unsigned i, j, k; + tsdn = tsdn_fetch(); + for (i = 1; i < (sizeof(uintptr_t) << 3); i++) { uintptr_t keys[] = {0, 1, (((uintptr_t)1) << (sizeof(uintptr_t)*8-i)) - 1}; extent_t extent; rtree_t rtree; - assert_false(rtree_new(&rtree, i, node_alloc, node_dalloc), + test_rtree = &rtree; + assert_false(rtree_new(&rtree, i), "Unexpected rtree_new() failure"); for (j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) { - assert_false(rtree_write(&rtree, keys[j], &extent), - "Unexpected rtree_write() failure"); + assert_false(rtree_write(tsdn, &rtree, keys[j], + &extent), "Unexpected rtree_write() failure"); for (k = 0; k < sizeof(keys)/sizeof(uintptr_t); k++) { - assert_ptr_eq(rtree_read(&rtree, keys[k], true), - &extent, "rtree_read() should return " - "previously set value and ignore " + assert_ptr_eq(rtree_read(tsdn, &rtree, keys[k], + true), &extent, "rtree_read() should " + "return previously set value and ignore " "insignificant key bits; i=%u, j=%u, k=%u, " "set key=%#"FMTxPTR", get key=%#"FMTxPTR, i, j, k, keys[j], keys[k]); } - assert_ptr_null(rtree_read(&rtree, + assert_ptr_null(rtree_read(tsdn, &rtree, (((uintptr_t)1) << (sizeof(uintptr_t)*8-i)), false), "Only leftmost rtree leaf should be set; " "i=%u, j=%u", i, j); - rtree_clear(&rtree, keys[j]); + rtree_clear(tsdn, &rtree, keys[j]); } - rtree_delete(&rtree); + rtree_delete(tsdn, &rtree); + test_rtree = NULL; } } TEST_END @@ -175,10 +211,12 @@ TEST_BEGIN(test_rtree_random) { unsigned i; sfmt_t *sfmt; + tsdn_t *tsdn; #define NSET 16 #define SEED 42 sfmt = init_gen_rand(SEED); + tsdn = tsdn_fetch(); for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) { uintptr_t keys[NSET]; extent_t extent; @@ -186,37 +224,40 @@ TEST_BEGIN(test_rtree_random) rtree_t rtree; rtree_elm_t *elm; - assert_false(rtree_new(&rtree, i, node_alloc, node_dalloc), + test_rtree = &rtree; + assert_false(rtree_new(&rtree, i), "Unexpected rtree_new() failure"); for (j = 0; j < NSET; j++) { keys[j] = (uintptr_t)gen_rand64(sfmt); - elm = rtree_elm_acquire(&rtree, keys[j], false, true); + elm = rtree_elm_acquire(tsdn, &rtree, keys[j], false, + true); assert_ptr_not_null(elm, "Unexpected rtree_elm_acquire() failure"); rtree_elm_write_acquired(elm, &extent); rtree_elm_release(elm); - assert_ptr_eq(rtree_read(&rtree, keys[j], true), + assert_ptr_eq(rtree_read(tsdn, &rtree, keys[j], true), &extent, "rtree_read() should return previously set value"); } for (j = 0; j < NSET; j++) { - assert_ptr_eq(rtree_read(&rtree, keys[j], true), + assert_ptr_eq(rtree_read(tsdn, &rtree, keys[j], true), &extent, "rtree_read() should return previously " "set value, j=%u", j); } for (j = 0; j < NSET; j++) { - rtree_clear(&rtree, keys[j]); - assert_ptr_null(rtree_read(&rtree, keys[j], true), + rtree_clear(tsdn, &rtree, keys[j]); + assert_ptr_null(rtree_read(tsdn, &rtree, keys[j], true), "rtree_read() should return previously set value"); } for (j = 0; j < NSET; j++) { - assert_ptr_null(rtree_read(&rtree, keys[j], true), + assert_ptr_null(rtree_read(tsdn, &rtree, keys[j], true), "rtree_read() should return previously set value"); } - rtree_delete(&rtree); + rtree_delete(tsdn, &rtree); + test_rtree = NULL; } fini_gen_rand(sfmt); #undef NSET @@ -228,6 +269,12 @@ int main(void) { + rtree_node_alloc_orig = rtree_node_alloc; + rtree_node_alloc = rtree_node_alloc_intercept; + rtree_node_dalloc_orig = rtree_node_dalloc; + rtree_node_dalloc = rtree_node_dalloc_intercept; + test_rtree = NULL; + return (test( test_rtree_read_empty, test_rtree_concurrent, -- GitLab From e75e9be130910a7344f553e5e6c664047a0d0464 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 17 Apr 2016 12:55:10 -0700 Subject: [PATCH 016/544] Add rtree element witnesses. --- include/jemalloc/internal/mutex.h | 11 +- include/jemalloc/internal/private_symbols.txt | 4 + include/jemalloc/internal/rtree.h | 76 +++++++++-- include/jemalloc/internal/tsd.h | 2 + include/jemalloc/internal/witness.h | 16 ++- src/mutex.c | 2 +- src/rtree.c | 123 ++++++++++++++++++ src/witness.c | 3 +- test/unit/rtree.c | 12 +- test/unit/witness.c | 32 +++-- 10 files changed, 241 insertions(+), 40 deletions(-) diff --git a/include/jemalloc/internal/mutex.h b/include/jemalloc/internal/mutex.h index 52217991..b4e01ff8 100644 --- a/include/jemalloc/internal/mutex.h +++ b/include/jemalloc/internal/mutex.h @@ -6,21 +6,24 @@ typedef struct malloc_mutex_s malloc_mutex_t; #ifdef _WIN32 # define MALLOC_MUTEX_INITIALIZER #elif (defined(JEMALLOC_OSSPIN)) -# define MALLOC_MUTEX_INITIALIZER {0, WITNESS_INITIALIZER(WITNESS_RANK_OMIT)} +# define MALLOC_MUTEX_INITIALIZER \ + {0, WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} #elif (defined(JEMALLOC_MUTEX_INIT_CB)) # define MALLOC_MUTEX_INITIALIZER \ - {PTHREAD_MUTEX_INITIALIZER, NULL, WITNESS_INITIALIZER(WITNESS_RANK_OMIT)} + {PTHREAD_MUTEX_INITIALIZER, NULL, \ + WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} #else # if (defined(JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP) && \ defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP)) # define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_ADAPTIVE_NP # define MALLOC_MUTEX_INITIALIZER \ {PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP, \ - WITNESS_INITIALIZER(WITNESS_RANK_OMIT)} + WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} # else # define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT # define MALLOC_MUTEX_INITIALIZER \ - {PTHREAD_MUTEX_INITIALIZER, WITNESS_INITIALIZER(WITNESS_RANK_OMIT)} + {PTHREAD_MUTEX_INITIALIZER, \ + WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} # endif #endif diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 42c730c6..102f01c0 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -468,6 +468,10 @@ rtree_elm_lookup rtree_elm_read rtree_elm_read_acquired rtree_elm_release +rtree_elm_witness_access +rtree_elm_witness_acquire +rtree_elm_witness_release +rtree_elm_witnesses_cleanup rtree_elm_write rtree_elm_write_acquired rtree_read diff --git a/include/jemalloc/internal/rtree.h b/include/jemalloc/internal/rtree.h index dbea434c..e62ab6b9 100644 --- a/include/jemalloc/internal/rtree.h +++ b/include/jemalloc/internal/rtree.h @@ -7,6 +7,8 @@ #ifdef JEMALLOC_H_TYPES typedef struct rtree_elm_s rtree_elm_t; +typedef struct rtree_elm_witness_s rtree_elm_witness_t; +typedef struct rtree_elm_witness_tsd_s rtree_elm_witness_tsd_t; typedef struct rtree_level_s rtree_level_t; typedef struct rtree_s rtree_t; @@ -23,6 +25,29 @@ typedef struct rtree_s rtree_t; /* Used for two-stage lock-free node initialization. */ #define RTREE_NODE_INITIALIZING ((rtree_elm_t *)0x1) +/* + * Maximum number of concurrently acquired elements per thread. This controls + * how many witness_t structures are embedded in tsd. Ideally rtree_elm_t would + * have a witness_t directly embedded, but that would dramatically bloat the + * tree. This must contain enough entries to e.g. coalesce two extents. + */ +#define RTREE_ELM_ACQUIRE_MAX 4 + +/* Initializers for rtree_elm_witness_tsd_t. */ +#define RTREE_ELM_WITNESS_INITIALIZER { \ + NULL, \ + WITNESS_INITIALIZER("rtree_elm", WITNESS_RANK_RTREE_ELM) \ +} + +#define RTREE_ELM_WITNESS_TSD_INITIALIZER { \ + { \ + RTREE_ELM_WITNESS_INITIALIZER, \ + RTREE_ELM_WITNESS_INITIALIZER, \ + RTREE_ELM_WITNESS_INITIALIZER, \ + RTREE_ELM_WITNESS_INITIALIZER \ + } \ +} + #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ #ifdef JEMALLOC_H_STRUCTS @@ -35,6 +60,15 @@ struct rtree_elm_s { }; }; +struct rtree_elm_witness_s { + const rtree_elm_t *elm; + witness_t witness; +}; + +struct rtree_elm_witness_tsd_s { + rtree_elm_witness_t witnesses[RTREE_ELM_ACQUIRE_MAX]; +}; + struct rtree_level_s { /* * A non-NULL subtree points to a subtree rooted along the hypothetical @@ -97,6 +131,13 @@ rtree_elm_t *rtree_subtree_read_hard(tsdn_t *tsdn, rtree_t *rtree, unsigned level); rtree_elm_t *rtree_child_read_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level); +void rtree_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, + uintptr_t key, const rtree_elm_t *elm); +void rtree_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, + const rtree_elm_t *elm); +void rtree_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, + const rtree_elm_t *elm); +void rtree_elm_witnesses_cleanup(tsd_t *tsd); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ @@ -125,9 +166,11 @@ extent_t *rtree_read(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, bool dependent); rtree_elm_t *rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, bool dependent, bool init_missing); -extent_t *rtree_elm_read_acquired(rtree_elm_t *elm); -void rtree_elm_write_acquired(rtree_elm_t *elm, const extent_t *extent); -void rtree_elm_release(rtree_elm_t *elm); +extent_t *rtree_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, + rtree_elm_t *elm); +void rtree_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, + rtree_elm_t *elm, const extent_t *extent); +void rtree_elm_release(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm); void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key); #endif @@ -393,11 +436,14 @@ rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, bool dependent, } while (atomic_cas_p(&elm->pun, (void *)extent, s)); } + if (config_debug) + rtree_elm_witness_acquire(tsdn, rtree, key, elm); + return (elm); } JEMALLOC_INLINE extent_t * -rtree_elm_read_acquired(rtree_elm_t *elm) +rtree_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm) { extent_t *extent; @@ -405,24 +451,34 @@ rtree_elm_read_acquired(rtree_elm_t *elm) extent = (extent_t *)((uintptr_t)elm->pun & ~((uintptr_t)0x1)); assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); + if (config_debug) + rtree_elm_witness_access(tsdn, rtree, elm); + return (extent); } JEMALLOC_INLINE void -rtree_elm_write_acquired(rtree_elm_t *elm, const extent_t *extent) +rtree_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm, + const extent_t *extent) { assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); assert(((uintptr_t)elm->pun & (uintptr_t)0x1) == (uintptr_t)0x1); + + if (config_debug) + rtree_elm_witness_access(tsdn, rtree, elm); + elm->pun = (void *)((uintptr_t)extent | (uintptr_t)0x1); - assert(rtree_elm_read_acquired(elm) == extent); + assert(rtree_elm_read_acquired(tsdn, rtree, elm) == extent); } JEMALLOC_INLINE void -rtree_elm_release(rtree_elm_t *elm) +rtree_elm_release(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm) { - rtree_elm_write(elm, rtree_elm_read_acquired(elm)); + rtree_elm_write(elm, rtree_elm_read_acquired(tsdn, rtree, elm)); + if (config_debug) + rtree_elm_witness_release(tsdn, rtree, elm); } JEMALLOC_INLINE void @@ -431,8 +487,8 @@ rtree_clear(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key) rtree_elm_t *elm; elm = rtree_elm_acquire(tsdn, rtree, key, true, false); - rtree_elm_write_acquired(elm, NULL); - rtree_elm_release(elm); + rtree_elm_write_acquired(tsdn, rtree, elm, NULL); + rtree_elm_release(tsdn, rtree, elm); } #endif diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h index f4ff8d76..ca8915ea 100644 --- a/include/jemalloc/internal/tsd.h +++ b/include/jemalloc/internal/tsd.h @@ -573,6 +573,7 @@ struct tsd_init_head_s { O(arenas_tdata_bypass, bool) \ O(tcache_enabled, tcache_enabled_t) \ O(witnesses, witness_list_t) \ + O(rtree_elm_witnesses, rtree_elm_witness_tsd_t) \ O(witness_fork, bool) \ #define TSD_INITIALIZER { \ @@ -588,6 +589,7 @@ struct tsd_init_head_s { false, \ tcache_enabled_default, \ ql_head_initializer(witnesses), \ + RTREE_ELM_WITNESS_TSD_INITIALIZER, \ false \ } diff --git a/include/jemalloc/internal/witness.h b/include/jemalloc/internal/witness.h index c68c9694..f15665bc 100644 --- a/include/jemalloc/internal/witness.h +++ b/include/jemalloc/internal/witness.h @@ -4,7 +4,8 @@ typedef struct witness_s witness_t; typedef unsigned witness_rank_t; typedef ql_head(witness_t) witness_list_t; -typedef int witness_comp_t (const witness_t *, const witness_t *); +typedef int witness_comp_t (const witness_t *, void *, const witness_t *, + void *); /* * Lock ranks. Witnesses with rank WITNESS_RANK_OMIT are completely ignored by @@ -26,7 +27,8 @@ typedef int witness_comp_t (const witness_t *, const witness_t *); #define WITNESS_RANK_ARENA_CHUNKS 9U #define WITNESS_RANK_ARENA_EXTENT_CACHE 10 -#define WITNESS_RANK_BASE 11U +#define WITNESS_RANK_RTREE_ELM 11U +#define WITNESS_RANK_BASE 12U #define WITNESS_RANK_LEAF 0xffffffffU #define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF @@ -38,7 +40,7 @@ typedef int witness_comp_t (const witness_t *, const witness_t *); #define WITNESS_RANK_PROF_NEXT_THR_UID WITNESS_RANK_LEAF #define WITNESS_RANK_PROF_THREAD_ACTIVE_INIT WITNESS_RANK_LEAF -#define WITNESS_INITIALIZER(rank) {"initializer", rank, NULL, {NULL, NULL}} +#define WITNESS_INITIALIZER(name, rank) {name, rank, NULL, NULL, {NULL, NULL}} #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ @@ -61,6 +63,9 @@ struct witness_s { */ witness_comp_t *comp; + /* Opaque data, passed to comp(). */ + void *opaque; + /* Linkage for thread's currently owned locks. */ ql_elm(witness_t) link; }; @@ -70,7 +75,7 @@ struct witness_s { #ifdef JEMALLOC_H_EXTERNS void witness_init(witness_t *witness, const char *name, witness_rank_t rank, - witness_comp_t *comp); + witness_comp_t *comp, void *opaque); #ifdef JEMALLOC_JET typedef void (witness_lock_error_t)(const witness_list_t *, const witness_t *); extern witness_lock_error_t *witness_lock_error; @@ -211,7 +216,8 @@ witness_lock(tsdn_t *tsdn, witness_t *witness) /* Not forking, rank order reversal. */ witness_lock_error(witnesses, witness); } else if (w->rank == witness->rank && (w->comp == NULL || w->comp != - witness->comp || w->comp(w, witness) > 0)) { + witness->comp || w->comp(w, w->opaque, witness, witness->opaque) > + 0)) { /* * Missing/incompatible comparison function, or comparison * function indicates rank order reversal. diff --git a/src/mutex.c b/src/mutex.c index a1fac342..119b8e35 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -104,7 +104,7 @@ malloc_mutex_init(malloc_mutex_t *mutex, const char *name, witness_rank_t rank) pthread_mutexattr_destroy(&attr); #endif if (config_debug) - witness_init(&mutex->witness, name, rank, NULL); + witness_init(&mutex->witness, name, rank, NULL, NULL); return (false); } diff --git a/src/rtree.c b/src/rtree.c index c6b64cf4..504f9f2e 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -169,3 +169,126 @@ rtree_child_read_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, return (rtree_node_init(tsdn, rtree, level, &elm->child)); } + +static int +rtree_elm_witness_comp(const witness_t *a, void *oa, const witness_t *b, + void *ob) +{ + uintptr_t ka = (uintptr_t)oa; + uintptr_t kb = (uintptr_t)ob; + + assert(ka != 0); + assert(kb != 0); + + return ((ka > kb) - (ka < kb)); +} + +static witness_t * +rtree_elm_witness_alloc(tsd_t *tsd, uintptr_t key, const rtree_elm_t *elm) +{ + witness_t *witness; + size_t i; + rtree_elm_witness_tsd_t *witnesses = tsd_rtree_elm_witnessesp_get(tsd); + + /* Iterate over entire array to detect double allocation attempts. */ + witness = NULL; + for (i = 0; i < sizeof(rtree_elm_witness_tsd_t) / sizeof(witness_t); + i++) { + rtree_elm_witness_t *rew = &witnesses->witnesses[i]; + + assert(rew->elm != elm); + if (rew->elm == NULL && witness == NULL) { + rew->elm = elm; + witness = &rew->witness; + witness_init(witness, "rtree_elm", + WITNESS_RANK_RTREE_ELM, rtree_elm_witness_comp, + (void *)key); + } + } + assert(witness != NULL); + return (witness); +} + +static witness_t * +rtree_elm_witness_find(tsd_t *tsd, const rtree_elm_t *elm) +{ + size_t i; + rtree_elm_witness_tsd_t *witnesses = tsd_rtree_elm_witnessesp_get(tsd); + + for (i = 0; i < sizeof(rtree_elm_witness_tsd_t) / sizeof(witness_t); + i++) { + rtree_elm_witness_t *rew = &witnesses->witnesses[i]; + + if (rew->elm == elm) + return (&rew->witness); + } + not_reached(); +} + +static void +rtree_elm_witness_dalloc(tsd_t *tsd, witness_t *witness, const rtree_elm_t *elm) +{ + size_t i; + rtree_elm_witness_tsd_t *witnesses = tsd_rtree_elm_witnessesp_get(tsd); + + for (i = 0; i < sizeof(rtree_elm_witness_tsd_t) / sizeof(witness_t); + i++) { + rtree_elm_witness_t *rew = &witnesses->witnesses[i]; + + if (rew->elm == elm) { + rew->elm = NULL; + witness_init(&rew->witness, "rtree_elm", + WITNESS_RANK_RTREE_ELM, rtree_elm_witness_comp, + NULL); + return; + } + } + not_reached(); +} + +void +rtree_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, uintptr_t key, + const rtree_elm_t *elm) +{ + witness_t *witness; + + if (tsdn_null(tsdn)) + return; + + witness = rtree_elm_witness_alloc(tsdn_tsd(tsdn), key, elm); + witness_lock(tsdn, witness); +} + +void +rtree_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, + const rtree_elm_t *elm) +{ + witness_t *witness; + + if (tsdn_null(tsdn)) + return; + + witness = rtree_elm_witness_find(tsdn_tsd(tsdn), elm); + witness_assert_owner(tsdn, witness); +} + +void +rtree_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, + const rtree_elm_t *elm) +{ + witness_t *witness; + + if (tsdn_null(tsdn)) + return; + + witness = rtree_elm_witness_find(tsdn_tsd(tsdn), elm); + witness_unlock(tsdn, witness); + rtree_elm_witness_dalloc(tsdn_tsd(tsdn), witness, elm); +} + +void +rtree_elm_witnesses_cleanup(tsd_t *tsd) +{ + + /* Do nothing. */ +} diff --git a/src/witness.c b/src/witness.c index 23753f24..8efff56d 100644 --- a/src/witness.c +++ b/src/witness.c @@ -3,12 +3,13 @@ void witness_init(witness_t *witness, const char *name, witness_rank_t rank, - witness_comp_t *comp) + witness_comp_t *comp, void *opaque) { witness->name = name; witness->rank = rank; witness->comp = comp; + witness->opaque = opaque; } #ifdef JEMALLOC_JET diff --git a/test/unit/rtree.c b/test/unit/rtree.c index 9c992e11..786cc351 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -85,15 +85,15 @@ thd_start(void *varg) true); assert_ptr_not_null(elm, "Unexpected rtree_elm_acquire() failure"); - rtree_elm_write_acquired(elm, extent); - rtree_elm_release(elm); + rtree_elm_write_acquired(tsdn, &arg->rtree, elm, extent); + rtree_elm_release(tsdn, &arg->rtree, elm); elm = rtree_elm_acquire(tsdn, &arg->rtree, key, true, false); assert_ptr_not_null(elm, "Unexpected rtree_elm_acquire() failure"); - rtree_elm_read_acquired(elm); - rtree_elm_release(elm); + rtree_elm_read_acquired(tsdn, &arg->rtree, elm); + rtree_elm_release(tsdn, &arg->rtree, elm); } else rtree_read(tsdn, &arg->rtree, key, false); } @@ -234,8 +234,8 @@ TEST_BEGIN(test_rtree_random) true); assert_ptr_not_null(elm, "Unexpected rtree_elm_acquire() failure"); - rtree_elm_write_acquired(elm, &extent); - rtree_elm_release(elm); + rtree_elm_write_acquired(tsdn, &rtree, elm, &extent); + rtree_elm_release(tsdn, &rtree, elm); assert_ptr_eq(rtree_read(tsdn, &rtree, keys[j], true), &extent, "rtree_read() should return previously set value"); diff --git a/test/unit/witness.c b/test/unit/witness.c index ed172753..2b012034 100644 --- a/test/unit/witness.c +++ b/test/unit/witness.c @@ -40,20 +40,26 @@ witness_lockless_error_intercept(const witness_list_t *witnesses) } static int -witness_comp(const witness_t *a, const witness_t *b) +witness_comp(const witness_t *a, void *oa, const witness_t *b, void *ob) { assert_u_eq(a->rank, b->rank, "Witnesses should have equal rank"); + assert(oa == (void *)a); + assert(ob == (void *)b); + return (strcmp(a->name, b->name)); } static int -witness_comp_reverse(const witness_t *a, const witness_t *b) +witness_comp_reverse(const witness_t *a, void *oa, const witness_t *b, void *ob) { assert_u_eq(a->rank, b->rank, "Witnesses should have equal rank"); + assert(oa == (void *)a); + assert(ob == (void *)b); + return (-strcmp(a->name, b->name)); } @@ -68,12 +74,12 @@ TEST_BEGIN(test_witness) witness_assert_lockless(tsdn); - witness_init(&a, "a", 1, NULL); + witness_init(&a, "a", 1, NULL, NULL); witness_assert_not_owner(tsdn, &a); witness_lock(tsdn, &a); witness_assert_owner(tsdn, &a); - witness_init(&b, "b", 2, NULL); + witness_init(&b, "b", 2, NULL, NULL); witness_assert_not_owner(tsdn, &b); witness_lock(tsdn, &b); witness_assert_owner(tsdn, &b); @@ -96,12 +102,12 @@ TEST_BEGIN(test_witness_comp) witness_assert_lockless(tsdn); - witness_init(&a, "a", 1, witness_comp); + witness_init(&a, "a", 1, witness_comp, &a); witness_assert_not_owner(tsdn, &a); witness_lock(tsdn, &a); witness_assert_owner(tsdn, &a); - witness_init(&b, "b", 1, witness_comp); + witness_init(&b, "b", 1, witness_comp, &b); witness_assert_not_owner(tsdn, &b); witness_lock(tsdn, &b); witness_assert_owner(tsdn, &b); @@ -111,7 +117,7 @@ TEST_BEGIN(test_witness_comp) witness_lock_error = witness_lock_error_intercept; saw_lock_error = false; - witness_init(&c, "c", 1, witness_comp_reverse); + witness_init(&c, "c", 1, witness_comp_reverse, &c); witness_assert_not_owner(tsdn, &c); assert_false(saw_lock_error, "Unexpected witness lock error"); witness_lock(tsdn, &c); @@ -120,7 +126,7 @@ TEST_BEGIN(test_witness_comp) saw_lock_error = false; - witness_init(&d, "d", 1, NULL); + witness_init(&d, "d", 1, NULL, NULL); witness_assert_not_owner(tsdn, &d); assert_false(saw_lock_error, "Unexpected witness lock error"); witness_lock(tsdn, &d); @@ -150,8 +156,8 @@ TEST_BEGIN(test_witness_reversal) witness_assert_lockless(tsdn); - witness_init(&a, "a", 1, NULL); - witness_init(&b, "b", 2, NULL); + witness_init(&a, "a", 1, NULL, NULL); + witness_init(&b, "b", 2, NULL, NULL); witness_lock(tsdn, &b); assert_false(saw_lock_error, "Unexpected witness lock error"); @@ -186,7 +192,7 @@ TEST_BEGIN(test_witness_recursive) witness_assert_lockless(tsdn); - witness_init(&a, "a", 1, NULL); + witness_init(&a, "a", 1, NULL, NULL); witness_lock(tsdn, &a); assert_false(saw_lock_error, "Unexpected witness lock error"); @@ -220,7 +226,7 @@ TEST_BEGIN(test_witness_unlock_not_owned) witness_assert_lockless(tsdn); - witness_init(&a, "a", 1, NULL); + witness_init(&a, "a", 1, NULL, NULL); assert_false(saw_owner_error, "Unexpected owner error"); witness_unlock(tsdn, &a); @@ -247,7 +253,7 @@ TEST_BEGIN(test_witness_lockful) witness_assert_lockless(tsdn); - witness_init(&a, "a", 1, NULL); + witness_init(&a, "a", 1, NULL, NULL); assert_false(saw_lockless_error, "Unexpected lockless error"); witness_assert_lockless(tsdn); -- GitLab From b2a9fae88652f39b80dc1d25fa842dae8166263d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 27 Mar 2016 18:51:12 -0700 Subject: [PATCH 017/544] Set/unset rtree node for last chunk of extents. Set/unset rtree node for last chunk of extents, so that the rtree can be used for chunk coalescing. --- src/chunk.c | 45 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/src/chunk.c b/src/chunk.c index 4443368a..beef41fe 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -143,14 +143,35 @@ chunk_hooks_assure_initialized(tsdn_t *tsdn, arena_t *arena, bool chunk_register(tsdn_t *tsdn, const void *chunk, const extent_t *extent) { + size_t size; + rtree_elm_t *elm_a; assert(extent_addr_get(extent) == chunk); - if (rtree_write(tsdn, &chunks_rtree, (uintptr_t)chunk, extent)) + size = extent_size_get(extent); + + if ((elm_a = rtree_elm_acquire(tsdn, &chunks_rtree, (uintptr_t)chunk, + false, true)) == NULL) return (true); + rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_a, extent); + if (size > chunksize) { + uintptr_t last = ((uintptr_t)chunk + + (uintptr_t)(CHUNK_CEILING(size - chunksize))); + rtree_elm_t *elm_b; + + if ((elm_b = rtree_elm_acquire(tsdn, &chunks_rtree, last, false, + true)) == NULL) { + rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_a, + NULL); + rtree_elm_release(tsdn, &chunks_rtree, elm_a); + return (true); + } + rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_b, extent); + rtree_elm_release(tsdn, &chunks_rtree, elm_b); + } + rtree_elm_release(tsdn, &chunks_rtree, elm_a); if (config_prof && opt_prof) { - size_t size = extent_size_get(extent); size_t nadd = (size == 0) ? 1 : size / chunksize; size_t cur = atomic_add_z(&curchunks, nadd); size_t high = atomic_read_z(&highchunks); @@ -171,10 +192,26 @@ chunk_register(tsdn_t *tsdn, const void *chunk, const extent_t *extent) void chunk_deregister(tsdn_t *tsdn, const void *chunk, const extent_t *extent) { + size_t size; + rtree_elm_t *elm_a; + + size = extent_size_get(extent); + + elm_a = rtree_elm_acquire(tsdn, &chunks_rtree, (uintptr_t)chunk, true, + false); + rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_a, NULL); + if (size > chunksize) { + uintptr_t last = ((uintptr_t)chunk + + (uintptr_t)(CHUNK_CEILING(size - chunksize))); + rtree_elm_t *elm_b = rtree_elm_acquire(tsdn, &chunks_rtree, + last, true, false); + + rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_b, NULL); + rtree_elm_release(tsdn, &chunks_rtree, elm_b); + } + rtree_elm_release(tsdn, &chunks_rtree, elm_a); - rtree_clear(tsdn, &chunks_rtree, (uintptr_t)chunk); if (config_prof && opt_prof) { - size_t size = extent_size_get(extent); size_t nsub = (size == 0) ? 1 : size / chunksize; assert(atomic_read_z(&curchunks) >= nsub); atomic_sub_z(&curchunks, nsub); -- GitLab From 6f718446596c83cadc3fa53625953291655bfcdf Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 7 Apr 2016 10:14:37 -0400 Subject: [PATCH 018/544] Move *PAGE* definitions to pages.h. --- include/jemalloc/internal/jemalloc_internal.h.in | 15 --------------- include/jemalloc/internal/pages.h | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index d1306e17..c7d97371 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -311,21 +311,6 @@ typedef unsigned szind_t; #define CACHELINE_CEILING(s) \ (((s) + CACHELINE_MASK) & ~CACHELINE_MASK) -/* Page size. LG_PAGE is determined by the configure script. */ -#ifdef PAGE_MASK -# undef PAGE_MASK -#endif -#define PAGE ((size_t)(1U << LG_PAGE)) -#define PAGE_MASK ((size_t)(PAGE - 1)) - -/* Return the page base address for the page containing address a. */ -#define PAGE_ADDR2BASE(a) \ - ((void *)((uintptr_t)(a) & ~PAGE_MASK)) - -/* Return the smallest pagesize multiple that is >= s. */ -#define PAGE_CEILING(s) \ - (((s) + PAGE_MASK) & ~PAGE_MASK) - /* Return the nearest aligned address at or below a. */ #define ALIGNMENT_ADDR2BASE(a, alignment) \ ((void *)((uintptr_t)(a) & (-(alignment)))) diff --git a/include/jemalloc/internal/pages.h b/include/jemalloc/internal/pages.h index e21effd1..16c657a0 100644 --- a/include/jemalloc/internal/pages.h +++ b/include/jemalloc/internal/pages.h @@ -1,6 +1,21 @@ /******************************************************************************/ #ifdef JEMALLOC_H_TYPES +/* Page size. LG_PAGE is determined by the configure script. */ +#ifdef PAGE_MASK +# undef PAGE_MASK +#endif +#define PAGE ((size_t)(1U << LG_PAGE)) +#define PAGE_MASK ((size_t)(PAGE - 1)) + +/* Return the page base address for the page containing address a. */ +#define PAGE_ADDR2BASE(a) \ + ((void *)((uintptr_t)(a) & ~PAGE_MASK)) + +/* Return the smallest pagesize multiple that is >= s. */ +#define PAGE_CEILING(s) \ + (((s) + PAGE_MASK) & ~PAGE_MASK) + #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ #ifdef JEMALLOC_H_STRUCTS -- GitLab From fae83440989e06c52acea0d06e70a4c27b9739f5 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 28 Mar 2016 03:17:10 -0700 Subject: [PATCH 019/544] Add extent_active_[gs]et(). Always initialize extents' runs_dirty and chunks_cache linkage. --- include/jemalloc/internal/extent.h | 31 +++++++++++++------ .../jemalloc/internal/jemalloc_internal.h.in | 1 + include/jemalloc/internal/private_symbols.txt | 3 +- src/arena.c | 6 ++-- src/base.c | 4 +-- src/chunk.c | 11 ++++--- src/huge.c | 2 +- 7 files changed, 37 insertions(+), 21 deletions(-) diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index acc67f00..33f5932c 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -18,6 +18,9 @@ struct extent_s { /* Total region size. */ size_t e_size; + /* True if extent is active (in use). */ + bool e_active; + /* * The zeroed flag is used by chunk recycling code to track whether * memory is zero-filled. @@ -73,6 +76,7 @@ rb_proto(, extent_tree_ad_, extent_tree_t, extent_t) arena_t *extent_arena_get(const extent_t *extent); void *extent_addr_get(const extent_t *extent); size_t extent_size_get(const extent_t *extent); +bool extent_active_get(const extent_t *extent); bool extent_zeroed_get(const extent_t *extent); bool extent_committed_get(const extent_t *extent); bool extent_achunk_get(const extent_t *extent); @@ -80,13 +84,13 @@ prof_tctx_t *extent_prof_tctx_get(const extent_t *extent); void extent_arena_set(extent_t *extent, arena_t *arena); void extent_addr_set(extent_t *extent, void *addr); void extent_size_set(extent_t *extent, size_t size); +void extent_active_set(extent_t *extent, bool active); void extent_zeroed_set(extent_t *extent, bool zeroed); void extent_committed_set(extent_t *extent, bool committed); void extent_achunk_set(extent_t *extent, bool achunk); void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx); void extent_init(extent_t *extent, arena_t *arena, void *addr, - size_t size, bool zeroed, bool committed); -void extent_dirty_linkage_init(extent_t *extent); + size_t size, bool active, bool zeroed, bool committed); void extent_dirty_insert(extent_t *extent, arena_runs_dirty_link_t *runs_dirty, extent_t *chunks_dirty); void extent_dirty_remove(extent_t *extent); @@ -114,6 +118,13 @@ extent_size_get(const extent_t *extent) return (extent->e_size); } +JEMALLOC_INLINE bool +extent_active_get(const extent_t *extent) +{ + + return (extent->e_active); +} + JEMALLOC_INLINE bool extent_zeroed_get(const extent_t *extent) { @@ -164,6 +175,13 @@ extent_size_set(extent_t *extent, size_t size) extent->e_size = size; } +JEMALLOC_INLINE void +extent_active_set(extent_t *extent, bool active) +{ + + extent->e_active = active; +} + JEMALLOC_INLINE void extent_zeroed_set(extent_t *extent, bool zeroed) { @@ -194,23 +212,18 @@ extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) JEMALLOC_INLINE void extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, - bool zeroed, bool committed) + bool active, bool zeroed, bool committed) { extent_arena_set(extent, arena); extent_addr_set(extent, addr); extent_size_set(extent, size); + extent_active_set(extent, active); extent_zeroed_set(extent, zeroed); extent_committed_set(extent, committed); extent_achunk_set(extent, false); if (config_prof) extent_prof_tctx_set(extent, NULL); -} - -JEMALLOC_INLINE void -extent_dirty_linkage_init(extent_t *extent) -{ - qr_new(&extent->rd, rd_link); qr_new(extent, cc_link); } diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index c7d97371..a7f07818 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -1093,6 +1093,7 @@ ivsalloc(tsdn_t *tsdn, const void *ptr, bool demote) extent = chunk_lookup(tsdn, ptr, false); if (extent == NULL) return (0); + assert(extent_active_get(extent)); /* Only arena chunks should be looked up via interior pointers. */ assert(extent_addr_get(extent) == ptr || extent_achunk_get(extent)); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 102f01c0..19402462 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -207,6 +207,8 @@ decay_ticker_get dss_prec_names extent_achunk_get extent_achunk_set +extent_active_get +extent_active_set extent_addr_get extent_addr_set extent_arena_get @@ -214,7 +216,6 @@ extent_arena_set extent_committed_get extent_committed_set extent_dirty_insert -extent_dirty_linkage_init extent_dirty_remove extent_init extent_prof_tctx_get diff --git a/src/arena.c b/src/arena.c index 8a93fca0..5a4605d0 100644 --- a/src/arena.c +++ b/src/arena.c @@ -225,7 +225,6 @@ arena_chunk_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache) { if (cache) { - extent_dirty_linkage_init(extent); extent_dirty_insert(extent, &arena->runs_dirty, &arena->chunks_cache); arena->ndirty += arena_chunk_dirty_npages(extent); @@ -526,7 +525,7 @@ arena_chunk_register(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, * runs is tracked individually, and upon chunk deallocation the entire * chunk is in a consistent commit state. */ - extent_init(&chunk->extent, arena, chunk, chunksize, zero, true); + extent_init(&chunk->extent, arena, chunk, chunksize, true, zero, true); extent_achunk_set(&chunk->extent, true); return (chunk_register(tsdn, chunk, &chunk->extent)); } @@ -1723,7 +1722,8 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) arena->lg_dirty_mult) < arena->ndirty || ndirty_limit == 0); qr_new(&purge_runs_sentinel, rd_link); - extent_dirty_linkage_init(&purge_chunks_sentinel); + extent_init(&purge_chunks_sentinel, arena, NULL, 0, false, false, + false); npurge = arena_stash_dirty(tsdn, arena, &chunk_hooks, ndirty_limit, &purge_runs_sentinel, &purge_chunks_sentinel); diff --git a/src/base.c b/src/base.c index a9ab279e..0176fb80 100644 --- a/src/base.c +++ b/src/base.c @@ -66,7 +66,7 @@ base_chunk_alloc(tsdn_t *tsdn, size_t minsize) base_resident += PAGE_CEILING(nsize); } } - extent_init(extent, NULL, addr, csize, true, true); + extent_init(extent, NULL, addr, csize, true, true, true); return (extent); } @@ -90,7 +90,7 @@ base_alloc(tsdn_t *tsdn, size_t size) csize = CACHELINE_CEILING(size); usize = s2u(csize); - extent_init(&key, NULL, NULL, usize, false, false); + extent_init(&key, NULL, NULL, usize, false, false, false); malloc_mutex_lock(tsdn, &base_mtx); extent = extent_tree_szad_nsearch(&base_avail_szad, &key); if (extent != NULL) { diff --git a/src/chunk.c b/src/chunk.c index beef41fe..055b4fcb 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -239,7 +239,7 @@ chunk_first_best_fit(arena_t *arena, extent_tree_t *chunks_szad, assert(size == CHUNK_CEILING(size)); - extent_init(&key, arena, NULL, size, false, false); + extent_init(&key, arena, NULL, size, false, false, false); return (extent_tree_szad_nsearch(chunks_szad, &key)); } @@ -270,7 +270,8 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); if (new_addr != NULL) { extent_t key; - extent_init(&key, arena, new_addr, alloc_size, false, false); + extent_init(&key, arena, new_addr, alloc_size, false, false, + false); extent = extent_tree_ad_search(chunks_ad, &key); } else { extent = chunk_first_best_fit(arena, chunks_szad, chunks_ad, @@ -336,7 +337,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } } extent_init(extent, arena, (void *)((uintptr_t)(ret) + size), - trailsize, zeroed, committed); + trailsize, false, zeroed, committed); extent_tree_szad_insert(chunks_szad, extent); extent_tree_ad_insert(chunks_ad, extent); arena_chunk_cache_maybe_insert(arena, extent, cache); @@ -534,7 +535,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, malloc_mutex_lock(tsdn, &arena->chunks_mtx); chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); extent_init(&key, arena, (void *)((uintptr_t)chunk + size), 0, false, - false); + false, false); extent = extent_tree_ad_nsearch(chunks_ad, &key); /* Try to coalesce forward. */ if (extent != NULL && extent_addr_get(extent) == extent_addr_get(&key) @@ -570,7 +571,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } goto label_return; } - extent_init(extent, arena, chunk, size, !unzeroed, + extent_init(extent, arena, chunk, size, false, !unzeroed, committed); extent_tree_ad_insert(chunks_ad, extent); extent_tree_szad_insert(chunks_szad, extent); diff --git a/src/huge.c b/src/huge.c index 0b91c369..b6ad4ba6 100644 --- a/src/huge.c +++ b/src/huge.c @@ -50,7 +50,7 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, return (NULL); } - extent_init(extent, arena, ret, usize, is_zeroed, true); + extent_init(extent, arena, ret, usize, true, is_zeroed, true); if (chunk_register(tsdn, ret, extent)) { arena_chunk_dalloc_huge(tsdn, arena, ret, usize); -- GitLab From d78846c98978ea439c2514638de69be6d3d86a11 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 7 Apr 2016 10:24:14 -0400 Subject: [PATCH 020/544] Replace extent_achunk_[gs]et() with extent_slab_[gs]et(). --- include/jemalloc/internal/arena.h | 10 +++---- include/jemalloc/internal/extent.h | 27 ++++++++++--------- .../jemalloc/internal/jemalloc_internal.h.in | 3 +-- include/jemalloc/internal/private_symbols.txt | 4 +-- src/arena.c | 6 ++--- src/base.c | 4 +-- src/chunk.c | 10 +++---- src/huge.c | 2 +- 8 files changed, 33 insertions(+), 33 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index ff3e01d8..52e7197a 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -1185,7 +1185,7 @@ arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) cassert(config_prof); assert(ptr != NULL); - if (likely(extent_achunk_get(extent))) { + if (likely(extent_slab_get(extent))) { arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; size_t mapbits = arena_mapbits_get(chunk, pageind); @@ -1211,7 +1211,7 @@ arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, cassert(config_prof); assert(ptr != NULL); - if (likely(extent_achunk_get(extent))) { + if (likely(extent_slab_get(extent))) { arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; @@ -1331,7 +1331,7 @@ arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr, bool demote) assert(ptr != NULL); - if (likely(extent_achunk_get(extent))) { + if (likely(extent_slab_get(extent))) { const arena_chunk_t *chunk = (const arena_chunk_t *)extent_addr_get(extent); @@ -1381,7 +1381,7 @@ arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); - if (likely(extent_achunk_get(extent))) { + if (likely(extent_slab_get(extent))) { arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; @@ -1428,7 +1428,7 @@ arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, assert(!tsdn_null(tsdn) || tcache == NULL); - if (likely(extent_achunk_get(extent))) { + if (likely(extent_slab_get(extent))) { arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); if (config_prof && opt_prof) { diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 33f5932c..d7db49d4 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -35,10 +35,11 @@ struct extent_s { bool e_committed; /* - * The achunk flag is used to validate that huge allocation lookups - * don't return arena chunks. + * The slab flag indicates whether the extent is used for a slab of + * small regions. This helps differentiate small size classes, and it + * indicates whether interior pointers can be looked up via iealloc(). */ - bool e_achunk; + bool e_slab; /* Profile counters, used for huge objects. */ prof_tctx_t *e_prof_tctx; @@ -79,7 +80,7 @@ size_t extent_size_get(const extent_t *extent); bool extent_active_get(const extent_t *extent); bool extent_zeroed_get(const extent_t *extent); bool extent_committed_get(const extent_t *extent); -bool extent_achunk_get(const extent_t *extent); +bool extent_slab_get(const extent_t *extent); prof_tctx_t *extent_prof_tctx_get(const extent_t *extent); void extent_arena_set(extent_t *extent, arena_t *arena); void extent_addr_set(extent_t *extent, void *addr); @@ -87,10 +88,10 @@ void extent_size_set(extent_t *extent, size_t size); void extent_active_set(extent_t *extent, bool active); void extent_zeroed_set(extent_t *extent, bool zeroed); void extent_committed_set(extent_t *extent, bool committed); -void extent_achunk_set(extent_t *extent, bool achunk); +void extent_slab_set(extent_t *extent, bool slab); void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx); void extent_init(extent_t *extent, arena_t *arena, void *addr, - size_t size, bool active, bool zeroed, bool committed); + size_t size, bool active, bool zeroed, bool committed, bool slab); void extent_dirty_insert(extent_t *extent, arena_runs_dirty_link_t *runs_dirty, extent_t *chunks_dirty); void extent_dirty_remove(extent_t *extent); @@ -136,15 +137,15 @@ JEMALLOC_INLINE bool extent_committed_get(const extent_t *extent) { - assert(!extent->e_achunk); + assert(!extent->e_slab); return (extent->e_committed); } JEMALLOC_INLINE bool -extent_achunk_get(const extent_t *extent) +extent_slab_get(const extent_t *extent) { - return (extent->e_achunk); + return (extent->e_slab); } JEMALLOC_INLINE prof_tctx_t * @@ -197,10 +198,10 @@ extent_committed_set(extent_t *extent, bool committed) } JEMALLOC_INLINE void -extent_achunk_set(extent_t *extent, bool achunk) +extent_slab_set(extent_t *extent, bool slab) { - extent->e_achunk = achunk; + extent->e_slab = slab; } JEMALLOC_INLINE void @@ -212,7 +213,7 @@ extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) JEMALLOC_INLINE void extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, - bool active, bool zeroed, bool committed) + bool active, bool zeroed, bool committed, bool slab) { extent_arena_set(extent, arena); @@ -221,7 +222,7 @@ extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, extent_active_set(extent, active); extent_zeroed_set(extent, zeroed); extent_committed_set(extent, committed); - extent_achunk_set(extent, false); + extent_slab_set(extent, slab); if (config_prof) extent_prof_tctx_set(extent, NULL); qr_new(&extent->rd, rd_link); diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index a7f07818..7afe5694 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -1095,8 +1095,7 @@ ivsalloc(tsdn_t *tsdn, const void *ptr, bool demote) return (0); assert(extent_active_get(extent)); /* Only arena chunks should be looked up via interior pointers. */ - assert(extent_addr_get(extent) == ptr || - extent_achunk_get(extent)); + assert(extent_addr_get(extent) == ptr || extent_slab_get(extent)); return (isalloc(tsdn, extent, ptr, demote)); } diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 19402462..23c206bc 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -205,8 +205,6 @@ ctl_postfork_parent ctl_prefork decay_ticker_get dss_prec_names -extent_achunk_get -extent_achunk_set extent_active_get extent_active_set extent_addr_get @@ -222,6 +220,8 @@ extent_prof_tctx_get extent_prof_tctx_set extent_size_get extent_size_set +extent_slab_get +extent_slab_set extent_tree_ad_destroy extent_tree_ad_destroy_recurse extent_tree_ad_empty diff --git a/src/arena.c b/src/arena.c index 5a4605d0..011320ed 100644 --- a/src/arena.c +++ b/src/arena.c @@ -525,8 +525,8 @@ arena_chunk_register(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, * runs is tracked individually, and upon chunk deallocation the entire * chunk is in a consistent commit state. */ - extent_init(&chunk->extent, arena, chunk, chunksize, true, zero, true); - extent_achunk_set(&chunk->extent, true); + extent_init(&chunk->extent, arena, chunk, chunksize, true, zero, true, + true); return (chunk_register(tsdn, chunk, &chunk->extent)); } @@ -1723,7 +1723,7 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) qr_new(&purge_runs_sentinel, rd_link); extent_init(&purge_chunks_sentinel, arena, NULL, 0, false, false, - false); + false, false); npurge = arena_stash_dirty(tsdn, arena, &chunk_hooks, ndirty_limit, &purge_runs_sentinel, &purge_chunks_sentinel); diff --git a/src/base.c b/src/base.c index 0176fb80..2a6df4dd 100644 --- a/src/base.c +++ b/src/base.c @@ -66,7 +66,7 @@ base_chunk_alloc(tsdn_t *tsdn, size_t minsize) base_resident += PAGE_CEILING(nsize); } } - extent_init(extent, NULL, addr, csize, true, true, true); + extent_init(extent, NULL, addr, csize, true, true, true, false); return (extent); } @@ -90,7 +90,7 @@ base_alloc(tsdn_t *tsdn, size_t size) csize = CACHELINE_CEILING(size); usize = s2u(csize); - extent_init(&key, NULL, NULL, usize, false, false, false); + extent_init(&key, NULL, NULL, usize, false, false, false, false); malloc_mutex_lock(tsdn, &base_mtx); extent = extent_tree_szad_nsearch(&base_avail_szad, &key); if (extent != NULL) { diff --git a/src/chunk.c b/src/chunk.c index 055b4fcb..b691286b 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -239,7 +239,7 @@ chunk_first_best_fit(arena_t *arena, extent_tree_t *chunks_szad, assert(size == CHUNK_CEILING(size)); - extent_init(&key, arena, NULL, size, false, false, false); + extent_init(&key, arena, NULL, size, false, false, false, false); return (extent_tree_szad_nsearch(chunks_szad, &key)); } @@ -271,7 +271,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, if (new_addr != NULL) { extent_t key; extent_init(&key, arena, new_addr, alloc_size, false, false, - false); + false, false); extent = extent_tree_ad_search(chunks_ad, &key); } else { extent = chunk_first_best_fit(arena, chunks_szad, chunks_ad, @@ -337,7 +337,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } } extent_init(extent, arena, (void *)((uintptr_t)(ret) + size), - trailsize, false, zeroed, committed); + trailsize, false, zeroed, committed, false); extent_tree_szad_insert(chunks_szad, extent); extent_tree_ad_insert(chunks_ad, extent); arena_chunk_cache_maybe_insert(arena, extent, cache); @@ -535,7 +535,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, malloc_mutex_lock(tsdn, &arena->chunks_mtx); chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); extent_init(&key, arena, (void *)((uintptr_t)chunk + size), 0, false, - false, false); + false, false, false); extent = extent_tree_ad_nsearch(chunks_ad, &key); /* Try to coalesce forward. */ if (extent != NULL && extent_addr_get(extent) == extent_addr_get(&key) @@ -572,7 +572,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, goto label_return; } extent_init(extent, arena, chunk, size, false, !unzeroed, - committed); + committed, false); extent_tree_ad_insert(chunks_ad, extent); extent_tree_szad_insert(chunks_szad, extent); arena_chunk_cache_maybe_insert(arena, extent, cache); diff --git a/src/huge.c b/src/huge.c index b6ad4ba6..03eea139 100644 --- a/src/huge.c +++ b/src/huge.c @@ -50,7 +50,7 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, return (NULL); } - extent_init(extent, arena, ret, usize, true, is_zeroed, true); + extent_init(extent, arena, ret, usize, true, is_zeroed, true, false); if (chunk_register(tsdn, ret, extent)) { arena_chunk_dalloc_huge(tsdn, arena, ret, usize); -- GitLab From 9aea58d9a242ac6d1623aa1c1fcd737823e5e51b Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 7 Apr 2016 10:34:26 -0400 Subject: [PATCH 021/544] Add extent_past_get(). --- include/jemalloc/internal/extent.h | 8 ++++++++ include/jemalloc/internal/private_symbols.txt | 1 + 2 files changed, 9 insertions(+) diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index d7db49d4..d6376d5d 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -77,6 +77,7 @@ rb_proto(, extent_tree_ad_, extent_tree_t, extent_t) arena_t *extent_arena_get(const extent_t *extent); void *extent_addr_get(const extent_t *extent); size_t extent_size_get(const extent_t *extent); +void *extent_past_get(const extent_t *extent); bool extent_active_get(const extent_t *extent); bool extent_zeroed_get(const extent_t *extent); bool extent_committed_get(const extent_t *extent); @@ -119,6 +120,13 @@ extent_size_get(const extent_t *extent) return (extent->e_size); } +JEMALLOC_INLINE void * +extent_past_get(const extent_t *extent) +{ + + return ((void *)(uintptr_t)extent->e_addr + extent->e_size); +} + JEMALLOC_INLINE bool extent_active_get(const extent_t *extent) { diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 23c206bc..f81cecc3 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -216,6 +216,7 @@ extent_committed_set extent_dirty_insert extent_dirty_remove extent_init +extent_past_get extent_prof_tctx_get extent_prof_tctx_set extent_size_get -- GitLab From f442254bdf4e15ce9f35fa667c5f0c8604c6910d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 17 May 2016 17:12:13 -0700 Subject: [PATCH 022/544] Fix opt_zero-triggered in-place huge reallocation zeroing. Fix huge_ralloc_no_move_expand() to update the extent's zeroed attribute based on the intersection of the previous value and that of the newly merged trailing extent. --- src/huge.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/huge.c b/src/huge.c index 03eea139..ea43236d 100644 --- a/src/huge.c +++ b/src/huge.c @@ -223,11 +223,10 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, void *ptr, malloc_mutex_unlock(tsdn, &arena->huge_mtx); /* - * Copy zero into is_zeroed_chunk and pass the copy to chunk_alloc(), so - * that it is possible to make correct junk/zero fill decisions below. + * Use is_zeroed_chunk to detect whether the trailing memory is zeroed, + * update extent's zeroed field, and zero as necessary. */ - is_zeroed_chunk = zero; - + is_zeroed_chunk = false; if (arena_chunk_ralloc_huge_expand(tsdn, arena, ptr, oldsize, usize, &is_zeroed_chunk)) return (true); @@ -236,6 +235,7 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, void *ptr, chunk_deregister(tsdn, ptr, extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); extent_size_set(extent, usize); + extent_zeroed_set(extent, extent_zeroed_get(extent) && is_zeroed_chunk); malloc_mutex_unlock(tsdn, &arena->huge_mtx); chunk_reregister(tsdn, ptr, extent); -- GitLab From 93e79c5c3fcb4987f7070cf92b5807ee615553b1 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 16 May 2016 13:37:41 -0700 Subject: [PATCH 023/544] Remove redundant chunk argument from chunk_{,de,re}register(). --- include/jemalloc/internal/chunk.h | 8 +++----- src/arena.c | 4 ++-- src/chunk.c | 22 ++++++++++++---------- src/huge.c | 16 ++++++++-------- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index be56c2bd..05cf3d05 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -52,11 +52,9 @@ chunk_hooks_t chunk_hooks_get(tsdn_t *tsdn, arena_t *arena); chunk_hooks_t chunk_hooks_set(tsdn_t *tsdn, arena_t *arena, const chunk_hooks_t *chunk_hooks); -bool chunk_register(tsdn_t *tsdn, const void *chunk, const extent_t *extent); -void chunk_deregister(tsdn_t *tsdn, const void *chunk, - const extent_t *extent); -void chunk_reregister(tsdn_t *tsdn, const void *chunk, - const extent_t *extent); +bool chunk_register(tsdn_t *tsdn, const extent_t *extent); +void chunk_deregister(tsdn_t *tsdn, const extent_t *extent); +void chunk_reregister(tsdn_t *tsdn, const extent_t *extent); void *chunk_alloc_base(size_t size); void *chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, diff --git a/src/arena.c b/src/arena.c index 011320ed..d5ac7a10 100644 --- a/src/arena.c +++ b/src/arena.c @@ -527,7 +527,7 @@ arena_chunk_register(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, */ extent_init(&chunk->extent, arena, chunk, chunksize, true, zero, true, true); - return (chunk_register(tsdn, chunk, &chunk->extent)); + return (chunk_register(tsdn, &chunk->extent)); } static arena_chunk_t * @@ -665,7 +665,7 @@ arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk) bool committed; chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; - chunk_deregister(tsdn, chunk, &chunk->extent); + chunk_deregister(tsdn, &chunk->extent); committed = (arena_mapbits_decommitted_get(chunk, map_bias) == 0); if (!committed) { diff --git a/src/chunk.c b/src/chunk.c index b691286b..5a7980f1 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -141,21 +141,21 @@ chunk_hooks_assure_initialized(tsdn_t *tsdn, arena_t *arena, } bool -chunk_register(tsdn_t *tsdn, const void *chunk, const extent_t *extent) +chunk_register(tsdn_t *tsdn, const extent_t *extent) { + const void *addr; size_t size; rtree_elm_t *elm_a; - assert(extent_addr_get(extent) == chunk); - + addr = extent_addr_get(extent); size = extent_size_get(extent); - if ((elm_a = rtree_elm_acquire(tsdn, &chunks_rtree, (uintptr_t)chunk, + if ((elm_a = rtree_elm_acquire(tsdn, &chunks_rtree, (uintptr_t)addr, false, true)) == NULL) return (true); rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_a, extent); if (size > chunksize) { - uintptr_t last = ((uintptr_t)chunk + + uintptr_t last = ((uintptr_t)addr + (uintptr_t)(CHUNK_CEILING(size - chunksize))); rtree_elm_t *elm_b; @@ -190,18 +190,20 @@ chunk_register(tsdn_t *tsdn, const void *chunk, const extent_t *extent) } void -chunk_deregister(tsdn_t *tsdn, const void *chunk, const extent_t *extent) +chunk_deregister(tsdn_t *tsdn, const extent_t *extent) { + const void *addr; size_t size; rtree_elm_t *elm_a; + addr = extent_addr_get(extent); size = extent_size_get(extent); - elm_a = rtree_elm_acquire(tsdn, &chunks_rtree, (uintptr_t)chunk, true, + elm_a = rtree_elm_acquire(tsdn, &chunks_rtree, (uintptr_t)addr, true, false); rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_a, NULL); if (size > chunksize) { - uintptr_t last = ((uintptr_t)chunk + + uintptr_t last = ((uintptr_t)addr + (uintptr_t)(CHUNK_CEILING(size - chunksize))); rtree_elm_t *elm_b = rtree_elm_acquire(tsdn, &chunks_rtree, last, true, false); @@ -219,11 +221,11 @@ chunk_deregister(tsdn_t *tsdn, const void *chunk, const extent_t *extent) } void -chunk_reregister(tsdn_t *tsdn, const void *chunk, const extent_t *extent) +chunk_reregister(tsdn_t *tsdn, const extent_t *extent) { bool err; - err = chunk_register(tsdn, chunk, extent); + err = chunk_register(tsdn, extent); assert(!err); } diff --git a/src/huge.c b/src/huge.c index ea43236d..48b191ad 100644 --- a/src/huge.c +++ b/src/huge.c @@ -52,7 +52,7 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, extent_init(extent, arena, ret, usize, true, is_zeroed, true, false); - if (chunk_register(tsdn, ret, extent)) { + if (chunk_register(tsdn, extent)) { arena_chunk_dalloc_huge(tsdn, arena, ret, usize); idalloctm(tsdn, iealloc(tsdn, extent), extent, NULL, true, true); @@ -135,11 +135,11 @@ huge_ralloc_no_move_similar(tsdn_t *tsdn, extent_t *extent, void *ptr, /* Update the size of the huge allocation. */ assert(extent_size_get(extent) != usize); - chunk_deregister(tsdn, ptr, extent); + chunk_deregister(tsdn, extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); extent_size_set(extent, usize); malloc_mutex_unlock(tsdn, &arena->huge_mtx); - chunk_reregister(tsdn, ptr, extent); + chunk_reregister(tsdn, extent); /* Update zeroed. */ extent_zeroed_set(extent, post_zeroed); @@ -196,13 +196,13 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, void *ptr, post_zeroed = pre_zeroed; /* Update the size of the huge allocation. */ - chunk_deregister(tsdn, ptr, extent); + chunk_deregister(tsdn, extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); extent_size_set(extent, usize); /* Update zeroed. */ extent_zeroed_set(extent, post_zeroed); malloc_mutex_unlock(tsdn, &arena->huge_mtx); - chunk_reregister(tsdn, ptr, extent); + chunk_reregister(tsdn, extent); /* Zap the excess chunks. */ arena_chunk_ralloc_huge_shrink(tsdn, arena, ptr, oldsize, usize); @@ -232,12 +232,12 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, void *ptr, return (true); /* Update the size of the huge allocation. */ - chunk_deregister(tsdn, ptr, extent); + chunk_deregister(tsdn, extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); extent_size_set(extent, usize); extent_zeroed_set(extent, extent_zeroed_get(extent) && is_zeroed_chunk); malloc_mutex_unlock(tsdn, &arena->huge_mtx); - chunk_reregister(tsdn, ptr, extent); + chunk_reregister(tsdn, extent); if (zero || (config_fill && unlikely(opt_zero))) { if (!is_zeroed_subchunk) { @@ -355,7 +355,7 @@ huge_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr) arena_t *arena; arena = extent_arena_get(extent); - chunk_deregister(tsdn, ptr, extent); + chunk_deregister(tsdn, extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); ql_remove(&arena->huge, extent, ql_link); malloc_mutex_unlock(tsdn, &arena->huge_mtx); -- GitLab From 25845db7c9fcc26a3478afd715a4fcd0798cb642 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 17 May 2016 10:36:17 -0700 Subject: [PATCH 024/544] Dodge ivsalloc() assertion in test code. --- test/unit/arena_reset.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index d7a02e0f..fa2c5cd5 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -78,6 +78,21 @@ get_huge_size(size_t ind) return (get_size_impl("arenas.hchunk.0.size", ind)); } +/* Like ivsalloc(), but safe to call on discarded allocations. */ +static size_t +vsalloc(tsdn_t *tsdn, const void *ptr) +{ + extent_t *extent; + + extent = chunk_lookup(tsdn, ptr, false); + if (extent == NULL) + return (0); + if (!extent_active_get(extent)) + return (0); + + return (isalloc(tsdn, extent, ptr, false)); +} + TEST_BEGIN(test_arena_reset) { #define NHUGE 4 @@ -139,7 +154,7 @@ TEST_BEGIN(test_arena_reset) /* Verify allocations no longer exist. */ for (i = 0; i < nptrs; i++) { - assert_zu_eq(ivsalloc(tsdn, ptrs[i], false), 0, + assert_zu_eq(vsalloc(tsdn, ptrs[i]), 0, "Allocation should no longer exist"); } -- GitLab From ffa45a53314d3ff4376c753c5609689d0f65f0e8 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 16 May 2016 13:25:18 -0700 Subject: [PATCH 025/544] Use rtree rather than [sz]ad trees for chunk split/coalesce operations. --- include/jemalloc/internal/arena.h | 9 +- include/jemalloc/internal/extent.h | 14 +- include/jemalloc/internal/private_symbols.txt | 20 +- src/arena.c | 2 - src/chunk.c | 373 +++++++++++------- src/extent.c | 12 - 6 files changed, 233 insertions(+), 197 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 52e7197a..97b5329e 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -418,16 +418,11 @@ struct arena_s { malloc_mutex_t huge_mtx; /* - * Trees of chunks that were previously allocated (trees differ only in - * extent ordering). These are used when allocating chunks, in an - * attempt to re-use address space. Depending on function, different - * tree orderings are needed, which is why there are two trees with the - * same contents. + * Trees of chunks that were previously allocated. These are used when + * allocating chunks, in an attempt to re-use address space. */ extent_tree_t chunks_szad_cached; - extent_tree_t chunks_ad_cached; extent_tree_t chunks_szad_retained; - extent_tree_t chunks_ad_retained; malloc_mutex_t chunks_mtx; /* Cache of extent structures that were allocated via base_alloc(). */ diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index d6376d5d..f067a296 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -55,9 +55,6 @@ struct extent_s { /* Linkage for arena's achunks, huge, and node_cache lists. */ ql_elm(extent_t) ql_link; }; - - /* Linkage for the address-ordered tree. */ - rb_node(extent_t) ad_link; }; typedef rb_tree(extent_t) extent_tree_t; @@ -67,8 +64,6 @@ typedef rb_tree(extent_t) extent_tree_t; rb_proto(, extent_tree_szad_, extent_tree_t, extent_t) -rb_proto(, extent_tree_ad_, extent_tree_t, extent_t) - #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ #ifdef JEMALLOC_H_INLINES @@ -79,6 +74,7 @@ void *extent_addr_get(const extent_t *extent); size_t extent_size_get(const extent_t *extent); void *extent_past_get(const extent_t *extent); bool extent_active_get(const extent_t *extent); +bool extent_retained_get(const extent_t *extent); bool extent_zeroed_get(const extent_t *extent); bool extent_committed_get(const extent_t *extent); bool extent_slab_get(const extent_t *extent); @@ -134,6 +130,14 @@ extent_active_get(const extent_t *extent) return (extent->e_active); } +JEMALLOC_INLINE bool +extent_retained_get(const extent_t *extent) +{ + + assert(!extent->e_slab); + return (qr_next(&extent->rd, rd_link) == &extent->rd); +} + JEMALLOC_INLINE bool extent_zeroed_get(const extent_t *extent) { diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index f81cecc3..247b8733 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -219,29 +219,11 @@ extent_init extent_past_get extent_prof_tctx_get extent_prof_tctx_set +extent_retained_get extent_size_get extent_size_set extent_slab_get extent_slab_set -extent_tree_ad_destroy -extent_tree_ad_destroy_recurse -extent_tree_ad_empty -extent_tree_ad_first -extent_tree_ad_insert -extent_tree_ad_iter -extent_tree_ad_iter_recurse -extent_tree_ad_iter_start -extent_tree_ad_last -extent_tree_ad_new -extent_tree_ad_next -extent_tree_ad_nsearch -extent_tree_ad_prev -extent_tree_ad_psearch -extent_tree_ad_remove -extent_tree_ad_reverse_iter -extent_tree_ad_reverse_iter_recurse -extent_tree_ad_reverse_iter_start -extent_tree_ad_search extent_tree_szad_destroy extent_tree_szad_destroy_recurse extent_tree_szad_empty diff --git a/src/arena.c b/src/arena.c index d5ac7a10..faf23495 100644 --- a/src/arena.c +++ b/src/arena.c @@ -3427,9 +3427,7 @@ arena_new(tsdn_t *tsdn, unsigned ind) return (NULL); extent_tree_szad_new(&arena->chunks_szad_cached); - extent_tree_ad_new(&arena->chunks_ad_cached); extent_tree_szad_new(&arena->chunks_szad_retained); - extent_tree_ad_new(&arena->chunks_ad_retained); if (malloc_mutex_init(&arena->chunks_mtx, "arena_chunks", WITNESS_RANK_ARENA_CHUNKS)) return (NULL); diff --git a/src/chunk.c b/src/chunk.c index 5a7980f1..9a9b08e3 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -50,9 +50,8 @@ const chunk_hooks_t chunk_hooks_default = { */ static void chunk_record(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, extent_tree_t *chunks_szad, - extent_tree_t *chunks_ad, bool cache, void *chunk, size_t size, bool zeroed, - bool committed); + chunk_hooks_t *chunk_hooks, extent_tree_t *chunks_szad, bool cache, + void *chunk, size_t size, bool zeroed, bool committed); /******************************************************************************/ @@ -140,39 +139,65 @@ chunk_hooks_assure_initialized(tsdn_t *tsdn, arena_t *arena, chunk_hooks_assure_initialized_impl(tsdn, arena, chunk_hooks, false); } -bool -chunk_register(tsdn_t *tsdn, const extent_t *extent) +static bool +extent_rtree_acquire(tsdn_t *tsdn, const extent_t *extent, bool dependent, + bool init_missing, rtree_elm_t **r_elm_a, rtree_elm_t **r_elm_b) { - const void *addr; - size_t size; - rtree_elm_t *elm_a; - addr = extent_addr_get(extent); - size = extent_size_get(extent); - - if ((elm_a = rtree_elm_acquire(tsdn, &chunks_rtree, (uintptr_t)addr, - false, true)) == NULL) + *r_elm_a = rtree_elm_acquire(tsdn, &chunks_rtree, + (uintptr_t)extent_addr_get(extent), dependent, init_missing); + if (!dependent && *r_elm_a == NULL) return (true); - rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_a, extent); - if (size > chunksize) { - uintptr_t last = ((uintptr_t)addr + - (uintptr_t)(CHUNK_CEILING(size - chunksize))); - rtree_elm_t *elm_b; - - if ((elm_b = rtree_elm_acquire(tsdn, &chunks_rtree, last, false, - true)) == NULL) { - rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_a, - NULL); - rtree_elm_release(tsdn, &chunks_rtree, elm_a); + assert(*r_elm_a != NULL); + + if (extent_size_get(extent) > chunksize) { + uintptr_t last = + (CHUNK_CEILING((uintptr_t)extent_past_get(extent) - + chunksize)); + + *r_elm_b = rtree_elm_acquire(tsdn, &chunks_rtree, last, + dependent, init_missing); + if (!dependent && *r_elm_b == NULL) return (true); - } + assert(*r_elm_b != NULL); + } else + *r_elm_b = NULL; + + return (false); +} + +static void +extent_rtree_write_acquired(tsdn_t *tsdn, rtree_elm_t *elm_a, + rtree_elm_t *elm_b, const extent_t *extent) +{ + + rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_a, extent); + if (elm_b != NULL) rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_b, extent); - rtree_elm_release(tsdn, &chunks_rtree, elm_b); - } +} + +static void +extent_rtree_release(tsdn_t *tsdn, rtree_elm_t *elm_a, rtree_elm_t *elm_b) +{ + rtree_elm_release(tsdn, &chunks_rtree, elm_a); + if (elm_b != NULL) + rtree_elm_release(tsdn, &chunks_rtree, elm_b); +} + +bool +chunk_register(tsdn_t *tsdn, const extent_t *extent) +{ + rtree_elm_t *elm_a, *elm_b; + + if (extent_rtree_acquire(tsdn, extent, false, true, &elm_a, &elm_b)) + return (true); + extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent); + extent_rtree_release(tsdn, elm_a, elm_b); if (config_prof && opt_prof) { - size_t nadd = (size == 0) ? 1 : size / chunksize; + size_t nadd = (extent_size_get(extent) == 0) ? 1 : + extent_size_get(extent) / chunksize; size_t cur = atomic_add_z(&curchunks, nadd); size_t high = atomic_read_z(&highchunks); while (cur > high && atomic_cas_z(&highchunks, high, cur)) { @@ -192,29 +217,15 @@ chunk_register(tsdn_t *tsdn, const extent_t *extent) void chunk_deregister(tsdn_t *tsdn, const extent_t *extent) { - const void *addr; - size_t size; - rtree_elm_t *elm_a; - - addr = extent_addr_get(extent); - size = extent_size_get(extent); - - elm_a = rtree_elm_acquire(tsdn, &chunks_rtree, (uintptr_t)addr, true, - false); - rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_a, NULL); - if (size > chunksize) { - uintptr_t last = ((uintptr_t)addr + - (uintptr_t)(CHUNK_CEILING(size - chunksize))); - rtree_elm_t *elm_b = rtree_elm_acquire(tsdn, &chunks_rtree, - last, true, false); + rtree_elm_t *elm_a, *elm_b; - rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_b, NULL); - rtree_elm_release(tsdn, &chunks_rtree, elm_b); - } - rtree_elm_release(tsdn, &chunks_rtree, elm_a); + extent_rtree_acquire(tsdn, extent, true, false, &elm_a, &elm_b); + extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL); + extent_rtree_release(tsdn, elm_a, elm_b); if (config_prof && opt_prof) { - size_t nsub = (size == 0) ? 1 : size / chunksize; + size_t nsub = (extent_size_get(extent) == 0) ? 1 : + extent_size_get(extent) / chunksize; assert(atomic_read_z(&curchunks) >= nsub); atomic_sub_z(&curchunks, nsub); } @@ -234,8 +245,7 @@ chunk_reregister(tsdn_t *tsdn, const extent_t *extent) * fits. */ static extent_t * -chunk_first_best_fit(arena_t *arena, extent_tree_t *chunks_szad, - extent_tree_t *chunks_ad, size_t size) +chunk_first_best_fit(arena_t *arena, extent_tree_t *chunks_szad, size_t size) { extent_t key; @@ -245,11 +255,25 @@ chunk_first_best_fit(arena_t *arena, extent_tree_t *chunks_szad, return (extent_tree_szad_nsearch(chunks_szad, &key)); } +static void +chunk_leak(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, bool cache, + void *addr, size_t size) +{ + + /* + * Leak chunk after making sure its pages have already been purged, so + * that this is only a virtual memory leak. + */ + if (cache) { + chunk_purge_wrapper(tsdn, arena, chunk_hooks, addr, size, 0, + size); + } +} + static void * chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, bool cache, - void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit, - bool dalloc_extent) + extent_tree_t *chunks_szad, bool cache, void *new_addr, size_t size, + size_t alignment, bool *zero, bool *commit, bool dalloc_extent) { void *ret; extent_t *extent; @@ -271,14 +295,21 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, malloc_mutex_lock(tsdn, &arena->chunks_mtx); chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); if (new_addr != NULL) { - extent_t key; - extent_init(&key, arena, new_addr, alloc_size, false, false, - false, false); - extent = extent_tree_ad_search(chunks_ad, &key); - } else { - extent = chunk_first_best_fit(arena, chunks_szad, chunks_ad, - alloc_size); - } + rtree_elm_t *elm; + + elm = rtree_elm_acquire(tsdn, &chunks_rtree, + (uintptr_t)new_addr, false, false); + if (elm != NULL) { + extent = rtree_elm_read_acquired(tsdn, &chunks_rtree, + elm); + if (extent != NULL && (extent_active_get(extent) || + extent_retained_get(extent) == cache)) + extent = NULL; + rtree_elm_release(tsdn, &chunks_rtree, elm); + } else + extent = NULL; + } else + extent = chunk_first_best_fit(arena, chunks_szad, alloc_size); if (extent == NULL || (new_addr != NULL && extent_size_get(extent) < size)) { malloc_mutex_unlock(tsdn, &arena->chunks_mtx); @@ -304,15 +335,20 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, return (NULL); } /* Remove extent from the tree. */ + chunk_deregister(tsdn, extent); extent_tree_szad_remove(chunks_szad, extent); - extent_tree_ad_remove(chunks_ad, extent); arena_chunk_cache_maybe_remove(arena, extent, cache); if (leadsize != 0) { /* Insert the leading space as a smaller chunk. */ extent_size_set(extent, leadsize); - extent_tree_szad_insert(chunks_szad, extent); - extent_tree_ad_insert(chunks_ad, extent); - arena_chunk_cache_maybe_insert(arena, extent, cache); + if (chunk_register(tsdn, extent)) { + chunk_leak(tsdn, arena, chunk_hooks, cache, + extent_addr_get(extent), extent_size_get(extent)); + arena_extent_dalloc(tsdn, arena, extent); + } else { + extent_tree_szad_insert(chunks_szad, extent); + arena_chunk_cache_maybe_insert(arena, extent, cache); + } extent = NULL; } if (trailsize != 0) { @@ -323,8 +359,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, arena_extent_dalloc(tsdn, arena, extent); malloc_mutex_unlock(tsdn, &arena->chunks_mtx); chunk_record(tsdn, arena, chunk_hooks, chunks_szad, - chunks_ad, cache, ret, size + trailsize, zeroed, - committed); + cache, ret, size + trailsize, zeroed, committed); return (NULL); } /* Insert the trailing space as a smaller chunk. */ @@ -333,22 +368,27 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, if (extent == NULL) { malloc_mutex_unlock(tsdn, &arena->chunks_mtx); chunk_record(tsdn, arena, chunk_hooks, - chunks_szad, chunks_ad, cache, ret, size + - trailsize, zeroed, committed); + chunks_szad, cache, ret, size + trailsize, + zeroed, committed); return (NULL); } } extent_init(extent, arena, (void *)((uintptr_t)(ret) + size), trailsize, false, zeroed, committed, false); - extent_tree_szad_insert(chunks_szad, extent); - extent_tree_ad_insert(chunks_ad, extent); - arena_chunk_cache_maybe_insert(arena, extent, cache); + if (chunk_register(tsdn, extent)) { + chunk_leak(tsdn, arena, chunk_hooks, cache, + extent_addr_get(extent), extent_size_get(extent)); + arena_extent_dalloc(tsdn, arena, extent); + } else { + extent_tree_szad_insert(chunks_szad, extent); + arena_chunk_cache_maybe_insert(arena, extent, cache); + } extent = NULL; } if (!committed && chunk_hooks->commit(ret, size, 0, size, arena->ind)) { malloc_mutex_unlock(tsdn, &arena->chunks_mtx); - chunk_record(tsdn, arena, chunk_hooks, chunks_szad, chunks_ad, - cache, ret, size, zeroed, committed); + chunk_record(tsdn, arena, chunk_hooks, chunks_szad, cache, ret, + size, zeroed, committed); return (NULL); } malloc_mutex_unlock(tsdn, &arena->chunks_mtx); @@ -441,8 +481,8 @@ chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, commit = true; ret = chunk_recycle(tsdn, arena, chunk_hooks, - &arena->chunks_szad_cached, &arena->chunks_ad_cached, true, - new_addr, size, alignment, zero, &commit, dalloc_extent); + &arena->chunks_szad_cached, true, new_addr, size, alignment, zero, + &commit, dalloc_extent); if (ret == NULL) return (NULL); assert(commit); @@ -493,8 +533,8 @@ chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert((alignment & chunksize_mask) == 0); ret = chunk_recycle(tsdn, arena, chunk_hooks, - &arena->chunks_szad_retained, &arena->chunks_ad_retained, false, - new_addr, size, alignment, zero, commit, true); + &arena->chunks_szad_retained, false, new_addr, size, alignment, + zero, commit, true); if (config_stats && ret != NULL) arena->stats.retained -= size; @@ -522,89 +562,118 @@ chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, return (ret); } +static bool +chunk_can_coalesce(const extent_t *a, const extent_t *b) +{ + + assert((void *)CHUNK_CEILING((uintptr_t)extent_past_get(a)) == + extent_addr_get(b)); + + if (extent_arena_get(a) != extent_arena_get(b)) + return (false); + if (extent_active_get(a) != extent_active_get(b)) + return (false); + if (extent_committed_get(a) != extent_committed_get(b)) + return (false); + if (extent_retained_get(a) != extent_retained_get(b)) + return (false); + + return (true); +} + +static void +chunk_try_coalesce(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, + extent_t *a, extent_t *b, extent_tree_t *chunks_szad, bool cache) +{ + rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; + + if (!chunk_can_coalesce(a, b)) + return; + + if (chunk_hooks->merge(extent_addr_get(a), extent_size_get(a), + extent_addr_get(b), extent_size_get(b), extent_committed_get(a), + arena->ind)) + return; + + /* + * The rtree writes must happen while all the relevant elements are + * owned, so the following code uses decomposed helper functions rather + * than chunk_{,de}register() to do things in the right order. + */ + extent_rtree_acquire(tsdn, a, true, false, &a_elm_a, &a_elm_b); + extent_rtree_acquire(tsdn, b, true, false, &b_elm_a, &b_elm_b); + + if (a_elm_b != NULL) { + rtree_elm_write_acquired(tsdn, &chunks_rtree, a_elm_b, NULL); + rtree_elm_release(tsdn, &chunks_rtree, a_elm_b); + } + if (b_elm_b != NULL) { + rtree_elm_write_acquired(tsdn, &chunks_rtree, b_elm_a, NULL); + rtree_elm_release(tsdn, &chunks_rtree, b_elm_a); + } else + b_elm_b = b_elm_a; + + extent_tree_szad_remove(chunks_szad, a); + extent_tree_szad_remove(chunks_szad, b); + + arena_chunk_cache_maybe_remove(extent_arena_get(a), a, cache); + arena_chunk_cache_maybe_remove(extent_arena_get(b), b, cache); + + extent_size_set(a, extent_size_get(a) + extent_size_get(b)); + extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b)); + + extent_tree_szad_insert(chunks_szad, a); + + extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a); + extent_rtree_release(tsdn, a_elm_a, b_elm_b); + + arena_chunk_cache_maybe_insert(extent_arena_get(a), a, cache); + + arena_extent_dalloc(tsdn, extent_arena_get(b), b); +} + static void chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - extent_tree_t *chunks_szad, extent_tree_t *chunks_ad, bool cache, - void *chunk, size_t size, bool zeroed, bool committed) + extent_tree_t *chunks_szad, bool cache, void *chunk, size_t size, + bool zeroed, bool committed) { - bool unzeroed; - extent_t *extent, *prev; - extent_t key; + extent_t *extent, *prev, *next; assert(!cache || !zeroed); - unzeroed = cache || !zeroed; malloc_mutex_lock(tsdn, &arena->chunks_mtx); chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); - extent_init(&key, arena, (void *)((uintptr_t)chunk + size), 0, false, - false, false, false); - extent = extent_tree_ad_nsearch(chunks_ad, &key); + + /* Create/initialize/insert extent. */ + extent = arena_extent_alloc(tsdn, arena); + if (extent == NULL) { + chunk_leak(tsdn, arena, chunk_hooks, cache, chunk, size); + goto label_return; + } + extent_init(extent, arena, chunk, size, false, !cache && zeroed, + committed, false); + if (chunk_register(tsdn, extent)) { + arena_extent_dalloc(tsdn, arena, extent); + chunk_leak(tsdn, arena, chunk_hooks, cache, chunk, size); + goto label_return; + } + extent_tree_szad_insert(chunks_szad, extent); + arena_chunk_cache_maybe_insert(arena, extent, cache); + /* Try to coalesce forward. */ - if (extent != NULL && extent_addr_get(extent) == extent_addr_get(&key) - && extent_committed_get(extent) == committed && - !chunk_hooks->merge(chunk, size, extent_addr_get(extent), - extent_size_get(extent), false, arena->ind)) { - /* - * Coalesce chunk with the following address range. This does - * not change the position within chunks_ad, so only - * remove/insert from/into chunks_szad. - */ - extent_tree_szad_remove(chunks_szad, extent); - arena_chunk_cache_maybe_remove(arena, extent, cache); - extent_addr_set(extent, chunk); - extent_size_set(extent, size + extent_size_get(extent)); - extent_zeroed_set(extent, extent_zeroed_get(extent) && - !unzeroed); - extent_tree_szad_insert(chunks_szad, extent); - arena_chunk_cache_maybe_insert(arena, extent, cache); - } else { - /* Coalescing forward failed, so insert a new extent. */ - extent = arena_extent_alloc(tsdn, arena); - if (extent == NULL) { - /* - * Node allocation failed, which is an exceedingly - * unlikely failure. Leak chunk after making sure its - * pages have already been purged, so that this is only - * a virtual memory leak. - */ - if (cache) { - chunk_purge_wrapper(tsdn, arena, chunk_hooks, - chunk, size, 0, size); - } - goto label_return; - } - extent_init(extent, arena, chunk, size, false, !unzeroed, - committed, false); - extent_tree_ad_insert(chunks_ad, extent); - extent_tree_szad_insert(chunks_szad, extent); - arena_chunk_cache_maybe_insert(arena, extent, cache); + next = rtree_read(tsdn, &chunks_rtree, + CHUNK_CEILING((uintptr_t)extent_past_get(extent)), false); + if (next != NULL) { + chunk_try_coalesce(tsdn, arena, chunk_hooks, extent, next, + chunks_szad, cache); } /* Try to coalesce backward. */ - prev = extent_tree_ad_prev(chunks_ad, extent); - if (prev != NULL && (void *)((uintptr_t)extent_addr_get(prev) + - extent_size_get(prev)) == chunk && extent_committed_get(prev) == - committed && !chunk_hooks->merge(extent_addr_get(prev), - extent_size_get(prev), chunk, size, false, arena->ind)) { - /* - * Coalesce chunk with the previous address range. This does - * not change the position within chunks_ad, so only - * remove/insert extent from/into chunks_szad. - */ - extent_tree_szad_remove(chunks_szad, prev); - extent_tree_ad_remove(chunks_ad, prev); - arena_chunk_cache_maybe_remove(arena, prev, cache); - extent_tree_szad_remove(chunks_szad, extent); - arena_chunk_cache_maybe_remove(arena, extent, cache); - extent_addr_set(extent, extent_addr_get(prev)); - extent_size_set(extent, extent_size_get(prev) + - extent_size_get(extent)); - extent_zeroed_set(extent, extent_zeroed_get(prev) && - extent_zeroed_get(extent)); - extent_tree_szad_insert(chunks_szad, extent); - arena_chunk_cache_maybe_insert(arena, extent, cache); - - arena_extent_dalloc(tsdn, arena, prev); + prev = rtree_read(tsdn, &chunks_rtree, + (uintptr_t)extent_addr_get(extent) - chunksize, false); + if (prev != NULL) { + chunk_try_coalesce(tsdn, arena, chunk_hooks, prev, extent, + chunks_szad, cache); } label_return: @@ -621,8 +690,8 @@ chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert(size != 0); assert((size & chunksize_mask) == 0); - chunk_record(tsdn, arena, chunk_hooks, &arena->chunks_szad_cached, - &arena->chunks_ad_cached, true, chunk, size, false, committed); + chunk_record(tsdn, arena, chunk_hooks, &arena->chunks_szad_cached, true, + chunk, size, false, committed); arena_maybe_purge(tsdn, arena); } @@ -658,7 +727,7 @@ chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, zeroed = !committed || !chunk_hooks->purge(chunk, size, 0, size, arena->ind); chunk_record(tsdn, arena, chunk_hooks, &arena->chunks_szad_retained, - &arena->chunks_ad_retained, false, chunk, size, zeroed, committed); + false, chunk, size, zeroed, committed); if (config_stats) arena->stats.retained += size; diff --git a/src/extent.c b/src/extent.c index 8d24d6d6..c550e6cb 100644 --- a/src/extent.c +++ b/src/extent.c @@ -39,15 +39,3 @@ extent_szad_comp(const extent_t *a, const extent_t *b) /* Generate red-black tree functions. */ rb_gen(, extent_tree_szad_, extent_tree_t, extent_t, szad_link, extent_szad_comp) - -JEMALLOC_INLINE_C int -extent_ad_comp(const extent_t *a, const extent_t *b) -{ - uintptr_t a_addr = (uintptr_t)extent_addr_get(a); - uintptr_t b_addr = (uintptr_t)extent_addr_get(b); - - return ((a_addr > b_addr) - (a_addr < b_addr)); -} - -/* Generate red-black tree functions. */ -rb_gen(, extent_tree_ad_, extent_tree_t, extent_t, ad_link, extent_ad_comp) -- GitLab From fc0372a15e6486d69e6f5f4c2b656aafbb013850 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 17 May 2016 14:58:56 -0700 Subject: [PATCH 026/544] Replace extent_tree_szad_* with extent_heap_*. --- Makefile.in | 1 + include/jemalloc/internal/arena.h | 6 +- include/jemalloc/internal/extent.h | 17 +- include/jemalloc/internal/private_symbols.txt | 21 +-- src/arena.c | 14 +- src/base.c | 35 ++-- src/chunk.c | 85 ++++++---- src/extent.c | 101 +++++++++--- test/unit/extent_quantize.c | 155 ++++++++++++++++++ 9 files changed, 332 insertions(+), 103 deletions(-) create mode 100644 test/unit/extent_quantize.c diff --git a/Makefile.in b/Makefile.in index 8cd6af98..7d73155a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -136,6 +136,7 @@ TESTS_UNIT := \ $(srcroot)test/unit/bitmap.c \ $(srcroot)test/unit/ckh.c \ $(srcroot)test/unit/decay.c \ + $(srcroot)test/unit/extent_quantize.c \ $(srcroot)test/unit/fork.c \ $(srcroot)test/unit/hash.c \ $(srcroot)test/unit/junk.c \ diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 97b5329e..b6bfb25c 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -418,11 +418,11 @@ struct arena_s { malloc_mutex_t huge_mtx; /* - * Trees of chunks that were previously allocated. These are used when + * Heaps of chunks that were previously allocated. These are used when * allocating chunks, in an attempt to re-use address space. */ - extent_tree_t chunks_szad_cached; - extent_tree_t chunks_szad_retained; + extent_heap_t chunks_cached[NPSIZES]; + extent_heap_t chunks_retained[NPSIZES]; malloc_mutex_t chunks_mtx; /* Cache of extent structures that were allocated via base_alloc(). */ diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index f067a296..82da8004 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -49,20 +49,29 @@ struct extent_s { qr(extent_t) cc_link; union { - /* Linkage for the size/address-ordered tree. */ - rb_node(extent_t) szad_link; + /* Linkage for per size class address-ordered heaps. */ + phn(extent_t) ph_link; /* Linkage for arena's achunks, huge, and node_cache lists. */ ql_elm(extent_t) ql_link; }; }; -typedef rb_tree(extent_t) extent_tree_t; +typedef ph(extent_t) extent_heap_t; #endif /* JEMALLOC_H_STRUCTS */ /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS -rb_proto(, extent_tree_szad_, extent_tree_t, extent_t) +#ifdef JEMALLOC_JET +typedef size_t (extent_size_quantize_t)(size_t); +extern extent_size_quantize_t *extent_size_quantize_floor; +extern extent_size_quantize_t *extent_size_quantize_ceil; +#else +size_t extent_size_quantize_floor(size_t size); +size_t extent_size_quantize_ceil(size_t size); +#endif + +ph_proto(, extent_heap_, extent_heap_t, extent_t) #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 247b8733..b3d18600 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -222,27 +222,10 @@ extent_prof_tctx_set extent_retained_get extent_size_get extent_size_set +extent_size_quantize_ceil +extent_size_quantize_floor extent_slab_get extent_slab_set -extent_tree_szad_destroy -extent_tree_szad_destroy_recurse -extent_tree_szad_empty -extent_tree_szad_first -extent_tree_szad_insert -extent_tree_szad_iter -extent_tree_szad_iter_recurse -extent_tree_szad_iter_start -extent_tree_szad_last -extent_tree_szad_new -extent_tree_szad_next -extent_tree_szad_nsearch -extent_tree_szad_prev -extent_tree_szad_psearch -extent_tree_szad_remove -extent_tree_szad_reverse_iter -extent_tree_szad_reverse_iter_recurse -extent_tree_szad_reverse_iter_start -extent_tree_szad_search extent_zeroed_get extent_zeroed_set ffs_llu diff --git a/src/arena.c b/src/arena.c index faf23495..720219d3 100644 --- a/src/arena.c +++ b/src/arena.c @@ -3411,10 +3411,6 @@ arena_new(tsdn_t *tsdn, unsigned ind) arena->nactive = 0; arena->ndirty = 0; - for (i = 0; i < sizeof(arena->runs_avail) / sizeof(arena_run_heap_t); - i++) - arena_run_heap_new(&arena->runs_avail[i]); - qr_new(&arena->runs_dirty, rd_link); qr_new(&arena->chunks_cache, cc_link); @@ -3426,8 +3422,11 @@ arena_new(tsdn_t *tsdn, unsigned ind) WITNESS_RANK_ARENA_HUGE)) return (NULL); - extent_tree_szad_new(&arena->chunks_szad_cached); - extent_tree_szad_new(&arena->chunks_szad_retained); + for (i = 0; i < NPSIZES; i++) { + extent_heap_new(&arena->chunks_cached[i]); + extent_heap_new(&arena->chunks_retained[i]); + } + if (malloc_mutex_init(&arena->chunks_mtx, "arena_chunks", WITNESS_RANK_ARENA_CHUNKS)) return (NULL); @@ -3450,6 +3449,9 @@ arena_new(tsdn_t *tsdn, unsigned ind) memset(&bin->stats, 0, sizeof(malloc_bin_stats_t)); } + for (i = 0; i < NPSIZES; i++) + arena_run_heap_new(&arena->runs_avail[i]); + return (arena); } diff --git a/src/base.c b/src/base.c index 2a6df4dd..8816738c 100644 --- a/src/base.c +++ b/src/base.c @@ -5,7 +5,7 @@ /* Data. */ static malloc_mutex_t base_mtx; -static extent_tree_t base_avail_szad; +static extent_heap_t base_avail[NSIZES]; static extent_t *base_extents; static size_t base_allocated; static size_t base_resident; @@ -79,9 +79,9 @@ void * base_alloc(tsdn_t *tsdn, size_t size) { void *ret; - size_t csize, usize; + size_t csize; + szind_t i; extent_t *extent; - extent_t key; /* * Round size up to nearest multiple of the cacheline size, so that @@ -89,14 +89,16 @@ base_alloc(tsdn_t *tsdn, size_t size) */ csize = CACHELINE_CEILING(size); - usize = s2u(csize); - extent_init(&key, NULL, NULL, usize, false, false, false, false); + extent = NULL; malloc_mutex_lock(tsdn, &base_mtx); - extent = extent_tree_szad_nsearch(&base_avail_szad, &key); - if (extent != NULL) { - /* Use existing space. */ - extent_tree_szad_remove(&base_avail_szad, extent); - } else { + for (i = size2index(csize); i < NSIZES; i++) { + extent = extent_heap_remove_first(&base_avail[i]); + if (extent != NULL) { + /* Use existing space. */ + break; + } + } + if (extent == NULL) { /* Try to allocate more space. */ extent = base_chunk_alloc(tsdn, csize); } @@ -107,9 +109,16 @@ base_alloc(tsdn_t *tsdn, size_t size) ret = extent_addr_get(extent); if (extent_size_get(extent) > csize) { + szind_t index_floor; + extent_addr_set(extent, (void *)((uintptr_t)ret + csize)); extent_size_set(extent, extent_size_get(extent) - csize); - extent_tree_szad_insert(&base_avail_szad, extent); + /* + * Compute the index for the largest size class that does not + * exceed extent's size. + */ + index_floor = size2index(extent_size_get(extent) + 1) - 1; + extent_heap_insert(&base_avail[index_floor], extent); } else base_extent_dalloc(tsdn, extent); if (config_stats) { @@ -143,10 +152,12 @@ base_stats_get(tsdn_t *tsdn, size_t *allocated, size_t *resident, bool base_boot(void) { + szind_t i; if (malloc_mutex_init(&base_mtx, "base", WITNESS_RANK_BASE)) return (true); - extent_tree_szad_new(&base_avail_szad); + for (i = 0; i < NSIZES; i++) + extent_heap_new(&base_avail[i]); base_extents = NULL; return (false); diff --git a/src/chunk.c b/src/chunk.c index 9a9b08e3..2463028b 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -50,11 +50,27 @@ const chunk_hooks_t chunk_hooks_default = { */ static void chunk_record(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, extent_tree_t *chunks_szad, bool cache, + chunk_hooks_t *chunk_hooks, extent_heap_t extent_heaps[NPSIZES], bool cache, void *chunk, size_t size, bool zeroed, bool committed); /******************************************************************************/ +static void +extent_heaps_insert(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) +{ + size_t psz = extent_size_quantize_floor(extent_size_get(extent)); + pszind_t pind = psz2ind(psz); + extent_heap_insert(&extent_heaps[pind], extent); +} + +static void +extent_heaps_remove(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) +{ + size_t psz = extent_size_quantize_floor(extent_size_get(extent)); + pszind_t pind = psz2ind(psz); + extent_heap_remove(&extent_heaps[pind], extent); +} + static chunk_hooks_t chunk_hooks_get_locked(arena_t *arena) { @@ -245,14 +261,21 @@ chunk_reregister(tsdn_t *tsdn, const extent_t *extent) * fits. */ static extent_t * -chunk_first_best_fit(arena_t *arena, extent_tree_t *chunks_szad, size_t size) +chunk_first_best_fit(arena_t *arena, extent_heap_t extent_heaps[NPSIZES], + size_t size) { - extent_t key; + pszind_t pind, i; assert(size == CHUNK_CEILING(size)); - extent_init(&key, arena, NULL, size, false, false, false, false); - return (extent_tree_szad_nsearch(chunks_szad, &key)); + pind = psz2ind(extent_size_quantize_ceil(size)); + for (i = pind; i < NPSIZES; i++) { + extent_t *extent = extent_heap_first(&extent_heaps[i]); + if (extent != NULL) + return (extent); + } + + return (NULL); } static void @@ -272,8 +295,8 @@ chunk_leak(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, bool cache, static void * chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - extent_tree_t *chunks_szad, bool cache, void *new_addr, size_t size, - size_t alignment, bool *zero, bool *commit, bool dalloc_extent) + extent_heap_t extent_heaps[NPSIZES], bool cache, void *new_addr, + size_t size, size_t alignment, bool *zero, bool *commit, bool dalloc_extent) { void *ret; extent_t *extent; @@ -309,7 +332,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } else extent = NULL; } else - extent = chunk_first_best_fit(arena, chunks_szad, alloc_size); + extent = chunk_first_best_fit(arena, extent_heaps, alloc_size); if (extent == NULL || (new_addr != NULL && extent_size_get(extent) < size)) { malloc_mutex_unlock(tsdn, &arena->chunks_mtx); @@ -334,9 +357,9 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, malloc_mutex_unlock(tsdn, &arena->chunks_mtx); return (NULL); } - /* Remove extent from the tree. */ + /* Remove extent from the heap. */ chunk_deregister(tsdn, extent); - extent_tree_szad_remove(chunks_szad, extent); + extent_heaps_remove(extent_heaps, extent); arena_chunk_cache_maybe_remove(arena, extent, cache); if (leadsize != 0) { /* Insert the leading space as a smaller chunk. */ @@ -346,7 +369,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_addr_get(extent), extent_size_get(extent)); arena_extent_dalloc(tsdn, arena, extent); } else { - extent_tree_szad_insert(chunks_szad, extent); + extent_heaps_insert(extent_heaps, extent); arena_chunk_cache_maybe_insert(arena, extent, cache); } extent = NULL; @@ -358,7 +381,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, if (dalloc_extent && extent != NULL) arena_extent_dalloc(tsdn, arena, extent); malloc_mutex_unlock(tsdn, &arena->chunks_mtx); - chunk_record(tsdn, arena, chunk_hooks, chunks_szad, + chunk_record(tsdn, arena, chunk_hooks, extent_heaps, cache, ret, size + trailsize, zeroed, committed); return (NULL); } @@ -368,7 +391,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, if (extent == NULL) { malloc_mutex_unlock(tsdn, &arena->chunks_mtx); chunk_record(tsdn, arena, chunk_hooks, - chunks_szad, cache, ret, size + trailsize, + extent_heaps, cache, ret, size + trailsize, zeroed, committed); return (NULL); } @@ -380,14 +403,14 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_addr_get(extent), extent_size_get(extent)); arena_extent_dalloc(tsdn, arena, extent); } else { - extent_tree_szad_insert(chunks_szad, extent); + extent_heaps_insert(extent_heaps, extent); arena_chunk_cache_maybe_insert(arena, extent, cache); } extent = NULL; } if (!committed && chunk_hooks->commit(ret, size, 0, size, arena->ind)) { malloc_mutex_unlock(tsdn, &arena->chunks_mtx); - chunk_record(tsdn, arena, chunk_hooks, chunks_szad, cache, ret, + chunk_record(tsdn, arena, chunk_hooks, extent_heaps, cache, ret, size, zeroed, committed); return (NULL); } @@ -480,9 +503,8 @@ chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert((alignment & chunksize_mask) == 0); commit = true; - ret = chunk_recycle(tsdn, arena, chunk_hooks, - &arena->chunks_szad_cached, true, new_addr, size, alignment, zero, - &commit, dalloc_extent); + ret = chunk_recycle(tsdn, arena, chunk_hooks, arena->chunks_cached, + true, new_addr, size, alignment, zero, &commit, dalloc_extent); if (ret == NULL) return (NULL); assert(commit); @@ -532,9 +554,8 @@ chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert(alignment != 0); assert((alignment & chunksize_mask) == 0); - ret = chunk_recycle(tsdn, arena, chunk_hooks, - &arena->chunks_szad_retained, false, new_addr, size, alignment, - zero, commit, true); + ret = chunk_recycle(tsdn, arena, chunk_hooks, arena->chunks_retained, + false, new_addr, size, alignment, zero, commit, true); if (config_stats && ret != NULL) arena->stats.retained -= size; @@ -583,7 +604,7 @@ chunk_can_coalesce(const extent_t *a, const extent_t *b) static void chunk_try_coalesce(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - extent_t *a, extent_t *b, extent_tree_t *chunks_szad, bool cache) + extent_t *a, extent_t *b, extent_heap_t extent_heaps[NPSIZES], bool cache) { rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; @@ -613,8 +634,8 @@ chunk_try_coalesce(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } else b_elm_b = b_elm_a; - extent_tree_szad_remove(chunks_szad, a); - extent_tree_szad_remove(chunks_szad, b); + extent_heaps_remove(extent_heaps, a); + extent_heaps_remove(extent_heaps, b); arena_chunk_cache_maybe_remove(extent_arena_get(a), a, cache); arena_chunk_cache_maybe_remove(extent_arena_get(b), b, cache); @@ -622,7 +643,7 @@ chunk_try_coalesce(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_size_set(a, extent_size_get(a) + extent_size_get(b)); extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b)); - extent_tree_szad_insert(chunks_szad, a); + extent_heaps_insert(extent_heaps, a); extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a); extent_rtree_release(tsdn, a_elm_a, b_elm_b); @@ -634,7 +655,7 @@ chunk_try_coalesce(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, static void chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - extent_tree_t *chunks_szad, bool cache, void *chunk, size_t size, + extent_heap_t extent_heaps[NPSIZES], bool cache, void *chunk, size_t size, bool zeroed, bool committed) { extent_t *extent, *prev, *next; @@ -657,7 +678,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunk_leak(tsdn, arena, chunk_hooks, cache, chunk, size); goto label_return; } - extent_tree_szad_insert(chunks_szad, extent); + extent_heaps_insert(extent_heaps, extent); arena_chunk_cache_maybe_insert(arena, extent, cache); /* Try to coalesce forward. */ @@ -665,7 +686,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, CHUNK_CEILING((uintptr_t)extent_past_get(extent)), false); if (next != NULL) { chunk_try_coalesce(tsdn, arena, chunk_hooks, extent, next, - chunks_szad, cache); + extent_heaps, cache); } /* Try to coalesce backward. */ @@ -673,7 +694,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, (uintptr_t)extent_addr_get(extent) - chunksize, false); if (prev != NULL) { chunk_try_coalesce(tsdn, arena, chunk_hooks, prev, extent, - chunks_szad, cache); + extent_heaps, cache); } label_return: @@ -690,7 +711,7 @@ chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert(size != 0); assert((size & chunksize_mask) == 0); - chunk_record(tsdn, arena, chunk_hooks, &arena->chunks_szad_cached, true, + chunk_record(tsdn, arena, chunk_hooks, arena->chunks_cached, true, chunk, size, false, committed); arena_maybe_purge(tsdn, arena); } @@ -726,8 +747,8 @@ chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } zeroed = !committed || !chunk_hooks->purge(chunk, size, 0, size, arena->ind); - chunk_record(tsdn, arena, chunk_hooks, &arena->chunks_szad_retained, - false, chunk, size, zeroed, committed); + chunk_record(tsdn, arena, chunk_hooks, arena->chunks_retained, false, + chunk, size, zeroed, committed); if (config_stats) arena->stats.retained += size; diff --git a/src/extent.c b/src/extent.c index c550e6cb..4757f750 100644 --- a/src/extent.c +++ b/src/extent.c @@ -3,39 +3,86 @@ /******************************************************************************/ -JEMALLOC_INLINE_C size_t -extent_quantize(size_t size) +#ifdef JEMALLOC_JET +#undef extent_size_quantize_floor +#define extent_size_quantize_floor JEMALLOC_N(n_extent_size_quantize_floor) +#endif +size_t +extent_size_quantize_floor(size_t size) { + size_t ret; + pszind_t pind; - /* - * Round down to the nearest chunk size that can actually be requested - * during normal huge allocation. - */ - return (index2size(size2index(size + 1) - 1)); + assert(size > 0); + assert(size <= HUGE_MAXCLASS); + assert((size & PAGE_MASK) == 0); + + assert(size != 0); + assert(size == PAGE_CEILING(size)); + + pind = psz2ind(size - large_pad + 1); + if (pind == 0) { + /* + * Avoid underflow. This short-circuit would also do the right + * thing for all sizes in the range for which there are + * PAGE-spaced size classes, but it's simplest to just handle + * the one case that would cause erroneous results. + */ + return (size); + } + ret = pind2sz(pind - 1) + large_pad; + assert(ret <= size); + return (ret); } +#ifdef JEMALLOC_JET +#undef extent_size_quantize_floor +#define extent_size_quantize_floor JEMALLOC_N(extent_size_quantize_floor) +extent_size_quantize_t *extent_size_quantize_floor = + JEMALLOC_N(n_extent_size_quantize_floor); +#endif -JEMALLOC_INLINE_C int -extent_szad_comp(const extent_t *a, const extent_t *b) +#ifdef JEMALLOC_JET +#undef extent_size_quantize_ceil +#define extent_size_quantize_ceil JEMALLOC_N(n_extent_size_quantize_ceil) +#endif +size_t +extent_size_quantize_ceil(size_t size) { - int ret; - size_t a_qsize = extent_quantize(extent_size_get(a)); - size_t b_qsize = extent_quantize(extent_size_get(b)); - - /* - * Compare based on quantized size rather than size, in order to sort - * equally useful extents only by address. - */ - ret = (a_qsize > b_qsize) - (a_qsize < b_qsize); - if (ret == 0) { - uintptr_t a_addr = (uintptr_t)extent_addr_get(a); - uintptr_t b_addr = (uintptr_t)extent_addr_get(b); - - ret = (a_addr > b_addr) - (a_addr < b_addr); - } + size_t ret; + + assert(size > 0); + assert(size <= HUGE_MAXCLASS); + assert((size & PAGE_MASK) == 0); + ret = extent_size_quantize_floor(size); + if (ret < size) { + /* + * Skip a quantization that may have an adequately large extent, + * because under-sized extents may be mixed in. This only + * happens when an unusual size is requested, i.e. for aligned + * allocation, and is just one of several places where linear + * search would potentially find sufficiently aligned available + * memory somewhere lower. + */ + ret = pind2sz(psz2ind(ret - large_pad + 1)) + large_pad; + } return (ret); } +#ifdef JEMALLOC_JET +#undef extent_size_quantize_ceil +#define extent_size_quantize_ceil JEMALLOC_N(extent_size_quantize_ceil) +extent_size_quantize_t *extent_size_quantize_ceil = + JEMALLOC_N(n_extent_size_quantize_ceil); +#endif + +JEMALLOC_INLINE_C int +extent_ad_comp(const extent_t *a, const extent_t *b) +{ + uintptr_t a_addr = (uintptr_t)extent_addr_get(a); + uintptr_t b_addr = (uintptr_t)extent_addr_get(b); + + return ((a_addr > b_addr) - (a_addr < b_addr)); +} -/* Generate red-black tree functions. */ -rb_gen(, extent_tree_szad_, extent_tree_t, extent_t, szad_link, - extent_szad_comp) +/* Generate pairing heap functions. */ +ph_gen(, extent_heap_, extent_heap_t, extent_t, ph_link, extent_ad_comp) diff --git a/test/unit/extent_quantize.c b/test/unit/extent_quantize.c new file mode 100644 index 00000000..d8846db4 --- /dev/null +++ b/test/unit/extent_quantize.c @@ -0,0 +1,155 @@ +#include "test/jemalloc_test.h" + +TEST_BEGIN(test_small_extent_size) +{ + unsigned nbins, i; + size_t sz, extent_size; + size_t mib[4]; + size_t miblen = sizeof(mib) / sizeof(size_t); + + /* + * Iterate over all small size classes, get their extent sizes, and + * verify that the quantized size is the same as the extent size. + */ + + sz = sizeof(unsigned); + assert_d_eq(mallctl("arenas.nbins", &nbins, &sz, NULL, 0), 0, + "Unexpected mallctl failure"); + + assert_d_eq(mallctlnametomib("arenas.bin.0.run_size", mib, &miblen), 0, + "Unexpected mallctlnametomib failure"); + for (i = 0; i < nbins; i++) { + mib[2] = i; + sz = sizeof(size_t); + assert_d_eq(mallctlbymib(mib, miblen, &extent_size, &sz, NULL, + 0), 0, "Unexpected mallctlbymib failure"); + assert_zu_eq(extent_size, + extent_size_quantize_floor(extent_size), + "Small extent quantization should be a no-op " + "(extent_size=%zu)", extent_size); + assert_zu_eq(extent_size, + extent_size_quantize_ceil(extent_size), + "Small extent quantization should be a no-op " + "(extent_size=%zu)", extent_size); + } +} +TEST_END + +TEST_BEGIN(test_large_extent_size) +{ + bool cache_oblivious; + unsigned nlruns, i; + size_t sz, extent_size_prev, ceil_prev; + size_t mib[4]; + size_t miblen = sizeof(mib) / sizeof(size_t); + + /* + * Iterate over all large size classes, get their extent sizes, and + * verify that the quantized size is the same as the extent size. + */ + + sz = sizeof(bool); + assert_d_eq(mallctl("config.cache_oblivious", &cache_oblivious, &sz, + NULL, 0), 0, "Unexpected mallctl failure"); + + sz = sizeof(unsigned); + assert_d_eq(mallctl("arenas.nlruns", &nlruns, &sz, NULL, 0), 0, + "Unexpected mallctl failure"); + + assert_d_eq(mallctlnametomib("arenas.lrun.0.size", mib, &miblen), 0, + "Unexpected mallctlnametomib failure"); + for (i = 0; i < nlruns; i++) { + size_t lextent_size, extent_size, floor, ceil; + + mib[2] = i; + sz = sizeof(size_t); + assert_d_eq(mallctlbymib(mib, miblen, &lextent_size, &sz, NULL, + 0), 0, "Unexpected mallctlbymib failure"); + extent_size = cache_oblivious ? lextent_size + PAGE : + lextent_size; + floor = extent_size_quantize_floor(extent_size); + ceil = extent_size_quantize_ceil(extent_size); + + assert_zu_eq(extent_size, floor, + "Large run quantization should be a no-op for precise " + "size (lextent_size=%zu, extent_size=%zu)", lextent_size, + extent_size); + assert_zu_eq(extent_size, ceil, + "Large run quantization should be a no-op for precise " + "size (lextent_size=%zu, extent_size=%zu)", lextent_size, + extent_size); + + if (i > 0) { + assert_zu_eq(extent_size_prev, + extent_size_quantize_floor(extent_size - PAGE), + "Floor should be a precise size"); + if (extent_size_prev < ceil_prev) { + assert_zu_eq(ceil_prev, extent_size, + "Ceiling should be a precise size " + "(extent_size_prev=%zu, ceil_prev=%zu, " + "extent_size=%zu)", extent_size_prev, + ceil_prev, extent_size); + } + } + extent_size_prev = floor; + ceil_prev = extent_size_quantize_ceil(extent_size + PAGE); + } +} +TEST_END + +TEST_BEGIN(test_monotonic) +{ + unsigned nbins, nlruns, i; + size_t sz, floor_prev, ceil_prev; + + /* + * Iterate over all extent sizes and verify that + * extent_size_quantize_{floor,ceil}() are monotonic. + */ + + sz = sizeof(unsigned); + assert_d_eq(mallctl("arenas.nbins", &nbins, &sz, NULL, 0), 0, + "Unexpected mallctl failure"); + + sz = sizeof(unsigned); + assert_d_eq(mallctl("arenas.nlruns", &nlruns, &sz, NULL, 0), 0, + "Unexpected mallctl failure"); + + floor_prev = 0; + ceil_prev = 0; + for (i = 1; i <= large_maxclass >> LG_PAGE; i++) { + size_t extent_size, floor, ceil; + + extent_size = i << LG_PAGE; + floor = extent_size_quantize_floor(extent_size); + ceil = extent_size_quantize_ceil(extent_size); + + assert_zu_le(floor, extent_size, + "Floor should be <= (floor=%zu, extent_size=%zu, ceil=%zu)", + floor, extent_size, ceil); + assert_zu_ge(ceil, extent_size, + "Ceiling should be >= (floor=%zu, extent_size=%zu, " + "ceil=%zu)", floor, extent_size, ceil); + + assert_zu_le(floor_prev, floor, "Floor should be monotonic " + "(floor_prev=%zu, floor=%zu, extent_size=%zu, ceil=%zu)", + floor_prev, floor, extent_size, ceil); + assert_zu_le(ceil_prev, ceil, "Ceiling should be monotonic " + "(floor=%zu, extent_size=%zu, ceil_prev=%zu, ceil=%zu)", + floor, extent_size, ceil_prev, ceil); + + floor_prev = floor; + ceil_prev = ceil; + } +} +TEST_END + +int +main(void) +{ + + return (test( + test_small_extent_size, + test_large_extent_size, + test_monotonic)); +} -- GitLab From 4d2d9cec5a82c80e0cabb1c4fc0473aca0cc5a09 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 17 May 2016 17:43:30 -0700 Subject: [PATCH 027/544] Merge chunk_alloc_base() into its only caller. --- include/jemalloc/internal/chunk.h | 1 - include/jemalloc/internal/private_symbols.txt | 1 - src/base.c | 10 +++++++++- src/chunk.c | 20 ------------------- 4 files changed, 9 insertions(+), 23 deletions(-) diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index 05cf3d05..ab102d2c 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -55,7 +55,6 @@ chunk_hooks_t chunk_hooks_set(tsdn_t *tsdn, arena_t *arena, bool chunk_register(tsdn_t *tsdn, const extent_t *extent); void chunk_deregister(tsdn_t *tsdn, const extent_t *extent); void chunk_reregister(tsdn_t *tsdn, const extent_t *extent); -void *chunk_alloc_base(size_t size); void *chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, bool *zero, bool dalloc_extent); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index b3d18600..c237ab33 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -154,7 +154,6 @@ bootstrap_free bootstrap_malloc bt_init buferror -chunk_alloc_base chunk_alloc_cache chunk_alloc_dss chunk_alloc_mmap diff --git a/src/base.c b/src/base.c index 8816738c..518f966c 100644 --- a/src/base.c +++ b/src/base.c @@ -50,7 +50,15 @@ base_chunk_alloc(tsdn_t *tsdn, size_t minsize) /* Allocate enough space to also carve an extent out if necessary. */ nsize = (extent == NULL) ? CACHELINE_CEILING(sizeof(extent_t)) : 0; csize = CHUNK_CEILING(minsize + nsize); - addr = chunk_alloc_base(csize); + /* + * Directly call chunk_alloc_mmap() because it's critical to allocate + * untouched demand-zeroed virtual memory. + */ + { + bool zero = true; + bool commit = true; + addr = chunk_alloc_mmap(NULL, csize, chunksize, &zero, &commit); + } if (addr == NULL) { if (extent != NULL) base_extent_dalloc(tsdn, extent); diff --git a/src/chunk.c b/src/chunk.c index 2463028b..a32eede9 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -469,26 +469,6 @@ chunk_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, return (NULL); } -void * -chunk_alloc_base(size_t size) -{ - void *ret; - bool zero, commit; - - /* - * Directly call chunk_alloc_mmap() rather than chunk_alloc_core() - * because it's critical that chunk_alloc_base() return untouched - * demand-zeroed virtual memory. - */ - zero = true; - commit = true; - ret = chunk_alloc_mmap(NULL, size, chunksize, &zero, &commit); - if (ret == NULL) - return (NULL); - - return (ret); -} - void * chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, bool *zero, -- GitLab From 56e0031d7d0c69c54de4bae1ca3a2fd2823f69ff Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 17 May 2016 18:17:04 -0700 Subject: [PATCH 028/544] Add/use chunk_decommit_wrapper(). --- include/jemalloc/internal/chunk.h | 3 +++ include/jemalloc/internal/private_symbols.txt | 1 + src/arena.c | 14 +++++++------- src/chunk.c | 9 +++++++++ 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index ab102d2c..8cd992d1 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -66,6 +66,9 @@ void chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, void chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool zeroed, bool committed); +bool chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, + chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t offset, + size_t length); bool chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t offset, size_t length); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index c237ab33..5261e02c 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -162,6 +162,7 @@ chunk_boot chunk_dalloc_cache chunk_dalloc_mmap chunk_dalloc_wrapper +chunk_decommit_wrapper chunk_deregister chunk_dss_boot chunk_dss_postfork_child diff --git a/src/arena.c b/src/arena.c index 720219d3..ee651947 100644 --- a/src/arena.c +++ b/src/arena.c @@ -552,8 +552,8 @@ arena_chunk_alloc_internal_hard(tsdn_t *tsdn, arena_t *arena, if (chunk != NULL && arena_chunk_register(tsdn, arena, chunk, *zero)) { if (!*commit) { /* Undo commit of header. */ - chunk_hooks->decommit(chunk, chunksize, 0, map_bias << - LG_PAGE, arena->ind); + chunk_decommit_wrapper(tsdn, arena, chunk_hooks, + chunk, chunksize, 0, map_bias << LG_PAGE); } chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, (void *)chunk, chunksize, *zero, *commit); @@ -675,9 +675,8 @@ arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk) * chunk as committed has a high potential for causing later * access of decommitted memory. */ - chunk_hooks = chunk_hooks_get(tsdn, arena); - chunk_hooks.decommit(chunk, chunksize, 0, map_bias << LG_PAGE, - arena->ind); + chunk_decommit_wrapper(tsdn, arena, &chunk_hooks, chunk, + chunksize, 0, map_bias << LG_PAGE); } chunk_dalloc_cache(tsdn, arena, &chunk_hooks, (void *)chunk, chunksize, @@ -1603,8 +1602,9 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert(!arena_mapbits_decommitted_get(chunk, pageind)); assert(!arena_mapbits_decommitted_get(chunk, pageind+npages-1)); - decommitted = !chunk_hooks->decommit(chunk, chunksize, - pageind << LG_PAGE, npages << LG_PAGE, arena->ind); + decommitted = !chunk_decommit_wrapper(tsdn, arena, + chunk_hooks, chunk, chunksize, pageind << LG_PAGE, + npages << LG_PAGE); if (decommitted) { flag_unzeroed = 0; flags = CHUNK_MAP_DECOMMITTED; diff --git a/src/chunk.c b/src/chunk.c index a32eede9..0d942d66 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -752,6 +752,15 @@ chunk_decommit_default(void *chunk, size_t size, size_t offset, size_t length, length)); } +bool +chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, + void *chunk, size_t size, size_t offset, size_t length) +{ + + chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); + return (chunk_hooks->decommit(chunk, size, offset, length, arena->ind)); +} + static bool chunk_purge_default(void *chunk, size_t size, size_t offset, size_t length, unsigned arena_ind) -- GitLab From 384e88f4518512bd2e727cfd6b73395635bbce50 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 17 May 2016 18:29:08 -0700 Subject: [PATCH 029/544] Add/use chunk_commit_wrapper(). --- include/jemalloc/internal/chunk.h | 3 + include/jemalloc/internal/private_symbols.txt | 1 + src/arena.c | 61 ++++++++++--------- src/chunk.c | 9 +++ 4 files changed, 44 insertions(+), 30 deletions(-) diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index 8cd992d1..52a6d565 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -66,6 +66,9 @@ void chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, void chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool zeroed, bool committed); +bool chunk_commit_wrapper(tsdn_t *tsdn, arena_t *arena, + chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t offset, + size_t length); bool chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t offset, size_t length); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 5261e02c..bd18e76b 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -159,6 +159,7 @@ chunk_alloc_dss chunk_alloc_mmap chunk_alloc_wrapper chunk_boot +chunk_commit_wrapper chunk_dalloc_cache chunk_dalloc_mmap chunk_dalloc_wrapper diff --git a/src/arena.c b/src/arena.c index ee651947..5ea3fc85 100644 --- a/src/arena.c +++ b/src/arena.c @@ -375,8 +375,8 @@ arena_run_split_remove(arena_t *arena, arena_chunk_t *chunk, size_t run_ind, } static bool -arena_run_split_large_helper(arena_t *arena, extent_t *extent, arena_run_t *run, - size_t size, bool remove, bool zero) +arena_run_split_large_helper(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + arena_run_t *run, size_t size, bool remove, bool zero) { arena_chunk_t *chunk; arena_chunk_map_misc_t *miscelm; @@ -391,8 +391,8 @@ arena_run_split_large_helper(arena_t *arena, extent_t *extent, arena_run_t *run, need_pages = (size >> LG_PAGE); assert(need_pages > 0); - if (flag_decommitted != 0 && arena->chunk_hooks.commit(chunk, chunksize, - run_ind << LG_PAGE, size, arena->ind)) + if (flag_decommitted != 0 && chunk_commit_wrapper(tsdn, arena, + &arena->chunk_hooks, chunk, chunksize, run_ind << LG_PAGE, size)) return (true); if (remove) { @@ -439,26 +439,26 @@ arena_run_split_large_helper(arena_t *arena, extent_t *extent, arena_run_t *run, } static bool -arena_run_split_large(arena_t *arena, extent_t *extent, arena_run_t *run, - size_t size, bool zero) +arena_run_split_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + arena_run_t *run, size_t size, bool zero) { - return (arena_run_split_large_helper(arena, extent, run, size, true, - zero)); + return (arena_run_split_large_helper(tsdn, arena, extent, run, size, + true, zero)); } static bool -arena_run_init_large(arena_t *arena, extent_t *extent, arena_run_t *run, - size_t size, bool zero) +arena_run_init_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + arena_run_t *run, size_t size, bool zero) { - return (arena_run_split_large_helper(arena, extent, run, size, false, - zero)); + return (arena_run_split_large_helper(tsdn, arena, extent, run, size, + false, zero)); } static bool -arena_run_split_small(arena_t *arena, extent_t *extent, arena_run_t *run, - size_t size, szind_t binind) +arena_run_split_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + arena_run_t *run, size_t size, szind_t binind) { arena_chunk_t *chunk; arena_chunk_map_misc_t *miscelm; @@ -474,8 +474,8 @@ arena_run_split_small(arena_t *arena, extent_t *extent, arena_run_t *run, need_pages = (size >> LG_PAGE); assert(need_pages > 0); - if (flag_decommitted != 0 && arena->chunk_hooks.commit(chunk, chunksize, - run_ind << LG_PAGE, size, arena->ind)) + if (flag_decommitted != 0 && chunk_commit_wrapper(tsdn, arena, + &arena->chunk_hooks, chunk, chunksize, run_ind << LG_PAGE, size)) return (true); arena_run_split_remove(arena, chunk, run_ind, flag_dirty, @@ -542,8 +542,8 @@ arena_chunk_alloc_internal_hard(tsdn_t *tsdn, arena_t *arena, NULL, chunksize, chunksize, zero, commit); if (chunk != NULL && !*commit) { /* Commit header. */ - if (chunk_hooks->commit(chunk, chunksize, 0, map_bias << - LG_PAGE, arena->ind)) { + if (chunk_commit_wrapper(tsdn, arena, chunk_hooks, chunk, + chunksize, 0, map_bias << LG_PAGE)) { chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, (void *)chunk, chunksize, *zero, *commit); chunk = NULL; @@ -1041,8 +1041,8 @@ arena_run_alloc_large_helper(tsdn_t *tsdn, arena_t *arena, size_t size, { arena_run_t *run = arena_run_first_best_fit(arena, s2u(size)); if (run != NULL) { - if (arena_run_split_large(arena, iealloc(tsdn, run), run, size, - zero)) + if (arena_run_split_large(tsdn, arena, iealloc(tsdn, run), run, + size, zero)) run = NULL; } return (run); @@ -1068,8 +1068,8 @@ arena_run_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t size, bool zero) chunk = arena_chunk_alloc(tsdn, arena); if (chunk != NULL) { run = &arena_miscelm_get_mutable(chunk, map_bias)->run; - if (arena_run_split_large(arena, iealloc(tsdn, run), run, size, - zero)) + if (arena_run_split_large(tsdn, arena, iealloc(tsdn, run), run, + size, zero)) run = NULL; return (run); } @@ -1088,8 +1088,8 @@ arena_run_alloc_small_helper(tsdn_t *tsdn, arena_t *arena, size_t size, { arena_run_t *run = arena_run_first_best_fit(arena, size); if (run != NULL) { - if (arena_run_split_small(arena, iealloc(tsdn, run), run, size, - binind)) + if (arena_run_split_small(tsdn, arena, iealloc(tsdn, run), run, + size, binind)) run = NULL; } return (run); @@ -1116,8 +1116,8 @@ arena_run_alloc_small(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t binind) chunk = arena_chunk_alloc(tsdn, arena); if (chunk != NULL) { run = &arena_miscelm_get_mutable(chunk, map_bias)->run; - if (arena_run_split_small(arena, iealloc(tsdn, run), run, size, - binind)) + if (arena_run_split_small(tsdn, arena, iealloc(tsdn, run), run, + size, binind)) run = NULL; return (run); } @@ -1534,8 +1534,8 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, arena_chunk_alloc(tsdn, arena); /* Temporarily allocate the free dirty run. */ - arena_run_split_large(arena, extent, run, run_size, - false); + arena_run_split_large(tsdn, arena, extent, run, + run_size, false); /* Stash. */ if (false) qr_new(rdelm, rd_link); /* Redundant. */ @@ -2569,7 +2569,8 @@ arena_palloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, arena_run_trim_tail(tsdn, arena, chunk, extent, run, usize + large_pad + trailsize, usize + large_pad, false); } - if (arena_run_init_large(arena, extent, run, usize + large_pad, zero)) { + if (arena_run_init_large(tsdn, arena, extent, run, usize + large_pad, + zero)) { size_t run_ind = arena_miscelm_to_pageind(arena_run_to_miscelm(run)); bool dirty = (arena_mapbits_dirty_get(chunk, run_ind) != 0); @@ -2944,7 +2945,7 @@ arena_ralloc_large_grow(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, goto label_fail; run = &arena_miscelm_get_mutable(chunk, pageind+npages)->run; - if (arena_run_split_large(arena, iealloc(tsdn, run), run, + if (arena_run_split_large(tsdn, arena, iealloc(tsdn, run), run, splitsize, zero)) goto label_fail; diff --git a/src/chunk.c b/src/chunk.c index 0d942d66..f8d9e634 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -743,6 +743,15 @@ chunk_commit_default(void *chunk, size_t size, size_t offset, size_t length, length)); } +bool +chunk_commit_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, + void *chunk, size_t size, size_t offset, size_t length) +{ + + chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); + return (chunk_hooks->commit(chunk, size, offset, length, arena->ind)); +} + static bool chunk_decommit_default(void *chunk, size_t size, size_t offset, size_t length, unsigned arena_ind) -- GitLab From 1ad060584f8ae4e0b9bc30c89ad7c1860ac3d89d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 18 May 2016 10:32:05 -0700 Subject: [PATCH 030/544] Add/use chunk_merge_wrapper(). --- include/jemalloc/internal/arena.h | 2 +- include/jemalloc/internal/chunk.h | 2 + include/jemalloc/internal/private_symbols.txt | 1 + src/arena.c | 90 ++++++++++--------- src/chunk.c | 79 +++++++++------- src/huge.c | 20 +---- 6 files changed, 101 insertions(+), 93 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index b6bfb25c..68d1015b 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -496,7 +496,7 @@ void arena_chunk_ralloc_huge_similar(tsdn_t *tsdn, arena_t *arena, void arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, void *chunk, size_t oldsize, size_t usize); bool arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, - void *chunk, size_t oldsize, size_t usize, bool *zero); + extent_t *extent, size_t usize); ssize_t arena_lg_dirty_mult_get(tsdn_t *tsdn, arena_t *arena); bool arena_lg_dirty_mult_set(tsdn_t *tsdn, arena_t *arena, ssize_t lg_dirty_mult); diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index 52a6d565..9634975f 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -75,6 +75,8 @@ bool chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, bool chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t offset, size_t length); +bool chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, + chunk_hooks_t *chunk_hooks, extent_t *a, extent_t *b); bool chunk_boot(void); void chunk_prefork(tsdn_t *tsdn); void chunk_postfork_parent(tsdn_t *tsdn); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index bd18e76b..9b507b1a 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -176,6 +176,7 @@ chunk_hooks_get chunk_hooks_set chunk_in_dss chunk_lookup +chunk_merge_wrapper chunk_npages chunk_postfork_child chunk_postfork_parent diff --git a/src/arena.c b/src/arena.c index 5ea3fc85..2b92733b 100644 --- a/src/arena.c +++ b/src/arena.c @@ -948,69 +948,71 @@ arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, void *chunk, malloc_mutex_unlock(tsdn, &arena->lock); } -static bool -arena_chunk_ralloc_huge_expand_hard(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *chunk, size_t oldsize, size_t usize, - bool *zero, void *nchunk, size_t udiff, size_t cdiff) -{ - bool err; - bool commit = true; - - err = (chunk_alloc_wrapper(tsdn, arena, chunk_hooks, nchunk, cdiff, - chunksize, zero, &commit) == NULL); - if (err) { - /* Revert optimistic stats updates. */ - malloc_mutex_lock(tsdn, &arena->lock); - if (config_stats) { - arena_huge_ralloc_stats_update_undo(arena, oldsize, - usize); - arena->stats.mapped -= cdiff; - } - arena_nactive_sub(arena, udiff >> LG_PAGE); - malloc_mutex_unlock(tsdn, &arena->lock); - } else if (chunk_hooks->merge(chunk, CHUNK_CEILING(oldsize), nchunk, - cdiff, true, arena->ind)) { - chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, nchunk, cdiff, - *zero, true); - err = true; - } - return (err); -} - bool -arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, void *chunk, - size_t oldsize, size_t usize, bool *zero) +arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + size_t usize) { bool err; + bool zero = false; chunk_hooks_t chunk_hooks = chunk_hooks_get(tsdn, arena); - void *nchunk = (void *)((uintptr_t)chunk + CHUNK_CEILING(oldsize)); - size_t udiff = usize - oldsize; - size_t cdiff = CHUNK_CEILING(usize) - CHUNK_CEILING(oldsize); + void *nchunk = + (void *)CHUNK_CEILING((uintptr_t)extent_past_get(extent)); + size_t udiff = usize - extent_size_get(extent); + size_t cdiff = CHUNK_CEILING(usize) - + CHUNK_CEILING(extent_size_get(extent)); + extent_t *trail; malloc_mutex_lock(tsdn, &arena->lock); /* Optimistically update stats. */ if (config_stats) { - arena_huge_ralloc_stats_update(arena, oldsize, usize); + arena_huge_ralloc_stats_update(arena, extent_size_get(extent), + usize); arena->stats.mapped += cdiff; } arena_nactive_add(arena, udiff >> LG_PAGE); err = (chunk_alloc_cache(tsdn, arena, &chunk_hooks, nchunk, cdiff, - chunksize, zero, true) == NULL); + chunksize, &zero, true) == NULL); malloc_mutex_unlock(tsdn, &arena->lock); + if (err) { - err = arena_chunk_ralloc_huge_expand_hard(tsdn, arena, - &chunk_hooks, chunk, oldsize, usize, zero, nchunk, udiff, - cdiff); - } else if (chunk_hooks.merge(chunk, CHUNK_CEILING(oldsize), nchunk, - cdiff, true, arena->ind)) { + bool commit = true; + + if (chunk_alloc_wrapper(tsdn, arena, &chunk_hooks, nchunk, + cdiff, chunksize, &zero, &commit) == NULL) + goto label_revert; + } + + trail = arena_extent_alloc(tsdn, arena); + if (trail == NULL) { + chunk_dalloc_wrapper(tsdn, arena, &chunk_hooks, nchunk, cdiff, + zero, true); + goto label_revert; + } + extent_init(trail, arena, nchunk, cdiff, true, zero, true, false); + if (chunk_merge_wrapper(tsdn, arena, &chunk_hooks, extent, trail)) { + arena_extent_dalloc(tsdn, arena, trail); chunk_dalloc_wrapper(tsdn, arena, &chunk_hooks, nchunk, cdiff, - *zero, true); - err = true; + zero, true); + goto label_revert; } - return (err); + if (usize < extent_size_get(extent)) + extent_size_set(extent, usize); + + return (false); +label_revert: + /* Revert optimistic stats updates. */ + malloc_mutex_lock(tsdn, &arena->lock); + if (config_stats) { + arena_huge_ralloc_stats_update_undo(arena, + extent_size_get(extent), usize); + arena->stats.mapped -= cdiff; + } + arena_nactive_sub(arena, udiff >> LG_PAGE); + malloc_mutex_unlock(tsdn, &arena->lock); + return (true); } /* diff --git a/src/chunk.c b/src/chunk.c index f8d9e634..59ebd291 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -586,51 +586,26 @@ static void chunk_try_coalesce(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *a, extent_t *b, extent_heap_t extent_heaps[NPSIZES], bool cache) { - rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; if (!chunk_can_coalesce(a, b)) return; - if (chunk_hooks->merge(extent_addr_get(a), extent_size_get(a), - extent_addr_get(b), extent_size_get(b), extent_committed_get(a), - arena->ind)) - return; - - /* - * The rtree writes must happen while all the relevant elements are - * owned, so the following code uses decomposed helper functions rather - * than chunk_{,de}register() to do things in the right order. - */ - extent_rtree_acquire(tsdn, a, true, false, &a_elm_a, &a_elm_b); - extent_rtree_acquire(tsdn, b, true, false, &b_elm_a, &b_elm_b); - - if (a_elm_b != NULL) { - rtree_elm_write_acquired(tsdn, &chunks_rtree, a_elm_b, NULL); - rtree_elm_release(tsdn, &chunks_rtree, a_elm_b); - } - if (b_elm_b != NULL) { - rtree_elm_write_acquired(tsdn, &chunks_rtree, b_elm_a, NULL); - rtree_elm_release(tsdn, &chunks_rtree, b_elm_a); - } else - b_elm_b = b_elm_a; - extent_heaps_remove(extent_heaps, a); extent_heaps_remove(extent_heaps, b); arena_chunk_cache_maybe_remove(extent_arena_get(a), a, cache); arena_chunk_cache_maybe_remove(extent_arena_get(b), b, cache); - extent_size_set(a, extent_size_get(a) + extent_size_get(b)); - extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b)); + if (chunk_merge_wrapper(tsdn, arena, chunk_hooks, a, b)) { + extent_heaps_insert(extent_heaps, a); + extent_heaps_insert(extent_heaps, b); + arena_chunk_cache_maybe_insert(extent_arena_get(a), a, cache); + arena_chunk_cache_maybe_insert(extent_arena_get(b), b, cache); + return; + } extent_heaps_insert(extent_heaps, a); - - extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a); - extent_rtree_release(tsdn, a_elm_a, b_elm_b); - arena_chunk_cache_maybe_insert(extent_arena_get(a), a, cache); - - arena_extent_dalloc(tsdn, extent_arena_get(b), b); } static void @@ -820,6 +795,46 @@ chunk_merge_default(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b, return (false); } +bool +chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, + extent_t *a, extent_t *b) +{ + rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; + + if (chunk_hooks->merge(extent_addr_get(a), extent_size_get(a), + extent_addr_get(b), extent_size_get(b), extent_committed_get(a), + arena->ind)) + return (true); + + /* + * The rtree writes must happen while all the relevant elements are + * owned, so the following code uses decomposed helper functions rather + * than chunk_{,de}register() to do things in the right order. + */ + extent_rtree_acquire(tsdn, a, true, false, &a_elm_a, &a_elm_b); + extent_rtree_acquire(tsdn, b, true, false, &b_elm_a, &b_elm_b); + + if (a_elm_b != NULL) { + rtree_elm_write_acquired(tsdn, &chunks_rtree, a_elm_b, NULL); + rtree_elm_release(tsdn, &chunks_rtree, a_elm_b); + } + if (b_elm_b != NULL) { + rtree_elm_write_acquired(tsdn, &chunks_rtree, b_elm_a, NULL); + rtree_elm_release(tsdn, &chunks_rtree, b_elm_a); + } else + b_elm_b = b_elm_a; + + extent_size_set(a, extent_size_get(a) + extent_size_get(b)); + extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b)); + + extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a); + extent_rtree_release(tsdn, a_elm_a, b_elm_b); + + arena_extent_dalloc(tsdn, extent_arena_get(b), b); + + return (false); +} + bool chunk_boot(void) { diff --git a/src/huge.c b/src/huge.c index 48b191ad..dc0d680e 100644 --- a/src/huge.c +++ b/src/huge.c @@ -215,31 +215,19 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t usize, bool zero) { arena_t *arena; - bool is_zeroed_subchunk, is_zeroed_chunk; + bool is_zeroed_subchunk; arena = extent_arena_get(extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); is_zeroed_subchunk = extent_zeroed_get(extent); malloc_mutex_unlock(tsdn, &arena->huge_mtx); - /* - * Use is_zeroed_chunk to detect whether the trailing memory is zeroed, - * update extent's zeroed field, and zero as necessary. - */ - is_zeroed_chunk = false; - if (arena_chunk_ralloc_huge_expand(tsdn, arena, ptr, oldsize, usize, - &is_zeroed_chunk)) + if (arena_chunk_ralloc_huge_expand(tsdn, arena, extent, usize)) return (true); - /* Update the size of the huge allocation. */ - chunk_deregister(tsdn, extent); - malloc_mutex_lock(tsdn, &arena->huge_mtx); - extent_size_set(extent, usize); - extent_zeroed_set(extent, extent_zeroed_get(extent) && is_zeroed_chunk); - malloc_mutex_unlock(tsdn, &arena->huge_mtx); - chunk_reregister(tsdn, extent); - if (zero || (config_fill && unlikely(opt_zero))) { + bool is_zeroed_chunk = extent_zeroed_get(extent); + if (!is_zeroed_subchunk) { memset((void *)((uintptr_t)ptr + oldsize), 0, CHUNK_CEILING(oldsize) - oldsize); -- GitLab From de0305a7f3e443d48e012272e1b91c44d2b129d2 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 18 May 2016 21:02:46 -0700 Subject: [PATCH 031/544] Add/use chunk_split_wrapper(). Remove redundant ptr/oldsize args from huge_*(). Refactor huge/chunk/arena code boundaries. --- include/jemalloc/internal/arena.h | 38 +- include/jemalloc/internal/chunk.h | 8 +- include/jemalloc/internal/huge.h | 21 +- include/jemalloc/internal/private_symbols.txt | 3 + src/arena.c | 511 +++++++++--------- src/chunk.c | 241 +++++---- src/huge.c | 260 ++++----- 7 files changed, 563 insertions(+), 519 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 68d1015b..187b6256 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -176,13 +176,6 @@ typedef ph(arena_chunk_map_misc_t) arena_run_heap_t; #ifdef JEMALLOC_ARENA_STRUCTS_B /* Arena chunk header. */ struct arena_chunk_s { - /* - * A pointer to the arena that owns the chunk is stored within the - * extent structure. This field as a whole is used by chunks_rtree to - * support both ivsalloc() and core-based debugging. - */ - extent_t extent; - /* * Map of pages within chunk that keeps track of free/large/small. The * first map_bias entries are omitted, since the chunk header does not @@ -315,7 +308,7 @@ struct arena_s { * order to avoid interactions between multiple threads that could make * a single spare inadequate. */ - arena_chunk_t *spare; + extent_t *spare; /* Minimum ratio (log base 2) of nactive:ndirty. */ ssize_t lg_dirty_mult; @@ -481,22 +474,27 @@ typedef size_t (run_quantize_t)(size_t); extern run_quantize_t *run_quantize_floor; extern run_quantize_t *run_quantize_ceil; #endif +extent_t *arena_chunk_cache_alloc(tsdn_t *tsdn, arena_t *arena, + chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, + bool *zero); +void arena_chunk_cache_dalloc(tsdn_t *tsdn, arena_t *arena, + chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool committed); void arena_chunk_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache); void arena_chunk_cache_maybe_remove(arena_t *arena, extent_t *extent, bool cache); extent_t *arena_extent_alloc(tsdn_t *tsdn, arena_t *arena); void arena_extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent); -void *arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, - size_t alignment, bool *zero); +extent_t *arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, + size_t usize, size_t alignment, bool *zero); void arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, void *chunk, size_t usize); void arena_chunk_ralloc_huge_similar(tsdn_t *tsdn, arena_t *arena, - void *chunk, size_t oldsize, size_t usize); + extent_t *extent, size_t oldsize); void arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, - void *chunk, size_t oldsize, size_t usize); -bool arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, - extent_t *extent, size_t usize); + extent_t *extent, size_t oldsize); +void arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, + extent_t *extent, size_t oldsize); ssize_t arena_lg_dirty_mult_get(tsdn_t *tsdn, arena_t *arena); bool arena_lg_dirty_mult_set(tsdn_t *tsdn, arena_t *arena, ssize_t lg_dirty_mult); @@ -1193,7 +1191,7 @@ arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) ret = atomic_read_p(&elm->prof_tctx_pun); } } else - ret = huge_prof_tctx_get(tsdn, extent, ptr); + ret = huge_prof_tctx_get(tsdn, extent); return (ret); } @@ -1230,7 +1228,7 @@ arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, assert(arena_mapbits_large_get(chunk, pageind) == 0); } } else - huge_prof_tctx_set(tsdn, extent, ptr, tctx); + huge_prof_tctx_set(tsdn, extent, tctx); } JEMALLOC_INLINE void @@ -1258,7 +1256,7 @@ arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, atomic_write_p(&elm->prof_tctx_pun, (prof_tctx_t *)(uintptr_t)1U); } else - huge_prof_tctx_reset(tsdn, extent, ptr); + huge_prof_tctx_reset(tsdn, extent); } } @@ -1362,7 +1360,7 @@ arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr, bool demote) ret = index2size(binind); } } else - ret = huge_salloc(tsdn, extent, ptr); + ret = huge_salloc(tsdn, extent); return (ret); } @@ -1413,7 +1411,7 @@ arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, } } } else - huge_dalloc(tsdn, extent, ptr); + huge_dalloc(tsdn, extent); } JEMALLOC_ALWAYS_INLINE void @@ -1470,7 +1468,7 @@ arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, } } } else - huge_dalloc(tsdn, extent, ptr); + huge_dalloc(tsdn, extent); } # endif /* JEMALLOC_ARENA_INLINE_B */ #endif diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index 9634975f..78cc4c2d 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -55,10 +55,10 @@ chunk_hooks_t chunk_hooks_set(tsdn_t *tsdn, arena_t *arena, bool chunk_register(tsdn_t *tsdn, const extent_t *extent); void chunk_deregister(tsdn_t *tsdn, const extent_t *extent); void chunk_reregister(tsdn_t *tsdn, const extent_t *extent); -void *chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, +extent_t *chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, - bool *zero, bool dalloc_extent); -void *chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, + bool *zero); +extent_t *chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit); void chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, @@ -75,6 +75,8 @@ bool chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, bool chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t offset, size_t length); +extent_t *chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, + chunk_hooks_t *chunk_hooks, extent_t *extent, size_t size_a, size_t size_b); bool chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *a, extent_t *b); bool chunk_boot(void); diff --git a/include/jemalloc/internal/huge.h b/include/jemalloc/internal/huge.h index a385a202..bdc8f847 100644 --- a/include/jemalloc/internal/huge.h +++ b/include/jemalloc/internal/huge.h @@ -12,22 +12,19 @@ void *huge_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero); void *huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero); -bool huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, - size_t oldsize, size_t usize_min, size_t usize_max, bool zero); -void *huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, - size_t oldsize, size_t usize, size_t alignment, bool zero, - tcache_t *tcache); +bool huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, + size_t usize_max, bool zero); +void *huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + size_t usize, size_t alignment, bool zero, tcache_t *tcache); #ifdef JEMALLOC_JET typedef void (huge_dalloc_junk_t)(tsdn_t *, void *, size_t); extern huge_dalloc_junk_t *huge_dalloc_junk; #endif -void huge_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr); -size_t huge_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr); -prof_tctx_t *huge_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, - const void *ptr); -void huge_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, - prof_tctx_t *tctx); -void huge_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr); +void huge_dalloc(tsdn_t *tsdn, extent_t *extent); +size_t huge_salloc(tsdn_t *tsdn, const extent_t *extent); +prof_tctx_t *huge_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent); +void huge_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx); +void huge_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 9b507b1a..34a6816f 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -12,6 +12,8 @@ arena_choose arena_choose_hard arena_choose_impl arena_chunk_alloc_huge +arena_chunk_cache_alloc +arena_chunk_cache_dalloc arena_chunk_cache_maybe_insert arena_chunk_cache_maybe_remove arena_chunk_dalloc_huge @@ -184,6 +186,7 @@ chunk_prefork chunk_purge_wrapper chunk_register chunk_reregister +chunk_split_wrapper chunks_rtree chunksize chunksize_mask diff --git a/src/arena.c b/src/arena.c index 2b92733b..a610ec15 100644 --- a/src/arena.c +++ b/src/arena.c @@ -220,6 +220,55 @@ arena_chunk_dirty_npages(const extent_t *extent) return (extent_size_get(extent) >> LG_PAGE); } +static extent_t * +arena_chunk_cache_alloc_locked(tsdn_t *tsdn, arena_t *arena, + chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, + bool *zero) +{ + + malloc_mutex_assert_owner(tsdn, &arena->lock); + + return (chunk_alloc_cache(tsdn, arena, chunk_hooks, new_addr, size, + alignment, zero)); +} + +extent_t * +arena_chunk_cache_alloc(tsdn_t *tsdn, arena_t *arena, + chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, + bool *zero) +{ + extent_t *extent; + + malloc_mutex_lock(tsdn, &arena->lock); + extent = arena_chunk_cache_alloc_locked(tsdn, arena, chunk_hooks, + new_addr, size, alignment, zero); + malloc_mutex_unlock(tsdn, &arena->lock); + + return (extent); +} + +static void +arena_chunk_cache_dalloc_locked(tsdn_t *tsdn, arena_t *arena, + chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool committed) +{ + + malloc_mutex_assert_owner(tsdn, &arena->lock); + + chunk_dalloc_cache(tsdn, arena, chunk_hooks, chunk, size, committed); + arena_maybe_purge(tsdn, arena); +} + +void +arena_chunk_cache_dalloc(tsdn_t *tsdn, arena_t *arena, + chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool committed) +{ + + malloc_mutex_lock(tsdn, &arena->lock); + arena_chunk_cache_dalloc_locked(tsdn, arena, chunk_hooks, chunk, size, + committed); + malloc_mutex_unlock(tsdn, &arena->lock); +} + void arena_chunk_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache) { @@ -492,112 +541,119 @@ arena_run_split_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, return (false); } -static arena_chunk_t * +static extent_t * arena_chunk_init_spare(arena_t *arena) { - arena_chunk_t *chunk; + extent_t *extent; assert(arena->spare != NULL); - chunk = arena->spare; + extent = arena->spare; arena->spare = NULL; - assert(arena_mapbits_allocated_get(chunk, map_bias) == 0); - assert(arena_mapbits_allocated_get(chunk, chunk_npages-1) == 0); - assert(arena_mapbits_unallocated_size_get(chunk, map_bias) == - arena_maxrun); - assert(arena_mapbits_unallocated_size_get(chunk, chunk_npages-1) == - arena_maxrun); - assert(arena_mapbits_dirty_get(chunk, map_bias) == - arena_mapbits_dirty_get(chunk, chunk_npages-1)); - - return (chunk); -} - -static bool -arena_chunk_register(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - bool zero) -{ + assert(arena_mapbits_allocated_get((arena_chunk_t *) + extent_addr_get(extent), map_bias) == 0); + assert(arena_mapbits_allocated_get((arena_chunk_t *) + extent_addr_get(extent), chunk_npages-1) == 0); + assert(arena_mapbits_unallocated_size_get((arena_chunk_t *) + extent_addr_get(extent), map_bias) == arena_maxrun); + assert(arena_mapbits_unallocated_size_get((arena_chunk_t *) + extent_addr_get(extent), chunk_npages-1) == arena_maxrun); + assert(arena_mapbits_dirty_get((arena_chunk_t *) + extent_addr_get(extent), map_bias) == + arena_mapbits_dirty_get((arena_chunk_t *)extent_addr_get(extent), + chunk_npages-1)); - /* - * The extent notion of "committed" doesn't directly apply to arena - * chunks. Arbitrarily mark them as committed. The commit state of - * runs is tracked individually, and upon chunk deallocation the entire - * chunk is in a consistent commit state. - */ - extent_init(&chunk->extent, arena, chunk, chunksize, true, zero, true, - true); - return (chunk_register(tsdn, &chunk->extent)); + return (extent); } -static arena_chunk_t * +static extent_t * arena_chunk_alloc_internal_hard(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, bool *zero, bool *commit) { - arena_chunk_t *chunk; + extent_t *extent; malloc_mutex_unlock(tsdn, &arena->lock); - chunk = (arena_chunk_t *)chunk_alloc_wrapper(tsdn, arena, chunk_hooks, - NULL, chunksize, chunksize, zero, commit); - if (chunk != NULL && !*commit) { + extent = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, chunksize, + chunksize, zero, commit); + if (extent != NULL && !*commit) { /* Commit header. */ - if (chunk_commit_wrapper(tsdn, arena, chunk_hooks, chunk, - chunksize, 0, map_bias << LG_PAGE)) { + if (chunk_commit_wrapper(tsdn, arena, chunk_hooks, + extent_addr_get(extent), extent_size_get(extent), 0, + map_bias << LG_PAGE)) { chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, - (void *)chunk, chunksize, *zero, *commit); - chunk = NULL; + extent_addr_get(extent), extent_size_get(extent), + extent_zeroed_get(extent), + extent_committed_get(extent)); + extent = NULL; } } - if (chunk != NULL && arena_chunk_register(tsdn, arena, chunk, *zero)) { - if (!*commit) { - /* Undo commit of header. */ - chunk_decommit_wrapper(tsdn, arena, chunk_hooks, - chunk, chunksize, 0, map_bias << LG_PAGE); + + if (extent != NULL) { + extent_slab_set(extent, true); + + if (chunk_register(tsdn, extent)) { + if (!*commit) { + /* Undo commit of header. */ + chunk_decommit_wrapper(tsdn, arena, chunk_hooks, + extent_addr_get(extent), + extent_size_get(extent), 0, map_bias << + LG_PAGE); + } + chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, + extent_addr_get(extent), extent_size_get(extent), + extent_zeroed_get(extent), + extent_committed_get(extent)); + extent = NULL; } - chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, (void *)chunk, - chunksize, *zero, *commit); - chunk = NULL; } malloc_mutex_lock(tsdn, &arena->lock); - return (chunk); + + return (extent); } -static arena_chunk_t * +static extent_t * arena_chunk_alloc_internal(tsdn_t *tsdn, arena_t *arena, bool *zero, bool *commit) { - arena_chunk_t *chunk; + extent_t *extent; chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; - chunk = chunk_alloc_cache(tsdn, arena, &chunk_hooks, NULL, chunksize, - chunksize, zero, true); - if (chunk != NULL) { - if (arena_chunk_register(tsdn, arena, chunk, *zero)) { - chunk_dalloc_cache(tsdn, arena, &chunk_hooks, chunk, - chunksize, true); + extent = arena_chunk_cache_alloc_locked(tsdn, arena, &chunk_hooks, NULL, + chunksize, chunksize, zero); + if (extent != NULL) { + extent_slab_set(extent, true); + + if (chunk_register(tsdn, extent)) { + arena_chunk_cache_dalloc_locked(tsdn, arena, + &chunk_hooks, extent_addr_get(extent), + extent_size_get(extent), true); return (NULL); } *commit = true; } - if (chunk == NULL) { - chunk = arena_chunk_alloc_internal_hard(tsdn, arena, + if (extent == NULL) { + extent = arena_chunk_alloc_internal_hard(tsdn, arena, &chunk_hooks, zero, commit); + if (extent == NULL) + return (NULL); } + assert(extent_slab_get(extent)); - if (config_stats && chunk != NULL) { - arena->stats.mapped += chunksize; + if (config_stats) { + arena->stats.mapped += extent_size_get(extent); arena->stats.metadata_mapped += (map_bias << LG_PAGE); } - return (chunk); + return (extent); } -static arena_chunk_t * +static extent_t * arena_chunk_init_hard(tsdn_t *tsdn, arena_t *arena) { - arena_chunk_t *chunk; + extent_t *extent; bool zero, commit; size_t flag_unzeroed, flag_decommitted, i; @@ -605,8 +661,8 @@ arena_chunk_init_hard(tsdn_t *tsdn, arena_t *arena) zero = false; commit = false; - chunk = arena_chunk_alloc_internal(tsdn, arena, &zero, &commit); - if (chunk == NULL) + extent = arena_chunk_alloc_internal(tsdn, arena, &zero, &commit); + if (extent == NULL) return (NULL); /* @@ -616,58 +672,63 @@ arena_chunk_init_hard(tsdn_t *tsdn, arena_t *arena) */ flag_unzeroed = (zero || !commit) ? 0 : CHUNK_MAP_UNZEROED; flag_decommitted = commit ? 0 : CHUNK_MAP_DECOMMITTED; - arena_mapbits_unallocated_set(chunk, map_bias, arena_maxrun, - flag_unzeroed | flag_decommitted); + arena_mapbits_unallocated_set((arena_chunk_t *)extent_addr_get(extent), + map_bias, arena_maxrun, flag_unzeroed | flag_decommitted); /* * There is no need to initialize the internal page map entries unless * the chunk is not zeroed. */ if (!zero) { - for (i = map_bias+1; i < chunk_npages-1; i++) - arena_mapbits_internal_set(chunk, i, flag_unzeroed); + for (i = map_bias+1; i < chunk_npages-1; i++) { + arena_mapbits_internal_set((arena_chunk_t *) + extent_addr_get(extent), i, flag_unzeroed); + } } else { if (config_debug) { for (i = map_bias+1; i < chunk_npages-1; i++) { - assert(arena_mapbits_unzeroed_get(chunk, i) == - flag_unzeroed); + assert(arena_mapbits_unzeroed_get( + (arena_chunk_t *)extent_addr_get(extent), i) + == flag_unzeroed); } } } - arena_mapbits_unallocated_set(chunk, chunk_npages-1, arena_maxrun, - flag_unzeroed); + arena_mapbits_unallocated_set((arena_chunk_t *)extent_addr_get(extent), + chunk_npages-1, arena_maxrun, flag_unzeroed); - return (chunk); + return (extent); } -static arena_chunk_t * +static extent_t * arena_chunk_alloc(tsdn_t *tsdn, arena_t *arena) { - arena_chunk_t *chunk; + extent_t *extent; if (arena->spare != NULL) - chunk = arena_chunk_init_spare(arena); + extent = arena_chunk_init_spare(arena); else { - chunk = arena_chunk_init_hard(tsdn, arena); - if (chunk == NULL) + extent = arena_chunk_init_hard(tsdn, arena); + if (extent == NULL) return (NULL); } - ql_elm_new(&chunk->extent, ql_link); - ql_tail_insert(&arena->achunks, &chunk->extent, ql_link); - arena_avail_insert(arena, chunk, map_bias, chunk_npages-map_bias); + ql_elm_new(extent, ql_link); + ql_tail_insert(&arena->achunks, extent, ql_link); + arena_avail_insert(arena, (arena_chunk_t *)extent_addr_get(extent), + map_bias, chunk_npages-map_bias); - return (chunk); + return (extent); } static void -arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk) +arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { bool committed; chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; - chunk_deregister(tsdn, &chunk->extent); + chunk_deregister(tsdn, extent); - committed = (arena_mapbits_decommitted_get(chunk, map_bias) == 0); + committed = (arena_mapbits_decommitted_get((arena_chunk_t *) + extent_addr_get(extent), map_bias) == 0); if (!committed) { /* * Decommit the header. Mark the chunk as decommitted even if @@ -675,37 +736,42 @@ arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk) * chunk as committed has a high potential for causing later * access of decommitted memory. */ - chunk_decommit_wrapper(tsdn, arena, &chunk_hooks, chunk, - chunksize, 0, map_bias << LG_PAGE); + chunk_decommit_wrapper(tsdn, arena, &chunk_hooks, + extent_addr_get(extent), extent_size_get(extent), 0, + map_bias << LG_PAGE); } - chunk_dalloc_cache(tsdn, arena, &chunk_hooks, (void *)chunk, chunksize, - committed); + arena_chunk_cache_dalloc_locked(tsdn, arena, &chunk_hooks, + extent_addr_get(extent), extent_size_get(extent), committed); if (config_stats) { - arena->stats.mapped -= chunksize; + arena->stats.mapped -= extent_size_get(extent); arena->stats.metadata_mapped -= (map_bias << LG_PAGE); } + + arena_extent_dalloc(tsdn, arena, extent); } static void -arena_spare_discard(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *spare) +arena_spare_discard(tsdn_t *tsdn, arena_t *arena, extent_t *spare) { assert(arena->spare != spare); - if (arena_mapbits_dirty_get(spare, map_bias) != 0) { - arena_run_dirty_remove(arena, spare, map_bias, - chunk_npages-map_bias); + if (arena_mapbits_dirty_get((arena_chunk_t *)extent_addr_get(spare), + map_bias) != 0) { + arena_run_dirty_remove(arena, (arena_chunk_t *) + extent_addr_get(spare), map_bias, chunk_npages-map_bias); } arena_chunk_discard(tsdn, arena, spare); } static void -arena_chunk_dalloc(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk) +arena_chunk_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { - arena_chunk_t *spare; + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + extent_t *spare; assert(arena_mapbits_allocated_get(chunk, map_bias) == 0); assert(arena_mapbits_allocated_get(chunk, chunk_npages-1) == 0); @@ -721,9 +787,9 @@ arena_chunk_dalloc(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk) /* Remove run from runs_avail, so that the arena does not use it. */ arena_avail_remove(arena, chunk, map_bias, chunk_npages-map_bias); - ql_remove(&arena->achunks, &chunk->extent, ql_link); + ql_remove(&arena->achunks, extent, ql_link); spare = arena->spare; - arena->spare = chunk; + arena->spare = extent; if (spare != NULL) arena_spare_discard(tsdn, arena, spare); } @@ -778,19 +844,6 @@ arena_huge_reset_stats_cancel(arena_t *arena, size_t usize) arena->stats.hstats[index].ndalloc--; } -static void -arena_huge_dalloc_stats_update_undo(arena_t *arena, size_t usize) -{ - szind_t index = size2index(usize) - nlclasses - NBINS; - - cassert(config_stats); - - arena->stats.ndalloc_huge--; - arena->stats.allocated_huge += usize; - arena->stats.hstats[index].ndalloc--; - arena->stats.hstats[index].curhchunks++; -} - static void arena_huge_ralloc_stats_update(arena_t *arena, size_t oldsize, size_t usize) { @@ -799,15 +852,6 @@ arena_huge_ralloc_stats_update(arena_t *arena, size_t oldsize, size_t usize) arena_huge_malloc_stats_update(arena, usize); } -static void -arena_huge_ralloc_stats_update_undo(arena_t *arena, size_t oldsize, - size_t usize) -{ - - arena_huge_dalloc_stats_update_undo(arena, oldsize); - arena_huge_malloc_stats_update_undo(arena, usize); -} - extent_t * arena_extent_alloc(tsdn_t *tsdn, arena_t *arena) { @@ -834,17 +878,17 @@ arena_extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); } -static void * +static extent_t * arena_chunk_alloc_huge_hard(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, size_t usize, size_t alignment, bool *zero, size_t csize) { - void *ret; + extent_t *extent; bool commit = true; - ret = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, csize, + extent = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, csize, alignment, zero, &commit); - if (ret == NULL) { + if (extent == NULL) { /* Revert optimistic stats updates. */ malloc_mutex_lock(tsdn, &arena->lock); if (config_stats) { @@ -855,14 +899,14 @@ arena_chunk_alloc_huge_hard(tsdn_t *tsdn, arena_t *arena, malloc_mutex_unlock(tsdn, &arena->lock); } - return (ret); + return (extent); } -void * +extent_t * arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero) { - void *ret; + extent_t *extent; chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; size_t csize = CHUNK_CEILING(usize); @@ -875,15 +919,15 @@ arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, } arena_nactive_add(arena, usize >> LG_PAGE); - ret = chunk_alloc_cache(tsdn, arena, &chunk_hooks, NULL, csize, - alignment, zero, true); + extent = arena_chunk_cache_alloc_locked(tsdn, arena, &chunk_hooks, NULL, + csize, alignment, zero); malloc_mutex_unlock(tsdn, &arena->lock); - if (ret == NULL) { - ret = arena_chunk_alloc_huge_hard(tsdn, arena, &chunk_hooks, + if (extent == NULL) { + extent = arena_chunk_alloc_huge_hard(tsdn, arena, &chunk_hooks, usize, alignment, zero, csize); } - return (ret); + return (extent); } void @@ -900,14 +944,16 @@ arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, void *chunk, size_t usize) } arena_nactive_sub(arena, usize >> LG_PAGE); - chunk_dalloc_cache(tsdn, arena, &chunk_hooks, chunk, csize, true); + arena_chunk_cache_dalloc_locked(tsdn, arena, &chunk_hooks, chunk, csize, + true); malloc_mutex_unlock(tsdn, &arena->lock); } void -arena_chunk_ralloc_huge_similar(tsdn_t *tsdn, arena_t *arena, void *chunk, - size_t oldsize, size_t usize) +arena_chunk_ralloc_huge_similar(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + size_t oldsize) { + size_t usize = extent_size_get(extent); assert(CHUNK_CEILING(oldsize) == CHUNK_CEILING(usize)); assert(oldsize != usize); @@ -923,9 +969,10 @@ arena_chunk_ralloc_huge_similar(tsdn_t *tsdn, arena_t *arena, void *chunk, } void -arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, void *chunk, - size_t oldsize, size_t usize) +arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + size_t oldsize) { + size_t usize = extent_size_get(extent); size_t udiff = oldsize - usize; size_t cdiff = CHUNK_CEILING(oldsize) - CHUNK_CEILING(usize); @@ -936,83 +983,24 @@ arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, void *chunk, arena->stats.mapped -= cdiff; } arena_nactive_sub(arena, udiff >> LG_PAGE); - - if (cdiff != 0) { - chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; - void *nchunk = (void *)((uintptr_t)chunk + - CHUNK_CEILING(usize)); - - chunk_dalloc_cache(tsdn, arena, &chunk_hooks, nchunk, cdiff, - true); - } malloc_mutex_unlock(tsdn, &arena->lock); } -bool +void arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - size_t usize) + size_t oldsize) { - bool err; - bool zero = false; - chunk_hooks_t chunk_hooks = chunk_hooks_get(tsdn, arena); - void *nchunk = - (void *)CHUNK_CEILING((uintptr_t)extent_past_get(extent)); - size_t udiff = usize - extent_size_get(extent); - size_t cdiff = CHUNK_CEILING(usize) - - CHUNK_CEILING(extent_size_get(extent)); - extent_t *trail; + size_t usize = extent_size_get(extent); + size_t cdiff = CHUNK_CEILING(usize) - CHUNK_CEILING(oldsize); + size_t udiff = usize - oldsize; malloc_mutex_lock(tsdn, &arena->lock); - - /* Optimistically update stats. */ if (config_stats) { - arena_huge_ralloc_stats_update(arena, extent_size_get(extent), - usize); + arena_huge_ralloc_stats_update(arena, oldsize, usize); arena->stats.mapped += cdiff; } arena_nactive_add(arena, udiff >> LG_PAGE); - - err = (chunk_alloc_cache(tsdn, arena, &chunk_hooks, nchunk, cdiff, - chunksize, &zero, true) == NULL); - malloc_mutex_unlock(tsdn, &arena->lock); - - if (err) { - bool commit = true; - - if (chunk_alloc_wrapper(tsdn, arena, &chunk_hooks, nchunk, - cdiff, chunksize, &zero, &commit) == NULL) - goto label_revert; - } - - trail = arena_extent_alloc(tsdn, arena); - if (trail == NULL) { - chunk_dalloc_wrapper(tsdn, arena, &chunk_hooks, nchunk, cdiff, - zero, true); - goto label_revert; - } - extent_init(trail, arena, nchunk, cdiff, true, zero, true, false); - if (chunk_merge_wrapper(tsdn, arena, &chunk_hooks, extent, trail)) { - arena_extent_dalloc(tsdn, arena, trail); - chunk_dalloc_wrapper(tsdn, arena, &chunk_hooks, nchunk, cdiff, - zero, true); - goto label_revert; - } - - if (usize < extent_size_get(extent)) - extent_size_set(extent, usize); - - return (false); -label_revert: - /* Revert optimistic stats updates. */ - malloc_mutex_lock(tsdn, &arena->lock); - if (config_stats) { - arena_huge_ralloc_stats_update_undo(arena, - extent_size_get(extent), usize); - arena->stats.mapped -= cdiff; - } - arena_nactive_sub(arena, udiff >> LG_PAGE); malloc_mutex_unlock(tsdn, &arena->lock); - return (true); } /* @@ -1053,8 +1041,8 @@ arena_run_alloc_large_helper(tsdn_t *tsdn, arena_t *arena, size_t size, static arena_run_t * arena_run_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t size, bool zero) { - arena_chunk_t *chunk; arena_run_t *run; + extent_t *extent; assert(size <= arena_maxrun); assert(size == PAGE_CEILING(size)); @@ -1067,9 +1055,10 @@ arena_run_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t size, bool zero) /* * No usable runs. Create a new chunk from which to allocate the run. */ - chunk = arena_chunk_alloc(tsdn, arena); - if (chunk != NULL) { - run = &arena_miscelm_get_mutable(chunk, map_bias)->run; + extent = arena_chunk_alloc(tsdn, arena); + if (extent != NULL) { + run = &arena_miscelm_get_mutable((arena_chunk_t *) + extent_addr_get(extent), map_bias)->run; if (arena_run_split_large(tsdn, arena, iealloc(tsdn, run), run, size, zero)) run = NULL; @@ -1100,8 +1089,8 @@ arena_run_alloc_small_helper(tsdn_t *tsdn, arena_t *arena, size_t size, static arena_run_t * arena_run_alloc_small(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t binind) { - arena_chunk_t *chunk; arena_run_t *run; + extent_t *extent; assert(size <= arena_maxrun); assert(size == PAGE_CEILING(size)); @@ -1115,9 +1104,10 @@ arena_run_alloc_small(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t binind) /* * No usable runs. Create a new chunk from which to allocate the run. */ - chunk = arena_chunk_alloc(tsdn, arena); - if (chunk != NULL) { - run = &arena_miscelm_get_mutable(chunk, map_bias)->run; + extent = arena_chunk_alloc(tsdn, arena); + if (extent != NULL) { + run = &arena_miscelm_get_mutable( + (arena_chunk_t *)extent_addr_get(extent), map_bias)->run; if (arena_run_split_small(tsdn, arena, iealloc(tsdn, run), run, size, binind)) run = NULL; @@ -1420,6 +1410,8 @@ void arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) { + malloc_mutex_assert_owner(tsdn, &arena->lock); + /* Don't recursively purge. */ if (arena->purging) return; @@ -1484,7 +1476,7 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, if (rdelm == &chunkselm->rd) { extent_t *chunkselm_next; bool zero; - UNUSED void *chunk; + UNUSED extent_t *extent; npages = extent_size_get(chunkselm) >> LG_PAGE; if (opt_purge == purge_mode_decay && arena->ndirty - @@ -1492,16 +1484,12 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, break; chunkselm_next = qr_next(chunkselm, cc_link); - /* - * Allocate. chunkselm remains valid due to the - * dalloc_extent=false argument to chunk_alloc_cache(). - */ + /* Allocate. */ zero = false; - chunk = chunk_alloc_cache(tsdn, arena, chunk_hooks, - extent_addr_get(chunkselm), - extent_size_get(chunkselm), chunksize, &zero, - false); - assert(chunk == extent_addr_get(chunkselm)); + extent = arena_chunk_cache_alloc_locked(tsdn, arena, + chunk_hooks, extent_addr_get(chunkselm), + extent_size_get(chunkselm), chunksize, &zero); + assert(extent == chunkselm); assert(zero == extent_zeroed_get(chunkselm)); extent_dirty_insert(chunkselm, purge_runs_sentinel, purge_chunks_sentinel); @@ -1510,14 +1498,13 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunkselm = chunkselm_next; } else { extent_t *extent = iealloc(tsdn, rdelm); - arena_chunk_t *chunk = - (arena_chunk_t *)extent_addr_get(extent); arena_chunk_map_misc_t *miscelm = arena_rd_to_miscelm(rdelm); size_t pageind = arena_miscelm_to_pageind(miscelm); arena_run_t *run = &miscelm->run; size_t run_size = - arena_mapbits_unallocated_size_get(chunk, pageind); + arena_mapbits_unallocated_size_get((arena_chunk_t *) + extent_addr_get(extent), pageind); npages = run_size >> LG_PAGE; if (opt_purge == purge_mode_decay && arena->ndirty - @@ -1525,14 +1512,16 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, break; assert(pageind + npages <= chunk_npages); - assert(arena_mapbits_dirty_get(chunk, pageind) == - arena_mapbits_dirty_get(chunk, pageind+npages-1)); + assert(arena_mapbits_dirty_get((arena_chunk_t *) + extent_addr_get(extent), pageind) == + arena_mapbits_dirty_get((arena_chunk_t *) + extent_addr_get(extent), pageind+npages-1)); /* * If purging the spare chunk's run, make it available * prior to allocation. */ - if (chunk == arena->spare) + if (extent == arena->spare) arena_chunk_alloc(tsdn, arena); /* Temporarily allocate the free dirty run. */ @@ -1757,8 +1746,9 @@ arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) } static void -arena_achunk_prof_reset(tsd_t *tsd, arena_t *arena, arena_chunk_t *chunk) +arena_achunk_prof_reset(tsd_t *tsd, arena_t *arena, extent_t *extent) { + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); size_t pageind, npages; cassert(config_prof); @@ -1773,10 +1763,10 @@ arena_achunk_prof_reset(tsd_t *tsd, arena_t *arena, arena_chunk_t *chunk) if (arena_mapbits_large_get(chunk, pageind) != 0) { void *ptr = (void *)((uintptr_t)chunk + (pageind << LG_PAGE)); - size_t usize = isalloc(tsd_tsdn(tsd), - &chunk->extent, ptr, config_prof); + size_t usize = isalloc(tsd_tsdn(tsd), extent, + ptr, config_prof); - prof_free(tsd, &chunk->extent, ptr, usize); + prof_free(tsd, extent, ptr, usize); npages = arena_mapbits_large_size_get(chunk, pageind) >> LG_PAGE; } else { @@ -1819,8 +1809,7 @@ arena_reset(tsd_t *tsd, arena_t *arena) /* Remove large allocations from prof sample set. */ if (config_prof && opt_prof) { ql_foreach(extent, &arena->achunks, ql_link) { - arena_achunk_prof_reset(tsd, arena, - extent_addr_get(extent)); + arena_achunk_prof_reset(tsd, arena, extent); } } @@ -1845,7 +1834,7 @@ arena_reset(tsd_t *tsd, arena_t *arena) /* Remove huge allocation from prof sample set. */ if (config_prof && opt_prof) prof_free(tsd, extent, ptr, usize); - huge_dalloc(tsd_tsdn(tsd), extent, ptr); + huge_dalloc(tsd_tsdn(tsd), extent); malloc_mutex_lock(tsd_tsdn(tsd), &arena->huge_mtx); /* Cancel out unwanted effects on stats. */ if (config_stats) @@ -1883,8 +1872,7 @@ arena_reset(tsd_t *tsd, arena_t *arena) for (extent = ql_last(&arena->achunks, ql_link); extent != NULL; extent = ql_last(&arena->achunks, ql_link)) { ql_remove(&arena->achunks, extent, ql_link); - arena_chunk_discard(tsd_tsdn(tsd), arena, - extent_addr_get(extent)); + arena_chunk_discard(tsd_tsdn(tsd), arena, extent); } /* Spare. */ @@ -2078,7 +2066,7 @@ arena_run_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, if (size == arena_maxrun) { assert(run_ind == map_bias); assert(run_pages == (arena_maxrun >> LG_PAGE)); - arena_chunk_dalloc(tsdn, arena, chunk); + arena_chunk_dalloc(tsdn, arena, extent); } /* @@ -3113,10 +3101,12 @@ arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); - } else { - return (huge_ralloc_no_move(tsdn, extent, ptr, oldsize, - usize_min, usize_max, zero)); + } else if (oldsize >= chunksize && usize_max >= chunksize) { + return (huge_ralloc_no_move(tsdn, extent, usize_min, usize_max, + zero)); } + + return (true); } static void * @@ -3138,42 +3128,41 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache) { void *ret; - size_t usize; + size_t usize, copysize; usize = s2u(size); if (unlikely(usize == 0 || size > HUGE_MAXCLASS)) return (NULL); if (likely(usize <= large_maxclass)) { - size_t copysize; - /* Try to avoid moving the allocation. */ if (!arena_ralloc_no_move(tsdn, extent, ptr, oldsize, usize, 0, zero)) return (ptr); + } - /* - * size and oldsize are different enough that we need to move - * the object. In that case, fall back to allocating new space - * and copying. - */ - ret = arena_ralloc_move_helper(tsdn, arena, usize, alignment, - zero, tcache); - if (ret == NULL) - return (NULL); + if (oldsize >= chunksize && usize >= chunksize) { + return (huge_ralloc(tsdn, arena, extent, usize, alignment, zero, + tcache)); + } - /* - * Junk/zero-filling were already done by - * ipalloc()/arena_malloc(). - */ + /* + * size and oldsize are different enough that we need to move the + * object. In that case, fall back to allocating new space and copying. + */ + ret = arena_ralloc_move_helper(tsdn, arena, usize, alignment, zero, + tcache); + if (ret == NULL) + return (NULL); - copysize = (usize < oldsize) ? usize : oldsize; - memcpy(ret, ptr, copysize); - isdalloct(tsdn, extent, ptr, oldsize, tcache, true); - } else { - ret = huge_ralloc(tsdn, arena, extent, ptr, oldsize, usize, - alignment, zero, tcache); - } + /* + * Junk/zero-filling were already done by + * ipalloc()/arena_malloc(). + */ + + copysize = (usize < oldsize) ? usize : oldsize; + memcpy(ret, ptr, copysize); + isdalloct(tsdn, extent, ptr, oldsize, tcache, true); return (ret); } diff --git a/src/chunk.c b/src/chunk.c index 59ebd291..4efba4a7 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -58,7 +58,8 @@ static void chunk_record(tsdn_t *tsdn, arena_t *arena, static void extent_heaps_insert(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) { - size_t psz = extent_size_quantize_floor(extent_size_get(extent)); + size_t psz = + extent_size_quantize_floor(CHUNK_CEILING(extent_size_get(extent))); pszind_t pind = psz2ind(psz); extent_heap_insert(&extent_heaps[pind], extent); } @@ -66,7 +67,8 @@ extent_heaps_insert(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) static void extent_heaps_remove(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) { - size_t psz = extent_size_quantize_floor(extent_size_get(extent)); + size_t psz = + extent_size_quantize_floor(CHUNK_CEILING(extent_size_get(extent))); pszind_t pind = psz2ind(psz); extent_heap_remove(&extent_heaps[pind], extent); } @@ -211,7 +213,7 @@ chunk_register(tsdn_t *tsdn, const extent_t *extent) extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent); extent_rtree_release(tsdn, elm_a, elm_b); - if (config_prof && opt_prof) { + if (config_prof && opt_prof && extent_active_get(extent)) { size_t nadd = (extent_size_get(extent) == 0) ? 1 : extent_size_get(extent) / chunksize; size_t cur = atomic_add_z(&curchunks, nadd); @@ -239,7 +241,7 @@ chunk_deregister(tsdn_t *tsdn, const extent_t *extent) extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL); extent_rtree_release(tsdn, elm_a, elm_b); - if (config_prof && opt_prof) { + if (config_prof && opt_prof && extent_active_get(extent)) { size_t nsub = (extent_size_get(extent) == 0) ? 1 : extent_size_get(extent) / chunksize; assert(atomic_read_z(&curchunks) >= nsub); @@ -293,23 +295,15 @@ chunk_leak(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, bool cache, } } -static void * +static extent_t * chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_heap_t extent_heaps[NPSIZES], bool cache, void *new_addr, - size_t size, size_t alignment, bool *zero, bool *commit, bool dalloc_extent) + size_t size, size_t alignment, bool *zero, bool *commit) { - void *ret; extent_t *extent; size_t alloc_size, leadsize, trailsize; - bool zeroed, committed; assert(new_addr == NULL || alignment == chunksize); - /* - * Cached chunks use the extent linkage embedded in their headers, in - * which case dalloc_extent is true, and new_addr is non-NULL because - * we're operating on a specific chunk. - */ - assert(dalloc_extent || new_addr != NULL); alloc_size = CHUNK_CEILING(s2u(size + alignment - chunksize)); /* Beware size_t wrap-around. */ @@ -338,99 +332,79 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, malloc_mutex_unlock(tsdn, &arena->chunks_mtx); return (NULL); } + extent_heaps_remove(extent_heaps, extent); + arena_chunk_cache_maybe_remove(arena, extent, cache); + leadsize = ALIGNMENT_CEILING((uintptr_t)extent_addr_get(extent), alignment) - (uintptr_t)extent_addr_get(extent); assert(new_addr == NULL || leadsize == 0); assert(extent_size_get(extent) >= leadsize + size); trailsize = extent_size_get(extent) - leadsize - size; - ret = (void *)((uintptr_t)extent_addr_get(extent) + leadsize); - zeroed = extent_zeroed_get(extent); - if (zeroed) + if (extent_zeroed_get(extent)) *zero = true; - committed = extent_committed_get(extent); - if (committed) + if (extent_committed_get(extent)) *commit = true; + /* Split the lead. */ - if (leadsize != 0 && - chunk_hooks->split(extent_addr_get(extent), - extent_size_get(extent), leadsize, size, false, arena->ind)) { - malloc_mutex_unlock(tsdn, &arena->chunks_mtx); - return (NULL); - } - /* Remove extent from the heap. */ - chunk_deregister(tsdn, extent); - extent_heaps_remove(extent_heaps, extent); - arena_chunk_cache_maybe_remove(arena, extent, cache); if (leadsize != 0) { - /* Insert the leading space as a smaller chunk. */ - extent_size_set(extent, leadsize); - if (chunk_register(tsdn, extent)) { + extent_t *lead = extent; + extent = chunk_split_wrapper(tsdn, arena, chunk_hooks, lead, + leadsize, size + trailsize); + if (extent == NULL) { chunk_leak(tsdn, arena, chunk_hooks, cache, - extent_addr_get(extent), extent_size_get(extent)); - arena_extent_dalloc(tsdn, arena, extent); - } else { - extent_heaps_insert(extent_heaps, extent); - arena_chunk_cache_maybe_insert(arena, extent, cache); - } - extent = NULL; - } - if (trailsize != 0) { - /* Split the trail. */ - if (chunk_hooks->split(ret, size + trailsize, size, - trailsize, false, arena->ind)) { - if (dalloc_extent && extent != NULL) - arena_extent_dalloc(tsdn, arena, extent); + extent_addr_get(lead), extent_size_get(lead)); + arena_extent_dalloc(tsdn, arena, lead); malloc_mutex_unlock(tsdn, &arena->chunks_mtx); - chunk_record(tsdn, arena, chunk_hooks, extent_heaps, - cache, ret, size + trailsize, zeroed, committed); return (NULL); } - /* Insert the trailing space as a smaller chunk. */ - if (extent == NULL) { - extent = arena_extent_alloc(tsdn, arena); - if (extent == NULL) { - malloc_mutex_unlock(tsdn, &arena->chunks_mtx); - chunk_record(tsdn, arena, chunk_hooks, - extent_heaps, cache, ret, size + trailsize, - zeroed, committed); - return (NULL); - } - } - extent_init(extent, arena, (void *)((uintptr_t)(ret) + size), - trailsize, false, zeroed, committed, false); - if (chunk_register(tsdn, extent)) { + extent_heaps_insert(extent_heaps, lead); + arena_chunk_cache_maybe_insert(arena, lead, cache); + } + + /* Split the trail. */ + if (trailsize != 0) { + extent_t *trail = chunk_split_wrapper(tsdn, arena, chunk_hooks, + extent, size, trailsize); + if (trail == NULL) { chunk_leak(tsdn, arena, chunk_hooks, cache, extent_addr_get(extent), extent_size_get(extent)); arena_extent_dalloc(tsdn, arena, extent); - } else { - extent_heaps_insert(extent_heaps, extent); - arena_chunk_cache_maybe_insert(arena, extent, cache); + malloc_mutex_unlock(tsdn, &arena->chunks_mtx); + return (NULL); } - extent = NULL; + extent_heaps_insert(extent_heaps, trail); + arena_chunk_cache_maybe_insert(arena, trail, cache); } - if (!committed && chunk_hooks->commit(ret, size, 0, size, arena->ind)) { + + if (!extent_committed_get(extent) && + chunk_hooks->commit(extent_addr_get(extent), + extent_size_get(extent), 0, extent_size_get(extent), arena->ind)) { malloc_mutex_unlock(tsdn, &arena->chunks_mtx); - chunk_record(tsdn, arena, chunk_hooks, extent_heaps, cache, ret, - size, zeroed, committed); + chunk_record(tsdn, arena, chunk_hooks, extent_heaps, cache, + extent_addr_get(extent), extent_size_get(extent), + extent_zeroed_get(extent), extent_committed_get(extent)); + arena_extent_dalloc(tsdn, arena, extent); return (NULL); } + + extent_active_set(extent, true); + malloc_mutex_unlock(tsdn, &arena->chunks_mtx); - assert(dalloc_extent || extent != NULL); - if (dalloc_extent && extent != NULL) - arena_extent_dalloc(tsdn, arena, extent); if (*zero) { - if (!zeroed) - memset(ret, 0, size); - else if (config_debug) { + if (!extent_zeroed_get(extent)) { + memset(extent_addr_get(extent), 0, + extent_size_get(extent)); + } else if (config_debug) { size_t i; - size_t *p = (size_t *)(uintptr_t)ret; + size_t *p = (size_t *)(uintptr_t) + extent_addr_get(extent); for (i = 0; i < size / sizeof(size_t); i++) assert(p[i] == 0); } } - return (ret); + return (extent); } /* @@ -469,12 +443,11 @@ chunk_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, return (NULL); } -void * +extent_t * chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - void *new_addr, size_t size, size_t alignment, bool *zero, - bool dalloc_extent) + void *new_addr, size_t size, size_t alignment, bool *zero) { - void *ret; + extent_t *extent; bool commit; assert(size != 0); @@ -483,12 +456,12 @@ chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert((alignment & chunksize_mask) == 0); commit = true; - ret = chunk_recycle(tsdn, arena, chunk_hooks, arena->chunks_cached, - true, new_addr, size, alignment, zero, &commit, dalloc_extent); - if (ret == NULL) + extent = chunk_recycle(tsdn, arena, chunk_hooks, arena->chunks_cached, + true, new_addr, size, alignment, zero, &commit); + if (extent == NULL) return (NULL); assert(commit); - return (ret); + return (extent); } static arena_t * @@ -523,44 +496,51 @@ chunk_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero, return (ret); } -static void * +static extent_t * chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit) { - void *ret; + extent_t *extent; assert(size != 0); assert((size & chunksize_mask) == 0); assert(alignment != 0); assert((alignment & chunksize_mask) == 0); - ret = chunk_recycle(tsdn, arena, chunk_hooks, arena->chunks_retained, - false, new_addr, size, alignment, zero, commit, true); + extent = chunk_recycle(tsdn, arena, chunk_hooks, arena->chunks_retained, + false, new_addr, size, alignment, zero, commit); - if (config_stats && ret != NULL) + if (config_stats && extent != NULL) arena->stats.retained -= size; - return (ret); + return (extent); } -void * +extent_t * chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit) { - void *ret; + extent_t *extent; chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); - ret = chunk_alloc_retained(tsdn, arena, chunk_hooks, new_addr, size, + extent = chunk_alloc_retained(tsdn, arena, chunk_hooks, new_addr, size, alignment, zero, commit); - if (ret == NULL) { - ret = chunk_hooks->alloc(new_addr, size, alignment, zero, - commit, arena->ind); - if (ret == NULL) + if (extent == NULL) { + void *chunk; + + extent = arena_extent_alloc(tsdn, arena); + if (extent == NULL) + return (NULL); + chunk = chunk_hooks->alloc(new_addr, size, alignment, + zero, commit, arena->ind); + if (chunk == NULL) return (NULL); + extent_init(extent, arena, chunk, size, true, zero, commit, + false); } - return (ret); + return (extent); } static bool @@ -668,7 +648,6 @@ chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunk_record(tsdn, arena, chunk_hooks, arena->chunks_cached, true, chunk, size, false, committed); - arena_maybe_purge(tsdn, arena); } static bool @@ -779,6 +758,67 @@ chunk_split_default(void *chunk, size_t size, size_t size_a, size_t size_b, return (false); } +extent_t * +chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, + extent_t *extent, size_t size_a, size_t size_b) +{ + extent_t *trail; + rtree_elm_t *lead_elm_a, *lead_elm_b, *trail_elm_a, *trail_elm_b; + + assert(CHUNK_CEILING(size_a) == size_a); + assert(CHUNK_CEILING(extent_size_get(extent)) == size_a + + CHUNK_CEILING(size_b)); + + chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); + + trail = arena_extent_alloc(tsdn, arena); + if (trail == NULL) + goto label_error_a; + + { + extent_t lead; + + extent_init(&lead, arena, extent_addr_get(extent), size_a, + extent_active_get(extent), extent_zeroed_get(extent), + extent_committed_get(extent), extent_slab_get(extent)); + + if (extent_rtree_acquire(tsdn, &lead, false, true, &lead_elm_a, + &lead_elm_b)) + goto label_error_b; + } + + extent_init(trail, arena, (void *)((uintptr_t)extent_addr_get(extent) + + size_a), CHUNK_CEILING(size_b), extent_active_get(extent), + extent_zeroed_get(extent), extent_committed_get(extent), + extent_slab_get(extent)); + if (extent_rtree_acquire(tsdn, trail, false, true, &trail_elm_a, + &trail_elm_b)) + goto label_error_c; + + if (chunk_hooks->split(extent_addr_get(extent), size_a + + CHUNK_CEILING(size_b), size_a, CHUNK_CEILING(size_b), + extent_committed_get(extent), arena->ind)) + goto label_error_d; + + extent_size_set(extent, size_a); + + extent_rtree_write_acquired(tsdn, lead_elm_a, lead_elm_b, extent); + extent_rtree_write_acquired(tsdn, trail_elm_a, trail_elm_b, trail); + + extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); + extent_rtree_release(tsdn, trail_elm_a, trail_elm_b); + + return (trail); +label_error_d: + extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); +label_error_c: + extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); +label_error_b: + arena_extent_dalloc(tsdn, arena, trail); +label_error_a: + return (NULL); +} + static bool chunk_merge_default(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b, bool committed, unsigned arena_ind) @@ -801,6 +841,7 @@ chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, { rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; + chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); if (chunk_hooks->merge(extent_addr_get(a), extent_size_get(a), extent_addr_get(b), extent_size_get(b), extent_committed_get(a), arena->ind)) diff --git a/src/huge.c b/src/huge.c index dc0d680e..fe4c6e00 100644 --- a/src/huge.c +++ b/src/huge.c @@ -16,7 +16,6 @@ void * huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero) { - void *ret; size_t ausize; extent_t *extent; bool is_zeroed; @@ -30,12 +29,6 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, return (NULL); assert(ausize >= chunksize); - /* Allocate an extent with which to track the chunk. */ - extent = ipallocztm(tsdn, CACHELINE_CEILING(sizeof(extent_t)), - CACHELINE, false, NULL, true, arena_ichoose(tsdn, arena)); - if (extent == NULL) - return (NULL); - /* * Copy zero into is_zeroed and pass the copy to chunk_alloc(), so that * it is possible to make correct junk/zero fill decisions below. @@ -43,19 +36,17 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, is_zeroed = zero; if (likely(!tsdn_null(tsdn))) arena = arena_choose(tsdn_tsd(tsdn), arena); - if (unlikely(arena == NULL) || (ret = arena_chunk_alloc_huge(tsdn, - arena, usize, alignment, &is_zeroed)) == NULL) { - idalloctm(tsdn, iealloc(tsdn, extent), extent, NULL, true, - true); + if (unlikely(arena == NULL) || (extent = arena_chunk_alloc_huge(tsdn, + arena, usize, alignment, &is_zeroed)) == NULL) return (NULL); - } - extent_init(extent, arena, ret, usize, true, is_zeroed, true, false); + if (usize < extent_size_get(extent)) + extent_size_set(extent, usize); if (chunk_register(tsdn, extent)) { - arena_chunk_dalloc_huge(tsdn, arena, ret, usize); - idalloctm(tsdn, iealloc(tsdn, extent), extent, NULL, true, - true); + arena_chunk_dalloc_huge(tsdn, arena, extent_addr_get(extent), + usize); + arena_extent_dalloc(tsdn, arena, extent); return (NULL); } @@ -67,12 +58,12 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, if (zero || (config_fill && unlikely(opt_zero))) { if (!is_zeroed) - memset(ret, 0, usize); + memset(extent_addr_get(extent), 0, usize); } else if (config_fill && unlikely(opt_junk_alloc)) - memset(ret, JEMALLOC_ALLOC_JUNK, usize); + memset(extent_addr_get(extent), JEMALLOC_ALLOC_JUNK, usize); arena_decay_tick(tsdn, arena); - return (ret); + return (extent_addr_get(extent)); } #ifdef JEMALLOC_JET @@ -99,11 +90,12 @@ huge_dalloc_junk_t *huge_dalloc_junk = JEMALLOC_N(huge_dalloc_junk_impl); #endif static void -huge_ralloc_no_move_similar(tsdn_t *tsdn, extent_t *extent, void *ptr, - size_t oldsize, size_t usize_min, size_t usize_max, bool zero) +huge_ralloc_no_move_similar(tsdn_t *tsdn, extent_t *extent, size_t usize_min, + size_t usize_max, bool zero) { size_t usize, usize_next; - arena_t *arena; + arena_t *arena = extent_arena_get(extent); + size_t oldsize = extent_size_get(extent); chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; bool pre_zeroed, post_zeroed; @@ -115,20 +107,19 @@ huge_ralloc_no_move_similar(tsdn_t *tsdn, extent_t *extent, void *ptr, if (oldsize == usize) return; - arena = extent_arena_get(extent); pre_zeroed = extent_zeroed_get(extent); /* Fill if necessary (shrinking). */ if (oldsize > usize) { size_t sdiff = oldsize - usize; if (config_fill && unlikely(opt_junk_free)) { - memset((void *)((uintptr_t)ptr + usize), - JEMALLOC_FREE_JUNK, sdiff); + memset((void *)((uintptr_t)extent_addr_get(extent) + + usize), JEMALLOC_FREE_JUNK, sdiff); post_zeroed = false; } else { post_zeroed = !chunk_purge_wrapper(tsdn, arena, - &chunk_hooks, ptr, CHUNK_CEILING(oldsize), usize, - sdiff); + &chunk_hooks, extent_addr_get(extent), + CHUNK_CEILING(oldsize), usize, sdiff); } } else post_zeroed = pre_zeroed; @@ -143,132 +134,157 @@ huge_ralloc_no_move_similar(tsdn_t *tsdn, extent_t *extent, void *ptr, /* Update zeroed. */ extent_zeroed_set(extent, post_zeroed); - arena_chunk_ralloc_huge_similar(tsdn, arena, ptr, oldsize, usize); + arena_chunk_ralloc_huge_similar(tsdn, arena, extent, oldsize); /* Fill if necessary (growing). */ if (oldsize < usize) { if (zero || (config_fill && unlikely(opt_zero))) { if (!pre_zeroed) { - memset((void *)((uintptr_t)ptr + oldsize), 0, - usize - oldsize); + memset((void *) + ((uintptr_t)extent_addr_get(extent) + + oldsize), 0, usize - oldsize); } } else if (config_fill && unlikely(opt_junk_alloc)) { - memset((void *)((uintptr_t)ptr + oldsize), - JEMALLOC_ALLOC_JUNK, usize - oldsize); + memset((void *)((uintptr_t)extent_addr_get(extent) + + oldsize), JEMALLOC_ALLOC_JUNK, usize - oldsize); } } } static bool -huge_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, void *ptr, - size_t oldsize, size_t usize) +huge_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { - arena_t *arena; - chunk_hooks_t chunk_hooks; - size_t cdiff; - bool pre_zeroed, post_zeroed; - - arena = extent_arena_get(extent); - pre_zeroed = extent_zeroed_get(extent); - chunk_hooks = chunk_hooks_get(tsdn, arena); + arena_t *arena = extent_arena_get(extent); + size_t oldsize = extent_size_get(extent); + chunk_hooks_t chunk_hooks = chunk_hooks_get(tsdn, arena); + size_t cdiff = CHUNK_CEILING(oldsize) - CHUNK_CEILING(usize); + size_t sdiff = CHUNK_CEILING(usize) - usize; assert(oldsize > usize); /* Split excess chunks. */ - cdiff = CHUNK_CEILING(oldsize) - CHUNK_CEILING(usize); - if (cdiff != 0 && chunk_hooks.split(ptr, CHUNK_CEILING(oldsize), - CHUNK_CEILING(usize), cdiff, true, arena->ind)) - return (true); + if (cdiff != 0) { + extent_t *trail = chunk_split_wrapper(tsdn, arena, &chunk_hooks, + extent, CHUNK_CEILING(usize), cdiff); + if (trail == NULL) + return (true); - if (oldsize > usize) { - size_t sdiff = oldsize - usize; if (config_fill && unlikely(opt_junk_free)) { - huge_dalloc_junk(tsdn, (void *)((uintptr_t)ptr + usize), - sdiff); + huge_dalloc_junk(tsdn, extent_addr_get(trail), + extent_size_get(trail)); + } + + arena_chunk_cache_dalloc(tsdn, arena, &chunk_hooks, + extent_addr_get(trail), extent_size_get(trail), + extent_committed_get(trail)); + + arena_extent_dalloc(tsdn, arena, trail); + } + + /* Optionally fill trailing subchunk. */ + if (sdiff != 0) { + bool post_zeroed; + + if (config_fill && unlikely(opt_junk_free)) { + huge_dalloc_junk(tsdn, + (void *)((uintptr_t)extent_addr_get(extent) + + usize), sdiff); post_zeroed = false; } else { post_zeroed = !chunk_purge_wrapper(tsdn, arena, - &chunk_hooks, CHUNK_ADDR2BASE((uintptr_t)ptr + - usize), CHUNK_CEILING(oldsize), - CHUNK_ADDR2OFFSET((uintptr_t)ptr + usize), sdiff); - } - } else - post_zeroed = pre_zeroed; + &chunk_hooks, extent_addr_get(extent), + CHUNK_CEILING(usize), usize, sdiff); - /* Update the size of the huge allocation. */ - chunk_deregister(tsdn, extent); - malloc_mutex_lock(tsdn, &arena->huge_mtx); - extent_size_set(extent, usize); - /* Update zeroed. */ - extent_zeroed_set(extent, post_zeroed); - malloc_mutex_unlock(tsdn, &arena->huge_mtx); - chunk_reregister(tsdn, extent); + if (config_fill && unlikely(opt_zero) && !post_zeroed) { + memset((void *) + ((uintptr_t)extent_addr_get(extent) + + usize), 0, sdiff); + } + } + extent_zeroed_set(extent, post_zeroed); + } - /* Zap the excess chunks. */ - arena_chunk_ralloc_huge_shrink(tsdn, arena, ptr, oldsize, usize); + arena_chunk_ralloc_huge_shrink(tsdn, arena, extent, oldsize); return (false); } static bool -huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, void *ptr, - size_t oldsize, size_t usize, bool zero) +huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, + bool zero) { - arena_t *arena; - bool is_zeroed_subchunk; - - arena = extent_arena_get(extent); - malloc_mutex_lock(tsdn, &arena->huge_mtx); - is_zeroed_subchunk = extent_zeroed_get(extent); - malloc_mutex_unlock(tsdn, &arena->huge_mtx); + arena_t *arena = extent_arena_get(extent); + size_t oldsize = extent_size_get(extent); + bool is_zeroed_subchunk = extent_zeroed_get(extent); + bool is_zeroed_chunk = false; + chunk_hooks_t chunk_hooks = chunk_hooks_get(tsdn, arena); + size_t cdiff = CHUNK_CEILING(usize) - CHUNK_CEILING(oldsize); + void *nchunk = + (void *)CHUNK_CEILING((uintptr_t)extent_past_get(extent)); + extent_t *trail; + + if ((trail = arena_chunk_cache_alloc(tsdn, arena, &chunk_hooks, nchunk, + cdiff, chunksize, &is_zeroed_chunk)) == NULL) { + bool commit = true; + if ((trail = chunk_alloc_wrapper(tsdn, arena, &chunk_hooks, + nchunk, cdiff, chunksize, &is_zeroed_chunk, &commit)) == + NULL) + return (true); + } - if (arena_chunk_ralloc_huge_expand(tsdn, arena, extent, usize)) + if (chunk_merge_wrapper(tsdn, arena, &chunk_hooks, extent, trail)) { + arena_extent_dalloc(tsdn, arena, trail); + chunk_dalloc_wrapper(tsdn, arena, &chunk_hooks, + extent_addr_get(trail), extent_size_get(trail), + extent_zeroed_get(trail), extent_committed_get(trail)); return (true); + } if (zero || (config_fill && unlikely(opt_zero))) { - bool is_zeroed_chunk = extent_zeroed_get(extent); - if (!is_zeroed_subchunk) { - memset((void *)((uintptr_t)ptr + oldsize), 0, - CHUNK_CEILING(oldsize) - oldsize); + memset((void *)((uintptr_t)extent_addr_get(extent) + + oldsize), 0, CHUNK_CEILING(oldsize) - oldsize); } if (!is_zeroed_chunk) { - memset((void *)((uintptr_t)ptr + + memset((void *)((uintptr_t)extent_addr_get(extent) + CHUNK_CEILING(oldsize)), 0, usize - CHUNK_CEILING(oldsize)); } } else if (config_fill && unlikely(opt_junk_alloc)) { - memset((void *)((uintptr_t)ptr + oldsize), JEMALLOC_ALLOC_JUNK, - usize - oldsize); + memset((void *)((uintptr_t)extent_addr_get(extent) + oldsize), + JEMALLOC_ALLOC_JUNK, usize - oldsize); } + if (usize < extent_size_get(extent)) + extent_size_set(extent, usize); + + arena_chunk_ralloc_huge_expand(tsdn, arena, extent, oldsize); + return (false); } bool -huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, - size_t usize_min, size_t usize_max, bool zero) +huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, + size_t usize_max, bool zero) { - assert(s2u(oldsize) == oldsize); + assert(s2u(extent_size_get(extent)) == extent_size_get(extent)); /* The following should have been caught by callers. */ assert(usize_min > 0 && usize_max <= HUGE_MAXCLASS); + /* Both allocation sizes must be huge to avoid a move. */ + assert(extent_size_get(extent) >= chunksize && usize_max >= chunksize); - /* Both allocations must be huge to avoid a move. */ - if (oldsize < chunksize || usize_max < chunksize) - return (true); - - if (CHUNK_CEILING(usize_max) > CHUNK_CEILING(oldsize)) { + if (CHUNK_CEILING(usize_max) > CHUNK_CEILING(extent_size_get(extent))) { /* Attempt to expand the allocation in-place. */ - if (!huge_ralloc_no_move_expand(tsdn, extent, ptr, oldsize, - usize_max, zero)) { + if (!huge_ralloc_no_move_expand(tsdn, extent, usize_max, + zero)) { arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } /* Try again, this time with usize_min. */ if (usize_min < usize_max && CHUNK_CEILING(usize_min) > - CHUNK_CEILING(oldsize) && huge_ralloc_no_move_expand(tsdn, - extent, ptr, oldsize, usize_min, zero)) { + CHUNK_CEILING(extent_size_get(extent)) && + huge_ralloc_no_move_expand(tsdn, extent, usize_min, zero)) { arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } @@ -278,18 +294,18 @@ huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, * Avoid moving the allocation if the existing chunk size accommodates * the new size. */ - if (CHUNK_CEILING(oldsize) >= CHUNK_CEILING(usize_min) - && CHUNK_CEILING(oldsize) <= CHUNK_CEILING(usize_max)) { - huge_ralloc_no_move_similar(tsdn, extent, ptr, oldsize, - usize_min, usize_max, zero); + if (CHUNK_CEILING(extent_size_get(extent)) >= CHUNK_CEILING(usize_min) + && CHUNK_CEILING(extent_size_get(extent)) <= + CHUNK_CEILING(usize_max)) { + huge_ralloc_no_move_similar(tsdn, extent, usize_min, usize_max, + zero); arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } /* Attempt to shrink the allocation in-place. */ - if (CHUNK_CEILING(oldsize) > CHUNK_CEILING(usize_max)) { - if (!huge_ralloc_no_move_shrink(tsdn, extent, ptr, oldsize, - usize_max)) { + if (CHUNK_CEILING(extent_size_get(extent)) > CHUNK_CEILING(usize_max)) { + if (!huge_ralloc_no_move_shrink(tsdn, extent, usize_max)) { arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } @@ -308,22 +324,23 @@ huge_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, } void * -huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, - size_t oldsize, size_t usize, size_t alignment, bool zero, tcache_t *tcache) +huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, + size_t alignment, bool zero, tcache_t *tcache) { void *ret; size_t copysize; /* The following should have been caught by callers. */ assert(usize > 0 && usize <= HUGE_MAXCLASS); + /* Both allocation sizes must be huge to avoid a move. */ + assert(extent_size_get(extent) >= chunksize && usize >= chunksize); /* Try to avoid moving the allocation. */ - if (!huge_ralloc_no_move(tsdn, extent, ptr, oldsize, usize, usize, - zero)) - return (ptr); + if (!huge_ralloc_no_move(tsdn, extent, usize, usize, zero)) + return (extent_addr_get(extent)); /* - * usize and oldsize are different enough that we need to use a + * usize and old size are different enough that we need to use a * different size class. In that case, fall back to allocating new * space and copying. */ @@ -331,14 +348,16 @@ huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, if (ret == NULL) return (NULL); - copysize = (usize < oldsize) ? usize : oldsize; - memcpy(ret, ptr, copysize); - isdalloct(tsdn, extent, ptr, oldsize, tcache, true); + copysize = (usize < extent_size_get(extent)) ? usize : + extent_size_get(extent); + memcpy(ret, extent_addr_get(extent), copysize); + isdalloct(tsdn, extent, extent_addr_get(extent), + extent_size_get(extent), tcache, true); return (ret); } void -huge_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr) +huge_dalloc(tsdn_t *tsdn, extent_t *extent) { arena_t *arena; @@ -352,13 +371,13 @@ huge_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr) extent_size_get(extent)); arena_chunk_dalloc_huge(tsdn, extent_arena_get(extent), extent_addr_get(extent), extent_size_get(extent)); - idalloctm(tsdn, iealloc(tsdn, extent), extent, NULL, true, true); + arena_extent_dalloc(tsdn, arena, extent); arena_decay_tick(tsdn, arena); } size_t -huge_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) +huge_salloc(tsdn_t *tsdn, const extent_t *extent) { size_t size; arena_t *arena; @@ -372,13 +391,11 @@ huge_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) } prof_tctx_t * -huge_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) +huge_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent) { prof_tctx_t *tctx; arena_t *arena; - assert(extent == iealloc(tsdn, ptr)); - arena = extent_arena_get(extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); tctx = extent_prof_tctx_get(extent); @@ -388,13 +405,10 @@ huge_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) } void -huge_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, - prof_tctx_t *tctx) +huge_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx) { arena_t *arena; - assert(extent == iealloc(tsdn, ptr)); - arena = extent_arena_get(extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); extent_prof_tctx_set(extent, tctx); @@ -402,8 +416,8 @@ huge_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, } void -huge_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr) +huge_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent) { - huge_prof_tctx_set(tsdn, extent, ptr, (prof_tctx_t *)(uintptr_t)1U); + huge_prof_tctx_set(tsdn, extent, (prof_tctx_t *)(uintptr_t)1U); } -- GitLab From 6c944708222b3f1843ad224c88ffdafa02da1bb8 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 23 May 2016 14:56:35 -0700 Subject: [PATCH 032/544] Refactor chunk_dalloc_{cache,wrapper}() to take extent arguments. Rename arena_extent_[d]alloc() to extent_[d]alloc(). Move all chunk [de]registration responsibility into chunk.c. --- include/jemalloc/internal/arena.h | 7 +- include/jemalloc/internal/chunk.h | 8 +- include/jemalloc/internal/extent.h | 3 + include/jemalloc/internal/private_symbols.txt | 7 +- src/arena.c | 106 +++----------- src/chunk.c | 131 +++++++++--------- src/chunk_dss.c | 19 ++- src/chunk_mmap.c | 1 - src/extent.c | 26 ++++ src/huge.c | 37 ++--- 10 files changed, 147 insertions(+), 198 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 187b6256..4e5e3029 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -478,17 +478,14 @@ extent_t *arena_chunk_cache_alloc(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, bool *zero); void arena_chunk_cache_dalloc(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool committed); + chunk_hooks_t *chunk_hooks, extent_t *extent); void arena_chunk_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache); void arena_chunk_cache_maybe_remove(arena_t *arena, extent_t *extent, bool cache); -extent_t *arena_extent_alloc(tsdn_t *tsdn, arena_t *arena); -void arena_extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent); extent_t *arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero); -void arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, void *chunk, - size_t usize); +void arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, extent_t *extent); void arena_chunk_ralloc_huge_similar(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); void arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index 78cc4c2d..cef9fe03 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -52,9 +52,6 @@ chunk_hooks_t chunk_hooks_get(tsdn_t *tsdn, arena_t *arena); chunk_hooks_t chunk_hooks_set(tsdn_t *tsdn, arena_t *arena, const chunk_hooks_t *chunk_hooks); -bool chunk_register(tsdn_t *tsdn, const extent_t *extent); -void chunk_deregister(tsdn_t *tsdn, const extent_t *extent); -void chunk_reregister(tsdn_t *tsdn, const extent_t *extent); extent_t *chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, bool *zero); @@ -62,10 +59,9 @@ extent_t *chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit); void chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool committed); + chunk_hooks_t *chunk_hooks, extent_t *extent); void chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool zeroed, - bool committed); + chunk_hooks_t *chunk_hooks, extent_t *extent); bool chunk_commit_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t offset, size_t length); diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 82da8004..cfc908d8 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -62,6 +62,9 @@ typedef ph(extent_t) extent_heap_t; /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS +extent_t *extent_alloc(tsdn_t *tsdn, arena_t *arena); +void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent); + #ifdef JEMALLOC_JET typedef size_t (extent_size_quantize_t)(size_t); extern extent_size_quantize_t *extent_size_quantize_floor; diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 34a6816f..8998aed9 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -37,8 +37,6 @@ arena_decay_time_get arena_decay_time_set arena_dss_prec_get arena_dss_prec_set -arena_extent_alloc -arena_extent_dalloc arena_get arena_ichoose arena_init @@ -166,7 +164,6 @@ chunk_dalloc_cache chunk_dalloc_mmap chunk_dalloc_wrapper chunk_decommit_wrapper -chunk_deregister chunk_dss_boot chunk_dss_postfork_child chunk_dss_postfork_parent @@ -184,8 +181,6 @@ chunk_postfork_child chunk_postfork_parent chunk_prefork chunk_purge_wrapper -chunk_register -chunk_reregister chunk_split_wrapper chunks_rtree chunksize @@ -214,10 +209,12 @@ extent_active_get extent_active_set extent_addr_get extent_addr_set +extent_alloc extent_arena_get extent_arena_set extent_committed_get extent_committed_set +extent_dalloc extent_dirty_insert extent_dirty_remove extent_init diff --git a/src/arena.c b/src/arena.c index a610ec15..9eb08979 100644 --- a/src/arena.c +++ b/src/arena.c @@ -249,23 +249,22 @@ arena_chunk_cache_alloc(tsdn_t *tsdn, arena_t *arena, static void arena_chunk_cache_dalloc_locked(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool committed) + chunk_hooks_t *chunk_hooks, extent_t *extent) { malloc_mutex_assert_owner(tsdn, &arena->lock); - chunk_dalloc_cache(tsdn, arena, chunk_hooks, chunk, size, committed); + chunk_dalloc_cache(tsdn, arena, chunk_hooks, extent); arena_maybe_purge(tsdn, arena); } void arena_chunk_cache_dalloc(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *chunk, size_t size, bool committed) + chunk_hooks_t *chunk_hooks, extent_t *extent) { malloc_mutex_lock(tsdn, &arena->lock); - arena_chunk_cache_dalloc_locked(tsdn, arena, chunk_hooks, chunk, size, - committed); + arena_chunk_cache_dalloc_locked(tsdn, arena, chunk_hooks, extent); malloc_mutex_unlock(tsdn, &arena->lock); } @@ -582,33 +581,14 @@ arena_chunk_alloc_internal_hard(tsdn_t *tsdn, arena_t *arena, if (chunk_commit_wrapper(tsdn, arena, chunk_hooks, extent_addr_get(extent), extent_size_get(extent), 0, map_bias << LG_PAGE)) { - chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, - extent_addr_get(extent), extent_size_get(extent), - extent_zeroed_get(extent), - extent_committed_get(extent)); + chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, extent); extent = NULL; } } - if (extent != NULL) { + if (extent != NULL) extent_slab_set(extent, true); - if (chunk_register(tsdn, extent)) { - if (!*commit) { - /* Undo commit of header. */ - chunk_decommit_wrapper(tsdn, arena, chunk_hooks, - extent_addr_get(extent), - extent_size_get(extent), 0, map_bias << - LG_PAGE); - } - chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, - extent_addr_get(extent), extent_size_get(extent), - extent_zeroed_get(extent), - extent_committed_get(extent)); - extent = NULL; - } - } - malloc_mutex_lock(tsdn, &arena->lock); return (extent); @@ -625,13 +605,6 @@ arena_chunk_alloc_internal(tsdn_t *tsdn, arena_t *arena, bool *zero, chunksize, chunksize, zero); if (extent != NULL) { extent_slab_set(extent, true); - - if (chunk_register(tsdn, extent)) { - arena_chunk_cache_dalloc_locked(tsdn, arena, - &chunk_hooks, extent_addr_get(extent), - extent_size_get(extent), true); - return (NULL); - } *commit = true; } if (extent == NULL) { @@ -722,14 +695,13 @@ arena_chunk_alloc(tsdn_t *tsdn, arena_t *arena) static void arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { - bool committed; chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; - chunk_deregister(tsdn, extent); - - committed = (arena_mapbits_decommitted_get((arena_chunk_t *) - extent_addr_get(extent), map_bias) == 0); - if (!committed) { + extent_committed_set(extent, + (arena_mapbits_decommitted_get((arena_chunk_t *) + extent_addr_get(extent), map_bias) == 0)); + extent_slab_set(extent, false); + if (!extent_committed_get(extent)) { /* * Decommit the header. Mark the chunk as decommitted even if * header decommit fails, since treating a partially committed @@ -741,15 +713,12 @@ arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, extent_t *extent) map_bias << LG_PAGE); } - arena_chunk_cache_dalloc_locked(tsdn, arena, &chunk_hooks, - extent_addr_get(extent), extent_size_get(extent), committed); - if (config_stats) { arena->stats.mapped -= extent_size_get(extent); arena->stats.metadata_mapped -= (map_bias << LG_PAGE); } - arena_extent_dalloc(tsdn, arena, extent); + arena_chunk_cache_dalloc_locked(tsdn, arena, &chunk_hooks, extent); } static void @@ -852,32 +821,6 @@ arena_huge_ralloc_stats_update(arena_t *arena, size_t oldsize, size_t usize) arena_huge_malloc_stats_update(arena, usize); } -extent_t * -arena_extent_alloc(tsdn_t *tsdn, arena_t *arena) -{ - extent_t *extent; - - malloc_mutex_lock(tsdn, &arena->extent_cache_mtx); - extent = ql_last(&arena->extent_cache, ql_link); - if (extent == NULL) { - malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); - return (base_alloc(tsdn, sizeof(extent_t))); - } - ql_tail_remove(&arena->extent_cache, extent_t, ql_link); - malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); - return (extent); -} - -void -arena_extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) -{ - - malloc_mutex_lock(tsdn, &arena->extent_cache_mtx); - ql_elm_new(extent, ql_link); - ql_tail_insert(&arena->extent_cache, extent, ql_link); - malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); -} - static extent_t * arena_chunk_alloc_huge_hard(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, size_t usize, size_t alignment, bool *zero, @@ -931,21 +874,21 @@ arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, } void -arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, void *chunk, size_t usize) +arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; - size_t csize; - csize = CHUNK_CEILING(usize); malloc_mutex_lock(tsdn, &arena->lock); if (config_stats) { - arena_huge_dalloc_stats_update(arena, usize); - arena->stats.mapped -= usize; + arena_huge_dalloc_stats_update(arena, extent_size_get(extent)); + arena->stats.mapped -= extent_size_get(extent); } - arena_nactive_sub(arena, usize >> LG_PAGE); + arena_nactive_sub(arena, extent_size_get(extent) >> LG_PAGE); - arena_chunk_cache_dalloc_locked(tsdn, arena, &chunk_hooks, chunk, csize, - true); + if ((extent_size_get(extent) & chunksize_mask) != 0) + extent_size_set(extent, CHUNK_CEILING(extent_size_get(extent))); + + arena_chunk_cache_dalloc_locked(tsdn, arena, &chunk_hooks, extent); malloc_mutex_unlock(tsdn, &arena->lock); } @@ -1656,15 +1599,10 @@ arena_unstash_purged(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, rdelm_next = qr_next(rdelm, rd_link); if (rdelm == &chunkselm->rd) { extent_t *chunkselm_next = qr_next(chunkselm, cc_link); - void *addr = extent_addr_get(chunkselm); - size_t size = extent_size_get(chunkselm); - bool zeroed = extent_zeroed_get(chunkselm); - bool committed = extent_committed_get(chunkselm); extent_dirty_remove(chunkselm); - arena_extent_dalloc(tsdn, arena, chunkselm); + chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, + chunkselm); chunkselm = chunkselm_next; - chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, addr, - size, zeroed, committed); } else { extent_t *extent = iealloc(tsdn, rdelm); arena_chunk_t *chunk = diff --git a/src/chunk.c b/src/chunk.c index 4efba4a7..d0763212 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -51,7 +51,7 @@ const chunk_hooks_t chunk_hooks_default = { static void chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_heap_t extent_heaps[NPSIZES], bool cache, - void *chunk, size_t size, bool zeroed, bool committed); + extent_t *extent); /******************************************************************************/ @@ -203,7 +203,7 @@ extent_rtree_release(tsdn_t *tsdn, rtree_elm_t *elm_a, rtree_elm_t *elm_b) rtree_elm_release(tsdn, &chunks_rtree, elm_b); } -bool +static bool chunk_register(tsdn_t *tsdn, const extent_t *extent) { rtree_elm_t *elm_a, *elm_b; @@ -232,7 +232,7 @@ chunk_register(tsdn_t *tsdn, const extent_t *extent) return (false); } -void +static void chunk_deregister(tsdn_t *tsdn, const extent_t *extent) { rtree_elm_t *elm_a, *elm_b; @@ -249,15 +249,6 @@ chunk_deregister(tsdn_t *tsdn, const extent_t *extent) } } -void -chunk_reregister(tsdn_t *tsdn, const extent_t *extent) -{ - bool err; - - err = chunk_register(tsdn, extent); - assert(!err); -} - /* * Do first-best-fit chunk selection, i.e. select the lowest chunk that best * fits. @@ -282,7 +273,7 @@ chunk_first_best_fit(arena_t *arena, extent_heap_t extent_heaps[NPSIZES], static void chunk_leak(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, bool cache, - void *addr, size_t size) + extent_t *extent) { /* @@ -290,9 +281,11 @@ chunk_leak(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, bool cache, * that this is only a virtual memory leak. */ if (cache) { - chunk_purge_wrapper(tsdn, arena, chunk_hooks, addr, size, 0, - size); + chunk_purge_wrapper(tsdn, arena, chunk_hooks, + extent_addr_get(extent), extent_size_get(extent), 0, + extent_size_get(extent)); } + extent_dalloc(tsdn, arena, extent); } static extent_t * @@ -351,9 +344,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent = chunk_split_wrapper(tsdn, arena, chunk_hooks, lead, leadsize, size + trailsize); if (extent == NULL) { - chunk_leak(tsdn, arena, chunk_hooks, cache, - extent_addr_get(lead), extent_size_get(lead)); - arena_extent_dalloc(tsdn, arena, lead); + chunk_leak(tsdn, arena, chunk_hooks, cache, lead); malloc_mutex_unlock(tsdn, &arena->chunks_mtx); return (NULL); } @@ -366,9 +357,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *trail = chunk_split_wrapper(tsdn, arena, chunk_hooks, extent, size, trailsize); if (trail == NULL) { - chunk_leak(tsdn, arena, chunk_hooks, cache, - extent_addr_get(extent), extent_size_get(extent)); - arena_extent_dalloc(tsdn, arena, extent); + chunk_leak(tsdn, arena, chunk_hooks, cache, extent); malloc_mutex_unlock(tsdn, &arena->chunks_mtx); return (NULL); } @@ -381,9 +370,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_size_get(extent), 0, extent_size_get(extent), arena->ind)) { malloc_mutex_unlock(tsdn, &arena->chunks_mtx); chunk_record(tsdn, arena, chunk_hooks, extent_heaps, cache, - extent_addr_get(extent), extent_size_get(extent), - extent_zeroed_get(extent), extent_committed_get(extent)); - arena_extent_dalloc(tsdn, arena, extent); + extent); return (NULL); } @@ -529,7 +516,7 @@ chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, if (extent == NULL) { void *chunk; - extent = arena_extent_alloc(tsdn, arena); + extent = extent_alloc(tsdn, arena); if (extent == NULL) return (NULL); chunk = chunk_hooks->alloc(new_addr, size, alignment, @@ -540,6 +527,11 @@ chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, false); } + if (chunk_register(tsdn, extent)) { + chunk_leak(tsdn, arena, chunk_hooks, false, extent); + return (NULL); + } + return (extent); } @@ -590,29 +582,21 @@ chunk_try_coalesce(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, static void chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - extent_heap_t extent_heaps[NPSIZES], bool cache, void *chunk, size_t size, - bool zeroed, bool committed) + extent_heap_t extent_heaps[NPSIZES], bool cache, extent_t *extent) { - extent_t *extent, *prev, *next; + extent_t *prev, *next; - assert(!cache || !zeroed); + assert(!cache || !extent_zeroed_get(extent)); malloc_mutex_lock(tsdn, &arena->chunks_mtx); chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); - /* Create/initialize/insert extent. */ - extent = arena_extent_alloc(tsdn, arena); - if (extent == NULL) { - chunk_leak(tsdn, arena, chunk_hooks, cache, chunk, size); - goto label_return; - } - extent_init(extent, arena, chunk, size, false, !cache && zeroed, - committed, false); - if (chunk_register(tsdn, extent)) { - arena_extent_dalloc(tsdn, arena, extent); - chunk_leak(tsdn, arena, chunk_hooks, cache, chunk, size); - goto label_return; - } + assert((extent_size_get(extent) & chunksize_mask) == 0); + extent_active_set(extent, false); + extent_zeroed_set(extent, !cache && extent_zeroed_get(extent)); + extent_slab_set(extent, false); + + assert(chunk_lookup(tsdn, extent_addr_get(extent), true) == extent); extent_heaps_insert(extent_heaps, extent); arena_chunk_cache_maybe_insert(arena, extent, cache); @@ -632,22 +616,24 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_heaps, cache); } -label_return: malloc_mutex_unlock(tsdn, &arena->chunks_mtx); } void chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - void *chunk, size_t size, bool committed) + extent_t *extent) { - assert(chunk != NULL); - assert(CHUNK_ADDR2BASE(chunk) == chunk); - assert(size != 0); - assert((size & chunksize_mask) == 0); + assert(extent_addr_get(extent) != NULL); + assert(CHUNK_ADDR2BASE(extent_addr_get(extent)) == + extent_addr_get(extent)); + assert(extent_size_get(extent) != 0); + assert((extent_size_get(extent) & chunksize_mask) == 0); + + extent_zeroed_set(extent, false); chunk_record(tsdn, arena, chunk_hooks, arena->chunks_cached, true, - chunk, size, false, committed); + extent); } static bool @@ -662,30 +648,40 @@ chunk_dalloc_default(void *chunk, size_t size, bool committed, void chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - void *chunk, size_t size, bool zeroed, bool committed) + extent_t *extent) { - assert(chunk != NULL); - assert(CHUNK_ADDR2BASE(chunk) == chunk); - assert(size != 0); - assert((size & chunksize_mask) == 0); + assert(extent_addr_get(extent) != NULL); + assert(CHUNK_ADDR2BASE(extent_addr_get(extent)) == + extent_addr_get(extent)); + assert(extent_size_get(extent) != 0); + assert((extent_size_get(extent) & chunksize_mask) == 0); chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); /* Try to deallocate. */ - if (!chunk_hooks->dalloc(chunk, size, committed, arena->ind)) + if (!chunk_hooks->dalloc(extent_addr_get(extent), + extent_size_get(extent), extent_committed_get(extent), + arena->ind)) { + chunk_deregister(tsdn, extent); + extent_dalloc(tsdn, arena, extent); return; + } /* Try to decommit; purge if that fails. */ - if (committed) { - committed = chunk_hooks->decommit(chunk, size, 0, size, - arena->ind); + if (extent_committed_get(extent)) { + extent_committed_set(extent, + chunk_hooks->decommit(extent_addr_get(extent), + extent_size_get(extent), 0, extent_size_get(extent), + arena->ind)); } - zeroed = !committed || !chunk_hooks->purge(chunk, size, 0, size, - arena->ind); - chunk_record(tsdn, arena, chunk_hooks, arena->chunks_retained, false, - chunk, size, zeroed, committed); + extent_zeroed_set(extent, !extent_committed_get(extent) || + !chunk_hooks->purge(extent_addr_get(extent), + extent_size_get(extent), 0, extent_size_get(extent), arena->ind)); if (config_stats) - arena->stats.retained += size; + arena->stats.retained += extent_size_get(extent); + + chunk_record(tsdn, arena, chunk_hooks, arena->chunks_retained, false, + extent); } static bool @@ -771,7 +767,7 @@ chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); - trail = arena_extent_alloc(tsdn, arena); + trail = extent_alloc(tsdn, arena); if (trail == NULL) goto label_error_a; @@ -814,7 +810,7 @@ label_error_d: label_error_c: extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); label_error_b: - arena_extent_dalloc(tsdn, arena, trail); + extent_dalloc(tsdn, arena, trail); label_error_a: return (NULL); } @@ -841,6 +837,9 @@ chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, { rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; + assert((extent_size_get(a) & chunksize_mask) == 0); + assert((extent_size_get(b) & chunksize_mask) == 0); + chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); if (chunk_hooks->merge(extent_addr_get(a), extent_size_get(a), extent_addr_get(b), extent_size_get(b), extent_committed_get(a), @@ -871,7 +870,7 @@ chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a); extent_rtree_release(tsdn, a_elm_a, b_elm_b); - arena_extent_dalloc(tsdn, extent_arena_get(b), b); + extent_dalloc(tsdn, extent_arena_get(b), b); return (false); } diff --git a/src/chunk_dss.c b/src/chunk_dss.c index d42aeb0b..251f17b8 100644 --- a/src/chunk_dss.c +++ b/src/chunk_dss.c @@ -89,7 +89,8 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, * malloc. */ do { - void *ret, *cpad, *dss_next; + void *ret, *cpad_addr, *dss_next; + extent_t *cpad; size_t gap_size, cpad_size; intptr_t incr; /* Avoid an unnecessary system call. */ @@ -114,10 +115,19 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, * necessary to satisfy alignment. This space can be * recycled for later use. */ - cpad = (void *)((uintptr_t)dss_max + gap_size); + cpad_addr = (void *)((uintptr_t)dss_max + gap_size); ret = (void *)ALIGNMENT_CEILING((uintptr_t)dss_max, alignment); - cpad_size = (uintptr_t)ret - (uintptr_t)cpad; + cpad_size = (uintptr_t)ret - (uintptr_t)cpad_addr; + if (cpad_size != 0) { + cpad = extent_alloc(tsdn, arena); + if (cpad == NULL) { + malloc_mutex_unlock(tsdn, &dss_mtx); + return (NULL); + } + extent_init(cpad, arena, cpad_addr, cpad_size, + false, false, true, false); + } dss_next = (void *)((uintptr_t)ret + size); if ((uintptr_t)ret < (uintptr_t)dss_max || (uintptr_t)dss_next < (uintptr_t)dss_max) { @@ -135,8 +145,7 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; chunk_dalloc_wrapper(tsdn, arena, - &chunk_hooks, cpad, cpad_size, - false, true); + &chunk_hooks, cpad); } if (*zero) memset(ret, 0, size); diff --git a/src/chunk_mmap.c b/src/chunk_mmap.c index f95ae756..13708027 100644 --- a/src/chunk_mmap.c +++ b/src/chunk_mmap.c @@ -73,6 +73,5 @@ chunk_dalloc_mmap(void *chunk, size_t size) if (config_munmap) pages_unmap(chunk, size); - return (!config_munmap); } diff --git a/src/extent.c b/src/extent.c index 4757f750..d7f3b6cc 100644 --- a/src/extent.c +++ b/src/extent.c @@ -3,6 +3,32 @@ /******************************************************************************/ +extent_t * +extent_alloc(tsdn_t *tsdn, arena_t *arena) +{ + extent_t *extent; + + malloc_mutex_lock(tsdn, &arena->extent_cache_mtx); + extent = ql_last(&arena->extent_cache, ql_link); + if (extent == NULL) { + malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); + return (base_alloc(tsdn, sizeof(extent_t))); + } + ql_tail_remove(&arena->extent_cache, extent_t, ql_link); + malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); + return (extent); +} + +void +extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) +{ + + malloc_mutex_lock(tsdn, &arena->extent_cache_mtx); + ql_elm_new(extent, ql_link); + ql_tail_insert(&arena->extent_cache, extent, ql_link); + malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); +} + #ifdef JEMALLOC_JET #undef extent_size_quantize_floor #define extent_size_quantize_floor JEMALLOC_N(n_extent_size_quantize_floor) diff --git a/src/huge.c b/src/huge.c index fe4c6e00..880e4333 100644 --- a/src/huge.c +++ b/src/huge.c @@ -43,13 +43,6 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, if (usize < extent_size_get(extent)) extent_size_set(extent, usize); - if (chunk_register(tsdn, extent)) { - arena_chunk_dalloc_huge(tsdn, arena, extent_addr_get(extent), - usize); - arena_extent_dalloc(tsdn, arena, extent); - return (NULL); - } - /* Insert extent into huge. */ malloc_mutex_lock(tsdn, &arena->huge_mtx); ql_elm_new(extent, ql_link); @@ -57,10 +50,14 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, malloc_mutex_unlock(tsdn, &arena->huge_mtx); if (zero || (config_fill && unlikely(opt_zero))) { - if (!is_zeroed) - memset(extent_addr_get(extent), 0, usize); - } else if (config_fill && unlikely(opt_junk_alloc)) - memset(extent_addr_get(extent), JEMALLOC_ALLOC_JUNK, usize); + if (!is_zeroed) { + memset(extent_addr_get(extent), 0, + extent_size_get(extent)); + } + } else if (config_fill && unlikely(opt_junk_alloc)) { + memset(extent_addr_get(extent), JEMALLOC_ALLOC_JUNK, + extent_size_get(extent)); + } arena_decay_tick(tsdn, arena); return (extent_addr_get(extent)); @@ -126,11 +123,9 @@ huge_ralloc_no_move_similar(tsdn_t *tsdn, extent_t *extent, size_t usize_min, /* Update the size of the huge allocation. */ assert(extent_size_get(extent) != usize); - chunk_deregister(tsdn, extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); extent_size_set(extent, usize); malloc_mutex_unlock(tsdn, &arena->huge_mtx); - chunk_reregister(tsdn, extent); /* Update zeroed. */ extent_zeroed_set(extent, post_zeroed); @@ -174,11 +169,7 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) extent_size_get(trail)); } - arena_chunk_cache_dalloc(tsdn, arena, &chunk_hooks, - extent_addr_get(trail), extent_size_get(trail), - extent_committed_get(trail)); - - arena_extent_dalloc(tsdn, arena, trail); + arena_chunk_cache_dalloc(tsdn, arena, &chunk_hooks, trail); } /* Optionally fill trailing subchunk. */ @@ -233,10 +224,7 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, } if (chunk_merge_wrapper(tsdn, arena, &chunk_hooks, extent, trail)) { - arena_extent_dalloc(tsdn, arena, trail); - chunk_dalloc_wrapper(tsdn, arena, &chunk_hooks, - extent_addr_get(trail), extent_size_get(trail), - extent_zeroed_get(trail), extent_committed_get(trail)); + chunk_dalloc_wrapper(tsdn, arena, &chunk_hooks, trail); return (true); } @@ -362,16 +350,13 @@ huge_dalloc(tsdn_t *tsdn, extent_t *extent) arena_t *arena; arena = extent_arena_get(extent); - chunk_deregister(tsdn, extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); ql_remove(&arena->huge, extent, ql_link); malloc_mutex_unlock(tsdn, &arena->huge_mtx); huge_dalloc_junk(tsdn, extent_addr_get(extent), extent_size_get(extent)); - arena_chunk_dalloc_huge(tsdn, extent_arena_get(extent), - extent_addr_get(extent), extent_size_get(extent)); - arena_extent_dalloc(tsdn, arena, extent); + arena_chunk_dalloc_huge(tsdn, extent_arena_get(extent), extent); arena_decay_tick(tsdn, arena); } -- GitLab From 0eb6f08959700428f3ae0df1d8ab1cd7bd4c82bc Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 23 May 2016 15:04:40 -0700 Subject: [PATCH 033/544] Refactor chunk_[de]commit_wrapper() to take extent arguments. --- include/jemalloc/internal/chunk.h | 6 ++---- src/arena.c | 14 ++++++-------- src/chunk.c | 10 ++++++---- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index cef9fe03..085b43c0 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -63,11 +63,9 @@ void chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, void chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *extent); bool chunk_commit_wrapper(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t offset, - size_t length); + chunk_hooks_t *chunk_hooks, extent_t *extent, size_t offset, size_t length); bool chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t offset, - size_t length); + chunk_hooks_t *chunk_hooks, extent_t *extent, size_t offset, size_t length); bool chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t offset, size_t length); diff --git a/src/arena.c b/src/arena.c index 9eb08979..24793549 100644 --- a/src/arena.c +++ b/src/arena.c @@ -440,7 +440,7 @@ arena_run_split_large_helper(tsdn_t *tsdn, arena_t *arena, extent_t *extent, assert(need_pages > 0); if (flag_decommitted != 0 && chunk_commit_wrapper(tsdn, arena, - &arena->chunk_hooks, chunk, chunksize, run_ind << LG_PAGE, size)) + &arena->chunk_hooks, extent, run_ind << LG_PAGE, size)) return (true); if (remove) { @@ -523,7 +523,7 @@ arena_run_split_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, assert(need_pages > 0); if (flag_decommitted != 0 && chunk_commit_wrapper(tsdn, arena, - &arena->chunk_hooks, chunk, chunksize, run_ind << LG_PAGE, size)) + &arena->chunk_hooks, extent, run_ind << LG_PAGE, size)) return (true); arena_run_split_remove(arena, chunk, run_ind, flag_dirty, @@ -578,8 +578,7 @@ arena_chunk_alloc_internal_hard(tsdn_t *tsdn, arena_t *arena, chunksize, zero, commit); if (extent != NULL && !*commit) { /* Commit header. */ - if (chunk_commit_wrapper(tsdn, arena, chunk_hooks, - extent_addr_get(extent), extent_size_get(extent), 0, + if (chunk_commit_wrapper(tsdn, arena, chunk_hooks, extent, 0, map_bias << LG_PAGE)) { chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, extent); extent = NULL; @@ -708,8 +707,7 @@ arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, extent_t *extent) * chunk as committed has a high potential for causing later * access of decommitted memory. */ - chunk_decommit_wrapper(tsdn, arena, &chunk_hooks, - extent_addr_get(extent), extent_size_get(extent), 0, + chunk_decommit_wrapper(tsdn, arena, &chunk_hooks, extent, 0, map_bias << LG_PAGE); } @@ -1537,8 +1535,8 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert(!arena_mapbits_decommitted_get(chunk, pageind+npages-1)); decommitted = !chunk_decommit_wrapper(tsdn, arena, - chunk_hooks, chunk, chunksize, pageind << LG_PAGE, - npages << LG_PAGE); + chunk_hooks, extent, pageind << LG_PAGE, npages << + LG_PAGE); if (decommitted) { flag_unzeroed = 0; flags = CHUNK_MAP_DECOMMITTED; diff --git a/src/chunk.c b/src/chunk.c index d0763212..363ce8f7 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -695,11 +695,12 @@ chunk_commit_default(void *chunk, size_t size, size_t offset, size_t length, bool chunk_commit_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - void *chunk, size_t size, size_t offset, size_t length) + extent_t *extent, size_t offset, size_t length) { chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); - return (chunk_hooks->commit(chunk, size, offset, length, arena->ind)); + return (chunk_hooks->commit(extent_addr_get(extent), + extent_size_get(extent), offset, length, arena->ind)); } static bool @@ -713,11 +714,12 @@ chunk_decommit_default(void *chunk, size_t size, size_t offset, size_t length, bool chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - void *chunk, size_t size, size_t offset, size_t length) + extent_t *extent, size_t offset, size_t length) { chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); - return (chunk_hooks->decommit(chunk, size, offset, length, arena->ind)); + return (chunk_hooks->decommit(extent_addr_get(extent), + extent_size_get(extent), offset, length, arena->ind)); } static bool -- GitLab From 5c6be2bdd33d1eb9d544f46f128ba93d05a01492 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 23 May 2016 15:10:25 -0700 Subject: [PATCH 034/544] Refactor chunk_purge_wrapper() to take extent argument. --- include/jemalloc/internal/chunk.h | 3 +-- src/arena.c | 4 ++-- src/chunk.c | 9 +++++---- src/huge.c | 6 ++---- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index 085b43c0..5f5629eb 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -67,8 +67,7 @@ bool chunk_commit_wrapper(tsdn_t *tsdn, arena_t *arena, bool chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *extent, size_t offset, size_t length); bool chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *chunk, size_t size, size_t offset, - size_t length); + chunk_hooks_t *chunk_hooks, extent_t *extent, size_t offset, size_t length); extent_t *chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *extent, size_t size_a, size_t size_b); bool chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, diff --git a/src/arena.c b/src/arena.c index 24793549..de3024da 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1542,8 +1542,8 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, flags = CHUNK_MAP_DECOMMITTED; } else { flag_unzeroed = chunk_purge_wrapper(tsdn, arena, - chunk_hooks, chunk, chunksize, pageind << - LG_PAGE, run_size) ? CHUNK_MAP_UNZEROED : 0; + chunk_hooks, extent, pageind << LG_PAGE, + run_size) ? CHUNK_MAP_UNZEROED : 0; flags = flag_unzeroed; } arena_mapbits_large_set(chunk, pageind+npages-1, 0, diff --git a/src/chunk.c b/src/chunk.c index 363ce8f7..d20c2dfb 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -281,8 +281,7 @@ chunk_leak(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, bool cache, * that this is only a virtual memory leak. */ if (cache) { - chunk_purge_wrapper(tsdn, arena, chunk_hooks, - extent_addr_get(extent), extent_size_get(extent), 0, + chunk_purge_wrapper(tsdn, arena, chunk_hooks, extent, 0, extent_size_get(extent)); } extent_dalloc(tsdn, arena, extent); @@ -739,11 +738,13 @@ chunk_purge_default(void *chunk, size_t size, size_t offset, size_t length, bool chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - void *chunk, size_t size, size_t offset, size_t length) + extent_t *extent, size_t offset, size_t length) { chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); - return (chunk_hooks->purge(chunk, size, offset, length, arena->ind)); + return (chunk_hooks->purge(extent_addr_get(extent), + CHUNK_CEILING(extent_size_get(extent)), offset, length, + arena->ind)); } static bool diff --git a/src/huge.c b/src/huge.c index 880e4333..70383144 100644 --- a/src/huge.c +++ b/src/huge.c @@ -115,8 +115,7 @@ huge_ralloc_no_move_similar(tsdn_t *tsdn, extent_t *extent, size_t usize_min, post_zeroed = false; } else { post_zeroed = !chunk_purge_wrapper(tsdn, arena, - &chunk_hooks, extent_addr_get(extent), - CHUNK_CEILING(oldsize), usize, sdiff); + &chunk_hooks, extent, usize, sdiff); } } else post_zeroed = pre_zeroed; @@ -183,8 +182,7 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) post_zeroed = false; } else { post_zeroed = !chunk_purge_wrapper(tsdn, arena, - &chunk_hooks, extent_addr_get(extent), - CHUNK_CEILING(usize), usize, sdiff); + &chunk_hooks, extent, usize, sdiff); if (config_fill && unlikely(opt_zero) && !post_zeroed) { memset((void *) -- GitLab From 47613afc34750016fdc95aaaee37c3be11f272b9 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 24 May 2016 18:22:10 -0700 Subject: [PATCH 035/544] Convert rtree from per chunk to per page. Refactor [de]registration to maintain interior rtree entries for slabs. --- include/jemalloc/internal/chunk.h | 4 +- include/jemalloc/internal/extent.h | 2 - src/arena.c | 28 +++----- src/chunk.c | 108 +++++++++++++++++++++-------- src/huge.c | 4 +- 5 files changed, 94 insertions(+), 52 deletions(-) diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index 5f5629eb..d1137387 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -54,10 +54,10 @@ chunk_hooks_t chunk_hooks_set(tsdn_t *tsdn, arena_t *arena, extent_t *chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, - bool *zero); + bool *zero, bool slab); extent_t *chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, - bool *zero, bool *commit); + bool *zero, bool *commit, bool slab); void chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *extent); void chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index cfc908d8..775f89bb 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -146,7 +146,6 @@ JEMALLOC_INLINE bool extent_retained_get(const extent_t *extent) { - assert(!extent->e_slab); return (qr_next(&extent->rd, rd_link) == &extent->rd); } @@ -161,7 +160,6 @@ JEMALLOC_INLINE bool extent_committed_get(const extent_t *extent) { - assert(!extent->e_slab); return (extent->e_committed); } diff --git a/src/arena.c b/src/arena.c index de3024da..17cf973a 100644 --- a/src/arena.c +++ b/src/arena.c @@ -223,13 +223,13 @@ arena_chunk_dirty_npages(const extent_t *extent) static extent_t * arena_chunk_cache_alloc_locked(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, - bool *zero) + bool *zero, bool slab) { malloc_mutex_assert_owner(tsdn, &arena->lock); return (chunk_alloc_cache(tsdn, arena, chunk_hooks, new_addr, size, - alignment, zero)); + alignment, zero, slab)); } extent_t * @@ -241,7 +241,7 @@ arena_chunk_cache_alloc(tsdn_t *tsdn, arena_t *arena, malloc_mutex_lock(tsdn, &arena->lock); extent = arena_chunk_cache_alloc_locked(tsdn, arena, chunk_hooks, - new_addr, size, alignment, zero); + new_addr, size, alignment, zero, false); malloc_mutex_unlock(tsdn, &arena->lock); return (extent); @@ -575,7 +575,7 @@ arena_chunk_alloc_internal_hard(tsdn_t *tsdn, arena_t *arena, malloc_mutex_unlock(tsdn, &arena->lock); extent = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, chunksize, - chunksize, zero, commit); + chunksize, zero, commit, true); if (extent != NULL && !*commit) { /* Commit header. */ if (chunk_commit_wrapper(tsdn, arena, chunk_hooks, extent, 0, @@ -585,9 +585,6 @@ arena_chunk_alloc_internal_hard(tsdn_t *tsdn, arena_t *arena, } } - if (extent != NULL) - extent_slab_set(extent, true); - malloc_mutex_lock(tsdn, &arena->lock); return (extent); @@ -601,11 +598,9 @@ arena_chunk_alloc_internal(tsdn_t *tsdn, arena_t *arena, bool *zero, chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; extent = arena_chunk_cache_alloc_locked(tsdn, arena, &chunk_hooks, NULL, - chunksize, chunksize, zero); - if (extent != NULL) { - extent_slab_set(extent, true); + chunksize, chunksize, zero, true); + if (extent != NULL) *commit = true; - } if (extent == NULL) { extent = arena_chunk_alloc_internal_hard(tsdn, arena, &chunk_hooks, zero, commit); @@ -699,7 +694,6 @@ arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, extent_t *extent) extent_committed_set(extent, (arena_mapbits_decommitted_get((arena_chunk_t *) extent_addr_get(extent), map_bias) == 0)); - extent_slab_set(extent, false); if (!extent_committed_get(extent)) { /* * Decommit the header. Mark the chunk as decommitted even if @@ -828,7 +822,7 @@ arena_chunk_alloc_huge_hard(tsdn_t *tsdn, arena_t *arena, bool commit = true; extent = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, csize, - alignment, zero, &commit); + alignment, zero, &commit, false); if (extent == NULL) { /* Revert optimistic stats updates. */ malloc_mutex_lock(tsdn, &arena->lock); @@ -861,7 +855,7 @@ arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, arena_nactive_add(arena, usize >> LG_PAGE); extent = arena_chunk_cache_alloc_locked(tsdn, arena, &chunk_hooks, NULL, - csize, alignment, zero); + csize, alignment, zero, false); malloc_mutex_unlock(tsdn, &arena->lock); if (extent == NULL) { extent = arena_chunk_alloc_huge_hard(tsdn, arena, &chunk_hooks, @@ -1429,7 +1423,8 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, zero = false; extent = arena_chunk_cache_alloc_locked(tsdn, arena, chunk_hooks, extent_addr_get(chunkselm), - extent_size_get(chunkselm), chunksize, &zero); + extent_size_get(chunkselm), chunksize, &zero, + false); assert(extent == chunkselm); assert(zero == extent_zeroed_get(chunkselm)); extent_dirty_insert(chunkselm, purge_runs_sentinel, @@ -2561,9 +2556,8 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, zero); } else if (likely(alignment <= chunksize)) ret = huge_malloc(tsdn, arena, usize, zero); - else { + else ret = huge_palloc(tsdn, arena, usize, alignment, zero); - } } return (ret); } diff --git a/src/chunk.c b/src/chunk.c index d20c2dfb..2ec12b4b 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -168,10 +168,9 @@ extent_rtree_acquire(tsdn_t *tsdn, const extent_t *extent, bool dependent, return (true); assert(*r_elm_a != NULL); - if (extent_size_get(extent) > chunksize) { + if (extent_size_get(extent) > PAGE) { uintptr_t last = - (CHUNK_CEILING((uintptr_t)extent_past_get(extent) - - chunksize)); + (CHUNK_CEILING((uintptr_t)extent_past_get(extent)) - PAGE); *r_elm_b = rtree_elm_acquire(tsdn, &chunks_rtree, last, dependent, init_missing); @@ -203,6 +202,20 @@ extent_rtree_release(tsdn_t *tsdn, rtree_elm_t *elm_a, rtree_elm_t *elm_b) rtree_elm_release(tsdn, &chunks_rtree, elm_b); } +static void +chunk_interior_register(tsdn_t *tsdn, const extent_t *extent) +{ + size_t i; + + assert(extent_slab_get(extent)); + + for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) { + rtree_write(tsdn, &chunks_rtree, + (uintptr_t)extent_addr_get(extent) + (uintptr_t)(i << + LG_PAGE), extent); + } +} + static bool chunk_register(tsdn_t *tsdn, const extent_t *extent) { @@ -211,6 +224,8 @@ chunk_register(tsdn_t *tsdn, const extent_t *extent) if (extent_rtree_acquire(tsdn, extent, false, true, &elm_a, &elm_b)) return (true); extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent); + if (extent_slab_get(extent)) + chunk_interior_register(tsdn, extent); extent_rtree_release(tsdn, elm_a, elm_b); if (config_prof && opt_prof && extent_active_get(extent)) { @@ -232,6 +247,20 @@ chunk_register(tsdn_t *tsdn, const extent_t *extent) return (false); } +static void +chunk_interior_deregister(tsdn_t *tsdn, const extent_t *extent) +{ + size_t i; + + assert(extent_slab_get(extent)); + + for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) { + rtree_clear(tsdn, &chunks_rtree, + (uintptr_t)extent_addr_get(extent) + (uintptr_t)(i << + LG_PAGE)); + } +} + static void chunk_deregister(tsdn_t *tsdn, const extent_t *extent) { @@ -239,6 +268,8 @@ chunk_deregister(tsdn_t *tsdn, const extent_t *extent) extent_rtree_acquire(tsdn, extent, true, false, &elm_a, &elm_b); extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL); + if (extent_slab_get(extent)) + chunk_interior_deregister(tsdn, extent); extent_rtree_release(tsdn, elm_a, elm_b); if (config_prof && opt_prof && extent_active_get(extent)) { @@ -290,7 +321,7 @@ chunk_leak(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, bool cache, static extent_t * chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_heap_t extent_heaps[NPSIZES], bool cache, void *new_addr, - size_t size, size_t alignment, bool *zero, bool *commit) + size_t size, size_t alignment, bool *zero, bool *commit, bool slab) { extent_t *extent; size_t alloc_size, leadsize, trailsize; @@ -374,6 +405,10 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } extent_active_set(extent, true); + if (slab) { + extent_slab_set(extent, slab); + chunk_interior_register(tsdn, extent); + } malloc_mutex_unlock(tsdn, &arena->chunks_mtx); @@ -431,7 +466,7 @@ chunk_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, extent_t * chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - void *new_addr, size_t size, size_t alignment, bool *zero) + void *new_addr, size_t size, size_t alignment, bool *zero, bool slab) { extent_t *extent; bool commit; @@ -443,7 +478,7 @@ chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, commit = true; extent = chunk_recycle(tsdn, arena, chunk_hooks, arena->chunks_cached, - true, new_addr, size, alignment, zero, &commit); + true, new_addr, size, alignment, zero, &commit, slab); if (extent == NULL) return (NULL); assert(commit); @@ -484,7 +519,8 @@ chunk_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero, static extent_t * chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit) + void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit, + bool slab) { extent_t *extent; @@ -494,7 +530,7 @@ chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert((alignment & chunksize_mask) == 0); extent = chunk_recycle(tsdn, arena, chunk_hooks, arena->chunks_retained, - false, new_addr, size, alignment, zero, commit); + false, new_addr, size, alignment, zero, commit, slab); if (config_stats && extent != NULL) arena->stats.retained -= size; @@ -502,33 +538,44 @@ chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, return (extent); } +static extent_t * +chunk_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, + chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, + bool *zero, bool *commit, bool slab) +{ + extent_t *extent; + void *addr; + + extent = extent_alloc(tsdn, arena); + if (extent == NULL) + return (NULL); + addr = chunk_hooks->alloc(new_addr, size, alignment, zero, commit, + arena->ind); + if (addr == NULL) + return (NULL); + extent_init(extent, arena, addr, size, true, zero, commit, slab); + if (chunk_register(tsdn, extent)) { + chunk_leak(tsdn, arena, chunk_hooks, false, extent); + return (NULL); + } + + return (extent); +} + extent_t * chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit) + void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit, + bool slab) { extent_t *extent; chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); extent = chunk_alloc_retained(tsdn, arena, chunk_hooks, new_addr, size, - alignment, zero, commit); + alignment, zero, commit, slab); if (extent == NULL) { - void *chunk; - - extent = extent_alloc(tsdn, arena); - if (extent == NULL) - return (NULL); - chunk = chunk_hooks->alloc(new_addr, size, alignment, - zero, commit, arena->ind); - if (chunk == NULL) - return (NULL); - extent_init(extent, arena, chunk, size, true, zero, commit, - false); - } - - if (chunk_register(tsdn, extent)) { - chunk_leak(tsdn, arena, chunk_hooks, false, extent); - return (NULL); + extent = chunk_alloc_wrapper_hard(tsdn, arena, chunk_hooks, + new_addr, size, alignment, zero, commit, slab); } return (extent); @@ -593,7 +640,10 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert((extent_size_get(extent) & chunksize_mask) == 0); extent_active_set(extent, false); extent_zeroed_set(extent, !cache && extent_zeroed_get(extent)); - extent_slab_set(extent, false); + if (extent_slab_get(extent)) { + chunk_interior_deregister(tsdn, extent); + extent_slab_set(extent, false); + } assert(chunk_lookup(tsdn, extent_addr_get(extent), true) == extent); extent_heaps_insert(extent_heaps, extent); @@ -609,7 +659,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, /* Try to coalesce backward. */ prev = rtree_read(tsdn, &chunks_rtree, - (uintptr_t)extent_addr_get(extent) - chunksize, false); + (uintptr_t)extent_addr_get(extent) - PAGE, false); if (prev != NULL) { chunk_try_coalesce(tsdn, arena, chunk_hooks, prev, extent, extent_heaps, cache); @@ -914,7 +964,7 @@ chunk_boot(void) if (have_dss && chunk_dss_boot()) return (true); if (rtree_new(&chunks_rtree, (unsigned)((ZU(1) << (LG_SIZEOF_PTR+3)) - - opt_lg_chunk))) + LG_PAGE))) return (true); return (false); diff --git a/src/huge.c b/src/huge.c index 70383144..31d3bcae 100644 --- a/src/huge.c +++ b/src/huge.c @@ -216,8 +216,8 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, cdiff, chunksize, &is_zeroed_chunk)) == NULL) { bool commit = true; if ((trail = chunk_alloc_wrapper(tsdn, arena, &chunk_hooks, - nchunk, cdiff, chunksize, &is_zeroed_chunk, &commit)) == - NULL) + nchunk, cdiff, chunksize, &is_zeroed_chunk, &commit, false)) + == NULL) return (true); } -- GitLab From 760bf11b23b96a9c26e48ca51df9644bb382892f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 24 May 2016 20:56:46 -0700 Subject: [PATCH 036/544] Add extent_dirty_[gs]et(). --- include/jemalloc/internal/extent.h | 25 +++++++++++++++++-- include/jemalloc/internal/private_symbols.txt | 2 ++ src/arena.c | 2 +- src/base.c | 2 +- src/chunk.c | 11 ++++---- src/chunk_dss.c | 2 +- 6 files changed, 34 insertions(+), 10 deletions(-) diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 775f89bb..a286fa9a 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -21,6 +21,9 @@ struct extent_s { /* True if extent is active (in use). */ bool e_active; + /* True if extent is dirty (touched). */ + bool e_dirty; + /* * The zeroed flag is used by chunk recycling code to track whether * memory is zero-filled. @@ -86,6 +89,7 @@ void *extent_addr_get(const extent_t *extent); size_t extent_size_get(const extent_t *extent); void *extent_past_get(const extent_t *extent); bool extent_active_get(const extent_t *extent); +bool extent_dirty_get(const extent_t *extent); bool extent_retained_get(const extent_t *extent); bool extent_zeroed_get(const extent_t *extent); bool extent_committed_get(const extent_t *extent); @@ -95,12 +99,14 @@ void extent_arena_set(extent_t *extent, arena_t *arena); void extent_addr_set(extent_t *extent, void *addr); void extent_size_set(extent_t *extent, size_t size); void extent_active_set(extent_t *extent, bool active); +void extent_dirty_set(extent_t *extent, bool dirty); void extent_zeroed_set(extent_t *extent, bool zeroed); void extent_committed_set(extent_t *extent, bool committed); void extent_slab_set(extent_t *extent, bool slab); void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx); void extent_init(extent_t *extent, arena_t *arena, void *addr, - size_t size, bool active, bool zeroed, bool committed, bool slab); + size_t size, bool active, bool dirty, bool zeroed, bool committed, + bool slab); void extent_dirty_insert(extent_t *extent, arena_runs_dirty_link_t *runs_dirty, extent_t *chunks_dirty); void extent_dirty_remove(extent_t *extent); @@ -142,6 +148,13 @@ extent_active_get(const extent_t *extent) return (extent->e_active); } +JEMALLOC_INLINE bool +extent_dirty_get(const extent_t *extent) +{ + + return (extent->e_dirty); +} + JEMALLOC_INLINE bool extent_retained_get(const extent_t *extent) { @@ -205,6 +218,13 @@ extent_active_set(extent_t *extent, bool active) extent->e_active = active; } +JEMALLOC_INLINE void +extent_dirty_set(extent_t *extent, bool dirty) +{ + + extent->e_dirty = dirty; +} + JEMALLOC_INLINE void extent_zeroed_set(extent_t *extent, bool zeroed) { @@ -235,13 +255,14 @@ extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) JEMALLOC_INLINE void extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, - bool active, bool zeroed, bool committed, bool slab) + bool active, bool dirty, bool zeroed, bool committed, bool slab) { extent_arena_set(extent, arena); extent_addr_set(extent, addr); extent_size_set(extent, size); extent_active_set(extent, active); + extent_dirty_set(extent, dirty); extent_zeroed_set(extent, zeroed); extent_committed_set(extent, committed); extent_slab_set(extent, slab); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 8998aed9..02bef63e 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -215,8 +215,10 @@ extent_arena_set extent_committed_get extent_committed_set extent_dalloc +extent_dirty_get extent_dirty_insert extent_dirty_remove +extent_dirty_set extent_init extent_past_get extent_prof_tctx_get diff --git a/src/arena.c b/src/arena.c index 17cf973a..a08a3245 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1644,7 +1644,7 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) arena->lg_dirty_mult) < arena->ndirty || ndirty_limit == 0); qr_new(&purge_runs_sentinel, rd_link); - extent_init(&purge_chunks_sentinel, arena, NULL, 0, false, false, + extent_init(&purge_chunks_sentinel, arena, NULL, 0, false, false, false, false, false); npurge = arena_stash_dirty(tsdn, arena, &chunk_hooks, ndirty_limit, diff --git a/src/base.c b/src/base.c index 518f966c..225f522b 100644 --- a/src/base.c +++ b/src/base.c @@ -74,7 +74,7 @@ base_chunk_alloc(tsdn_t *tsdn, size_t minsize) base_resident += PAGE_CEILING(nsize); } } - extent_init(extent, NULL, addr, csize, true, true, true, false); + extent_init(extent, NULL, addr, csize, true, false, true, true, false); return (extent); } diff --git a/src/chunk.c b/src/chunk.c index 2ec12b4b..c1094ff4 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -553,7 +553,7 @@ chunk_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, arena->ind); if (addr == NULL) return (NULL); - extent_init(extent, arena, addr, size, true, zero, commit, slab); + extent_init(extent, arena, addr, size, true, false, zero, commit, slab); if (chunk_register(tsdn, extent)) { chunk_leak(tsdn, arena, chunk_hooks, false, extent); return (NULL); @@ -828,8 +828,9 @@ chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t lead; extent_init(&lead, arena, extent_addr_get(extent), size_a, - extent_active_get(extent), extent_zeroed_get(extent), - extent_committed_get(extent), extent_slab_get(extent)); + extent_active_get(extent), extent_dirty_get(extent), + extent_zeroed_get(extent), extent_committed_get(extent), + extent_slab_get(extent)); if (extent_rtree_acquire(tsdn, &lead, false, true, &lead_elm_a, &lead_elm_b)) @@ -838,8 +839,8 @@ chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_init(trail, arena, (void *)((uintptr_t)extent_addr_get(extent) + size_a), CHUNK_CEILING(size_b), extent_active_get(extent), - extent_zeroed_get(extent), extent_committed_get(extent), - extent_slab_get(extent)); + extent_dirty_get(extent), extent_zeroed_get(extent), + extent_committed_get(extent), extent_slab_get(extent)); if (extent_rtree_acquire(tsdn, trail, false, true, &trail_elm_a, &trail_elm_b)) goto label_error_c; diff --git a/src/chunk_dss.c b/src/chunk_dss.c index 251f17b8..6b90c53e 100644 --- a/src/chunk_dss.c +++ b/src/chunk_dss.c @@ -126,7 +126,7 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, return (NULL); } extent_init(cpad, arena, cpad_addr, cpad_size, - false, false, true, false); + false, true, false, true, false); } dss_next = (void *)((uintptr_t)ret + size); if ((uintptr_t)ret < (uintptr_t)dss_max || -- GitLab From 23c52c895f96c1dc2492855438fde04d9a10869e Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 24 May 2016 21:13:36 -0700 Subject: [PATCH 037/544] Make extent_prof_tctx_[gs]et() atomic. --- include/jemalloc/internal/extent.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index a286fa9a..c3bdacb4 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -45,7 +45,10 @@ struct extent_s { bool e_slab; /* Profile counters, used for huge objects. */ - prof_tctx_t *e_prof_tctx; + union { + void *e_prof_tctx_pun; + prof_tctx_t *e_prof_tctx; + }; /* Linkage for arena's runs_dirty and chunks_cache rings. */ arena_runs_dirty_link_t rd; @@ -187,7 +190,8 @@ JEMALLOC_INLINE prof_tctx_t * extent_prof_tctx_get(const extent_t *extent) { - return (extent->e_prof_tctx); + return ((prof_tctx_t *)atomic_read_p( + &((extent_t *)extent)->e_prof_tctx_pun)); } JEMALLOC_INLINE void @@ -250,7 +254,7 @@ JEMALLOC_INLINE void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) { - extent->e_prof_tctx = tctx; + atomic_write_p(&extent->e_prof_tctx_pun, tctx); } JEMALLOC_INLINE void -- GitLab From 741967e79d10c94005b0f4065586c1b488a21fde Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 25 May 2016 16:21:37 -0700 Subject: [PATCH 038/544] Remove CHUNK_ADDR2BASE() and CHUNK_ADDR2OFFSET(). --- include/jemalloc/internal/arena.h | 112 ++------ include/jemalloc/internal/chunk.h | 8 - include/jemalloc/internal/private_symbols.txt | 1 - src/arena.c | 243 ++++++++++++------ src/chunk.c | 5 - src/chunk_dss.c | 4 +- 6 files changed, 190 insertions(+), 183 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 4e5e3029..fac6fd34 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -580,10 +580,14 @@ arena_chunk_map_misc_t *arena_miscelm_get_mutable(arena_chunk_t *chunk, size_t pageind); const arena_chunk_map_misc_t *arena_miscelm_get_const( const arena_chunk_t *chunk, size_t pageind); -size_t arena_miscelm_to_pageind(const arena_chunk_map_misc_t *miscelm); -void *arena_miscelm_to_rpages(const arena_chunk_map_misc_t *miscelm); -arena_chunk_map_misc_t *arena_rd_to_miscelm(arena_runs_dirty_link_t *rd); -arena_chunk_map_misc_t *arena_run_to_miscelm(arena_run_t *run); +size_t arena_miscelm_to_pageind(const extent_t *extent, + const arena_chunk_map_misc_t *miscelm); +void *arena_miscelm_to_rpages(const extent_t *extent, + const arena_chunk_map_misc_t *miscelm); +arena_chunk_map_misc_t *arena_rd_to_miscelm(const extent_t *extent, + arena_runs_dirty_link_t *rd); +arena_chunk_map_misc_t *arena_run_to_miscelm(const extent_t *extent, + arena_run_t *run); size_t *arena_mapbitsp_get_mutable(arena_chunk_t *chunk, size_t pageind); const size_t *arena_mapbitsp_get_const(const arena_chunk_t *chunk, size_t pageind); @@ -626,8 +630,6 @@ bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes); szind_t arena_ptr_small_binind_get(tsdn_t *tsdn, const void *ptr, size_t mapbits); szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin); -size_t arena_run_regind(arena_run_t *run, const arena_bin_info_t *bin_info, - const void *ptr); prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr); void arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, @@ -685,9 +687,10 @@ arena_miscelm_get_const(const arena_chunk_t *chunk, size_t pageind) } JEMALLOC_ALWAYS_INLINE size_t -arena_miscelm_to_pageind(const arena_chunk_map_misc_t *miscelm) +arena_miscelm_to_pageind(const extent_t *extent, + const arena_chunk_map_misc_t *miscelm) { - arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(miscelm); + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); size_t pageind = ((uintptr_t)miscelm - ((uintptr_t)chunk + map_misc_offset)) / sizeof(arena_chunk_map_misc_t) + map_bias; @@ -698,34 +701,35 @@ arena_miscelm_to_pageind(const arena_chunk_map_misc_t *miscelm) } JEMALLOC_ALWAYS_INLINE void * -arena_miscelm_to_rpages(const arena_chunk_map_misc_t *miscelm) +arena_miscelm_to_rpages(const extent_t *extent, + const arena_chunk_map_misc_t *miscelm) { - arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(miscelm); - size_t pageind = arena_miscelm_to_pageind(miscelm); + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + size_t pageind = arena_miscelm_to_pageind(extent, miscelm); return ((void *)((uintptr_t)chunk + (pageind << LG_PAGE))); } JEMALLOC_ALWAYS_INLINE arena_chunk_map_misc_t * -arena_rd_to_miscelm(arena_runs_dirty_link_t *rd) +arena_rd_to_miscelm(const extent_t *extent, arena_runs_dirty_link_t *rd) { arena_chunk_map_misc_t *miscelm = (arena_chunk_map_misc_t *)((uintptr_t)rd - offsetof(arena_chunk_map_misc_t, rd)); - assert(arena_miscelm_to_pageind(miscelm) >= map_bias); - assert(arena_miscelm_to_pageind(miscelm) < chunk_npages); + assert(arena_miscelm_to_pageind(extent, miscelm) >= map_bias); + assert(arena_miscelm_to_pageind(extent, miscelm) < chunk_npages); return (miscelm); } JEMALLOC_ALWAYS_INLINE arena_chunk_map_misc_t * -arena_run_to_miscelm(arena_run_t *run) +arena_run_to_miscelm(const extent_t *extent, arena_run_t *run) { arena_chunk_map_misc_t *miscelm = (arena_chunk_map_misc_t *)((uintptr_t)run - offsetof(arena_chunk_map_misc_t, run)); - assert(arena_miscelm_to_pageind(miscelm) >= map_bias); - assert(arena_miscelm_to_pageind(miscelm) < chunk_npages); + assert(arena_miscelm_to_pageind(extent, miscelm) >= map_bias); + assert(arena_miscelm_to_pageind(extent, miscelm) < chunk_npages); return (miscelm); } @@ -1079,7 +1083,7 @@ arena_ptr_small_binind_get(tsdn_t *tsdn, const void *ptr, size_t mapbits) actual_binind = (szind_t)(bin - arena->bins); assert(run_binind == actual_binind); bin_info = &arena_bin_info[actual_binind]; - rpages = arena_miscelm_to_rpages(miscelm); + rpages = arena_miscelm_to_rpages(extent, miscelm); assert(((uintptr_t)ptr - (uintptr_t)rpages) % bin_info->reg_size == 0); } @@ -1095,78 +1099,6 @@ arena_bin_index(arena_t *arena, arena_bin_t *bin) return (binind); } -JEMALLOC_INLINE size_t -arena_run_regind(arena_run_t *run, const arena_bin_info_t *bin_info, - const void *ptr) -{ - size_t diff, interval, shift, regind; - arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(run); - void *rpages = arena_miscelm_to_rpages(miscelm); - - /* - * Freeing a pointer lower than region zero can cause assertion - * failure. - */ - assert((uintptr_t)ptr >= (uintptr_t)rpages); - - /* - * Avoid doing division with a variable divisor if possible. Using - * actual division here can reduce allocator throughput by over 20%! - */ - diff = (size_t)((uintptr_t)ptr - (uintptr_t)rpages); - - /* Rescale (factor powers of 2 out of the numerator and denominator). */ - interval = bin_info->reg_size; - shift = ffs_zu(interval) - 1; - diff >>= shift; - interval >>= shift; - - if (interval == 1) { - /* The divisor was a power of 2. */ - regind = diff; - } else { - /* - * To divide by a number D that is not a power of two we - * multiply by (2^21 / D) and then right shift by 21 positions. - * - * X / D - * - * becomes - * - * (X * interval_invs[D - 3]) >> SIZE_INV_SHIFT - * - * We can omit the first three elements, because we never - * divide by 0, and 1 and 2 are both powers of two, which are - * handled above. - */ -#define SIZE_INV_SHIFT ((sizeof(size_t) << 3) - LG_RUN_MAXREGS) -#define SIZE_INV(s) (((ZU(1) << SIZE_INV_SHIFT) / (s)) + 1) - static const size_t interval_invs[] = { - SIZE_INV(3), - SIZE_INV(4), SIZE_INV(5), SIZE_INV(6), SIZE_INV(7), - SIZE_INV(8), SIZE_INV(9), SIZE_INV(10), SIZE_INV(11), - SIZE_INV(12), SIZE_INV(13), SIZE_INV(14), SIZE_INV(15), - SIZE_INV(16), SIZE_INV(17), SIZE_INV(18), SIZE_INV(19), - SIZE_INV(20), SIZE_INV(21), SIZE_INV(22), SIZE_INV(23), - SIZE_INV(24), SIZE_INV(25), SIZE_INV(26), SIZE_INV(27), - SIZE_INV(28), SIZE_INV(29), SIZE_INV(30), SIZE_INV(31) - }; - - if (likely(interval <= ((sizeof(interval_invs) / sizeof(size_t)) - + 2))) { - regind = (diff * interval_invs[interval - 3]) >> - SIZE_INV_SHIFT; - } else - regind = diff / interval; -#undef SIZE_INV -#undef SIZE_INV_SHIFT - } - assert(diff == regind * interval); - assert(regind < bin_info->nregs); - - return (regind); -} - JEMALLOC_INLINE prof_tctx_t * arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index d1137387..0c0084b0 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -7,14 +7,6 @@ */ #define LG_CHUNK_DEFAULT 21 -/* Return the chunk address for allocation address a. */ -#define CHUNK_ADDR2BASE(a) \ - ((void *)((uintptr_t)(a) & ~chunksize_mask)) - -/* Return the chunk offset of address a. */ -#define CHUNK_ADDR2OFFSET(a) \ - ((size_t)((uintptr_t)(a) & chunksize_mask)) - /* Return the smallest chunk multiple that is >= s. */ #define CHUNK_CEILING(s) \ (((s) + chunksize_mask) & ~chunksize_mask) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 02bef63e..c4466013 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -104,7 +104,6 @@ arena_ralloc_junk_large arena_ralloc_no_move arena_rd_to_miscelm arena_reset -arena_run_regind arena_run_to_miscelm arena_salloc arena_sdalloc diff --git a/src/arena.c b/src/arena.c index a08a3245..39764c3f 100644 --- a/src/arena.c +++ b/src/arena.c @@ -49,20 +49,17 @@ static void arena_run_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, arena_run_t *run, bool dirty, bool cleaned, bool decommitted); static void arena_dalloc_bin_run(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, extent_t *extent, arena_run_t *run, arena_bin_t *bin); -static void arena_bin_lower_run(arena_t *arena, arena_chunk_t *chunk, - arena_run_t *run, arena_bin_t *bin); +static void arena_bin_lower_run(tsdn_t *tsdn, arena_t *arena, + extent_t *extent, arena_run_t *run, arena_bin_t *bin); /******************************************************************************/ JEMALLOC_INLINE_C size_t -arena_miscelm_size_get(const arena_chunk_map_misc_t *miscelm) +arena_miscelm_size_get(extent_t *extent, const arena_chunk_map_misc_t *miscelm) { - arena_chunk_t *chunk; - size_t pageind, mapbits; - - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(miscelm); - pageind = arena_miscelm_to_pageind(miscelm); - mapbits = arena_mapbits_get(chunk, pageind); + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + size_t pageind = arena_miscelm_to_pageind(extent, miscelm); + size_t mapbits = arena_mapbits_get(chunk, pageind); return (arena_mapbits_size_decode(mapbits)); } @@ -154,11 +151,12 @@ run_quantize_t *run_quantize_ceil = JEMALLOC_N(n_run_quantize_ceil); #endif static void -arena_avail_insert(arena_t *arena, arena_chunk_t *chunk, size_t pageind, +arena_avail_insert(arena_t *arena, extent_t *extent, size_t pageind, size_t npages) { + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); pszind_t pind = psz2ind(run_quantize_floor(arena_miscelm_size_get( - arena_miscelm_get_const(chunk, pageind)))); + extent, arena_miscelm_get_const(chunk, pageind)))); assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >> LG_PAGE)); arena_run_heap_insert(&arena->runs_avail[pind], @@ -166,11 +164,12 @@ arena_avail_insert(arena_t *arena, arena_chunk_t *chunk, size_t pageind, } static void -arena_avail_remove(arena_t *arena, arena_chunk_t *chunk, size_t pageind, +arena_avail_remove(arena_t *arena, extent_t *extent, size_t pageind, size_t npages) { + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); pszind_t pind = psz2ind(run_quantize_floor(arena_miscelm_size_get( - arena_miscelm_get_const(chunk, pageind)))); + extent, arena_miscelm_get_const(chunk, pageind)))); assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >> LG_PAGE)); arena_run_heap_remove(&arena->runs_avail[pind], @@ -291,9 +290,11 @@ arena_chunk_cache_maybe_remove(arena_t *arena, extent_t *extent, bool dirty) } JEMALLOC_INLINE_C void * -arena_run_reg_alloc(arena_run_t *run, const arena_bin_info_t *bin_info) +arena_run_reg_alloc(tsdn_t *tsdn, arena_run_t *run, + const arena_bin_info_t *bin_info) { void *ret; + extent_t *extent; size_t regind; arena_chunk_map_misc_t *miscelm; void *rpages; @@ -301,15 +302,88 @@ arena_run_reg_alloc(arena_run_t *run, const arena_bin_info_t *bin_info) assert(run->nfree > 0); assert(!bitmap_full(run->bitmap, &bin_info->bitmap_info)); + extent = iealloc(tsdn, run); regind = (unsigned)bitmap_sfu(run->bitmap, &bin_info->bitmap_info); - miscelm = arena_run_to_miscelm(run); - rpages = arena_miscelm_to_rpages(miscelm); + miscelm = arena_run_to_miscelm(extent, run); + rpages = arena_miscelm_to_rpages(extent, miscelm); ret = (void *)((uintptr_t)rpages + (uintptr_t)(bin_info->reg_size * regind)); run->nfree--; return (ret); } +JEMALLOC_INLINE_C size_t +arena_run_regind(extent_t *extent, arena_run_t *run, + const arena_bin_info_t *bin_info, const void *ptr) +{ + size_t diff, interval, shift, regind; + arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(extent, run); + void *rpages = arena_miscelm_to_rpages(extent, miscelm); + + /* + * Freeing a pointer lower than region zero can cause assertion + * failure. + */ + assert((uintptr_t)ptr >= (uintptr_t)rpages); + + /* + * Avoid doing division with a variable divisor if possible. Using + * actual division here can reduce allocator throughput by over 20%! + */ + diff = (size_t)((uintptr_t)ptr - (uintptr_t)rpages); + + /* Rescale (factor powers of 2 out of the numerator and denominator). */ + interval = bin_info->reg_size; + shift = ffs_zu(interval) - 1; + diff >>= shift; + interval >>= shift; + + if (interval == 1) { + /* The divisor was a power of 2. */ + regind = diff; + } else { + /* + * To divide by a number D that is not a power of two we + * multiply by (2^21 / D) and then right shift by 21 positions. + * + * X / D + * + * becomes + * + * (X * interval_invs[D - 3]) >> SIZE_INV_SHIFT + * + * We can omit the first three elements, because we never + * divide by 0, and 1 and 2 are both powers of two, which are + * handled above. + */ +#define SIZE_INV_SHIFT ((sizeof(size_t) << 3) - LG_RUN_MAXREGS) +#define SIZE_INV(s) (((ZU(1) << SIZE_INV_SHIFT) / (s)) + 1) + static const size_t interval_invs[] = { + SIZE_INV(3), + SIZE_INV(4), SIZE_INV(5), SIZE_INV(6), SIZE_INV(7), + SIZE_INV(8), SIZE_INV(9), SIZE_INV(10), SIZE_INV(11), + SIZE_INV(12), SIZE_INV(13), SIZE_INV(14), SIZE_INV(15), + SIZE_INV(16), SIZE_INV(17), SIZE_INV(18), SIZE_INV(19), + SIZE_INV(20), SIZE_INV(21), SIZE_INV(22), SIZE_INV(23), + SIZE_INV(24), SIZE_INV(25), SIZE_INV(26), SIZE_INV(27), + SIZE_INV(28), SIZE_INV(29), SIZE_INV(30), SIZE_INV(31) + }; + + if (likely(interval <= ((sizeof(interval_invs) / sizeof(size_t)) + + 2))) { + regind = (diff * interval_invs[interval - 3]) >> + SIZE_INV_SHIFT; + } else + regind = diff / interval; +#undef SIZE_INV +#undef SIZE_INV_SHIFT + } + assert(diff == regind * interval); + assert(regind < bin_info->nregs); + + return (regind); +} + JEMALLOC_INLINE_C void arena_run_reg_dalloc(tsdn_t *tsdn, arena_run_t *run, extent_t *extent, void *ptr) @@ -319,15 +393,17 @@ arena_run_reg_dalloc(tsdn_t *tsdn, arena_run_t *run, extent_t *extent, size_t mapbits = arena_mapbits_get(chunk, pageind); szind_t binind = arena_ptr_small_binind_get(tsdn, ptr, mapbits); const arena_bin_info_t *bin_info = &arena_bin_info[binind]; - size_t regind = arena_run_regind(run, bin_info, ptr); + size_t regind = arena_run_regind(extent, run, bin_info, ptr); assert(run->nfree < bin_info->nregs); /* Freeing an interior pointer can cause assertion failure. */ assert(((uintptr_t)ptr - - (uintptr_t)arena_miscelm_to_rpages(arena_run_to_miscelm(run))) % - (uintptr_t)bin_info->reg_size == 0); + (uintptr_t)arena_miscelm_to_rpages(extent, + arena_run_to_miscelm(extent, run))) % (uintptr_t)bin_info->reg_size + == 0); assert((uintptr_t)ptr >= - (uintptr_t)arena_miscelm_to_rpages(arena_run_to_miscelm(run))); + (uintptr_t)arena_miscelm_to_rpages(extent, + arena_run_to_miscelm(extent, run))); /* Freeing an unallocated pointer can cause assertion failure. */ assert(bitmap_get(run->bitmap, &bin_info->bitmap_info, regind)); @@ -381,9 +457,10 @@ arena_nactive_sub(arena_t *arena, size_t sub_pages) } static void -arena_run_split_remove(arena_t *arena, arena_chunk_t *chunk, size_t run_ind, +arena_run_split_remove(arena_t *arena, extent_t *extent, size_t run_ind, size_t flag_dirty, size_t flag_decommitted, size_t need_pages) { + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); size_t total_pages, rem_pages; assert(flag_dirty == 0 || flag_decommitted == 0); @@ -395,7 +472,7 @@ arena_run_split_remove(arena_t *arena, arena_chunk_t *chunk, size_t run_ind, assert(need_pages <= total_pages); rem_pages = total_pages - need_pages; - arena_avail_remove(arena, chunk, run_ind, total_pages); + arena_avail_remove(arena, extent, run_ind, total_pages); if (flag_dirty != 0) arena_run_dirty_remove(arena, chunk, run_ind, total_pages); arena_nactive_add(arena, need_pages); @@ -418,7 +495,8 @@ arena_run_split_remove(arena_t *arena, arena_chunk_t *chunk, size_t run_ind, arena_run_dirty_insert(arena, chunk, run_ind+need_pages, rem_pages); } - arena_avail_insert(arena, chunk, run_ind+need_pages, rem_pages); + arena_avail_insert(arena, extent, run_ind+need_pages, + rem_pages); } } @@ -432,8 +510,8 @@ arena_run_split_large_helper(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t flag_unzeroed_mask; chunk = (arena_chunk_t *)extent_addr_get(extent); - miscelm = arena_run_to_miscelm(run); - run_ind = arena_miscelm_to_pageind(miscelm); + miscelm = arena_run_to_miscelm(extent, run); + run_ind = arena_miscelm_to_pageind(extent, miscelm); flag_dirty = arena_mapbits_dirty_get(chunk, run_ind); flag_decommitted = arena_mapbits_decommitted_get(chunk, run_ind); need_pages = (size >> LG_PAGE); @@ -444,7 +522,7 @@ arena_run_split_large_helper(tsdn_t *tsdn, arena_t *arena, extent_t *extent, return (true); if (remove) { - arena_run_split_remove(arena, chunk, run_ind, flag_dirty, + arena_run_split_remove(arena, extent, run_ind, flag_dirty, flag_decommitted, need_pages); } @@ -515,8 +593,8 @@ arena_run_split_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, assert(binind != BININD_INVALID); chunk = (arena_chunk_t *)extent_addr_get(extent); - miscelm = arena_run_to_miscelm(run); - run_ind = arena_miscelm_to_pageind(miscelm); + miscelm = arena_run_to_miscelm(extent, run); + run_ind = arena_miscelm_to_pageind(extent, miscelm); flag_dirty = arena_mapbits_dirty_get(chunk, run_ind); flag_decommitted = arena_mapbits_decommitted_get(chunk, run_ind); need_pages = (size >> LG_PAGE); @@ -526,7 +604,7 @@ arena_run_split_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, &arena->chunk_hooks, extent, run_ind << LG_PAGE, size)) return (true); - arena_run_split_remove(arena, chunk, run_ind, flag_dirty, + arena_run_split_remove(arena, extent, run_ind, flag_dirty, flag_decommitted, need_pages); for (i = 0; i < need_pages; i++) { @@ -680,8 +758,7 @@ arena_chunk_alloc(tsdn_t *tsdn, arena_t *arena) ql_elm_new(extent, ql_link); ql_tail_insert(&arena->achunks, extent, ql_link); - arena_avail_insert(arena, (arena_chunk_t *)extent_addr_get(extent), - map_bias, chunk_npages-map_bias); + arena_avail_insert(arena, extent, map_bias, chunk_npages-map_bias); return (extent); } @@ -746,7 +823,7 @@ arena_chunk_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) arena_mapbits_decommitted_get(chunk, chunk_npages-1)); /* Remove run from runs_avail, so that the arena does not use it. */ - arena_avail_remove(arena, chunk, map_bias, chunk_npages-map_bias); + arena_avail_remove(arena, extent, map_bias, chunk_npages-map_bias); ql_remove(&arena->achunks, extent, ql_link); spare = arena->spare; @@ -1377,8 +1454,9 @@ arena_dirty_count(tsdn_t *tsdn, arena_t *arena) arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); arena_chunk_map_misc_t *miscelm = - arena_rd_to_miscelm(rdelm); - size_t pageind = arena_miscelm_to_pageind(miscelm); + arena_rd_to_miscelm(extent, rdelm); + size_t pageind = arena_miscelm_to_pageind(extent, + miscelm); assert(arena_mapbits_allocated_get(chunk, pageind) == 0); assert(arena_mapbits_large_get(chunk, pageind) == 0); @@ -1435,8 +1513,9 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } else { extent_t *extent = iealloc(tsdn, rdelm); arena_chunk_map_misc_t *miscelm = - arena_rd_to_miscelm(rdelm); - size_t pageind = arena_miscelm_to_pageind(miscelm); + arena_rd_to_miscelm(extent, rdelm); + size_t pageind = arena_miscelm_to_pageind(extent, + miscelm); arena_run_t *run = &miscelm->run; size_t run_size = arena_mapbits_unallocated_size_get((arena_chunk_t *) @@ -1520,8 +1599,8 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); arena_chunk_map_misc_t *miscelm = - arena_rd_to_miscelm(rdelm); - pageind = arena_miscelm_to_pageind(miscelm); + arena_rd_to_miscelm(extent, rdelm); + pageind = arena_miscelm_to_pageind(extent, miscelm); run_size = arena_mapbits_large_size_get(chunk, pageind); npages = run_size >> LG_PAGE; @@ -1601,8 +1680,9 @@ arena_unstash_purged(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); arena_chunk_map_misc_t *miscelm = - arena_rd_to_miscelm(rdelm); - size_t pageind = arena_miscelm_to_pageind(miscelm); + arena_rd_to_miscelm(extent, rdelm); + size_t pageind = arena_miscelm_to_pageind(extent, + miscelm); bool decommitted = (arena_mapbits_decommitted_get(chunk, pageind) != 0); arena_run_t *run = &miscelm->run; @@ -1823,10 +1903,11 @@ arena_reset(tsd_t *tsd, arena_t *arena) } static void -arena_run_coalesce(arena_t *arena, arena_chunk_t *chunk, size_t *p_size, +arena_run_coalesce(arena_t *arena, extent_t *extent, size_t *p_size, size_t *p_run_ind, size_t *p_run_pages, size_t flag_dirty, size_t flag_decommitted) { + arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); size_t size = *p_size; size_t run_ind = *p_run_ind; size_t run_pages = *p_run_pages; @@ -1851,7 +1932,8 @@ arena_run_coalesce(arena_t *arena, arena_chunk_t *chunk, size_t *p_size, run_ind+run_pages+nrun_pages-1) == flag_dirty); assert(arena_mapbits_decommitted_get(chunk, run_ind+run_pages+nrun_pages-1) == flag_decommitted); - arena_avail_remove(arena, chunk, run_ind+run_pages, nrun_pages); + arena_avail_remove(arena, extent, run_ind+run_pages, + nrun_pages); /* * If the successor is dirty, remove it from the set of dirty @@ -1890,7 +1972,7 @@ arena_run_coalesce(arena_t *arena, arena_chunk_t *chunk, size_t *p_size, assert(arena_mapbits_dirty_get(chunk, run_ind) == flag_dirty); assert(arena_mapbits_decommitted_get(chunk, run_ind) == flag_decommitted); - arena_avail_remove(arena, chunk, run_ind, prun_pages); + arena_avail_remove(arena, extent, run_ind, prun_pages); /* * If the predecessor is dirty, remove it from the set of dirty @@ -1944,8 +2026,8 @@ arena_run_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t size, run_ind, run_pages, flag_dirty, flag_decommitted; chunk = (arena_chunk_t *)extent_addr_get(extent); - miscelm = arena_run_to_miscelm(run); - run_ind = arena_miscelm_to_pageind(miscelm); + miscelm = arena_run_to_miscelm(extent, run); + run_ind = arena_miscelm_to_pageind(extent, miscelm); assert(run_ind >= map_bias); assert(run_ind < chunk_npages); size = arena_run_size_get(arena, chunk, run, run_ind); @@ -1978,7 +2060,7 @@ arena_run_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, arena_mapbits_unzeroed_get(chunk, run_ind+run_pages-1)); } - arena_run_coalesce(arena, chunk, &size, &run_ind, &run_pages, + arena_run_coalesce(arena, extent, &size, &run_ind, &run_pages, flag_dirty, flag_decommitted); /* Insert into runs_avail, now that coalescing is complete. */ @@ -1988,7 +2070,7 @@ arena_run_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, arena_mapbits_dirty_get(chunk, run_ind+run_pages-1)); assert(arena_mapbits_decommitted_get(chunk, run_ind) == arena_mapbits_decommitted_get(chunk, run_ind+run_pages-1)); - arena_avail_insert(arena, chunk, run_ind, run_pages); + arena_avail_insert(arena, extent, run_ind, run_pages); if (dirty) arena_run_dirty_insert(arena, chunk, run_ind, run_pages); @@ -2015,8 +2097,8 @@ static void arena_run_trim_head(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, extent_t *extent, arena_run_t *run, size_t oldsize, size_t newsize) { - arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(run); - size_t pageind = arena_miscelm_to_pageind(miscelm); + arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(extent, run); + size_t pageind = arena_miscelm_to_pageind(extent, miscelm); size_t head_npages = (oldsize - newsize) >> LG_PAGE; size_t flag_dirty = arena_mapbits_dirty_get(chunk, pageind); size_t flag_decommitted = arena_mapbits_decommitted_get(chunk, pageind); @@ -2057,8 +2139,8 @@ arena_run_trim_tail(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, extent_t *extent, arena_run_t *run, size_t oldsize, size_t newsize, bool dirty) { - arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(run); - size_t pageind = arena_miscelm_to_pageind(miscelm); + arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(extent, run); + size_t pageind = arena_miscelm_to_pageind(extent, miscelm); size_t head_npages = newsize >> LG_PAGE; size_t flag_dirty = arena_mapbits_dirty_get(chunk, pageind); size_t flag_decommitted = arena_mapbits_decommitted_get(chunk, pageind); @@ -2099,9 +2181,9 @@ arena_run_trim_tail(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, } static void -arena_bin_runs_insert(arena_bin_t *bin, arena_run_t *run) +arena_bin_runs_insert(arena_bin_t *bin, extent_t *extent, arena_run_t *run) { - arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(run); + arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(extent, run); arena_run_heap_insert(&bin->runs, miscelm); } @@ -2189,7 +2271,7 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin) */ void *ret; assert(bin->runcur->nfree > 0); - ret = arena_run_reg_alloc(bin->runcur, bin_info); + ret = arena_run_reg_alloc(tsdn, bin->runcur, bin_info); if (run != NULL) { extent_t *extent; arena_chunk_t *chunk; @@ -2207,8 +2289,10 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin) if (run->nfree == bin_info->nregs) { arena_dalloc_bin_run(tsdn, arena, chunk, extent, run, bin); - } else - arena_bin_lower_run(arena, chunk, run, bin); + } else { + arena_bin_lower_run(tsdn, arena, extent, run, + bin); + } } return (ret); } @@ -2220,7 +2304,7 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin) assert(bin->runcur->nfree > 0); - return (arena_run_reg_alloc(bin->runcur, bin_info)); + return (arena_run_reg_alloc(tsdn, bin->runcur, bin_info)); } void @@ -2240,9 +2324,10 @@ arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_bin_t *tbin, tbin->lg_fill_div); i < nfill; i++) { arena_run_t *run; void *ptr; - if ((run = bin->runcur) != NULL && run->nfree > 0) - ptr = arena_run_reg_alloc(run, &arena_bin_info[binind]); - else + if ((run = bin->runcur) != NULL && run->nfree > 0) { + ptr = arena_run_reg_alloc(tsdn, run, + &arena_bin_info[binind]); + } else ptr = arena_bin_malloc_hard(tsdn, arena, bin); if (ptr == NULL) { /* @@ -2314,7 +2399,7 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) malloc_mutex_lock(tsdn, &bin->lock); if ((run = bin->runcur) != NULL && run->nfree > 0) - ret = arena_run_reg_alloc(run, &arena_bin_info[binind]); + ret = arena_run_reg_alloc(tsdn, run, &arena_bin_info[binind]); else ret = arena_bin_malloc_hard(tsdn, arena, bin); @@ -2359,6 +2444,7 @@ arena_malloc_large(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) size_t usize; uintptr_t random_offset; arena_run_t *run; + extent_t *extent; arena_chunk_map_misc_t *miscelm; UNUSED bool idump JEMALLOC_CC_SILENCE_INIT(false); @@ -2382,8 +2468,9 @@ arena_malloc_large(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) malloc_mutex_unlock(tsdn, &arena->lock); return (NULL); } - miscelm = arena_run_to_miscelm(run); - ret = (void *)((uintptr_t)arena_miscelm_to_rpages(miscelm) + + extent = iealloc(tsdn, run); + miscelm = arena_run_to_miscelm(extent, run); + ret = (void *)((uintptr_t)arena_miscelm_to_rpages(extent, miscelm) + random_offset); if (config_stats) { szind_t index = binind - NBINS; @@ -2465,8 +2552,8 @@ arena_palloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, } extent = iealloc(tsdn, run); chunk = (arena_chunk_t *)extent_addr_get(extent); - miscelm = arena_run_to_miscelm(run); - rpages = arena_miscelm_to_rpages(miscelm); + miscelm = arena_run_to_miscelm(extent, run); + rpages = arena_miscelm_to_rpages(extent, miscelm); leadsize = ALIGNMENT_CEILING((uintptr_t)rpages, alignment) - (uintptr_t)rpages; @@ -2478,8 +2565,8 @@ arena_palloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, extent_t *head_extent = extent; miscelm = arena_miscelm_get_mutable(chunk, - arena_miscelm_to_pageind(head_miscelm) + (leadsize >> - LG_PAGE)); + arena_miscelm_to_pageind(head_extent, head_miscelm) + + (leadsize >> LG_PAGE)); run = &miscelm->run; extent = iealloc(tsdn, run); @@ -2492,8 +2579,8 @@ arena_palloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, } if (arena_run_init_large(tsdn, arena, extent, run, usize + large_pad, zero)) { - size_t run_ind = - arena_miscelm_to_pageind(arena_run_to_miscelm(run)); + size_t run_ind = arena_miscelm_to_pageind(extent, + arena_run_to_miscelm(extent, run)); bool dirty = (arena_mapbits_dirty_get(chunk, run_ind) != 0); bool decommitted = (arena_mapbits_decommitted_get(chunk, run_ind) != 0); @@ -2504,7 +2591,7 @@ arena_palloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, malloc_mutex_unlock(tsdn, &arena->lock); return (NULL); } - ret = arena_miscelm_to_rpages(miscelm); + ret = arena_miscelm_to_rpages(extent, miscelm); if (config_stats) { szind_t index = size2index(usize) - NBINS; @@ -2605,7 +2692,7 @@ arena_dissociate_bin_run(extent_t *extent, arena_run_t *run, arena_bin_t *bin) */ if (bin_info->nregs != 1) { arena_chunk_map_misc_t *miscelm = - arena_run_to_miscelm(run); + arena_run_to_miscelm(extent, run); arena_run_heap_remove(&bin->runs, miscelm); } @@ -2631,8 +2718,8 @@ arena_dalloc_bin_run(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, } static void -arena_bin_lower_run(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, - arena_bin_t *bin) +arena_bin_lower_run(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + arena_run_t *run, arena_bin_t *bin) { /* @@ -2642,13 +2729,15 @@ arena_bin_lower_run(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, */ if ((uintptr_t)run < (uintptr_t)bin->runcur) { /* Switch runcur. */ - if (bin->runcur->nfree > 0) - arena_bin_runs_insert(bin, bin->runcur); + if (bin->runcur->nfree > 0) { + arena_bin_runs_insert(bin, iealloc(tsdn, bin->runcur), + bin->runcur); + } bin->runcur = run; if (config_stats) bin->stats.reruns++; } else - arena_bin_runs_insert(bin, run); + arena_bin_runs_insert(bin, extent, run); } static void @@ -2676,7 +2765,7 @@ arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, arena_dissociate_bin_run(extent, run, bin); arena_dalloc_bin_run(tsdn, arena, chunk, extent, run, bin); } else if (run->nfree == 1 && run != bin->runcur) - arena_bin_lower_run(arena, chunk, run, bin); + arena_bin_lower_run(tsdn, arena, extent, run, bin); if (config_stats) { bin->stats.ndalloc++; diff --git a/src/chunk.c b/src/chunk.c index c1094ff4..ba9084e3 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -674,8 +674,6 @@ chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, { assert(extent_addr_get(extent) != NULL); - assert(CHUNK_ADDR2BASE(extent_addr_get(extent)) == - extent_addr_get(extent)); assert(extent_size_get(extent) != 0); assert((extent_size_get(extent) & chunksize_mask) == 0); @@ -701,8 +699,6 @@ chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, { assert(extent_addr_get(extent) != NULL); - assert(CHUNK_ADDR2BASE(extent_addr_get(extent)) == - extent_addr_get(extent)); assert(extent_size_get(extent) != 0); assert((extent_size_get(extent) & chunksize_mask) == 0); @@ -777,7 +773,6 @@ chunk_purge_default(void *chunk, size_t size, size_t offset, size_t length, { assert(chunk != NULL); - assert(CHUNK_ADDR2BASE(chunk) == chunk); assert((offset & PAGE_MASK) == 0); assert(length != 0); assert((length & PAGE_MASK) == 0); diff --git a/src/chunk_dss.c b/src/chunk_dss.c index 6b90c53e..d0fae7bc 100644 --- a/src/chunk_dss.c +++ b/src/chunk_dss.c @@ -108,8 +108,8 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, * Calculate how much padding is necessary to * chunk-align the end of the DSS. */ - gap_size = (chunksize - CHUNK_ADDR2OFFSET(dss_max)) & - chunksize_mask; + gap_size = (chunksize - ALIGNMENT_ADDR2OFFSET(dss_max, + chunksize)) & chunksize_mask; /* * Compute how much chunk-aligned pad space (if any) is * necessary to satisfy alignment. This space can be -- GitLab From 4731cd47f7168e70809d83c8569f501891ecffa1 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 26 May 2016 22:12:38 -0700 Subject: [PATCH 039/544] Allow chunks to not be naturally aligned. Precisely size extents for huge size classes that aren't multiples of chunksize. --- include/jemalloc/internal/arena.h | 2 - include/jemalloc/internal/extent.h | 16 ++ .../jemalloc/internal/jemalloc_internal.h.in | 22 +-- include/jemalloc/internal/private_symbols.txt | 3 +- src/arena.c | 41 +---- src/base.c | 2 +- src/chunk.c | 57 ++----- src/chunk_dss.c | 68 ++++---- src/chunk_mmap.c | 1 - src/huge.c | 145 +++--------------- test/integration/chunk.c | 16 -- 11 files changed, 105 insertions(+), 268 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index fac6fd34..c298df92 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -486,8 +486,6 @@ void arena_chunk_cache_maybe_remove(arena_t *arena, extent_t *extent, extent_t *arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero); void arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, extent_t *extent); -void arena_chunk_ralloc_huge_similar(tsdn_t *tsdn, arena_t *arena, - extent_t *extent, size_t oldsize); void arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); void arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index c3bdacb4..919b74f6 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -90,6 +90,8 @@ ph_proto(, extent_heap_, extent_heap_t, extent_t) arena_t *extent_arena_get(const extent_t *extent); void *extent_addr_get(const extent_t *extent); size_t extent_size_get(const extent_t *extent); +void *extent_before_get(const extent_t *extent); +void *extent_last_get(const extent_t *extent); void *extent_past_get(const extent_t *extent); bool extent_active_get(const extent_t *extent); bool extent_dirty_get(const extent_t *extent); @@ -137,6 +139,20 @@ extent_size_get(const extent_t *extent) return (extent->e_size); } +JEMALLOC_INLINE void * +extent_before_get(const extent_t *extent) +{ + + return ((void *)(uintptr_t)extent->e_addr - PAGE); +} + +JEMALLOC_INLINE void * +extent_last_get(const extent_t *extent) +{ + + return ((void *)(uintptr_t)extent->e_addr + extent->e_size - PAGE); +} + JEMALLOC_INLINE void * extent_past_get(const extent_t *extent) { diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 7afe5694..ef4e0522 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -797,14 +797,14 @@ sa2u(size_t size, size_t alignment) return (usize); } - /* Try for a large size class. */ - if (likely(size <= large_maxclass) && likely(alignment < chunksize)) { - /* - * We can't achieve subpage alignment, so round up alignment - * to the minimum that can actually be supported. - */ - alignment = PAGE_CEILING(alignment); + /* + * We can't achieve subpage alignment, so round up alignment to the + * minimum that can actually be supported. + */ + alignment = PAGE_CEILING(alignment); + /* Try for a large size class. */ + if (likely(size <= large_maxclass) && likely(alignment == PAGE)) { /* Make sure result is a large size class. */ usize = (size <= LARGE_MINCLASS) ? LARGE_MINCLASS : s2u(size); @@ -821,12 +821,6 @@ sa2u(size_t size, size_t alignment) if (unlikely(alignment > HUGE_MAXCLASS)) return (0); - /* - * We can't achieve subchunk alignment, so round up alignment to the - * minimum that can actually be supported. - */ - alignment = CHUNK_CEILING(alignment); - /* Make sure result is a huge size class. */ if (size <= chunksize) usize = chunksize; @@ -839,7 +833,7 @@ sa2u(size_t size, size_t alignment) } /* - * Calculate the multi-chunk mapping that huge_palloc() would need in + * Calculate the multi-page mapping that huge_palloc() would need in * order to guarantee the alignment. */ if (usize + alignment < usize) { diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index c4466013..44a2cd31 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -19,7 +19,6 @@ arena_chunk_cache_maybe_remove arena_chunk_dalloc_huge arena_chunk_ralloc_huge_expand arena_chunk_ralloc_huge_shrink -arena_chunk_ralloc_huge_similar arena_cleanup arena_dalloc arena_dalloc_bin @@ -211,6 +210,7 @@ extent_addr_set extent_alloc extent_arena_get extent_arena_set +extent_before_get extent_committed_get extent_committed_set extent_dalloc @@ -219,6 +219,7 @@ extent_dirty_insert extent_dirty_remove extent_dirty_set extent_init +extent_last_get extent_past_get extent_prof_tctx_get extent_prof_tctx_set diff --git a/src/arena.c b/src/arena.c index 39764c3f..aff11961 100644 --- a/src/arena.c +++ b/src/arena.c @@ -653,7 +653,7 @@ arena_chunk_alloc_internal_hard(tsdn_t *tsdn, arena_t *arena, malloc_mutex_unlock(tsdn, &arena->lock); extent = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, chunksize, - chunksize, zero, commit, true); + PAGE, zero, commit, true); if (extent != NULL && !*commit) { /* Commit header. */ if (chunk_commit_wrapper(tsdn, arena, chunk_hooks, extent, 0, @@ -676,7 +676,7 @@ arena_chunk_alloc_internal(tsdn_t *tsdn, arena_t *arena, bool *zero, chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; extent = arena_chunk_cache_alloc_locked(tsdn, arena, &chunk_hooks, NULL, - chunksize, chunksize, zero, true); + chunksize, PAGE, zero, true); if (extent != NULL) *commit = true; if (extent == NULL) { @@ -892,13 +892,12 @@ arena_huge_ralloc_stats_update(arena_t *arena, size_t oldsize, size_t usize) static extent_t * arena_chunk_alloc_huge_hard(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, size_t usize, size_t alignment, bool *zero, - size_t csize) + chunk_hooks_t *chunk_hooks, size_t usize, size_t alignment, bool *zero) { extent_t *extent; bool commit = true; - extent = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, csize, + extent = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, usize, alignment, zero, &commit, false); if (extent == NULL) { /* Revert optimistic stats updates. */ @@ -920,7 +919,6 @@ arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, { extent_t *extent; chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; - size_t csize = CHUNK_CEILING(usize); malloc_mutex_lock(tsdn, &arena->lock); @@ -932,11 +930,11 @@ arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, arena_nactive_add(arena, usize >> LG_PAGE); extent = arena_chunk_cache_alloc_locked(tsdn, arena, &chunk_hooks, NULL, - csize, alignment, zero, false); + usize, alignment, zero, false); malloc_mutex_unlock(tsdn, &arena->lock); if (extent == NULL) { extent = arena_chunk_alloc_huge_hard(tsdn, arena, &chunk_hooks, - usize, alignment, zero, csize); + usize, alignment, zero); } return (extent); @@ -954,32 +952,10 @@ arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, extent_t *extent) } arena_nactive_sub(arena, extent_size_get(extent) >> LG_PAGE); - if ((extent_size_get(extent) & chunksize_mask) != 0) - extent_size_set(extent, CHUNK_CEILING(extent_size_get(extent))); - arena_chunk_cache_dalloc_locked(tsdn, arena, &chunk_hooks, extent); malloc_mutex_unlock(tsdn, &arena->lock); } -void -arena_chunk_ralloc_huge_similar(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - size_t oldsize) -{ - size_t usize = extent_size_get(extent); - - assert(CHUNK_CEILING(oldsize) == CHUNK_CEILING(usize)); - assert(oldsize != usize); - - malloc_mutex_lock(tsdn, &arena->lock); - if (config_stats) - arena_huge_ralloc_stats_update(arena, oldsize, usize); - if (oldsize < usize) - arena_nactive_add(arena, (usize - oldsize) >> LG_PAGE); - else - arena_nactive_sub(arena, (oldsize - usize) >> LG_PAGE); - malloc_mutex_unlock(tsdn, &arena->lock); -} - void arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize) @@ -1501,8 +1477,7 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, zero = false; extent = arena_chunk_cache_alloc_locked(tsdn, arena, chunk_hooks, extent_addr_get(chunkselm), - extent_size_get(chunkselm), chunksize, &zero, - false); + extent_size_get(chunkselm), PAGE, &zero, false); assert(extent == chunkselm); assert(zero == extent_zeroed_get(chunkselm)); extent_dirty_insert(chunkselm, purge_runs_sentinel, @@ -2641,7 +2616,7 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, if (likely(usize <= large_maxclass)) { ret = arena_palloc_large(tsdn, arena, usize, alignment, zero); - } else if (likely(alignment <= chunksize)) + } else if (likely(alignment <= PAGE)) ret = huge_malloc(tsdn, arena, usize, zero); else ret = huge_palloc(tsdn, arena, usize, alignment, zero); diff --git a/src/base.c b/src/base.c index 225f522b..1e32d955 100644 --- a/src/base.c +++ b/src/base.c @@ -57,7 +57,7 @@ base_chunk_alloc(tsdn_t *tsdn, size_t minsize) { bool zero = true; bool commit = true; - addr = chunk_alloc_mmap(NULL, csize, chunksize, &zero, &commit); + addr = chunk_alloc_mmap(NULL, csize, PAGE, &zero, &commit); } if (addr == NULL) { if (extent != NULL) diff --git a/src/chunk.c b/src/chunk.c index ba9084e3..2b599610 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -58,8 +58,7 @@ static void chunk_record(tsdn_t *tsdn, arena_t *arena, static void extent_heaps_insert(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) { - size_t psz = - extent_size_quantize_floor(CHUNK_CEILING(extent_size_get(extent))); + size_t psz = extent_size_quantize_floor(extent_size_get(extent)); pszind_t pind = psz2ind(psz); extent_heap_insert(&extent_heaps[pind], extent); } @@ -67,8 +66,7 @@ extent_heaps_insert(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) static void extent_heaps_remove(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) { - size_t psz = - extent_size_quantize_floor(CHUNK_CEILING(extent_size_get(extent))); + size_t psz = extent_size_quantize_floor(extent_size_get(extent)); pszind_t pind = psz2ind(psz); extent_heap_remove(&extent_heaps[pind], extent); } @@ -169,11 +167,9 @@ extent_rtree_acquire(tsdn_t *tsdn, const extent_t *extent, bool dependent, assert(*r_elm_a != NULL); if (extent_size_get(extent) > PAGE) { - uintptr_t last = - (CHUNK_CEILING((uintptr_t)extent_past_get(extent)) - PAGE); - - *r_elm_b = rtree_elm_acquire(tsdn, &chunks_rtree, last, - dependent, init_missing); + *r_elm_b = rtree_elm_acquire(tsdn, &chunks_rtree, + (uintptr_t)extent_last_get(extent), dependent, + init_missing); if (!dependent && *r_elm_b == NULL) return (true); assert(*r_elm_b != NULL); @@ -290,8 +286,6 @@ chunk_first_best_fit(arena_t *arena, extent_heap_t extent_heaps[NPSIZES], { pszind_t pind, i; - assert(size == CHUNK_CEILING(size)); - pind = psz2ind(extent_size_quantize_ceil(size)); for (i = pind; i < NPSIZES; i++) { extent_t *extent = extent_heap_first(&extent_heaps[i]); @@ -326,9 +320,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *extent; size_t alloc_size, leadsize, trailsize; - assert(new_addr == NULL || alignment == chunksize); - - alloc_size = CHUNK_CEILING(s2u(size + alignment - chunksize)); + alloc_size = s2u(size + alignment - PAGE); /* Beware size_t wrap-around. */ if (alloc_size < size) return (NULL); @@ -441,9 +433,7 @@ chunk_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, void *ret; assert(size != 0); - assert((size & chunksize_mask) == 0); assert(alignment != 0); - assert((alignment & chunksize_mask) == 0); /* "primary" dss. */ if (have_dss && dss_prec == dss_prec_primary && (ret = @@ -472,9 +462,7 @@ chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, bool commit; assert(size != 0); - assert((size & chunksize_mask) == 0); assert(alignment != 0); - assert((alignment & chunksize_mask) == 0); commit = true; extent = chunk_recycle(tsdn, arena, chunk_hooks, arena->chunks_cached, @@ -525,9 +513,7 @@ chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *extent; assert(size != 0); - assert((size & chunksize_mask) == 0); assert(alignment != 0); - assert((alignment & chunksize_mask) == 0); extent = chunk_recycle(tsdn, arena, chunk_hooks, arena->chunks_retained, false, new_addr, size, alignment, zero, commit, slab); @@ -551,8 +537,10 @@ chunk_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, return (NULL); addr = chunk_hooks->alloc(new_addr, size, alignment, zero, commit, arena->ind); - if (addr == NULL) + if (addr == NULL) { + extent_dalloc(tsdn, arena, extent); return (NULL); + } extent_init(extent, arena, addr, size, true, false, zero, commit, slab); if (chunk_register(tsdn, extent)) { chunk_leak(tsdn, arena, chunk_hooks, false, extent); @@ -585,9 +573,6 @@ static bool chunk_can_coalesce(const extent_t *a, const extent_t *b) { - assert((void *)CHUNK_CEILING((uintptr_t)extent_past_get(a)) == - extent_addr_get(b)); - if (extent_arena_get(a) != extent_arena_get(b)) return (false); if (extent_active_get(a) != extent_active_get(b)) @@ -637,7 +622,6 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, malloc_mutex_lock(tsdn, &arena->chunks_mtx); chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); - assert((extent_size_get(extent) & chunksize_mask) == 0); extent_active_set(extent, false); extent_zeroed_set(extent, !cache && extent_zeroed_get(extent)); if (extent_slab_get(extent)) { @@ -651,7 +635,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, /* Try to coalesce forward. */ next = rtree_read(tsdn, &chunks_rtree, - CHUNK_CEILING((uintptr_t)extent_past_get(extent)), false); + (uintptr_t)extent_past_get(extent), false); if (next != NULL) { chunk_try_coalesce(tsdn, arena, chunk_hooks, extent, next, extent_heaps, cache); @@ -659,7 +643,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, /* Try to coalesce backward. */ prev = rtree_read(tsdn, &chunks_rtree, - (uintptr_t)extent_addr_get(extent) - PAGE, false); + (uintptr_t)extent_before_get(extent), false); if (prev != NULL) { chunk_try_coalesce(tsdn, arena, chunk_hooks, prev, extent, extent_heaps, cache); @@ -675,7 +659,6 @@ chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert(extent_addr_get(extent) != NULL); assert(extent_size_get(extent) != 0); - assert((extent_size_get(extent) & chunksize_mask) == 0); extent_zeroed_set(extent, false); @@ -700,7 +683,6 @@ chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert(extent_addr_get(extent) != NULL); assert(extent_size_get(extent) != 0); - assert((extent_size_get(extent) & chunksize_mask) == 0); chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); /* Try to deallocate. */ @@ -788,8 +770,7 @@ chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); return (chunk_hooks->purge(extent_addr_get(extent), - CHUNK_CEILING(extent_size_get(extent)), offset, length, - arena->ind)); + extent_size_get(extent), offset, length, arena->ind)); } static bool @@ -809,9 +790,7 @@ chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *trail; rtree_elm_t *lead_elm_a, *lead_elm_b, *trail_elm_a, *trail_elm_b; - assert(CHUNK_CEILING(size_a) == size_a); - assert(CHUNK_CEILING(extent_size_get(extent)) == size_a + - CHUNK_CEILING(size_b)); + assert(extent_size_get(extent) == size_a + size_b); chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); @@ -833,16 +812,15 @@ chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } extent_init(trail, arena, (void *)((uintptr_t)extent_addr_get(extent) + - size_a), CHUNK_CEILING(size_b), extent_active_get(extent), + size_a), size_b, extent_active_get(extent), extent_dirty_get(extent), extent_zeroed_get(extent), extent_committed_get(extent), extent_slab_get(extent)); if (extent_rtree_acquire(tsdn, trail, false, true, &trail_elm_a, &trail_elm_b)) goto label_error_c; - if (chunk_hooks->split(extent_addr_get(extent), size_a + - CHUNK_CEILING(size_b), size_a, CHUNK_CEILING(size_b), - extent_committed_get(extent), arena->ind)) + if (chunk_hooks->split(extent_addr_get(extent), size_a + size_b, size_a, + size_b, extent_committed_get(extent), arena->ind)) goto label_error_d; extent_size_set(extent, size_a); @@ -886,9 +864,6 @@ chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, { rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; - assert((extent_size_get(a) & chunksize_mask) == 0); - assert((extent_size_get(b) & chunksize_mask) == 0); - chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); if (chunk_hooks->merge(extent_addr_get(a), extent_size_get(a), extent_addr_get(b), extent_size_get(b), extent_committed_get(a), diff --git a/src/chunk_dss.c b/src/chunk_dss.c index d0fae7bc..0119c12b 100644 --- a/src/chunk_dss.c +++ b/src/chunk_dss.c @@ -69,9 +69,12 @@ void * chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit) { + void *ret; + extent_t *pad; + cassert(have_dss); - assert(size > 0 && (size & chunksize_mask) == 0); - assert(alignment > 0 && (alignment & chunksize_mask) == 0); + assert(size > 0); + assert(alignment > 0); /* * sbrk() uses a signed increment argument, so take care not to @@ -80,19 +83,22 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, if ((intptr_t)size < 0) return (NULL); + pad = extent_alloc(tsdn, arena); + if (pad == NULL) + return (NULL); + malloc_mutex_lock(tsdn, &dss_mtx); if (dss_prev != (void *)-1) { - /* * The loop is necessary to recover from races with other * threads that are using the DSS for something other than * malloc. */ - do { - void *ret, *cpad_addr, *dss_next; - extent_t *cpad; - size_t gap_size, cpad_size; + while (true) { + void *pad_addr, *dss_next; + size_t pad_size; intptr_t incr; + /* Avoid an unnecessary system call. */ if (new_addr != NULL && dss_max != new_addr) break; @@ -105,58 +111,48 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, break; /* - * Calculate how much padding is necessary to - * chunk-align the end of the DSS. + * Compute how much pad space (if any) is necessary to + * satisfy alignment. This space can be recycled for + * later use. */ - gap_size = (chunksize - ALIGNMENT_ADDR2OFFSET(dss_max, - chunksize)) & chunksize_mask; - /* - * Compute how much chunk-aligned pad space (if any) is - * necessary to satisfy alignment. This space can be - * recycled for later use. - */ - cpad_addr = (void *)((uintptr_t)dss_max + gap_size); + pad_addr = (void *)((uintptr_t)dss_max); ret = (void *)ALIGNMENT_CEILING((uintptr_t)dss_max, alignment); - cpad_size = (uintptr_t)ret - (uintptr_t)cpad_addr; - if (cpad_size != 0) { - cpad = extent_alloc(tsdn, arena); - if (cpad == NULL) { - malloc_mutex_unlock(tsdn, &dss_mtx); - return (NULL); - } - extent_init(cpad, arena, cpad_addr, cpad_size, + pad_size = (uintptr_t)ret - (uintptr_t)pad_addr; + if (pad_size != 0) { + extent_init(pad, arena, pad_addr, pad_size, false, true, false, true, false); } dss_next = (void *)((uintptr_t)ret + size); if ((uintptr_t)ret < (uintptr_t)dss_max || - (uintptr_t)dss_next < (uintptr_t)dss_max) { - /* Wrap-around. */ - malloc_mutex_unlock(tsdn, &dss_mtx); - return (NULL); - } - incr = gap_size + cpad_size + size; + (uintptr_t)dss_next < (uintptr_t)dss_max) + break; /* Wrap-around. */ + incr = pad_size + size; dss_prev = chunk_dss_sbrk(incr); + if (dss_prev == (void *)-1) + break; if (dss_prev == dss_max) { /* Success. */ dss_max = dss_next; malloc_mutex_unlock(tsdn, &dss_mtx); - if (cpad_size != 0) { + if (pad_size != 0) { chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; chunk_dalloc_wrapper(tsdn, arena, - &chunk_hooks, cpad); - } + &chunk_hooks, pad); + } else + extent_dalloc(tsdn, arena, pad); if (*zero) memset(ret, 0, size); if (!*commit) *commit = pages_decommit(ret, size); return (ret); } - } while (dss_prev != (void *)-1); + } } + /* OOM. */ malloc_mutex_unlock(tsdn, &dss_mtx); - + extent_dalloc(tsdn, arena, pad); return (NULL); } diff --git a/src/chunk_mmap.c b/src/chunk_mmap.c index 13708027..e1ee26f4 100644 --- a/src/chunk_mmap.c +++ b/src/chunk_mmap.c @@ -50,7 +50,6 @@ chunk_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, */ assert(alignment != 0); - assert((alignment & chunksize_mask) == 0); ret = pages_map(new_addr, size, commit); if (ret == NULL || ret == new_addr) diff --git a/src/huge.c b/src/huge.c index 31d3bcae..69cf034a 100644 --- a/src/huge.c +++ b/src/huge.c @@ -9,7 +9,7 @@ huge_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero) assert(usize == s2u(usize)); - return (huge_palloc(tsdn, arena, usize, chunksize, zero)); + return (huge_palloc(tsdn, arena, usize, PAGE, zero)); } void * @@ -20,14 +20,11 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, extent_t *extent; bool is_zeroed; - /* Allocate one or more contiguous chunks for this request. */ - assert(!tsdn_null(tsdn) || arena != NULL); ausize = sa2u(usize, alignment); if (unlikely(ausize == 0 || ausize > HUGE_MAXCLASS)) return (NULL); - assert(ausize >= chunksize); /* * Copy zero into is_zeroed and pass the copy to chunk_alloc(), so that @@ -40,9 +37,6 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, arena, usize, alignment, &is_zeroed)) == NULL) return (NULL); - if (usize < extent_size_get(extent)) - extent_size_set(extent, usize); - /* Insert extent into huge. */ malloc_mutex_lock(tsdn, &arena->huge_mtx); ql_elm_new(extent, ql_link); @@ -86,80 +80,20 @@ huge_dalloc_junk(tsdn_t *tsdn, void *ptr, size_t usize) huge_dalloc_junk_t *huge_dalloc_junk = JEMALLOC_N(huge_dalloc_junk_impl); #endif -static void -huge_ralloc_no_move_similar(tsdn_t *tsdn, extent_t *extent, size_t usize_min, - size_t usize_max, bool zero) -{ - size_t usize, usize_next; - arena_t *arena = extent_arena_get(extent); - size_t oldsize = extent_size_get(extent); - chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; - bool pre_zeroed, post_zeroed; - - /* Increase usize to incorporate extra. */ - for (usize = usize_min; usize < usize_max && (usize_next = s2u(usize+1)) - <= oldsize; usize = usize_next) - ; /* Do nothing. */ - - if (oldsize == usize) - return; - - pre_zeroed = extent_zeroed_get(extent); - - /* Fill if necessary (shrinking). */ - if (oldsize > usize) { - size_t sdiff = oldsize - usize; - if (config_fill && unlikely(opt_junk_free)) { - memset((void *)((uintptr_t)extent_addr_get(extent) + - usize), JEMALLOC_FREE_JUNK, sdiff); - post_zeroed = false; - } else { - post_zeroed = !chunk_purge_wrapper(tsdn, arena, - &chunk_hooks, extent, usize, sdiff); - } - } else - post_zeroed = pre_zeroed; - - /* Update the size of the huge allocation. */ - assert(extent_size_get(extent) != usize); - malloc_mutex_lock(tsdn, &arena->huge_mtx); - extent_size_set(extent, usize); - malloc_mutex_unlock(tsdn, &arena->huge_mtx); - /* Update zeroed. */ - extent_zeroed_set(extent, post_zeroed); - - arena_chunk_ralloc_huge_similar(tsdn, arena, extent, oldsize); - - /* Fill if necessary (growing). */ - if (oldsize < usize) { - if (zero || (config_fill && unlikely(opt_zero))) { - if (!pre_zeroed) { - memset((void *) - ((uintptr_t)extent_addr_get(extent) + - oldsize), 0, usize - oldsize); - } - } else if (config_fill && unlikely(opt_junk_alloc)) { - memset((void *)((uintptr_t)extent_addr_get(extent) + - oldsize), JEMALLOC_ALLOC_JUNK, usize - oldsize); - } - } -} - static bool huge_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { arena_t *arena = extent_arena_get(extent); size_t oldsize = extent_size_get(extent); chunk_hooks_t chunk_hooks = chunk_hooks_get(tsdn, arena); - size_t cdiff = CHUNK_CEILING(oldsize) - CHUNK_CEILING(usize); - size_t sdiff = CHUNK_CEILING(usize) - usize; + size_t diff = oldsize - usize; assert(oldsize > usize); - /* Split excess chunks. */ - if (cdiff != 0) { + /* Split excess pages. */ + if (diff != 0) { extent_t *trail = chunk_split_wrapper(tsdn, arena, &chunk_hooks, - extent, CHUNK_CEILING(usize), cdiff); + extent, usize, diff); if (trail == NULL) return (true); @@ -171,28 +105,6 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) arena_chunk_cache_dalloc(tsdn, arena, &chunk_hooks, trail); } - /* Optionally fill trailing subchunk. */ - if (sdiff != 0) { - bool post_zeroed; - - if (config_fill && unlikely(opt_junk_free)) { - huge_dalloc_junk(tsdn, - (void *)((uintptr_t)extent_addr_get(extent) + - usize), sdiff); - post_zeroed = false; - } else { - post_zeroed = !chunk_purge_wrapper(tsdn, arena, - &chunk_hooks, extent, usize, sdiff); - - if (config_fill && unlikely(opt_zero) && !post_zeroed) { - memset((void *) - ((uintptr_t)extent_addr_get(extent) + - usize), 0, sdiff); - } - } - extent_zeroed_set(extent, post_zeroed); - } - arena_chunk_ralloc_huge_shrink(tsdn, arena, extent, oldsize); return (false); @@ -204,20 +116,18 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, { arena_t *arena = extent_arena_get(extent); size_t oldsize = extent_size_get(extent); - bool is_zeroed_subchunk = extent_zeroed_get(extent); - bool is_zeroed_chunk = false; + bool is_zeroed_trail = false; chunk_hooks_t chunk_hooks = chunk_hooks_get(tsdn, arena); - size_t cdiff = CHUNK_CEILING(usize) - CHUNK_CEILING(oldsize); - void *nchunk = - (void *)CHUNK_CEILING((uintptr_t)extent_past_get(extent)); + size_t trailsize = usize - oldsize; extent_t *trail; - if ((trail = arena_chunk_cache_alloc(tsdn, arena, &chunk_hooks, nchunk, - cdiff, chunksize, &is_zeroed_chunk)) == NULL) { + if ((trail = arena_chunk_cache_alloc(tsdn, arena, &chunk_hooks, + extent_past_get(extent), trailsize, PAGE, &is_zeroed_trail)) == + NULL) { bool commit = true; if ((trail = chunk_alloc_wrapper(tsdn, arena, &chunk_hooks, - nchunk, cdiff, chunksize, &is_zeroed_chunk, &commit, false)) - == NULL) + extent_past_get(extent), trailsize, PAGE, &is_zeroed_trail, + &commit, false)) == NULL) return (true); } @@ -227,23 +137,15 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, } if (zero || (config_fill && unlikely(opt_zero))) { - if (!is_zeroed_subchunk) { + if (!is_zeroed_trail) { memset((void *)((uintptr_t)extent_addr_get(extent) + - oldsize), 0, CHUNK_CEILING(oldsize) - oldsize); - } - if (!is_zeroed_chunk) { - memset((void *)((uintptr_t)extent_addr_get(extent) + - CHUNK_CEILING(oldsize)), 0, usize - - CHUNK_CEILING(oldsize)); + oldsize), 0, usize - oldsize); } } else if (config_fill && unlikely(opt_junk_alloc)) { memset((void *)((uintptr_t)extent_addr_get(extent) + oldsize), JEMALLOC_ALLOC_JUNK, usize - oldsize); } - if (usize < extent_size_get(extent)) - extent_size_set(extent, usize); - arena_chunk_ralloc_huge_expand(tsdn, arena, extent, oldsize); return (false); @@ -260,7 +162,7 @@ huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, /* Both allocation sizes must be huge to avoid a move. */ assert(extent_size_get(extent) >= chunksize && usize_max >= chunksize); - if (CHUNK_CEILING(usize_max) > CHUNK_CEILING(extent_size_get(extent))) { + if (usize_max > extent_size_get(extent)) { /* Attempt to expand the allocation in-place. */ if (!huge_ralloc_no_move_expand(tsdn, extent, usize_max, zero)) { @@ -268,9 +170,9 @@ huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, return (false); } /* Try again, this time with usize_min. */ - if (usize_min < usize_max && CHUNK_CEILING(usize_min) > - CHUNK_CEILING(extent_size_get(extent)) && - huge_ralloc_no_move_expand(tsdn, extent, usize_min, zero)) { + if (usize_min < usize_max && usize_min > extent_size_get(extent) + && huge_ralloc_no_move_expand(tsdn, extent, usize_min, + zero)) { arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } @@ -280,17 +182,14 @@ huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, * Avoid moving the allocation if the existing chunk size accommodates * the new size. */ - if (CHUNK_CEILING(extent_size_get(extent)) >= CHUNK_CEILING(usize_min) - && CHUNK_CEILING(extent_size_get(extent)) <= - CHUNK_CEILING(usize_max)) { - huge_ralloc_no_move_similar(tsdn, extent, usize_min, usize_max, - zero); + if (extent_size_get(extent) >= usize_min && extent_size_get(extent) <= + usize_max) { arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } /* Attempt to shrink the allocation in-place. */ - if (CHUNK_CEILING(extent_size_get(extent)) > CHUNK_CEILING(usize_max)) { + if (extent_size_get(extent) > usize_max) { if (!huge_ralloc_no_move_shrink(tsdn, extent, usize_max)) { arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); @@ -304,7 +203,7 @@ huge_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero) { - if (alignment <= chunksize) + if (alignment <= PAGE) return (huge_malloc(tsdn, arena, usize, zero)); return (huge_palloc(tsdn, arena, usize, alignment, zero)); } diff --git a/test/integration/chunk.c b/test/integration/chunk.c index ff9bf967..092472c6 100644 --- a/test/integration/chunk.c +++ b/test/integration/chunk.c @@ -224,22 +224,6 @@ TEST_BEGIN(test_chunk) do_dalloc = true; do_decommit = false; - /* Test purge for partial-chunk huge allocations. */ - if (huge0 * 2 > huge2) { - /* - * There are at least four size classes per doubling, so a - * successful xallocx() from size=huge2 to size=huge1 is - * guaranteed to leave trailing purgeable memory. - */ - p = mallocx(huge2, flags); - assert_ptr_not_null(p, "Unexpected mallocx() error"); - did_purge = false; - assert_zu_eq(xallocx(p, huge1, 0, flags), huge1, - "Unexpected xallocx() failure"); - assert_true(did_purge, "Expected purge"); - dallocx(p, flags); - } - /* Test decommit for large allocations. */ do_decommit = true; p = mallocx(large1, flags); -- GitLab From b46261d58b449cc4c099ed2384451a2499688f0e Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 27 May 2016 18:57:15 -0700 Subject: [PATCH 040/544] Implement cache-oblivious support for huge size classes. --- include/jemalloc/internal/arena.h | 21 ++-- include/jemalloc/internal/chunk.h | 8 +- include/jemalloc/internal/extent.h | 42 +++++++ include/jemalloc/internal/private_symbols.txt | 4 + include/jemalloc/internal/prng.h | 35 ++++-- src/arena.c | 107 +++++++++--------- src/chunk.c | 98 +++++++++------- src/ckh.c | 5 +- src/huge.c | 88 ++++++++------ src/prof.c | 2 +- src/tcache.c | 4 +- test/unit/prng.c | 54 +++++++-- 12 files changed, 298 insertions(+), 170 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index c298df92..4d2b25a0 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -688,7 +688,7 @@ JEMALLOC_ALWAYS_INLINE size_t arena_miscelm_to_pageind(const extent_t *extent, const arena_chunk_map_misc_t *miscelm) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); size_t pageind = ((uintptr_t)miscelm - ((uintptr_t)chunk + map_misc_offset)) / sizeof(arena_chunk_map_misc_t) + map_bias; @@ -702,7 +702,7 @@ JEMALLOC_ALWAYS_INLINE void * arena_miscelm_to_rpages(const extent_t *extent, const arena_chunk_map_misc_t *miscelm) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); size_t pageind = arena_miscelm_to_pageind(extent, miscelm); return ((void *)((uintptr_t)chunk + (pageind << LG_PAGE))); @@ -1065,7 +1065,7 @@ arena_ptr_small_binind_get(tsdn_t *tsdn, const void *ptr, size_t mapbits) assert(binind != BININD_INVALID); assert(binind < NBINS); extent = iealloc(tsdn, ptr); - chunk = (arena_chunk_t *)extent_addr_get(extent); + chunk = (arena_chunk_t *)extent_base_get(extent); arena = extent_arena_get(extent); pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; actual_mapbits = arena_mapbits_get(chunk, pageind); @@ -1106,7 +1106,7 @@ arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) assert(ptr != NULL); if (likely(extent_slab_get(extent))) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; size_t mapbits = arena_mapbits_get(chunk, pageind); assert((mapbits & CHUNK_MAP_ALLOCATED) != 0); @@ -1132,7 +1132,7 @@ arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, assert(ptr != NULL); if (likely(extent_slab_get(extent))) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; assert(arena_mapbits_allocated_get(chunk, pageind) != 0); @@ -1168,8 +1168,9 @@ arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, if (unlikely(usize > SMALL_MAXCLASS || (ptr == old_ptr && (uintptr_t)old_tctx > (uintptr_t)1U))) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); - if (likely(chunk != ptr)) { + if (likely(extent_slab_get(extent))) { + arena_chunk_t *chunk = + (arena_chunk_t *)extent_base_get(extent); size_t pageind; arena_chunk_map_misc_t *elm; @@ -1253,7 +1254,7 @@ arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr, bool demote) if (likely(extent_slab_get(extent))) { const arena_chunk_t *chunk = - (const arena_chunk_t *)extent_addr_get(extent); + (const arena_chunk_t *)extent_base_get(extent); pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; assert(arena_mapbits_allocated_get(chunk, pageind) != 0); @@ -1302,7 +1303,7 @@ arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, assert(ptr != NULL); if (likely(extent_slab_get(extent))) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; mapbits = arena_mapbits_get(chunk, pageind); @@ -1349,7 +1350,7 @@ arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, assert(!tsdn_null(tsdn) || tcache == NULL); if (likely(extent_slab_get(extent))) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); if (config_prof && opt_prof) { size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index 0c0084b0..624073d9 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -45,11 +45,11 @@ chunk_hooks_t chunk_hooks_set(tsdn_t *tsdn, arena_t *arena, const chunk_hooks_t *chunk_hooks); extent_t *chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, - bool *zero, bool slab); + chunk_hooks_t *chunk_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool slab); extent_t *chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, - bool *zero, bool *commit, bool slab); + chunk_hooks_t *chunk_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool *commit, bool slab); void chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *extent); void chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 919b74f6..4023f82d 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -88,8 +88,10 @@ ph_proto(, extent_heap_, extent_heap_t, extent_t) #ifndef JEMALLOC_ENABLE_INLINE arena_t *extent_arena_get(const extent_t *extent); +void *extent_base_get(const extent_t *extent); void *extent_addr_get(const extent_t *extent); size_t extent_size_get(const extent_t *extent); +size_t extent_usize_get(const extent_t *extent); void *extent_before_get(const extent_t *extent); void *extent_last_get(const extent_t *extent); void *extent_past_get(const extent_t *extent); @@ -102,6 +104,7 @@ bool extent_slab_get(const extent_t *extent); prof_tctx_t *extent_prof_tctx_get(const extent_t *extent); void extent_arena_set(extent_t *extent, arena_t *arena); void extent_addr_set(extent_t *extent, void *addr); +void extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment); void extent_size_set(extent_t *extent, size_t size); void extent_active_set(extent_t *extent, bool active); void extent_dirty_set(extent_t *extent, bool dirty); @@ -125,10 +128,21 @@ extent_arena_get(const extent_t *extent) return (extent->e_arena); } +JEMALLOC_INLINE void * +extent_base_get(const extent_t *extent) +{ + + assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || + !extent->e_slab); + return (PAGE_ADDR2BASE(extent->e_addr)); +} + JEMALLOC_INLINE void * extent_addr_get(const extent_t *extent) { + assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || + !extent->e_slab); return (extent->e_addr); } @@ -139,6 +153,14 @@ extent_size_get(const extent_t *extent) return (extent->e_size); } +JEMALLOC_INLINE size_t +extent_usize_get(const extent_t *extent) +{ + + assert(!extent->e_slab); + return (extent->e_size - large_pad); +} + JEMALLOC_INLINE void * extent_before_get(const extent_t *extent) { @@ -224,6 +246,24 @@ extent_addr_set(extent_t *extent, void *addr) extent->e_addr = addr; } +JEMALLOC_INLINE void +extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment) +{ + + assert(extent_base_get(extent) == extent_addr_get(extent)); + + if (alignment < PAGE) { + unsigned lg_range = LG_PAGE - + lg_floor(CACHELINE_CEILING(alignment)); + uint64_t r = + prng_lg_range(&extent_arena_get(extent)->offset_state, + lg_range, true); + uintptr_t random_offset = ((uintptr_t)r) << lg_range; + extent->e_addr = (void *)((uintptr_t)extent->e_addr + + random_offset); + } +} + JEMALLOC_INLINE void extent_size_set(extent_t *extent, size_t size) { @@ -278,6 +318,8 @@ extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, bool active, bool dirty, bool zeroed, bool committed, bool slab) { + assert(addr == PAGE_ADDR2BASE(addr) || !slab); + extent_arena_set(extent, arena); extent_addr_set(extent, addr); extent_size_set(extent, size); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 44a2cd31..75a1dace 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -206,10 +206,12 @@ dss_prec_names extent_active_get extent_active_set extent_addr_get +extent_addr_randomize extent_addr_set extent_alloc extent_arena_get extent_arena_set +extent_base_get extent_before_get extent_committed_get extent_committed_set @@ -230,6 +232,7 @@ extent_size_quantize_ceil extent_size_quantize_floor extent_slab_get extent_slab_set +extent_usize_get extent_zeroed_get extent_zeroed_set ffs_llu @@ -373,6 +376,7 @@ pow2_ceil_u64 pow2_ceil_zu prng_lg_range prng_range +prng_state_next prof_active prof_active_get prof_active_get_unlocked diff --git a/include/jemalloc/internal/prng.h b/include/jemalloc/internal/prng.h index 5830f8b7..ebe916f8 100644 --- a/include/jemalloc/internal/prng.h +++ b/include/jemalloc/internal/prng.h @@ -35,28 +35,45 @@ #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE -uint64_t prng_lg_range(uint64_t *state, unsigned lg_range); -uint64_t prng_range(uint64_t *state, uint64_t range); +uint64_t prng_state_next(uint64_t state); +uint64_t prng_lg_range(uint64_t *state, unsigned lg_range, bool atomic); +uint64_t prng_range(uint64_t *state, uint64_t range, bool atomic); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PRNG_C_)) JEMALLOC_ALWAYS_INLINE uint64_t -prng_lg_range(uint64_t *state, unsigned lg_range) +prng_state_next(uint64_t state) { - uint64_t ret; + + return ((state * PRNG_A) + PRNG_C); +} + +JEMALLOC_ALWAYS_INLINE uint64_t +prng_lg_range(uint64_t *state, unsigned lg_range, bool atomic) +{ + uint64_t ret, state1; assert(lg_range > 0); assert(lg_range <= 64); - ret = (*state * PRNG_A) + PRNG_C; - *state = ret; - ret >>= (64 - lg_range); + if (atomic) { + uint64_t state0; + + do { + state0 = atomic_read_uint64(state); + state1 = prng_state_next(state0); + } while (atomic_cas_uint64(state, state0, state1)); + } else { + state1 = prng_state_next(*state); + *state = state1; + } + ret = state1 >> (64 - lg_range); return (ret); } JEMALLOC_ALWAYS_INLINE uint64_t -prng_range(uint64_t *state, uint64_t range) +prng_range(uint64_t *state, uint64_t range, bool atomic) { uint64_t ret; unsigned lg_range; @@ -68,7 +85,7 @@ prng_range(uint64_t *state, uint64_t range) /* Generate a result in [0..range) via repeated trial. */ do { - ret = prng_lg_range(state, lg_range); + ret = prng_lg_range(state, lg_range, atomic); } while (ret >= range); return (ret); diff --git a/src/arena.c b/src/arena.c index aff11961..4ce55577 100644 --- a/src/arena.c +++ b/src/arena.c @@ -57,7 +57,7 @@ static void arena_bin_lower_run(tsdn_t *tsdn, arena_t *arena, JEMALLOC_INLINE_C size_t arena_miscelm_size_get(extent_t *extent, const arena_chunk_map_misc_t *miscelm) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); size_t pageind = arena_miscelm_to_pageind(extent, miscelm); size_t mapbits = arena_mapbits_get(chunk, pageind); return (arena_mapbits_size_decode(mapbits)); @@ -154,7 +154,7 @@ static void arena_avail_insert(arena_t *arena, extent_t *extent, size_t pageind, size_t npages) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); pszind_t pind = psz2ind(run_quantize_floor(arena_miscelm_size_get( extent, arena_miscelm_get_const(chunk, pageind)))); assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >> @@ -167,7 +167,7 @@ static void arena_avail_remove(arena_t *arena, extent_t *extent, size_t pageind, size_t npages) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); pszind_t pind = psz2ind(run_quantize_floor(arena_miscelm_size_get( extent, arena_miscelm_get_const(chunk, pageind)))); assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >> @@ -221,14 +221,14 @@ arena_chunk_dirty_npages(const extent_t *extent) static extent_t * arena_chunk_cache_alloc_locked(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, - bool *zero, bool slab) + chunk_hooks_t *chunk_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool slab) { malloc_mutex_assert_owner(tsdn, &arena->lock); - return (chunk_alloc_cache(tsdn, arena, chunk_hooks, new_addr, size, - alignment, zero, slab)); + return (chunk_alloc_cache(tsdn, arena, chunk_hooks, new_addr, usize, + pad, alignment, zero, slab)); } extent_t * @@ -240,7 +240,7 @@ arena_chunk_cache_alloc(tsdn_t *tsdn, arena_t *arena, malloc_mutex_lock(tsdn, &arena->lock); extent = arena_chunk_cache_alloc_locked(tsdn, arena, chunk_hooks, - new_addr, size, alignment, zero, false); + new_addr, size, 0, alignment, zero, false); malloc_mutex_unlock(tsdn, &arena->lock); return (extent); @@ -388,7 +388,7 @@ JEMALLOC_INLINE_C void arena_run_reg_dalloc(tsdn_t *tsdn, arena_run_t *run, extent_t *extent, void *ptr) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; size_t mapbits = arena_mapbits_get(chunk, pageind); szind_t binind = arena_ptr_small_binind_get(tsdn, ptr, mapbits); @@ -460,7 +460,7 @@ static void arena_run_split_remove(arena_t *arena, extent_t *extent, size_t run_ind, size_t flag_dirty, size_t flag_decommitted, size_t need_pages) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); size_t total_pages, rem_pages; assert(flag_dirty == 0 || flag_decommitted == 0); @@ -509,7 +509,7 @@ arena_run_split_large_helper(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t flag_dirty, flag_decommitted, run_ind, need_pages; size_t flag_unzeroed_mask; - chunk = (arena_chunk_t *)extent_addr_get(extent); + chunk = (arena_chunk_t *)extent_base_get(extent); miscelm = arena_run_to_miscelm(extent, run); run_ind = arena_miscelm_to_pageind(extent, miscelm); flag_dirty = arena_mapbits_dirty_get(chunk, run_ind); @@ -592,7 +592,7 @@ arena_run_split_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, assert(binind != BININD_INVALID); - chunk = (arena_chunk_t *)extent_addr_get(extent); + chunk = (arena_chunk_t *)extent_base_get(extent); miscelm = arena_run_to_miscelm(extent, run); run_ind = arena_miscelm_to_pageind(extent, miscelm); flag_dirty = arena_mapbits_dirty_get(chunk, run_ind); @@ -629,16 +629,16 @@ arena_chunk_init_spare(arena_t *arena) arena->spare = NULL; assert(arena_mapbits_allocated_get((arena_chunk_t *) - extent_addr_get(extent), map_bias) == 0); + extent_base_get(extent), map_bias) == 0); assert(arena_mapbits_allocated_get((arena_chunk_t *) - extent_addr_get(extent), chunk_npages-1) == 0); + extent_base_get(extent), chunk_npages-1) == 0); assert(arena_mapbits_unallocated_size_get((arena_chunk_t *) - extent_addr_get(extent), map_bias) == arena_maxrun); + extent_base_get(extent), map_bias) == arena_maxrun); assert(arena_mapbits_unallocated_size_get((arena_chunk_t *) - extent_addr_get(extent), chunk_npages-1) == arena_maxrun); + extent_base_get(extent), chunk_npages-1) == arena_maxrun); assert(arena_mapbits_dirty_get((arena_chunk_t *) - extent_addr_get(extent), map_bias) == - arena_mapbits_dirty_get((arena_chunk_t *)extent_addr_get(extent), + extent_base_get(extent), map_bias) == + arena_mapbits_dirty_get((arena_chunk_t *)extent_base_get(extent), chunk_npages-1)); return (extent); @@ -653,7 +653,7 @@ arena_chunk_alloc_internal_hard(tsdn_t *tsdn, arena_t *arena, malloc_mutex_unlock(tsdn, &arena->lock); extent = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, chunksize, - PAGE, zero, commit, true); + 0, CACHELINE, zero, commit, true); if (extent != NULL && !*commit) { /* Commit header. */ if (chunk_commit_wrapper(tsdn, arena, chunk_hooks, extent, 0, @@ -676,7 +676,7 @@ arena_chunk_alloc_internal(tsdn_t *tsdn, arena_t *arena, bool *zero, chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; extent = arena_chunk_cache_alloc_locked(tsdn, arena, &chunk_hooks, NULL, - chunksize, PAGE, zero, true); + chunksize, 0, CACHELINE, zero, true); if (extent != NULL) *commit = true; if (extent == NULL) { @@ -717,7 +717,7 @@ arena_chunk_init_hard(tsdn_t *tsdn, arena_t *arena) */ flag_unzeroed = (zero || !commit) ? 0 : CHUNK_MAP_UNZEROED; flag_decommitted = commit ? 0 : CHUNK_MAP_DECOMMITTED; - arena_mapbits_unallocated_set((arena_chunk_t *)extent_addr_get(extent), + arena_mapbits_unallocated_set((arena_chunk_t *)extent_base_get(extent), map_bias, arena_maxrun, flag_unzeroed | flag_decommitted); /* * There is no need to initialize the internal page map entries unless @@ -726,18 +726,18 @@ arena_chunk_init_hard(tsdn_t *tsdn, arena_t *arena) if (!zero) { for (i = map_bias+1; i < chunk_npages-1; i++) { arena_mapbits_internal_set((arena_chunk_t *) - extent_addr_get(extent), i, flag_unzeroed); + extent_base_get(extent), i, flag_unzeroed); } } else { if (config_debug) { for (i = map_bias+1; i < chunk_npages-1; i++) { assert(arena_mapbits_unzeroed_get( - (arena_chunk_t *)extent_addr_get(extent), i) + (arena_chunk_t *)extent_base_get(extent), i) == flag_unzeroed); } } } - arena_mapbits_unallocated_set((arena_chunk_t *)extent_addr_get(extent), + arena_mapbits_unallocated_set((arena_chunk_t *)extent_base_get(extent), chunk_npages-1, arena_maxrun, flag_unzeroed); return (extent); @@ -770,7 +770,7 @@ arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, extent_t *extent) extent_committed_set(extent, (arena_mapbits_decommitted_get((arena_chunk_t *) - extent_addr_get(extent), map_bias) == 0)); + extent_base_get(extent), map_bias) == 0)); if (!extent_committed_get(extent)) { /* * Decommit the header. Mark the chunk as decommitted even if @@ -796,10 +796,10 @@ arena_spare_discard(tsdn_t *tsdn, arena_t *arena, extent_t *spare) assert(arena->spare != spare); - if (arena_mapbits_dirty_get((arena_chunk_t *)extent_addr_get(spare), + if (arena_mapbits_dirty_get((arena_chunk_t *)extent_base_get(spare), map_bias) != 0) { arena_run_dirty_remove(arena, (arena_chunk_t *) - extent_addr_get(spare), map_bias, chunk_npages-map_bias); + extent_base_get(spare), map_bias, chunk_npages-map_bias); } arena_chunk_discard(tsdn, arena, spare); @@ -808,7 +808,7 @@ arena_spare_discard(tsdn_t *tsdn, arena_t *arena, extent_t *spare) static void arena_chunk_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); extent_t *spare; assert(arena_mapbits_allocated_get(chunk, map_bias) == 0); @@ -898,7 +898,7 @@ arena_chunk_alloc_huge_hard(tsdn_t *tsdn, arena_t *arena, bool commit = true; extent = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, usize, - alignment, zero, &commit, false); + large_pad, alignment, zero, &commit, false); if (extent == NULL) { /* Revert optimistic stats updates. */ malloc_mutex_lock(tsdn, &arena->lock); @@ -930,7 +930,7 @@ arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, arena_nactive_add(arena, usize >> LG_PAGE); extent = arena_chunk_cache_alloc_locked(tsdn, arena, &chunk_hooks, NULL, - usize, alignment, zero, false); + usize, large_pad, alignment, zero, false); malloc_mutex_unlock(tsdn, &arena->lock); if (extent == NULL) { extent = arena_chunk_alloc_huge_hard(tsdn, arena, &chunk_hooks, @@ -1046,7 +1046,7 @@ arena_run_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t size, bool zero) extent = arena_chunk_alloc(tsdn, arena); if (extent != NULL) { run = &arena_miscelm_get_mutable((arena_chunk_t *) - extent_addr_get(extent), map_bias)->run; + extent_base_get(extent), map_bias)->run; if (arena_run_split_large(tsdn, arena, iealloc(tsdn, run), run, size, zero)) run = NULL; @@ -1095,7 +1095,7 @@ arena_run_alloc_small(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t binind) extent = arena_chunk_alloc(tsdn, arena); if (extent != NULL) { run = &arena_miscelm_get_mutable( - (arena_chunk_t *)extent_addr_get(extent), map_bias)->run; + (arena_chunk_t *)extent_base_get(extent), map_bias)->run; if (arena_run_split_small(tsdn, arena, iealloc(tsdn, run), run, size, binind)) run = NULL; @@ -1161,7 +1161,7 @@ arena_decay_deadline_init(arena_t *arena) nstime_t jitter; nstime_init(&jitter, prng_range(&arena->decay_jitter_state, - nstime_ns(&arena->decay_interval))); + nstime_ns(&arena->decay_interval), false)); nstime_add(&arena->decay_deadline, &jitter); } } @@ -1428,7 +1428,7 @@ arena_dirty_count(tsdn_t *tsdn, arena_t *arena) } else { extent_t *extent = iealloc(tsdn, rdelm); arena_chunk_t *chunk = - (arena_chunk_t *)extent_addr_get(extent); + (arena_chunk_t *)extent_base_get(extent); arena_chunk_map_misc_t *miscelm = arena_rd_to_miscelm(extent, rdelm); size_t pageind = arena_miscelm_to_pageind(extent, @@ -1476,8 +1476,9 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, /* Allocate. */ zero = false; extent = arena_chunk_cache_alloc_locked(tsdn, arena, - chunk_hooks, extent_addr_get(chunkselm), - extent_size_get(chunkselm), PAGE, &zero, false); + chunk_hooks, extent_base_get(chunkselm), + extent_size_get(chunkselm), 0, CACHELINE, &zero, + false); assert(extent == chunkselm); assert(zero == extent_zeroed_get(chunkselm)); extent_dirty_insert(chunkselm, purge_runs_sentinel, @@ -1494,7 +1495,7 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, arena_run_t *run = &miscelm->run; size_t run_size = arena_mapbits_unallocated_size_get((arena_chunk_t *) - extent_addr_get(extent), pageind); + extent_base_get(extent), pageind); npages = run_size >> LG_PAGE; if (opt_purge == purge_mode_decay && arena->ndirty - @@ -1503,9 +1504,9 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert(pageind + npages <= chunk_npages); assert(arena_mapbits_dirty_get((arena_chunk_t *) - extent_addr_get(extent), pageind) == + extent_base_get(extent), pageind) == arena_mapbits_dirty_get((arena_chunk_t *) - extent_addr_get(extent), pageind+npages-1)); + extent_base_get(extent), pageind+npages-1)); /* * If purging the spare chunk's run, make it available @@ -1572,7 +1573,7 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, bool decommitted; extent_t *extent = iealloc(tsdn, rdelm); arena_chunk_t *chunk = - (arena_chunk_t *)extent_addr_get(extent); + (arena_chunk_t *)extent_base_get(extent); arena_chunk_map_misc_t *miscelm = arena_rd_to_miscelm(extent, rdelm); pageind = arena_miscelm_to_pageind(extent, miscelm); @@ -1653,7 +1654,7 @@ arena_unstash_purged(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } else { extent_t *extent = iealloc(tsdn, rdelm); arena_chunk_t *chunk = - (arena_chunk_t *)extent_addr_get(extent); + (arena_chunk_t *)extent_base_get(extent); arena_chunk_map_misc_t *miscelm = arena_rd_to_miscelm(extent, rdelm); size_t pageind = arena_miscelm_to_pageind(extent, @@ -1734,7 +1735,7 @@ arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) static void arena_achunk_prof_reset(tsd_t *tsd, arena_t *arena, extent_t *extent) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); size_t pageind, npages; cassert(config_prof); @@ -1809,7 +1810,7 @@ arena_reset(tsd_t *tsd, arena_t *arena) malloc_mutex_lock(tsd_tsdn(tsd), &arena->huge_mtx); for (extent = ql_last(&arena->huge, ql_link); extent != NULL; extent = ql_last(&arena->huge, ql_link)) { - void *ptr = extent_addr_get(extent); + void *ptr = extent_base_get(extent); size_t usize; malloc_mutex_unlock(tsd_tsdn(tsd), &arena->huge_mtx); @@ -1882,7 +1883,7 @@ arena_run_coalesce(arena_t *arena, extent_t *extent, size_t *p_size, size_t *p_run_ind, size_t *p_run_pages, size_t flag_dirty, size_t flag_decommitted) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_addr_get(extent); + arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); size_t size = *p_size; size_t run_ind = *p_run_ind; size_t run_pages = *p_run_pages; @@ -2000,7 +2001,7 @@ arena_run_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, arena_chunk_map_misc_t *miscelm; size_t size, run_ind, run_pages, flag_dirty, flag_decommitted; - chunk = (arena_chunk_t *)extent_addr_get(extent); + chunk = (arena_chunk_t *)extent_base_get(extent); miscelm = arena_run_to_miscelm(extent, run); run_ind = arena_miscelm_to_pageind(extent, miscelm); assert(run_ind >= map_bias); @@ -2260,7 +2261,7 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin) * were just deallocated from the run. */ extent = iealloc(tsdn, run); - chunk = (arena_chunk_t *)extent_addr_get(extent); + chunk = (arena_chunk_t *)extent_base_get(extent); if (run->nfree == bin_info->nregs) { arena_dalloc_bin_run(tsdn, arena, chunk, extent, run, bin); @@ -2425,7 +2426,6 @@ arena_malloc_large(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) /* Large allocation. */ usize = index2size(binind); - malloc_mutex_lock(tsdn, &arena->lock); if (config_cache_oblivious) { uint64_t r; @@ -2434,10 +2434,12 @@ arena_malloc_large(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) * that is a multiple of the cacheline size, e.g. [0 .. 63) * 64 * for 4 KiB pages and 64-byte cachelines. */ - r = prng_lg_range(&arena->offset_state, LG_PAGE - LG_CACHELINE); + r = prng_lg_range(&arena->offset_state, LG_PAGE - LG_CACHELINE, + true); random_offset = ((uintptr_t)r) << LG_CACHELINE; } else random_offset = 0; + malloc_mutex_lock(tsdn, &arena->lock); run = arena_run_alloc_large(tsdn, arena, usize + large_pad, zero); if (run == NULL) { malloc_mutex_unlock(tsdn, &arena->lock); @@ -2526,7 +2528,7 @@ arena_palloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, return (NULL); } extent = iealloc(tsdn, run); - chunk = (arena_chunk_t *)extent_addr_get(extent); + chunk = (arena_chunk_t *)extent_base_get(extent); miscelm = arena_run_to_miscelm(extent, run); rpages = arena_miscelm_to_rpages(extent, miscelm); @@ -2616,7 +2618,7 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, if (likely(usize <= large_maxclass)) { ret = arena_palloc_large(tsdn, arena, usize, alignment, zero); - } else if (likely(alignment <= PAGE)) + } else if (likely(alignment <= CACHELINE)) ret = huge_malloc(tsdn, arena, usize, zero); else ret = huge_palloc(tsdn, arena, usize, alignment, zero); @@ -2634,12 +2636,11 @@ arena_prof_promoted(tsdn_t *tsdn, const extent_t *extent, const void *ptr, cassert(config_prof); assert(ptr != NULL); - assert(extent_addr_get(extent) != ptr); assert(isalloc(tsdn, extent, ptr, false) == LARGE_MINCLASS); assert(isalloc(tsdn, extent, ptr, true) == LARGE_MINCLASS); assert(size <= SMALL_MAXCLASS); - chunk = (arena_chunk_t *)extent_addr_get(extent); + chunk = (arena_chunk_t *)extent_base_get(extent); pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; binind = size2index(size); assert(binind < NBINS); @@ -3030,7 +3031,7 @@ arena_ralloc_large(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, return (false); } - chunk = (arena_chunk_t *)extent_addr_get(extent); + chunk = (arena_chunk_t *)extent_base_get(extent); arena = extent_arena_get(extent); if (oldsize < usize_max) { diff --git a/src/chunk.c b/src/chunk.c index 2b599610..4b213a90 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -161,7 +161,7 @@ extent_rtree_acquire(tsdn_t *tsdn, const extent_t *extent, bool dependent, { *r_elm_a = rtree_elm_acquire(tsdn, &chunks_rtree, - (uintptr_t)extent_addr_get(extent), dependent, init_missing); + (uintptr_t)extent_base_get(extent), dependent, init_missing); if (!dependent && *r_elm_a == NULL) return (true); assert(*r_elm_a != NULL); @@ -207,7 +207,7 @@ chunk_interior_register(tsdn_t *tsdn, const extent_t *extent) for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) { rtree_write(tsdn, &chunks_rtree, - (uintptr_t)extent_addr_get(extent) + (uintptr_t)(i << + (uintptr_t)extent_base_get(extent) + (uintptr_t)(i << LG_PAGE), extent); } } @@ -252,7 +252,7 @@ chunk_interior_deregister(tsdn_t *tsdn, const extent_t *extent) for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) { rtree_clear(tsdn, &chunks_rtree, - (uintptr_t)extent_addr_get(extent) + (uintptr_t)(i << + (uintptr_t)extent_base_get(extent) + (uintptr_t)(i << LG_PAGE)); } } @@ -315,14 +315,19 @@ chunk_leak(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, bool cache, static extent_t * chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_heap_t extent_heaps[NPSIZES], bool cache, void *new_addr, - size_t size, size_t alignment, bool *zero, bool *commit, bool slab) + size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, + bool slab) { extent_t *extent; - size_t alloc_size, leadsize, trailsize; + size_t size, alloc_size, leadsize, trailsize; + + assert(new_addr == NULL || !slab); + assert(pad == 0 || !slab); - alloc_size = s2u(size + alignment - PAGE); + size = usize + pad; + alloc_size = s2u(size + PAGE_CEILING(alignment) - PAGE); /* Beware size_t wrap-around. */ - if (alloc_size < size) + if (alloc_size < usize) return (NULL); malloc_mutex_lock(tsdn, &arena->chunks_mtx); chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); @@ -350,8 +355,8 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_heaps_remove(extent_heaps, extent); arena_chunk_cache_maybe_remove(arena, extent, cache); - leadsize = ALIGNMENT_CEILING((uintptr_t)extent_addr_get(extent), - alignment) - (uintptr_t)extent_addr_get(extent); + leadsize = ALIGNMENT_CEILING((uintptr_t)extent_base_get(extent), + PAGE_CEILING(alignment)) - (uintptr_t)extent_base_get(extent); assert(new_addr == NULL || leadsize == 0); assert(extent_size_get(extent) >= leadsize + size); trailsize = extent_size_get(extent) - leadsize - size; @@ -388,7 +393,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } if (!extent_committed_get(extent) && - chunk_hooks->commit(extent_addr_get(extent), + chunk_hooks->commit(extent_base_get(extent), extent_size_get(extent), 0, extent_size_get(extent), arena->ind)) { malloc_mutex_unlock(tsdn, &arena->chunks_mtx); chunk_record(tsdn, arena, chunk_hooks, extent_heaps, cache, @@ -396,6 +401,8 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, return (NULL); } + if (pad != 0) + extent_addr_randomize(tsdn, extent, alignment); extent_active_set(extent, true); if (slab) { extent_slab_set(extent, slab); @@ -407,13 +414,13 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, if (*zero) { if (!extent_zeroed_get(extent)) { memset(extent_addr_get(extent), 0, - extent_size_get(extent)); + extent_usize_get(extent)); } else if (config_debug) { size_t i; size_t *p = (size_t *)(uintptr_t) extent_addr_get(extent); - for (i = 0; i < size / sizeof(size_t); i++) + for (i = 0; i < usize / sizeof(size_t); i++) assert(p[i] == 0); } } @@ -456,17 +463,18 @@ chunk_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, extent_t * chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - void *new_addr, size_t size, size_t alignment, bool *zero, bool slab) + void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, + bool slab) { extent_t *extent; bool commit; - assert(size != 0); + assert(usize + pad != 0); assert(alignment != 0); commit = true; extent = chunk_recycle(tsdn, arena, chunk_hooks, arena->chunks_cached, - true, new_addr, size, alignment, zero, &commit, slab); + true, new_addr, usize, pad, alignment, zero, &commit, slab); if (extent == NULL) return (NULL); assert(commit); @@ -507,31 +515,34 @@ chunk_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero, static extent_t * chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit, - bool slab) + void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, + bool *commit, bool slab) { extent_t *extent; - assert(size != 0); + assert(usize != 0); assert(alignment != 0); extent = chunk_recycle(tsdn, arena, chunk_hooks, arena->chunks_retained, - false, new_addr, size, alignment, zero, commit, slab); - - if (config_stats && extent != NULL) + false, new_addr, usize, pad, alignment, zero, commit, slab); + if (extent != NULL && config_stats) { + size_t size = usize + pad; arena->stats.retained -= size; + } return (extent); } static extent_t * chunk_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, - bool *zero, bool *commit, bool slab) + chunk_hooks_t *chunk_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool *commit, bool slab) { extent_t *extent; + size_t size; void *addr; + size = usize + pad; extent = extent_alloc(tsdn, arena); if (extent == NULL) return (NULL); @@ -542,6 +553,8 @@ chunk_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, return (NULL); } extent_init(extent, arena, addr, size, true, false, zero, commit, slab); + if (pad != 0) + extent_addr_randomize(tsdn, extent, alignment); if (chunk_register(tsdn, extent)) { chunk_leak(tsdn, arena, chunk_hooks, false, extent); return (NULL); @@ -552,18 +565,18 @@ chunk_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, extent_t * chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit, - bool slab) + void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, + bool *commit, bool slab) { extent_t *extent; chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); - extent = chunk_alloc_retained(tsdn, arena, chunk_hooks, new_addr, size, - alignment, zero, commit, slab); + extent = chunk_alloc_retained(tsdn, arena, chunk_hooks, new_addr, usize, + pad, alignment, zero, commit, slab); if (extent == NULL) { extent = chunk_alloc_wrapper_hard(tsdn, arena, chunk_hooks, - new_addr, size, alignment, zero, commit, slab); + new_addr, usize, pad, alignment, zero, commit, slab); } return (extent); @@ -629,7 +642,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_slab_set(extent, false); } - assert(chunk_lookup(tsdn, extent_addr_get(extent), true) == extent); + assert(chunk_lookup(tsdn, extent_base_get(extent), true) == extent); extent_heaps_insert(extent_heaps, extent); arena_chunk_cache_maybe_insert(arena, extent, cache); @@ -657,9 +670,10 @@ chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *extent) { - assert(extent_addr_get(extent) != NULL); + assert(extent_base_get(extent) != NULL); assert(extent_size_get(extent) != 0); + extent_addr_set(extent, extent_base_get(extent)); extent_zeroed_set(extent, false); chunk_record(tsdn, arena, chunk_hooks, arena->chunks_cached, true, @@ -681,12 +695,14 @@ chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *extent) { - assert(extent_addr_get(extent) != NULL); + assert(extent_base_get(extent) != NULL); assert(extent_size_get(extent) != 0); + extent_addr_set(extent, extent_base_get(extent)); + chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); /* Try to deallocate. */ - if (!chunk_hooks->dalloc(extent_addr_get(extent), + if (!chunk_hooks->dalloc(extent_base_get(extent), extent_size_get(extent), extent_committed_get(extent), arena->ind)) { chunk_deregister(tsdn, extent); @@ -696,12 +712,12 @@ chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, /* Try to decommit; purge if that fails. */ if (extent_committed_get(extent)) { extent_committed_set(extent, - chunk_hooks->decommit(extent_addr_get(extent), + chunk_hooks->decommit(extent_base_get(extent), extent_size_get(extent), 0, extent_size_get(extent), arena->ind)); } extent_zeroed_set(extent, !extent_committed_get(extent) || - !chunk_hooks->purge(extent_addr_get(extent), + !chunk_hooks->purge(extent_base_get(extent), extent_size_get(extent), 0, extent_size_get(extent), arena->ind)); if (config_stats) @@ -726,7 +742,7 @@ chunk_commit_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, { chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); - return (chunk_hooks->commit(extent_addr_get(extent), + return (chunk_hooks->commit(extent_base_get(extent), extent_size_get(extent), offset, length, arena->ind)); } @@ -745,7 +761,7 @@ chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, { chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); - return (chunk_hooks->decommit(extent_addr_get(extent), + return (chunk_hooks->decommit(extent_base_get(extent), extent_size_get(extent), offset, length, arena->ind)); } @@ -769,7 +785,7 @@ chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, { chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); - return (chunk_hooks->purge(extent_addr_get(extent), + return (chunk_hooks->purge(extent_base_get(extent), extent_size_get(extent), offset, length, arena->ind)); } @@ -811,7 +827,7 @@ chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, goto label_error_b; } - extent_init(trail, arena, (void *)((uintptr_t)extent_addr_get(extent) + + extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) + size_a), size_b, extent_active_get(extent), extent_dirty_get(extent), extent_zeroed_get(extent), extent_committed_get(extent), extent_slab_get(extent)); @@ -819,7 +835,7 @@ chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, &trail_elm_b)) goto label_error_c; - if (chunk_hooks->split(extent_addr_get(extent), size_a + size_b, size_a, + if (chunk_hooks->split(extent_base_get(extent), size_a + size_b, size_a, size_b, extent_committed_get(extent), arena->ind)) goto label_error_d; @@ -865,8 +881,8 @@ chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); - if (chunk_hooks->merge(extent_addr_get(a), extent_size_get(a), - extent_addr_get(b), extent_size_get(b), extent_committed_get(a), + if (chunk_hooks->merge(extent_base_get(a), extent_size_get(a), + extent_base_get(b), extent_size_get(b), extent_committed_get(a), arena->ind)) return (true); diff --git a/src/ckh.c b/src/ckh.c index 2c120ac8..5ec0f60a 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -99,7 +99,8 @@ ckh_try_bucket_insert(ckh_t *ckh, size_t bucket, const void *key, * Cycle through the cells in the bucket, starting at a random position. * The randomness avoids worst-case search overhead as buckets fill up. */ - offset = (unsigned)prng_lg_range(&ckh->prng_state, LG_CKH_BUCKET_CELLS); + offset = (unsigned)prng_lg_range(&ckh->prng_state, LG_CKH_BUCKET_CELLS, + false); for (i = 0; i < (ZU(1) << LG_CKH_BUCKET_CELLS); i++) { cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + ((i + offset) & ((ZU(1) << LG_CKH_BUCKET_CELLS) - 1))]; @@ -142,7 +143,7 @@ ckh_evict_reloc_insert(ckh_t *ckh, size_t argbucket, void const **argkey, * bucket. */ i = (unsigned)prng_lg_range(&ckh->prng_state, - LG_CKH_BUCKET_CELLS); + LG_CKH_BUCKET_CELLS, false); cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + i]; assert(cell->key != NULL); diff --git a/src/huge.c b/src/huge.c index 69cf034a..b00be904 100644 --- a/src/huge.c +++ b/src/huge.c @@ -9,7 +9,7 @@ huge_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero) assert(usize == s2u(usize)); - return (huge_palloc(tsdn, arena, usize, PAGE, zero)); + return (huge_palloc(tsdn, arena, usize, CACHELINE, zero)); } void * @@ -46,11 +46,11 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, if (zero || (config_fill && unlikely(opt_zero))) { if (!is_zeroed) { memset(extent_addr_get(extent), 0, - extent_size_get(extent)); + extent_usize_get(extent)); } } else if (config_fill && unlikely(opt_junk_alloc)) { memset(extent_addr_get(extent), JEMALLOC_ALLOC_JUNK, - extent_size_get(extent)); + extent_usize_get(extent)); } arena_decay_tick(tsdn, arena); @@ -84,28 +84,28 @@ static bool huge_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { arena_t *arena = extent_arena_get(extent); - size_t oldsize = extent_size_get(extent); + size_t oldusize = extent_usize_get(extent); chunk_hooks_t chunk_hooks = chunk_hooks_get(tsdn, arena); - size_t diff = oldsize - usize; + size_t diff = extent_size_get(extent) - (usize + large_pad); - assert(oldsize > usize); + assert(oldusize > usize); /* Split excess pages. */ if (diff != 0) { extent_t *trail = chunk_split_wrapper(tsdn, arena, &chunk_hooks, - extent, usize, diff); + extent, usize + large_pad, diff); if (trail == NULL) return (true); if (config_fill && unlikely(opt_junk_free)) { huge_dalloc_junk(tsdn, extent_addr_get(trail), - extent_size_get(trail)); + extent_usize_get(trail)); } arena_chunk_cache_dalloc(tsdn, arena, &chunk_hooks, trail); } - arena_chunk_ralloc_huge_shrink(tsdn, arena, extent, oldsize); + arena_chunk_ralloc_huge_shrink(tsdn, arena, extent, oldusize); return (false); } @@ -115,19 +115,19 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, bool zero) { arena_t *arena = extent_arena_get(extent); - size_t oldsize = extent_size_get(extent); + size_t oldusize = extent_usize_get(extent); bool is_zeroed_trail = false; chunk_hooks_t chunk_hooks = chunk_hooks_get(tsdn, arena); - size_t trailsize = usize - oldsize; + size_t trailsize = usize - extent_usize_get(extent); extent_t *trail; if ((trail = arena_chunk_cache_alloc(tsdn, arena, &chunk_hooks, - extent_past_get(extent), trailsize, PAGE, &is_zeroed_trail)) == - NULL) { + extent_past_get(extent), trailsize, CACHELINE, &is_zeroed_trail)) + == NULL) { bool commit = true; if ((trail = chunk_alloc_wrapper(tsdn, arena, &chunk_hooks, - extent_past_get(extent), trailsize, PAGE, &is_zeroed_trail, - &commit, false)) == NULL) + extent_past_get(extent), trailsize, 0, CACHELINE, + &is_zeroed_trail, &commit, false)) == NULL) return (true); } @@ -137,16 +137,32 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, } if (zero || (config_fill && unlikely(opt_zero))) { + if (config_cache_oblivious) { + /* + * Zero the trailing bytes of the original allocation's + * last page, since they are in an indeterminate state. + * There will always be trailing bytes, because ptr's + * offset from the beginning of the run is a multiple of + * CACHELINE in [0 .. PAGE). + */ + void *zbase = (void *) + ((uintptr_t)extent_addr_get(extent) + oldusize); + void *zpast = PAGE_ADDR2BASE((void *)((uintptr_t)zbase + + PAGE)); + size_t nzero = (uintptr_t)zpast - (uintptr_t)zbase; + assert(nzero > 0); + memset(zbase, 0, nzero); + } if (!is_zeroed_trail) { memset((void *)((uintptr_t)extent_addr_get(extent) + - oldsize), 0, usize - oldsize); + oldusize), 0, usize - oldusize); } } else if (config_fill && unlikely(opt_junk_alloc)) { - memset((void *)((uintptr_t)extent_addr_get(extent) + oldsize), - JEMALLOC_ALLOC_JUNK, usize - oldsize); + memset((void *)((uintptr_t)extent_addr_get(extent) + oldusize), + JEMALLOC_ALLOC_JUNK, usize - oldusize); } - arena_chunk_ralloc_huge_expand(tsdn, arena, extent, oldsize); + arena_chunk_ralloc_huge_expand(tsdn, arena, extent, oldusize); return (false); } @@ -156,13 +172,13 @@ huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, size_t usize_max, bool zero) { - assert(s2u(extent_size_get(extent)) == extent_size_get(extent)); + assert(s2u(extent_usize_get(extent)) == extent_usize_get(extent)); /* The following should have been caught by callers. */ assert(usize_min > 0 && usize_max <= HUGE_MAXCLASS); /* Both allocation sizes must be huge to avoid a move. */ - assert(extent_size_get(extent) >= chunksize && usize_max >= chunksize); + assert(extent_usize_get(extent) >= chunksize && usize_max >= chunksize); - if (usize_max > extent_size_get(extent)) { + if (usize_max > extent_usize_get(extent)) { /* Attempt to expand the allocation in-place. */ if (!huge_ralloc_no_move_expand(tsdn, extent, usize_max, zero)) { @@ -170,9 +186,9 @@ huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, return (false); } /* Try again, this time with usize_min. */ - if (usize_min < usize_max && usize_min > extent_size_get(extent) - && huge_ralloc_no_move_expand(tsdn, extent, usize_min, - zero)) { + if (usize_min < usize_max && usize_min > + extent_usize_get(extent) && huge_ralloc_no_move_expand(tsdn, + extent, usize_min, zero)) { arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } @@ -182,14 +198,14 @@ huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, * Avoid moving the allocation if the existing chunk size accommodates * the new size. */ - if (extent_size_get(extent) >= usize_min && extent_size_get(extent) <= + if (extent_usize_get(extent) >= usize_min && extent_usize_get(extent) <= usize_max) { arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } /* Attempt to shrink the allocation in-place. */ - if (extent_size_get(extent) > usize_max) { + if (extent_usize_get(extent) > usize_max) { if (!huge_ralloc_no_move_shrink(tsdn, extent, usize_max)) { arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); @@ -203,7 +219,7 @@ huge_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero) { - if (alignment <= PAGE) + if (alignment <= CACHELINE) return (huge_malloc(tsdn, arena, usize, zero)); return (huge_palloc(tsdn, arena, usize, alignment, zero)); } @@ -218,7 +234,7 @@ huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, /* The following should have been caught by callers. */ assert(usize > 0 && usize <= HUGE_MAXCLASS); /* Both allocation sizes must be huge to avoid a move. */ - assert(extent_size_get(extent) >= chunksize && usize >= chunksize); + assert(extent_usize_get(extent) >= chunksize && usize >= chunksize); /* Try to avoid moving the allocation. */ if (!huge_ralloc_no_move(tsdn, extent, usize, usize, zero)) @@ -233,11 +249,11 @@ huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, if (ret == NULL) return (NULL); - copysize = (usize < extent_size_get(extent)) ? usize : - extent_size_get(extent); + copysize = (usize < extent_usize_get(extent)) ? usize : + extent_usize_get(extent); memcpy(ret, extent_addr_get(extent), copysize); isdalloct(tsdn, extent, extent_addr_get(extent), - extent_size_get(extent), tcache, true); + extent_usize_get(extent), tcache, true); return (ret); } @@ -252,7 +268,7 @@ huge_dalloc(tsdn_t *tsdn, extent_t *extent) malloc_mutex_unlock(tsdn, &arena->huge_mtx); huge_dalloc_junk(tsdn, extent_addr_get(extent), - extent_size_get(extent)); + extent_usize_get(extent)); arena_chunk_dalloc_huge(tsdn, extent_arena_get(extent), extent); arena_decay_tick(tsdn, arena); @@ -261,15 +277,15 @@ huge_dalloc(tsdn_t *tsdn, extent_t *extent) size_t huge_salloc(tsdn_t *tsdn, const extent_t *extent) { - size_t size; + size_t usize; arena_t *arena; arena = extent_arena_get(extent); malloc_mutex_lock(tsdn, &arena->huge_mtx); - size = extent_size_get(extent); + usize = extent_usize_get(extent); malloc_mutex_unlock(tsdn, &arena->huge_mtx); - return (size); + return (usize); } prof_tctx_t * diff --git a/src/prof.c b/src/prof.c index 03979ca3..5eb9a3d1 100644 --- a/src/prof.c +++ b/src/prof.c @@ -879,7 +879,7 @@ prof_sample_threshold_update(prof_tdata_t *tdata) * pp 500 * (http://luc.devroye.org/rnbookindex.html) */ - r = prng_lg_range(&tdata->prng_state, 53); + r = prng_lg_range(&tdata->prng_state, 53, false); u = (double)r * (1.0/9007199254740992.0L); tdata->bytes_until_sample = (uint64_t)(log(u) / log(1.0 - (1.0 / (double)((uint64_t)1U << lg_prof_sample)))) diff --git a/src/tcache.c b/src/tcache.c index 8bd8df01..d3ef9992 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -128,7 +128,7 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, extent = iealloc(tsd_tsdn(tsd), ptr); if (extent_arena_get(extent) == bin_arena) { arena_chunk_t *chunk = - (arena_chunk_t *)extent_addr_get(extent); + (arena_chunk_t *)extent_base_get(extent); size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; arena_chunk_map_bits_t *bitselm = @@ -214,7 +214,7 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, extent = iealloc(tsd_tsdn(tsd), ptr); if (extent_arena_get(extent) == locked_arena) { arena_chunk_t *chunk = - (arena_chunk_t *)extent_addr_get(extent); + (arena_chunk_t *)extent_base_get(extent); arena_dalloc_large_junked_locked(tsd_tsdn(tsd), locked_arena, chunk, extent, ptr); } else { diff --git a/test/unit/prng.c b/test/unit/prng.c index b22bd2f5..f3234455 100644 --- a/test/unit/prng.c +++ b/test/unit/prng.c @@ -1,33 +1,34 @@ #include "test/jemalloc_test.h" -TEST_BEGIN(test_prng_lg_range) +static void +test_prng_lg_range(bool atomic) { uint64_t sa, sb, ra, rb; unsigned lg_range; sa = 42; - ra = prng_lg_range(&sa, 64); + ra = prng_lg_range(&sa, 64, atomic); sa = 42; - rb = prng_lg_range(&sa, 64); + rb = prng_lg_range(&sa, 64, atomic); assert_u64_eq(ra, rb, "Repeated generation should produce repeated results"); sb = 42; - rb = prng_lg_range(&sb, 64); + rb = prng_lg_range(&sb, 64, atomic); assert_u64_eq(ra, rb, "Equivalent generation should produce equivalent results"); sa = 42; - ra = prng_lg_range(&sa, 64); - rb = prng_lg_range(&sa, 64); + ra = prng_lg_range(&sa, 64, atomic); + rb = prng_lg_range(&sa, 64, atomic); assert_u64_ne(ra, rb, "Full-width results must not immediately repeat"); sa = 42; - ra = prng_lg_range(&sa, 64); + ra = prng_lg_range(&sa, 64, atomic); for (lg_range = 63; lg_range > 0; lg_range--) { sb = 42; - rb = prng_lg_range(&sb, lg_range); + rb = prng_lg_range(&sb, lg_range, atomic); assert_u64_eq((rb & (UINT64_C(0xffffffffffffffff) << lg_range)), 0, "High order bits should be 0, lg_range=%u", lg_range); assert_u64_eq(rb, (ra >> (64 - lg_range)), @@ -35,9 +36,23 @@ TEST_BEGIN(test_prng_lg_range) "lg_range=%u", lg_range); } } + +TEST_BEGIN(test_prng_lg_range_nonatomic) +{ + + test_prng_lg_range(false); +} +TEST_END + +TEST_BEGIN(test_prng_lg_range_atomic) +{ + + test_prng_lg_range(true); +} TEST_END -TEST_BEGIN(test_prng_range) +static void +test_prng_range(bool atomic) { uint64_t range; #define MAX_RANGE 10000000 @@ -50,12 +65,25 @@ TEST_BEGIN(test_prng_range) s = range; for (rep = 0; rep < NREPS; rep++) { - uint64_t r = prng_range(&s, range); + uint64_t r = prng_range(&s, range, atomic); assert_u64_lt(r, range, "Out of range"); } } } + +TEST_BEGIN(test_prng_range_nonatomic) +{ + + test_prng_range(false); +} +TEST_END + +TEST_BEGIN(test_prng_range_atomic) +{ + + test_prng_range(true); +} TEST_END int @@ -63,6 +91,8 @@ main(void) { return (test( - test_prng_lg_range, - test_prng_range)); + test_prng_lg_range_nonatomic, + test_prng_lg_range_atomic, + test_prng_range_nonatomic, + test_prng_range_atomic)); } -- GitLab From ed2c2427a7684bc8f41da54319c5dff00e177f76 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 28 May 2016 00:17:28 -0700 Subject: [PATCH 041/544] Use huge size class infrastructure for large size classes. --- Makefile.in | 1 - doc/jemalloc.xml.in | 88 +- include/jemalloc/internal/arena.h | 197 ++-- include/jemalloc/internal/chunk.h | 3 +- include/jemalloc/internal/ctl.h | 3 +- include/jemalloc/internal/extent.h | 36 +- include/jemalloc/internal/huge.h | 5 +- .../jemalloc/internal/jemalloc_internal.h.in | 50 +- include/jemalloc/internal/private_symbols.txt | 11 +- include/jemalloc/internal/prof.h | 6 +- include/jemalloc/internal/stats.h | 34 +- include/jemalloc/internal/tcache.h | 33 +- src/arena.c | 870 ++---------------- src/base.c | 3 +- src/chunk.c | 27 +- src/chunk_dss.c | 2 +- src/ctl.c | 175 +--- src/extent.c | 4 +- src/huge.c | 67 +- src/jemalloc.c | 46 +- src/stats.c | 86 +- src/tcache.c | 41 +- src/zone.c | 8 +- test/integration/chunk.c | 28 +- test/integration/xallocx.c | 103 +-- test/unit/arena_reset.c | 33 +- test/unit/decay.c | 41 +- test/unit/extent_quantize.c | 41 +- test/unit/junk.c | 91 +- test/unit/mallctl.c | 23 +- test/unit/prof_idump.c | 13 +- test/unit/run_quantize.c | 149 --- test/unit/stats.c | 105 +-- test/unit/zero.c | 11 +- 34 files changed, 459 insertions(+), 1975 deletions(-) delete mode 100644 test/unit/run_quantize.c diff --git a/Makefile.in b/Makefile.in index 7d73155a..2e9bbbc2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -159,7 +159,6 @@ TESTS_UNIT := \ $(srcroot)test/unit/qr.c \ $(srcroot)test/unit/rb.c \ $(srcroot)test/unit/rtree.c \ - $(srcroot)test/unit/run_quantize.c \ $(srcroot)test/unit/SFMT.c \ $(srcroot)test/unit/size_classes.c \ $(srcroot)test/unit/smoothstep.c \ diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index e3c97bd8..efb4bfe4 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -417,22 +417,21 @@ for (i = 0; i < nbins; i++) { write_cb, or malloc_message if write_cb is NULL. This - function can be called repeatedly. General information that never - changes during execution can be omitted by specifying "g" as a character - within the opts string. Note that + function can be called repeatedly. General information that never changes + during execution can be omitted by specifying "g" as a character within + the opts string. Note that malloc_message uses the mallctl* functions internally, so inconsistent statistics can be reported if multiple threads use these - functions simultaneously. If is - specified during configuration, “m” and “a” can - be specified to omit merged arena and per arena statistics, respectively; - “b”, “l”, and “h” can be specified to - omit per size class statistics for bins, large objects, and huge objects, - respectively. Unrecognized characters are silently ignored. Note that - thread caching may prevent some statistics from being completely up to - date, since extra locking would be required to merge counters that track - thread cache operations. - + functions simultaneously. If is specified + during configuration, “m” and “a” can be specified + to omit merged arena and per arena statistics, respectively; + “b” and “l” can be specified to omit per size + class statistics for bins and large objects, respectively. Unrecognized + characters are silently ignored. Note that thread caching may prevent + some statistics from being completely up to date, since extra locking + would be required to merge counters that track thread cache + operations. The malloc_usable_size function returns the usable size of the allocation pointed to by @@ -1888,25 +1887,6 @@ typedef struct { Number of bytes per page run. - - - arenas.nlruns - (unsigned) - r- - - Total number of large size classes. - - - - - arenas.lrun.<i>.size - (size_t) - r- - - Maximum size supported by this large size - class. - - arenas.nhchunks @@ -2534,50 +2514,6 @@ typedef struct { Current number of runs. - - - stats.arenas.<i>.lruns.<j>.nmalloc - (uint64_t) - r- - [] - - Cumulative number of allocation requests for this size - class served directly by the arena. - - - - - stats.arenas.<i>.lruns.<j>.ndalloc - (uint64_t) - r- - [] - - Cumulative number of deallocation requests for this - size class served directly by the arena. - - - - - stats.arenas.<i>.lruns.<j>.nrequests - (uint64_t) - r- - [] - - Cumulative number of allocation requests for this size - class. - - - - - stats.arenas.<i>.lruns.<j>.curruns - (size_t) - r- - [] - - Current number of runs for this size class. - - - stats.arenas.<i>.hchunks.<j>.nmalloc diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 4d2b25a0..bf16e8e9 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -294,7 +294,6 @@ struct arena_s { dss_prec_t dss_prec; - /* Extant arena chunks. */ ql_head(extent_t) achunks; @@ -465,9 +464,6 @@ extern const arena_bin_info_t arena_bin_info[NBINS]; extern size_t map_bias; /* Number of arena chunk header pages. */ extern size_t map_misc_offset; extern size_t arena_maxrun; /* Max run size for arenas. */ -extern size_t large_maxclass; /* Max large size class. */ -extern unsigned nlclasses; /* Number of large size classes. */ -extern unsigned nhclasses; /* Number of huge size classes. */ #ifdef JEMALLOC_JET typedef size_t (run_quantize_t)(size_t); @@ -485,7 +481,8 @@ void arena_chunk_cache_maybe_remove(arena_t *arena, extent_t *extent, bool cache); extent_t *arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero); -void arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, extent_t *extent); +void arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + bool locked); void arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); void arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, @@ -508,33 +505,19 @@ extern arena_dalloc_junk_small_t *arena_dalloc_junk_small; #else void arena_dalloc_junk_small(void *ptr, const arena_bin_info_t *bin_info); #endif -void *arena_malloc_large(tsdn_t *tsdn, arena_t *arena, szind_t ind, - bool zero); void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero); void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero, tcache_t *tcache); -void arena_prof_promoted(tsdn_t *tsdn, const extent_t *extent, - const void *ptr, size_t size); +void arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize); +void arena_dalloc_promoted(tsdn_t *tsdn, extent_t *extent, void *ptr, + tcache_t *tcache, bool slow_path); void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, extent_t *extent, void *ptr, arena_chunk_map_bits_t *bitselm); void arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, extent_t *extent, void *ptr, size_t pageind); -#ifdef JEMALLOC_JET -typedef void (arena_dalloc_junk_large_t)(void *, size_t); -extern arena_dalloc_junk_large_t *arena_dalloc_junk_large; -#else -void arena_dalloc_junk_large(void *ptr, size_t usize); -#endif -void arena_dalloc_large_junked_locked(tsdn_t *tsdn, arena_t *arena, - arena_chunk_t *chunk, extent_t *extent, void *ptr); -void arena_dalloc_large(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - extent_t *extent, void *ptr); -#ifdef JEMALLOC_JET -typedef void (arena_ralloc_junk_large_t)(void *, size_t, size_t); -extern arena_ralloc_junk_large_t *arena_ralloc_junk_large; -#endif bool arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t extra, bool zero); void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, @@ -551,8 +534,7 @@ void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *lg_dirty_mult, ssize_t *decay_time, size_t *nactive, size_t *ndirty, arena_stats_t *astats, - malloc_bin_stats_t *bstats, malloc_large_stats_t *lstats, - malloc_huge_stats_t *hstats); + malloc_bin_stats_t *bstats, malloc_huge_stats_t *hstats); unsigned arena_nthreads_get(arena_t *arena, bool internal); void arena_nthreads_inc(arena_t *arena, bool internal); void arena_nthreads_dec(arena_t *arena, bool internal); @@ -639,8 +621,7 @@ void arena_decay_tick(tsdn_t *tsdn, arena_t *arena); void *arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, tcache_t *tcache, bool slow_path); arena_t *arena_aalloc(tsdn_t *tsdn, const void *ptr); -size_t arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr, - bool demote); +size_t arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr); void arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, bool slow_path); void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, @@ -1225,7 +1206,7 @@ arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, tcache, size, ind, zero, slow_path)); } if (likely(size <= tcache_maxclass)) { - return (tcache_alloc_large(tsdn_tsd(tsdn), arena, + return (tcache_alloc_huge(tsdn_tsd(tsdn), arena, tcache, size, ind, zero, slow_path)); } /* (size > tcache_maxclass) case falls through. */ @@ -1244,49 +1225,25 @@ arena_aalloc(tsdn_t *tsdn, const void *ptr) /* Return the size of the allocation pointed to by ptr. */ JEMALLOC_ALWAYS_INLINE size_t -arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr, bool demote) +arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { size_t ret; - size_t pageind; - szind_t binind; assert(ptr != NULL); if (likely(extent_slab_get(extent))) { const arena_chunk_t *chunk = (const arena_chunk_t *)extent_base_get(extent); + size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; + szind_t binind; - pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; assert(arena_mapbits_allocated_get(chunk, pageind) != 0); binind = arena_mapbits_binind_get(chunk, pageind); - if (unlikely(binind == BININD_INVALID || (config_prof && !demote - && arena_mapbits_large_get(chunk, pageind) != 0))) { - /* - * Large allocation. In the common case (demote), and - * as this is an inline function, most callers will only - * end up looking at binind to determine that ptr is a - * small allocation. - */ - assert(config_cache_oblivious || ((uintptr_t)ptr & - PAGE_MASK) == 0); - ret = arena_mapbits_large_size_get(chunk, pageind) - - large_pad; - assert(ret != 0); - assert(pageind + ((ret+large_pad)>>LG_PAGE) <= - chunk_npages); - assert(arena_mapbits_dirty_get(chunk, pageind) == - arena_mapbits_dirty_get(chunk, - pageind+((ret+large_pad)>>LG_PAGE)-1)); - } else { - /* - * Small allocation (possibly promoted to a large - * object). - */ - assert(arena_mapbits_large_get(chunk, pageind) != 0 || - arena_ptr_small_binind_get(tsdn, ptr, - arena_mapbits_get(chunk, pageind)) == binind); - ret = index2size(binind); - } + /* Small allocation. */ + assert(arena_mapbits_large_get(chunk, pageind) != 0 || + arena_ptr_small_binind_get(tsdn, ptr, + arena_mapbits_get(chunk, pageind)) == binind); + ret = index2size(binind); } else ret = huge_salloc(tsdn, extent); @@ -1297,49 +1254,40 @@ JEMALLOC_ALWAYS_INLINE void arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, bool slow_path) { - size_t pageind, mapbits; assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); if (likely(extent_slab_get(extent))) { + /* Small allocation. */ arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); - - pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - mapbits = arena_mapbits_get(chunk, pageind); + size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; + size_t mapbits = arena_mapbits_get(chunk, pageind); assert(arena_mapbits_allocated_get(chunk, pageind) != 0); - if (likely((mapbits & CHUNK_MAP_LARGE) == 0)) { - /* Small allocation. */ - if (likely(tcache != NULL)) { - szind_t binind = - arena_ptr_small_binind_get(tsdn, ptr, - mapbits); - tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, - binind, slow_path); - } else { - arena_dalloc_small(tsdn, - extent_arena_get(extent), chunk, extent, - ptr, pageind); - } + assert((mapbits & CHUNK_MAP_LARGE) == 0); + if (likely(tcache != NULL)) { + szind_t binind = arena_ptr_small_binind_get(tsdn, ptr, + mapbits); + tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, binind, + slow_path); } else { - size_t size = arena_mapbits_large_size_get(chunk, - pageind); - - assert(config_cache_oblivious || ((uintptr_t)ptr & - PAGE_MASK) == 0); + arena_dalloc_small(tsdn, extent_arena_get(extent), + chunk, extent, ptr, pageind); + } + } else { + size_t usize = extent_usize_get(extent); - if (likely(tcache != NULL) && size - large_pad <= - tcache_maxclass) { - tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, - size - large_pad, slow_path); + if (likely(tcache != NULL) && usize <= tcache_maxclass) { + if (config_prof && unlikely(usize <= SMALL_MAXCLASS)) { + arena_dalloc_promoted(tsdn, extent, ptr, + tcache, slow_path); } else { - arena_dalloc_large(tsdn, - extent_arena_get(extent), chunk, extent, - ptr); + tcache_dalloc_huge(tsdn_tsd(tsdn), tcache, ptr, + usize, slow_path); } - } - } else - huge_dalloc(tsdn, extent); + } else + huge_dalloc(tsdn, extent); + } } JEMALLOC_ALWAYS_INLINE void @@ -1348,55 +1296,34 @@ arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, { assert(!tsdn_null(tsdn) || tcache == NULL); + assert(ptr != NULL); if (likely(extent_slab_get(extent))) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); - - if (config_prof && opt_prof) { - size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> - LG_PAGE; - assert(arena_mapbits_allocated_get(chunk, pageind) != - 0); - if (arena_mapbits_large_get(chunk, pageind) != 0) { - /* - * Make sure to use promoted size, not request - * size. - */ - size = arena_mapbits_large_size_get(chunk, - pageind) - large_pad; - } + /* Small allocation. */ + if (likely(tcache != NULL)) { + szind_t binind = size2index(size); + tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, binind, + slow_path); + } else { + arena_chunk_t *chunk = + (arena_chunk_t *)extent_base_get(extent); + size_t pageind = ((uintptr_t)ptr - + (uintptr_t)chunk) >> LG_PAGE; + arena_dalloc_small(tsdn, extent_arena_get(extent), + chunk, extent, ptr, pageind); } - assert(s2u(size) == s2u(arena_salloc(tsdn, extent, ptr, - false))); - - if (likely(size <= SMALL_MAXCLASS)) { - /* Small allocation. */ - if (likely(tcache != NULL)) { - szind_t binind = size2index(size); - tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, - binind, slow_path); + } else { + if (likely(tcache != NULL) && size <= tcache_maxclass) { + if (config_prof && unlikely(size <= SMALL_MAXCLASS)) { + arena_dalloc_promoted(tsdn, extent, ptr, + tcache, slow_path); } else { - size_t pageind = ((uintptr_t)ptr - - (uintptr_t)chunk) >> LG_PAGE; - arena_dalloc_small(tsdn, - extent_arena_get(extent), chunk, extent, - ptr, pageind); - } - } else { - assert(config_cache_oblivious || ((uintptr_t)ptr & - PAGE_MASK) == 0); - - if (likely(tcache != NULL) && size <= tcache_maxclass) { - tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, + tcache_dalloc_huge(tsdn_tsd(tsdn), tcache, ptr, size, slow_path); - } else { - arena_dalloc_large(tsdn, - extent_arena_get(extent), chunk, extent, - ptr); } - } - } else - huge_dalloc(tsdn, extent); + } else + huge_dalloc(tsdn, extent); + } } # endif /* JEMALLOC_ARENA_INLINE_B */ #endif diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index 624073d9..6f50302e 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -61,7 +61,8 @@ bool chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, bool chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *extent, size_t offset, size_t length); extent_t *chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, extent_t *extent, size_t size_a, size_t size_b); + chunk_hooks_t *chunk_hooks, extent_t *extent, size_t size_a, size_t usize_a, + size_t size_b, size_t usize_b); bool chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t *a, extent_t *b); bool chunk_boot(void); diff --git a/include/jemalloc/internal/ctl.h b/include/jemalloc/internal/ctl.h index af0f6d7c..00deeb8a 100644 --- a/include/jemalloc/internal/ctl.h +++ b/include/jemalloc/internal/ctl.h @@ -51,8 +51,7 @@ struct ctl_arena_stats_s { uint64_t nrequests_small; malloc_bin_stats_t bstats[NBINS]; - malloc_large_stats_t *lstats; /* nlclasses elements. */ - malloc_huge_stats_t *hstats; /* nhclasses elements. */ + malloc_huge_stats_t hstats[NSIZES - NBINS]; }; struct ctl_stats_s { diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 4023f82d..4e1e97ea 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -15,9 +15,15 @@ struct extent_s { /* Pointer to the extent that this structure is responsible for. */ void *e_addr; - /* Total region size. */ + /* Extent size. */ size_t e_size; + /* + * Usable size, typically smaller than extent size due to large_pad or + * promotion of sampled small regions. + */ + size_t e_usize; + /* True if extent is active (in use). */ bool e_active; @@ -106,6 +112,7 @@ void extent_arena_set(extent_t *extent, arena_t *arena); void extent_addr_set(extent_t *extent, void *addr); void extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment); void extent_size_set(extent_t *extent, size_t size); +void extent_usize_set(extent_t *extent, size_t usize); void extent_active_set(extent_t *extent, bool active); void extent_dirty_set(extent_t *extent, bool dirty); void extent_zeroed_set(extent_t *extent, bool zeroed); @@ -113,8 +120,8 @@ void extent_committed_set(extent_t *extent, bool committed); void extent_slab_set(extent_t *extent, bool slab); void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx); void extent_init(extent_t *extent, arena_t *arena, void *addr, - size_t size, bool active, bool dirty, bool zeroed, bool committed, - bool slab); + size_t size, size_t usize, bool active, bool dirty, bool zeroed, + bool committed, bool slab); void extent_dirty_insert(extent_t *extent, arena_runs_dirty_link_t *runs_dirty, extent_t *chunks_dirty); void extent_dirty_remove(extent_t *extent); @@ -158,7 +165,7 @@ extent_usize_get(const extent_t *extent) { assert(!extent->e_slab); - return (extent->e_size - large_pad); + return (extent->e_usize); } JEMALLOC_INLINE void * @@ -172,14 +179,15 @@ JEMALLOC_INLINE void * extent_last_get(const extent_t *extent) { - return ((void *)(uintptr_t)extent->e_addr + extent->e_size - PAGE); + return ((void *)(uintptr_t)extent->e_addr + extent_size_get(extent) - + PAGE); } JEMALLOC_INLINE void * extent_past_get(const extent_t *extent) { - return ((void *)(uintptr_t)extent->e_addr + extent->e_size); + return ((void *)(uintptr_t)extent->e_addr + extent_size_get(extent)); } JEMALLOC_INLINE bool @@ -258,9 +266,12 @@ extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment) uint64_t r = prng_lg_range(&extent_arena_get(extent)->offset_state, lg_range, true); - uintptr_t random_offset = ((uintptr_t)r) << lg_range; + uintptr_t random_offset = ((uintptr_t)r) << (LG_PAGE - + lg_range); extent->e_addr = (void *)((uintptr_t)extent->e_addr + random_offset); + assert(ALIGNMENT_ADDR2BASE(extent->e_addr, alignment) == + extent->e_addr); } } @@ -271,6 +282,13 @@ extent_size_set(extent_t *extent, size_t size) extent->e_size = size; } +JEMALLOC_INLINE void +extent_usize_set(extent_t *extent, size_t usize) +{ + + extent->e_usize = usize; +} + JEMALLOC_INLINE void extent_active_set(extent_t *extent, bool active) { @@ -315,7 +333,8 @@ extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) JEMALLOC_INLINE void extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, - bool active, bool dirty, bool zeroed, bool committed, bool slab) + size_t usize, bool active, bool dirty, bool zeroed, bool committed, + bool slab) { assert(addr == PAGE_ADDR2BASE(addr) || !slab); @@ -323,6 +342,7 @@ extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, extent_arena_set(extent, arena); extent_addr_set(extent, addr); extent_size_set(extent, size); + extent_usize_set(extent, usize); extent_active_set(extent, active); extent_dirty_set(extent, dirty); extent_zeroed_set(extent, zeroed); diff --git a/include/jemalloc/internal/huge.h b/include/jemalloc/internal/huge.h index bdc8f847..836f1b50 100644 --- a/include/jemalloc/internal/huge.h +++ b/include/jemalloc/internal/huge.h @@ -17,9 +17,12 @@ bool huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, void *huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, size_t alignment, bool zero, tcache_t *tcache); #ifdef JEMALLOC_JET -typedef void (huge_dalloc_junk_t)(tsdn_t *, void *, size_t); +typedef void (huge_dalloc_junk_t)(void *, size_t); extern huge_dalloc_junk_t *huge_dalloc_junk; +#else +void huge_dalloc_junk(void *ptr, size_t usize); #endif +void huge_dalloc_junked_locked(tsdn_t *tsdn, extent_t *extent); void huge_dalloc(tsdn_t *tsdn, extent_t *extent); size_t huge_salloc(tsdn_t *tsdn, const extent_t *extent); prof_tctx_t *huge_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent); diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index ef4e0522..f4d26beb 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -797,33 +797,14 @@ sa2u(size_t size, size_t alignment) return (usize); } - /* - * We can't achieve subpage alignment, so round up alignment to the - * minimum that can actually be supported. - */ - alignment = PAGE_CEILING(alignment); - - /* Try for a large size class. */ - if (likely(size <= large_maxclass) && likely(alignment == PAGE)) { - /* Make sure result is a large size class. */ - usize = (size <= LARGE_MINCLASS) ? LARGE_MINCLASS : s2u(size); - - /* - * Calculate the size of the over-size run that arena_palloc() - * would need to allocate in order to guarantee the alignment. - */ - if (usize + large_pad + alignment <= arena_maxrun) - return (usize); - } - /* Huge size class. Beware of overflow. */ if (unlikely(alignment > HUGE_MAXCLASS)) return (0); - /* Make sure result is a huge size class. */ - if (size <= chunksize) - usize = chunksize; + /* Make sure result is a large size class. */ + if (size <= LARGE_MINCLASS) + usize = LARGE_MINCLASS; else { usize = s2u(size); if (usize < size) { @@ -836,7 +817,7 @@ sa2u(size_t size, size_t alignment) * Calculate the multi-page mapping that huge_palloc() would need in * order to guarantee the alignment. */ - if (usize + alignment < usize) { + if (usize + large_pad + PAGE_CEILING(alignment) < usize) { /* size_t overflow. */ return (0); } @@ -960,8 +941,7 @@ iealloc(tsdn_t *tsdn, const void *ptr) #ifndef JEMALLOC_ENABLE_INLINE arena_t *iaalloc(tsdn_t *tsdn, const void *ptr); -size_t isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr, - bool demote); +size_t isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr); void *iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, bool is_metadata, arena_t *arena, bool slow_path); void *ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, @@ -971,7 +951,7 @@ void *ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, void *ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); void *ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero); -size_t ivsalloc(tsdn_t *tsdn, const void *ptr, bool demote); +size_t ivsalloc(tsdn_t *tsdn, const void *ptr); void idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, bool is_metadata, bool slow_path); void idalloc(tsd_t *tsd, extent_t *extent, void *ptr); @@ -1003,17 +983,15 @@ iaalloc(tsdn_t *tsdn, const void *ptr) * tsdn_t *tsdn = [...] * void *ptr = [...] * extent_t *extent = iealloc(tsdn, ptr); - * size_t sz = isalloc(tsdn, extent, ptr, config_prof); + * size_t sz = isalloc(tsdn, extent, ptr); */ JEMALLOC_ALWAYS_INLINE size_t -isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr, bool demote) +isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { assert(ptr != NULL); - /* Demotion only makes sense if config_prof is true. */ - assert(config_prof || !demote); - return (arena_salloc(tsdn, extent, ptr, demote)); + return (arena_salloc(tsdn, extent, ptr)); } JEMALLOC_ALWAYS_INLINE void * @@ -1029,7 +1007,7 @@ iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, ret = arena_malloc(tsdn, arena, size, ind, zero, tcache, slow_path); if (config_stats && is_metadata && likely(ret != NULL)) { arena_metadata_allocated_add(iaalloc(tsdn, ret), isalloc(tsdn, - iealloc(tsdn, ret), ret, config_prof)); + iealloc(tsdn, ret), ret)); } return (ret); } @@ -1057,7 +1035,7 @@ ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret); if (config_stats && is_metadata && likely(ret != NULL)) { arena_metadata_allocated_add(iaalloc(tsdn, ret), isalloc(tsdn, - iealloc(tsdn, ret), ret, config_prof)); + iealloc(tsdn, ret), ret)); } return (ret); } @@ -1079,7 +1057,7 @@ ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero) } JEMALLOC_ALWAYS_INLINE size_t -ivsalloc(tsdn_t *tsdn, const void *ptr, bool demote) +ivsalloc(tsdn_t *tsdn, const void *ptr) { extent_t *extent; @@ -1091,7 +1069,7 @@ ivsalloc(tsdn_t *tsdn, const void *ptr, bool demote) /* Only arena chunks should be looked up via interior pointers. */ assert(extent_addr_get(extent) == ptr || extent_slab_get(extent)); - return (isalloc(tsdn, extent, ptr, demote)); + return (isalloc(tsdn, extent, ptr)); } JEMALLOC_ALWAYS_INLINE void @@ -1104,7 +1082,7 @@ idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, assert(!is_metadata || iaalloc(tsdn, ptr)->ind < narenas_auto); if (config_stats && is_metadata) { arena_metadata_allocated_sub(iaalloc(tsdn, ptr), isalloc(tsdn, - extent, ptr, config_prof)); + extent, ptr)); } arena_dalloc(tsdn, extent, ptr, tcache, slow_path); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 75a1dace..5f94d2c2 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -23,10 +23,8 @@ arena_cleanup arena_dalloc arena_dalloc_bin arena_dalloc_bin_junked_locked -arena_dalloc_junk_large arena_dalloc_junk_small -arena_dalloc_large -arena_dalloc_large_junked_locked +arena_dalloc_promoted arena_dalloc_small arena_decay_tick arena_decay_ticks @@ -45,7 +43,6 @@ arena_lg_dirty_mult_get arena_lg_dirty_mult_set arena_malloc arena_malloc_hard -arena_malloc_large arena_mapbits_allocated_get arena_mapbits_binind_get arena_mapbits_decommitted_get @@ -92,7 +89,7 @@ arena_prefork3 arena_prof_accum arena_prof_accum_impl arena_prof_accum_locked -arena_prof_promoted +arena_prof_promote arena_prof_tctx_get arena_prof_tctx_reset arena_prof_tctx_set @@ -254,6 +251,7 @@ hash_x86_128 hash_x86_32 huge_dalloc huge_dalloc_junk +huge_dalloc_junked_locked huge_malloc huge_palloc huge_prof_tctx_get @@ -287,7 +285,6 @@ ixalloc jemalloc_postfork_child jemalloc_postfork_parent jemalloc_prefork -large_maxclass lg_floor lg_prof_sample malloc_cprintf @@ -320,8 +317,6 @@ narenas_tdata_cleanup narenas_total_get ncpus nhbins -nhclasses -nlclasses nstime_add nstime_compare nstime_copy diff --git a/include/jemalloc/internal/prof.h b/include/jemalloc/internal/prof.h index 81f02d11..7da20ad0 100644 --- a/include/jemalloc/internal/prof.h +++ b/include/jemalloc/internal/prof.h @@ -489,7 +489,7 @@ prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, cassert(config_prof); assert(ptr != NULL); - assert(usize == isalloc(tsdn, extent, ptr, true)); + assert(usize == isalloc(tsdn, extent, ptr)); if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) prof_malloc_sample_object(tsdn, extent, ptr, usize, tctx); @@ -510,7 +510,7 @@ prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, assert(ptr != NULL || (uintptr_t)tctx <= (uintptr_t)1U); if (prof_active && !updated && ptr != NULL) { - assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr, true)); + assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr)); if (prof_sample_accum_update(tsd, usize, true, NULL)) { /* * Don't sample. The usize passed to prof_alloc_prep() @@ -544,7 +544,7 @@ prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, size_t usize) prof_tctx_t *tctx = prof_tctx_get(tsd_tsdn(tsd), extent, ptr); cassert(config_prof); - assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr, true)); + assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr)); if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) prof_free_sampled_object(tsd, usize, tctx); diff --git a/include/jemalloc/internal/stats.h b/include/jemalloc/internal/stats.h index b6218178..c9a716d7 100644 --- a/include/jemalloc/internal/stats.h +++ b/include/jemalloc/internal/stats.h @@ -3,7 +3,6 @@ typedef struct tcache_bin_stats_s tcache_bin_stats_t; typedef struct malloc_bin_stats_s malloc_bin_stats_t; -typedef struct malloc_large_stats_s malloc_large_stats_t; typedef struct malloc_huge_stats_s malloc_huge_stats_t; typedef struct arena_stats_s arena_stats_t; typedef struct chunk_stats_s chunk_stats_t; @@ -62,12 +61,10 @@ struct malloc_bin_stats_s { size_t curruns; }; -struct malloc_large_stats_s { +struct malloc_huge_stats_s { /* * Total number of allocation/deallocation requests served directly by - * the arena. Note that tcache may allocate an object, then recycle it - * many times, resulting many increments to nrequests, but only one - * each to nmalloc and ndalloc. + * the arena. */ uint64_t nmalloc; uint64_t ndalloc; @@ -79,21 +76,6 @@ struct malloc_large_stats_s { */ uint64_t nrequests; - /* - * Current number of runs of this size class, including runs currently - * cached by tcache. - */ - size_t curruns; -}; - -struct malloc_huge_stats_s { - /* - * Total number of allocation/deallocation requests served directly by - * the arena. - */ - uint64_t nmalloc; - uint64_t ndalloc; - /* Current number of (multi-)chunk allocations of this size class. */ size_t curhchunks; }; @@ -126,21 +108,13 @@ struct arena_stats_s { size_t metadata_mapped; size_t metadata_allocated; /* Protected via atomic_*_z(). */ - /* Per-size-category statistics. */ - size_t allocated_large; - uint64_t nmalloc_large; - uint64_t ndalloc_large; - uint64_t nrequests_large; - size_t allocated_huge; uint64_t nmalloc_huge; uint64_t ndalloc_huge; - - /* One element for each large size class. */ - malloc_large_stats_t *lstats; + uint64_t nrequests_huge; /* One element for each huge size class. */ - malloc_huge_stats_t *hstats; + malloc_huge_stats_t hstats[NSIZES - NBINS]; }; #endif /* JEMALLOC_H_STRUCTS */ diff --git a/include/jemalloc/internal/tcache.h b/include/jemalloc/internal/tcache.h index ee63a652..186adf28 100644 --- a/include/jemalloc/internal/tcache.h +++ b/include/jemalloc/internal/tcache.h @@ -30,8 +30,8 @@ typedef struct tcaches_s tcaches_t; */ #define TCACHE_NSLOTS_SMALL_MAX 200 -/* Number of cache slots for large size classes. */ -#define TCACHE_NSLOTS_LARGE 20 +/* Number of cache slots for huge size classes. */ +#define TCACHE_NSLOTS_HUGE 20 /* (1U << opt_lg_tcache_max) is used to compute tcache_maxclass. */ #define LG_TCACHE_MAXCLASS_DEFAULT 15 @@ -113,7 +113,7 @@ extern tcache_bin_info_t *tcache_bin_info; /* * Number of tcache bins. There are NBINS small-object bins, plus 0 or more - * large-object bins. + * huge-object bins. */ extern unsigned nhbins; @@ -136,7 +136,7 @@ void *tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, tcache_bin_t *tbin, szind_t binind, bool *tcache_success); void tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, szind_t binind, unsigned rem); -void tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, +void tcache_bin_flush_huge(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, unsigned rem, tcache_t *tcache); void tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *oldarena, arena_t *newarena); @@ -163,11 +163,11 @@ void tcache_enabled_set(bool enabled); void *tcache_alloc_easy(tcache_bin_t *tbin, bool *tcache_success); void *tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, szind_t ind, bool zero, bool slow_path); -void *tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, +void *tcache_alloc_huge(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, szind_t ind, bool zero, bool slow_path); void tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, bool slow_path); -void tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, +void tcache_dalloc_huge(tsd_t *tsd, tcache_t *tcache, void *ptr, size_t size, bool slow_path); tcache_t *tcaches_get(tsd_t *tsd, unsigned ind); #endif @@ -336,7 +336,7 @@ tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, } JEMALLOC_ALWAYS_INLINE void * -tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, +tcache_alloc_huge(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, szind_t binind, bool zero, bool slow_path) { void *ret; @@ -349,14 +349,14 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, assert(tcache_success == (ret != NULL)); if (unlikely(!tcache_success)) { /* - * Only allocate one large object at a time, because it's quite + * Only allocate one huge object at a time, because it's quite * expensive to create one and not use it. */ arena = arena_choose(tsd, arena); if (unlikely(arena == NULL)) return (NULL); - ret = arena_malloc_large(tsd_tsdn(tsd), arena, binind, zero); + ret = huge_malloc(tsd_tsdn(tsd), arena, s2u(size), zero); if (ret == NULL) return (NULL); } else { @@ -369,14 +369,6 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, assert(usize <= tcache_maxclass); } - if (config_prof && usize == LARGE_MINCLASS) { - arena_chunk_t *chunk =(arena_chunk_t *)extent_addr_get( - iealloc(tsd_tsdn(tsd), ret)); - size_t pageind = (((uintptr_t)ret - (uintptr_t)chunk) >> - LG_PAGE); - arena_mapbits_large_binind_set(chunk, pageind, - BININD_INVALID); - } if (likely(!zero)) { if (slow_path && config_fill) { if (unlikely(opt_junk_alloc)) { @@ -424,26 +416,25 @@ tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, } JEMALLOC_ALWAYS_INLINE void -tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, size_t size, +tcache_dalloc_huge(tsd_t *tsd, tcache_t *tcache, void *ptr, size_t size, bool slow_path) { szind_t binind; tcache_bin_t *tbin; tcache_bin_info_t *tbin_info; - assert((size & PAGE_MASK) == 0); assert(tcache_salloc(tsd_tsdn(tsd), ptr) > SMALL_MAXCLASS); assert(tcache_salloc(tsd_tsdn(tsd), ptr) <= tcache_maxclass); binind = size2index(size); if (slow_path && config_fill && unlikely(opt_junk_free)) - arena_dalloc_junk_large(ptr, size); + huge_dalloc_junk(ptr, size); tbin = &tcache->tbins[binind]; tbin_info = &tcache_bin_info[binind]; if (unlikely(tbin->ncached == tbin_info->ncached_max)) { - tcache_bin_flush_large(tsd, tbin, binind, + tcache_bin_flush_huge(tsd, tbin, binind, (tbin_info->ncached_max >> 1), tcache); } assert(tbin->ncached < tbin_info->ncached_max); diff --git a/src/arena.c b/src/arena.c index 4ce55577..d9882a45 100644 --- a/src/arena.c +++ b/src/arena.c @@ -33,9 +33,6 @@ const arena_bin_info_t arena_bin_info[NBINS] = { size_t map_bias; size_t map_misc_offset; size_t arena_maxrun; /* Max run size for arenas. */ -size_t large_maxclass; /* Max large size class. */ -unsigned nlclasses; /* Number of large size classes. */ -unsigned nhclasses; /* Number of huge size classes. */ /******************************************************************************/ /* @@ -447,6 +444,7 @@ static void arena_nactive_sub(arena_t *arena, size_t sub_pages) { + assert(arena->nactive >= sub_pages); if (config_stats) { size_t cactive_sub = CHUNK_CEILING(arena->nactive << LG_PAGE) - CHUNK_CEILING((arena->nactive - sub_pages) << LG_PAGE); @@ -573,15 +571,6 @@ arena_run_split_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, true, zero)); } -static bool -arena_run_init_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - arena_run_t *run, size_t size, bool zero) -{ - - return (arena_run_split_large_helper(tsdn, arena, extent, run, size, - false, zero)); -} - static bool arena_run_split_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, arena_run_t *run, size_t size, szind_t binind) @@ -835,58 +824,64 @@ arena_chunk_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) static void arena_huge_malloc_stats_update(arena_t *arena, size_t usize) { - szind_t index = size2index(usize) - nlclasses - NBINS; + szind_t index = size2index(usize); + szind_t hindex = (index >= NBINS) ? index - NBINS : 0; cassert(config_stats); arena->stats.nmalloc_huge++; arena->stats.allocated_huge += usize; - arena->stats.hstats[index].nmalloc++; - arena->stats.hstats[index].curhchunks++; + arena->stats.hstats[hindex].nmalloc++; + arena->stats.hstats[hindex].nrequests++; + arena->stats.hstats[hindex].curhchunks++; } static void arena_huge_malloc_stats_update_undo(arena_t *arena, size_t usize) { - szind_t index = size2index(usize) - nlclasses - NBINS; + szind_t index = size2index(usize); + szind_t hindex = (index >= NBINS) ? index - NBINS : 0; cassert(config_stats); arena->stats.nmalloc_huge--; arena->stats.allocated_huge -= usize; - arena->stats.hstats[index].nmalloc--; - arena->stats.hstats[index].curhchunks--; + arena->stats.hstats[hindex].nmalloc--; + arena->stats.hstats[hindex].nrequests--; + arena->stats.hstats[hindex].curhchunks--; } static void arena_huge_dalloc_stats_update(arena_t *arena, size_t usize) { - szind_t index = size2index(usize) - nlclasses - NBINS; + szind_t index = size2index(usize); + szind_t hindex = (index >= NBINS) ? index - NBINS : 0; cassert(config_stats); arena->stats.ndalloc_huge++; arena->stats.allocated_huge -= usize; - arena->stats.hstats[index].ndalloc++; - arena->stats.hstats[index].curhchunks--; + arena->stats.hstats[hindex].ndalloc++; + arena->stats.hstats[hindex].curhchunks--; } static void arena_huge_reset_stats_cancel(arena_t *arena, size_t usize) { - szind_t index = size2index(usize) - nlclasses - NBINS; + szind_t index = size2index(usize); + szind_t hindex = (index >= NBINS) ? index - NBINS : 0; cassert(config_stats); arena->stats.ndalloc_huge++; - arena->stats.hstats[index].ndalloc--; + arena->stats.hstats[hindex].ndalloc--; } static void -arena_huge_ralloc_stats_update(arena_t *arena, size_t oldsize, size_t usize) +arena_huge_ralloc_stats_update(arena_t *arena, size_t oldusize, size_t usize) { - arena_huge_dalloc_stats_update(arena, oldsize); + arena_huge_dalloc_stats_update(arena, oldusize); arena_huge_malloc_stats_update(arena, usize); } @@ -906,7 +901,7 @@ arena_chunk_alloc_huge_hard(tsdn_t *tsdn, arena_t *arena, arena_huge_malloc_stats_update_undo(arena, usize); arena->stats.mapped -= usize; } - arena_nactive_sub(arena, usize >> LG_PAGE); + arena_nactive_sub(arena, (usize + large_pad) >> LG_PAGE); malloc_mutex_unlock(tsdn, &arena->lock); } @@ -927,7 +922,7 @@ arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, arena_huge_malloc_stats_update(arena, usize); arena->stats.mapped += usize; } - arena_nactive_add(arena, usize >> LG_PAGE); + arena_nactive_add(arena, (usize + large_pad) >> LG_PAGE); extent = arena_chunk_cache_alloc_locked(tsdn, arena, &chunk_hooks, NULL, usize, large_pad, alignment, zero, false); @@ -941,34 +936,35 @@ arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, } void -arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, extent_t *extent) +arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + bool locked) { chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; - malloc_mutex_lock(tsdn, &arena->lock); + if (!locked) + malloc_mutex_lock(tsdn, &arena->lock); if (config_stats) { - arena_huge_dalloc_stats_update(arena, extent_size_get(extent)); + arena_huge_dalloc_stats_update(arena, extent_usize_get(extent)); arena->stats.mapped -= extent_size_get(extent); } arena_nactive_sub(arena, extent_size_get(extent) >> LG_PAGE); arena_chunk_cache_dalloc_locked(tsdn, arena, &chunk_hooks, extent); - malloc_mutex_unlock(tsdn, &arena->lock); + if (!locked) + malloc_mutex_unlock(tsdn, &arena->lock); } void arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - size_t oldsize) + size_t oldusize) { - size_t usize = extent_size_get(extent); - size_t udiff = oldsize - usize; - size_t cdiff = CHUNK_CEILING(oldsize) - CHUNK_CEILING(usize); + size_t usize = extent_usize_get(extent); + size_t udiff = oldusize - usize; malloc_mutex_lock(tsdn, &arena->lock); if (config_stats) { - arena_huge_ralloc_stats_update(arena, oldsize, usize); - if (cdiff != 0) - arena->stats.mapped -= cdiff; + arena_huge_ralloc_stats_update(arena, oldusize, usize); + arena->stats.mapped -= udiff; } arena_nactive_sub(arena, udiff >> LG_PAGE); malloc_mutex_unlock(tsdn, &arena->lock); @@ -976,16 +972,15 @@ arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - size_t oldsize) + size_t oldusize) { - size_t usize = extent_size_get(extent); - size_t cdiff = CHUNK_CEILING(usize) - CHUNK_CEILING(oldsize); - size_t udiff = usize - oldsize; + size_t usize = extent_usize_get(extent); + size_t udiff = usize - oldusize; malloc_mutex_lock(tsdn, &arena->lock); if (config_stats) { - arena_huge_ralloc_stats_update(arena, oldsize, usize); - arena->stats.mapped += cdiff; + arena_huge_ralloc_stats_update(arena, oldusize, usize); + arena->stats.mapped += udiff; } arena_nactive_add(arena, udiff >> LG_PAGE); malloc_mutex_unlock(tsdn, &arena->lock); @@ -1003,7 +998,7 @@ arena_run_first_best_fit(arena_t *arena, size_t size) pind = psz2ind(run_quantize_ceil(size)); - for (i = pind; pind2sz(i) <= large_maxclass; i++) { + for (i = pind; pind2sz(i) <= arena_maxrun; i++) { arena_chunk_map_misc_t *miscelm = arena_run_heap_first( &arena->runs_avail[i]); if (miscelm != NULL) @@ -1013,54 +1008,6 @@ arena_run_first_best_fit(arena_t *arena, size_t size) return (NULL); } -static arena_run_t * -arena_run_alloc_large_helper(tsdn_t *tsdn, arena_t *arena, size_t size, - bool zero) -{ - arena_run_t *run = arena_run_first_best_fit(arena, s2u(size)); - if (run != NULL) { - if (arena_run_split_large(tsdn, arena, iealloc(tsdn, run), run, - size, zero)) - run = NULL; - } - return (run); -} - -static arena_run_t * -arena_run_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t size, bool zero) -{ - arena_run_t *run; - extent_t *extent; - - assert(size <= arena_maxrun); - assert(size == PAGE_CEILING(size)); - - /* Search the arena's chunks for the lowest best fit. */ - run = arena_run_alloc_large_helper(tsdn, arena, size, zero); - if (run != NULL) - return (run); - - /* - * No usable runs. Create a new chunk from which to allocate the run. - */ - extent = arena_chunk_alloc(tsdn, arena); - if (extent != NULL) { - run = &arena_miscelm_get_mutable((arena_chunk_t *) - extent_base_get(extent), map_bias)->run; - if (arena_run_split_large(tsdn, arena, iealloc(tsdn, run), run, - size, zero)) - run = NULL; - return (run); - } - - /* - * arena_chunk_alloc() failed, but another thread may have made - * sufficient memory available while this one dropped arena->lock in - * arena_chunk_alloc(), so search one more time. - */ - return (arena_run_alloc_large_helper(tsdn, arena, size, zero)); -} - static arena_run_t * arena_run_alloc_small_helper(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t binind) @@ -1700,8 +1647,8 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) arena->lg_dirty_mult) < arena->ndirty || ndirty_limit == 0); qr_new(&purge_runs_sentinel, rd_link); - extent_init(&purge_chunks_sentinel, arena, NULL, 0, false, false, false, - false, false); + extent_init(&purge_chunks_sentinel, arena, NULL, 0, 0, false, false, + false, false, false); npurge = arena_stash_dirty(tsdn, arena, &chunk_hooks, ndirty_limit, &purge_runs_sentinel, &purge_chunks_sentinel); @@ -1732,47 +1679,6 @@ arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) malloc_mutex_unlock(tsdn, &arena->lock); } -static void -arena_achunk_prof_reset(tsd_t *tsd, arena_t *arena, extent_t *extent) -{ - arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); - size_t pageind, npages; - - cassert(config_prof); - assert(opt_prof); - - /* - * Iterate over the allocated runs and remove profiled allocations from - * the sample set. - */ - for (pageind = map_bias; pageind < chunk_npages; pageind += npages) { - if (arena_mapbits_allocated_get(chunk, pageind) != 0) { - if (arena_mapbits_large_get(chunk, pageind) != 0) { - void *ptr = (void *)((uintptr_t)chunk + (pageind - << LG_PAGE)); - size_t usize = isalloc(tsd_tsdn(tsd), extent, - ptr, config_prof); - - prof_free(tsd, extent, ptr, usize); - npages = arena_mapbits_large_size_get(chunk, - pageind) >> LG_PAGE; - } else { - /* Skip small run. */ - size_t binind = arena_mapbits_binind_get(chunk, - pageind); - const arena_bin_info_t *bin_info = - &arena_bin_info[binind]; - npages = bin_info->run_size >> LG_PAGE; - } - } else { - /* Skip unallocated run. */ - npages = arena_mapbits_unallocated_size_get(chunk, - pageind) >> LG_PAGE; - } - assert(pageind + npages <= chunk_npages); - } -} - void arena_reset(tsd_t *tsd, arena_t *arena) { @@ -1793,19 +1699,6 @@ arena_reset(tsd_t *tsd, arena_t *arena) * stats refreshes would impose an inconvenient burden. */ - /* Remove large allocations from prof sample set. */ - if (config_prof && opt_prof) { - ql_foreach(extent, &arena->achunks, ql_link) { - arena_achunk_prof_reset(tsd, arena, extent); - } - } - - /* Reset curruns for large size classes. */ - if (config_stats) { - for (i = 0; i < nlclasses; i++) - arena->stats.lstats[i].curruns = 0; - } - /* Huge allocations. */ malloc_mutex_lock(tsd_tsdn(tsd), &arena->huge_mtx); for (extent = ql_last(&arena->huge, ql_link); extent != NULL; extent = @@ -1814,10 +1707,8 @@ arena_reset(tsd_t *tsd, arena_t *arena) size_t usize; malloc_mutex_unlock(tsd_tsdn(tsd), &arena->huge_mtx); - if (config_stats || (config_prof && opt_prof)) { - usize = isalloc(tsd_tsdn(tsd), extent, ptr, - config_prof); - } + if (config_stats || (config_prof && opt_prof)) + usize = isalloc(tsd_tsdn(tsd), extent, ptr); /* Remove huge allocation from prof sample set. */ if (config_prof && opt_prof) prof_free(tsd, extent, ptr, usize); @@ -2069,93 +1960,6 @@ arena_run_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, arena_maybe_purge(tsdn, arena); } -static void -arena_run_trim_head(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - extent_t *extent, arena_run_t *run, size_t oldsize, size_t newsize) -{ - arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(extent, run); - size_t pageind = arena_miscelm_to_pageind(extent, miscelm); - size_t head_npages = (oldsize - newsize) >> LG_PAGE; - size_t flag_dirty = arena_mapbits_dirty_get(chunk, pageind); - size_t flag_decommitted = arena_mapbits_decommitted_get(chunk, pageind); - size_t flag_unzeroed_mask = (flag_dirty | flag_decommitted) == 0 ? - CHUNK_MAP_UNZEROED : 0; - - assert(oldsize > newsize); - - /* - * Update the chunk map so that arena_run_dalloc() can treat the - * leading run as separately allocated. Set the last element of each - * run first, in case of single-page runs. - */ - assert(arena_mapbits_large_size_get(chunk, pageind) == oldsize); - arena_mapbits_large_set(chunk, pageind+head_npages-1, 0, flag_dirty | - (flag_unzeroed_mask & arena_mapbits_unzeroed_get(chunk, - pageind+head_npages-1))); - arena_mapbits_large_set(chunk, pageind, oldsize-newsize, flag_dirty | - (flag_unzeroed_mask & arena_mapbits_unzeroed_get(chunk, pageind))); - - if (config_debug) { - UNUSED size_t tail_npages = newsize >> LG_PAGE; - assert(arena_mapbits_large_size_get(chunk, - pageind+head_npages+tail_npages-1) == 0); - assert(arena_mapbits_dirty_get(chunk, - pageind+head_npages+tail_npages-1) == flag_dirty); - } - arena_mapbits_large_set(chunk, pageind+head_npages, newsize, - flag_dirty | (flag_unzeroed_mask & arena_mapbits_unzeroed_get(chunk, - pageind+head_npages))); - - arena_run_dalloc(tsdn, arena, extent, run, false, false, - (flag_decommitted != 0)); -} - -static void -arena_run_trim_tail(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - extent_t *extent, arena_run_t *run, size_t oldsize, size_t newsize, - bool dirty) -{ - arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(extent, run); - size_t pageind = arena_miscelm_to_pageind(extent, miscelm); - size_t head_npages = newsize >> LG_PAGE; - size_t flag_dirty = arena_mapbits_dirty_get(chunk, pageind); - size_t flag_decommitted = arena_mapbits_decommitted_get(chunk, pageind); - size_t flag_unzeroed_mask = (flag_dirty | flag_decommitted) == 0 ? - CHUNK_MAP_UNZEROED : 0; - arena_chunk_map_misc_t *tail_miscelm; - arena_run_t *tail_run; - - assert(oldsize > newsize); - - /* - * Update the chunk map so that arena_run_dalloc() can treat the - * trailing run as separately allocated. Set the last element of each - * run first, in case of single-page runs. - */ - assert(arena_mapbits_large_size_get(chunk, pageind) == oldsize); - arena_mapbits_large_set(chunk, pageind+head_npages-1, 0, flag_dirty | - (flag_unzeroed_mask & arena_mapbits_unzeroed_get(chunk, - pageind+head_npages-1))); - arena_mapbits_large_set(chunk, pageind, newsize, flag_dirty | - (flag_unzeroed_mask & arena_mapbits_unzeroed_get(chunk, pageind))); - - if (config_debug) { - UNUSED size_t tail_npages = (oldsize - newsize) >> LG_PAGE; - assert(arena_mapbits_large_size_get(chunk, - pageind+head_npages+tail_npages-1) == 0); - assert(arena_mapbits_dirty_get(chunk, - pageind+head_npages+tail_npages-1) == flag_dirty); - } - arena_mapbits_large_set(chunk, pageind+head_npages, oldsize-newsize, - flag_dirty | (flag_unzeroed_mask & arena_mapbits_unzeroed_get(chunk, - pageind+head_npages))); - - tail_miscelm = arena_miscelm_get_mutable(chunk, pageind + head_npages); - tail_run = &tail_miscelm->run; - arena_run_dalloc(tsdn, arena, extent, tail_run, dirty, false, - (flag_decommitted != 0)); -} - static void arena_bin_runs_insert(arena_bin_t *bin, extent_t *extent, arena_run_t *run) { @@ -2390,7 +2194,7 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) bin->stats.curregs++; } malloc_mutex_unlock(tsdn, &bin->lock); - if (config_prof && !isthreaded && arena_prof_accum(tsdn, arena, usize)) + if (config_prof && arena_prof_accum(tsdn, arena, usize)) prof_idump(tsdn); if (!zero) { @@ -2413,71 +2217,6 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) return (ret); } -void * -arena_malloc_large(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) -{ - void *ret; - size_t usize; - uintptr_t random_offset; - arena_run_t *run; - extent_t *extent; - arena_chunk_map_misc_t *miscelm; - UNUSED bool idump JEMALLOC_CC_SILENCE_INIT(false); - - /* Large allocation. */ - usize = index2size(binind); - if (config_cache_oblivious) { - uint64_t r; - - /* - * Compute a uniformly distributed offset within the first page - * that is a multiple of the cacheline size, e.g. [0 .. 63) * 64 - * for 4 KiB pages and 64-byte cachelines. - */ - r = prng_lg_range(&arena->offset_state, LG_PAGE - LG_CACHELINE, - true); - random_offset = ((uintptr_t)r) << LG_CACHELINE; - } else - random_offset = 0; - malloc_mutex_lock(tsdn, &arena->lock); - run = arena_run_alloc_large(tsdn, arena, usize + large_pad, zero); - if (run == NULL) { - malloc_mutex_unlock(tsdn, &arena->lock); - return (NULL); - } - extent = iealloc(tsdn, run); - miscelm = arena_run_to_miscelm(extent, run); - ret = (void *)((uintptr_t)arena_miscelm_to_rpages(extent, miscelm) + - random_offset); - if (config_stats) { - szind_t index = binind - NBINS; - - arena->stats.nmalloc_large++; - arena->stats.nrequests_large++; - arena->stats.allocated_large += usize; - arena->stats.lstats[index].nmalloc++; - arena->stats.lstats[index].nrequests++; - arena->stats.lstats[index].curruns++; - } - if (config_prof) - idump = arena_prof_accum_locked(arena, usize); - malloc_mutex_unlock(tsdn, &arena->lock); - if (config_prof && idump) - prof_idump(tsdn); - - if (!zero) { - if (config_fill) { - if (unlikely(opt_junk_alloc)) - memset(ret, JEMALLOC_ALLOC_JUNK, usize); - else if (unlikely(opt_zero)) - memset(ret, 0, usize); - } - } - - arena_decay_tick(tsdn, arena); - return (ret); -} - void * arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero) @@ -2492,106 +2231,9 @@ arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, if (likely(size <= SMALL_MAXCLASS)) return (arena_malloc_small(tsdn, arena, ind, zero)); - if (likely(size <= large_maxclass)) - return (arena_malloc_large(tsdn, arena, ind, zero)); return (huge_malloc(tsdn, arena, index2size(ind), zero)); } -/* Only handles large allocations that require more than page alignment. */ -static void * -arena_palloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, - bool zero) -{ - void *ret; - size_t alloc_size, leadsize, trailsize; - arena_run_t *run; - extent_t *extent; - arena_chunk_t *chunk; - arena_chunk_map_misc_t *miscelm; - void *rpages; - - assert(!tsdn_null(tsdn) || arena != NULL); - assert(usize == PAGE_CEILING(usize)); - - if (likely(!tsdn_null(tsdn))) - arena = arena_choose(tsdn_tsd(tsdn), arena); - if (unlikely(arena == NULL)) - return (NULL); - - alignment = PAGE_CEILING(alignment); - alloc_size = usize + large_pad + alignment; - - malloc_mutex_lock(tsdn, &arena->lock); - run = arena_run_alloc_large(tsdn, arena, alloc_size, false); - if (run == NULL) { - malloc_mutex_unlock(tsdn, &arena->lock); - return (NULL); - } - extent = iealloc(tsdn, run); - chunk = (arena_chunk_t *)extent_base_get(extent); - miscelm = arena_run_to_miscelm(extent, run); - rpages = arena_miscelm_to_rpages(extent, miscelm); - - leadsize = ALIGNMENT_CEILING((uintptr_t)rpages, alignment) - - (uintptr_t)rpages; - assert(alloc_size >= leadsize + usize); - trailsize = alloc_size - leadsize - usize - large_pad; - if (leadsize != 0) { - arena_chunk_map_misc_t *head_miscelm = miscelm; - arena_run_t *head_run = run; - extent_t *head_extent = extent; - - miscelm = arena_miscelm_get_mutable(chunk, - arena_miscelm_to_pageind(head_extent, head_miscelm) + - (leadsize >> LG_PAGE)); - run = &miscelm->run; - extent = iealloc(tsdn, run); - - arena_run_trim_head(tsdn, arena, chunk, head_extent, head_run, - alloc_size, alloc_size - leadsize); - } - if (trailsize != 0) { - arena_run_trim_tail(tsdn, arena, chunk, extent, run, usize + - large_pad + trailsize, usize + large_pad, false); - } - if (arena_run_init_large(tsdn, arena, extent, run, usize + large_pad, - zero)) { - size_t run_ind = arena_miscelm_to_pageind(extent, - arena_run_to_miscelm(extent, run)); - bool dirty = (arena_mapbits_dirty_get(chunk, run_ind) != 0); - bool decommitted = (arena_mapbits_decommitted_get(chunk, - run_ind) != 0); - - assert(decommitted); /* Cause of OOM. */ - arena_run_dalloc(tsdn, arena, extent, run, dirty, false, - decommitted); - malloc_mutex_unlock(tsdn, &arena->lock); - return (NULL); - } - ret = arena_miscelm_to_rpages(extent, miscelm); - - if (config_stats) { - szind_t index = size2index(usize) - NBINS; - - arena->stats.nmalloc_large++; - arena->stats.nrequests_large++; - arena->stats.allocated_large += usize; - arena->stats.lstats[index].nmalloc++; - arena->stats.lstats[index].nrequests++; - arena->stats.lstats[index].curruns++; - } - malloc_mutex_unlock(tsdn, &arena->lock); - - if (config_fill && !zero) { - if (unlikely(opt_junk_alloc)) - memset(ret, JEMALLOC_ALLOC_JUNK, usize); - else if (unlikely(opt_zero)) - memset(ret, 0, usize); - } - arena_decay_tick(tsdn, arena); - return (ret); -} - void * arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero, tcache_t *tcache) @@ -2603,22 +2245,8 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, /* Small; alignment doesn't require special run placement. */ ret = arena_malloc(tsdn, arena, usize, size2index(usize), zero, tcache, true); - } else if (usize <= large_maxclass && alignment <= PAGE) { - /* - * Large; alignment doesn't require special run placement. - * However, the cached pointer may be at a random offset from - * the base of the run, so do some bit manipulation to retrieve - * the base. - */ - ret = arena_malloc(tsdn, arena, usize, size2index(usize), zero, - tcache, true); - if (config_cache_oblivious) - ret = (void *)((uintptr_t)ret & ~PAGE_MASK); } else { - if (likely(usize <= large_maxclass)) { - ret = arena_palloc_large(tsdn, arena, usize, alignment, - zero); - } else if (likely(alignment <= CACHELINE)) + if (likely(alignment <= CACHELINE)) ret = huge_malloc(tsdn, arena, usize, zero); else ret = huge_palloc(tsdn, arena, usize, alignment, zero); @@ -2627,27 +2255,49 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, } void -arena_prof_promoted(tsdn_t *tsdn, const extent_t *extent, const void *ptr, - size_t size) +arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize) { - arena_chunk_t *chunk; - size_t pageind; - szind_t binind; cassert(config_prof); assert(ptr != NULL); - assert(isalloc(tsdn, extent, ptr, false) == LARGE_MINCLASS); - assert(isalloc(tsdn, extent, ptr, true) == LARGE_MINCLASS); - assert(size <= SMALL_MAXCLASS); + assert(isalloc(tsdn, extent, ptr) == LARGE_MINCLASS); + assert(usize <= SMALL_MAXCLASS); - chunk = (arena_chunk_t *)extent_base_get(extent); - pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - binind = size2index(size); - assert(binind < NBINS); - arena_mapbits_large_binind_set(chunk, pageind, binind); + extent_usize_set(extent, usize); - assert(isalloc(tsdn, extent, ptr, false) == LARGE_MINCLASS); - assert(isalloc(tsdn, extent, ptr, true) == size); + assert(isalloc(tsdn, extent, ptr) == usize); +} + +static size_t +arena_prof_demote(tsdn_t *tsdn, extent_t *extent, const void *ptr) +{ + + cassert(config_prof); + assert(ptr != NULL); + + extent_usize_set(extent, LARGE_MINCLASS); + + assert(isalloc(tsdn, extent, ptr) == LARGE_MINCLASS); + + return (LARGE_MINCLASS); +} + +void +arena_dalloc_promoted(tsdn_t *tsdn, extent_t *extent, void *ptr, + tcache_t *tcache, bool slow_path) +{ + size_t usize; + + cassert(config_prof); + assert(opt_prof); + + usize = arena_prof_demote(tsdn, extent, ptr); + if (usize <= tcache_maxclass) { + tcache_dalloc_huge(tsdn_tsd(tsdn), tcache, ptr, usize, + slow_path); + } else + huge_dalloc(tsdn, extent); } static void @@ -2792,274 +2442,6 @@ arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, arena_decay_tick(tsdn, arena); } -#ifdef JEMALLOC_JET -#undef arena_dalloc_junk_large -#define arena_dalloc_junk_large JEMALLOC_N(n_arena_dalloc_junk_large) -#endif -void -arena_dalloc_junk_large(void *ptr, size_t usize) -{ - - if (config_fill && unlikely(opt_junk_free)) - memset(ptr, JEMALLOC_FREE_JUNK, usize); -} -#ifdef JEMALLOC_JET -#undef arena_dalloc_junk_large -#define arena_dalloc_junk_large JEMALLOC_N(arena_dalloc_junk_large) -arena_dalloc_junk_large_t *arena_dalloc_junk_large = - JEMALLOC_N(n_arena_dalloc_junk_large); -#endif - -static void -arena_dalloc_large_locked_impl(tsdn_t *tsdn, arena_t *arena, - arena_chunk_t *chunk, extent_t *extent, void *ptr, bool junked) -{ - size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - arena_chunk_map_misc_t *miscelm = arena_miscelm_get_mutable(chunk, - pageind); - arena_run_t *run = &miscelm->run; - - if (config_fill || config_stats) { - size_t usize = arena_mapbits_large_size_get(chunk, pageind) - - large_pad; - - if (!junked) - arena_dalloc_junk_large(ptr, usize); - if (config_stats) { - szind_t index = size2index(usize) - NBINS; - - arena->stats.ndalloc_large++; - arena->stats.allocated_large -= usize; - arena->stats.lstats[index].ndalloc++; - arena->stats.lstats[index].curruns--; - } - } - - arena_run_dalloc(tsdn, arena, extent, run, true, false, false); -} - -void -arena_dalloc_large_junked_locked(tsdn_t *tsdn, arena_t *arena, - arena_chunk_t *chunk, extent_t *extent, void *ptr) -{ - - arena_dalloc_large_locked_impl(tsdn, arena, chunk, extent, ptr, true); -} - -void -arena_dalloc_large(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - extent_t *extent, void *ptr) -{ - - malloc_mutex_lock(tsdn, &arena->lock); - arena_dalloc_large_locked_impl(tsdn, arena, chunk, extent, ptr, false); - malloc_mutex_unlock(tsdn, &arena->lock); - arena_decay_tick(tsdn, arena); -} - -static void -arena_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - extent_t *extent, void *ptr, size_t oldsize, size_t size) -{ - size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - arena_chunk_map_misc_t *miscelm = arena_miscelm_get_mutable(chunk, - pageind); - arena_run_t *run = &miscelm->run; - - assert(size < oldsize); - - /* - * Shrink the run, and make trailing pages available for other - * allocations. - */ - malloc_mutex_lock(tsdn, &arena->lock); - arena_run_trim_tail(tsdn, arena, chunk, extent, run, oldsize + - large_pad, size + large_pad, true); - if (config_stats) { - szind_t oldindex = size2index(oldsize) - NBINS; - szind_t index = size2index(size) - NBINS; - - arena->stats.ndalloc_large++; - arena->stats.allocated_large -= oldsize; - arena->stats.lstats[oldindex].ndalloc++; - arena->stats.lstats[oldindex].curruns--; - - arena->stats.nmalloc_large++; - arena->stats.nrequests_large++; - arena->stats.allocated_large += size; - arena->stats.lstats[index].nmalloc++; - arena->stats.lstats[index].nrequests++; - arena->stats.lstats[index].curruns++; - } - malloc_mutex_unlock(tsdn, &arena->lock); -} - -static bool -arena_ralloc_large_grow(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - void *ptr, size_t oldsize, size_t usize_min, size_t usize_max, bool zero) -{ - size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - size_t npages = (oldsize + large_pad) >> LG_PAGE; - size_t followsize; - - assert(oldsize == arena_mapbits_large_size_get(chunk, pageind) - - large_pad); - - /* Try to extend the run. */ - malloc_mutex_lock(tsdn, &arena->lock); - if (pageind+npages >= chunk_npages || arena_mapbits_allocated_get(chunk, - pageind+npages) != 0) - goto label_fail; - followsize = arena_mapbits_unallocated_size_get(chunk, pageind+npages); - if (oldsize + followsize >= usize_min) { - /* - * The next run is available and sufficiently large. Split the - * following run, then merge the first part with the existing - * allocation. - */ - arena_run_t *run; - size_t usize, splitsize, size, flag_dirty, flag_unzeroed_mask; - - usize = usize_max; - while (oldsize + followsize < usize) - usize = index2size(size2index(usize)-1); - assert(usize >= usize_min); - assert(usize >= oldsize); - splitsize = usize - oldsize; - if (splitsize == 0) - goto label_fail; - - run = &arena_miscelm_get_mutable(chunk, pageind+npages)->run; - if (arena_run_split_large(tsdn, arena, iealloc(tsdn, run), run, - splitsize, zero)) - goto label_fail; - - if (config_cache_oblivious && zero) { - /* - * Zero the trailing bytes of the original allocation's - * last page, since they are in an indeterminate state. - * There will always be trailing bytes, because ptr's - * offset from the beginning of the run is a multiple of - * CACHELINE in [0 .. PAGE). - */ - void *zbase = (void *)((uintptr_t)ptr + oldsize); - void *zpast = PAGE_ADDR2BASE((void *)((uintptr_t)zbase + - PAGE)); - size_t nzero = (uintptr_t)zpast - (uintptr_t)zbase; - assert(nzero > 0); - memset(zbase, 0, nzero); - } - - size = oldsize + splitsize; - npages = (size + large_pad) >> LG_PAGE; - - /* - * Mark the extended run as dirty if either portion of the run - * was dirty before allocation. This is rather pedantic, - * because there's not actually any sequence of events that - * could cause the resulting run to be passed to - * arena_run_dalloc() with the dirty argument set to false - * (which is when dirty flag consistency would really matter). - */ - flag_dirty = arena_mapbits_dirty_get(chunk, pageind) | - arena_mapbits_dirty_get(chunk, pageind+npages-1); - flag_unzeroed_mask = flag_dirty == 0 ? CHUNK_MAP_UNZEROED : 0; - arena_mapbits_large_set(chunk, pageind, size + large_pad, - flag_dirty | (flag_unzeroed_mask & - arena_mapbits_unzeroed_get(chunk, pageind))); - arena_mapbits_large_set(chunk, pageind+npages-1, 0, flag_dirty | - (flag_unzeroed_mask & arena_mapbits_unzeroed_get(chunk, - pageind+npages-1))); - - if (config_stats) { - szind_t oldindex = size2index(oldsize) - NBINS; - szind_t index = size2index(size) - NBINS; - - arena->stats.ndalloc_large++; - arena->stats.allocated_large -= oldsize; - arena->stats.lstats[oldindex].ndalloc++; - arena->stats.lstats[oldindex].curruns--; - - arena->stats.nmalloc_large++; - arena->stats.nrequests_large++; - arena->stats.allocated_large += size; - arena->stats.lstats[index].nmalloc++; - arena->stats.lstats[index].nrequests++; - arena->stats.lstats[index].curruns++; - } - malloc_mutex_unlock(tsdn, &arena->lock); - return (false); - } -label_fail: - malloc_mutex_unlock(tsdn, &arena->lock); - return (true); -} - -#ifdef JEMALLOC_JET -#undef arena_ralloc_junk_large -#define arena_ralloc_junk_large JEMALLOC_N(n_arena_ralloc_junk_large) -#endif -static void -arena_ralloc_junk_large(void *ptr, size_t old_usize, size_t usize) -{ - - if (config_fill && unlikely(opt_junk_free)) { - memset((void *)((uintptr_t)ptr + usize), JEMALLOC_FREE_JUNK, - old_usize - usize); - } -} -#ifdef JEMALLOC_JET -#undef arena_ralloc_junk_large -#define arena_ralloc_junk_large JEMALLOC_N(arena_ralloc_junk_large) -arena_ralloc_junk_large_t *arena_ralloc_junk_large = - JEMALLOC_N(n_arena_ralloc_junk_large); -#endif - -/* - * Try to resize a large allocation, in order to avoid copying. This will - * always fail if growing an object, and the following run is already in use. - */ -static bool -arena_ralloc_large(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, - size_t usize_min, size_t usize_max, bool zero) -{ - arena_chunk_t *chunk; - arena_t *arena; - - if (oldsize == usize_max) { - /* Current size class is compatible and maximal. */ - return (false); - } - - chunk = (arena_chunk_t *)extent_base_get(extent); - arena = extent_arena_get(extent); - - if (oldsize < usize_max) { - bool ret = arena_ralloc_large_grow(tsdn, arena, chunk, ptr, - oldsize, usize_min, usize_max, zero); - if (config_fill && !ret && !zero) { - if (unlikely(opt_junk_alloc)) { - memset((void *)((uintptr_t)ptr + oldsize), - JEMALLOC_ALLOC_JUNK, - isalloc(tsdn, extent, ptr, config_prof) - - oldsize); - } else if (unlikely(opt_zero)) { - memset((void *)((uintptr_t)ptr + oldsize), 0, - isalloc(tsdn, extent, ptr, config_prof) - - oldsize); - } - } - return (ret); - } - - assert(oldsize > usize_max); - /* Fill before shrinking in order avoid a race. */ - arena_ralloc_junk_large(ptr, oldsize, usize_max); - arena_ralloc_large_shrink(tsdn, arena, chunk, extent, ptr, oldsize, - usize_max); - return (false); -} - bool arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t extra, bool zero) @@ -3074,29 +2456,21 @@ arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, usize_min = s2u(size); usize_max = s2u(size + extra); - if (likely(oldsize <= large_maxclass && usize_min <= large_maxclass)) { + if (likely(oldsize <= SMALL_MAXCLASS && usize_min <= SMALL_MAXCLASS)) { /* * Avoid moving the allocation if the size class can be left the * same. */ - if (oldsize <= SMALL_MAXCLASS) { - assert(arena_bin_info[size2index(oldsize)].reg_size == - oldsize); - if ((usize_max > SMALL_MAXCLASS || - size2index(usize_max) != size2index(oldsize)) && - (size > oldsize || usize_max < oldsize)) - return (true); - } else { - if (usize_max <= SMALL_MAXCLASS) - return (true); - if (arena_ralloc_large(tsdn, extent, ptr, oldsize, - usize_min, usize_max, zero)) - return (true); - } + assert(arena_bin_info[size2index(oldsize)].reg_size == + oldsize); + if ((usize_max > SMALL_MAXCLASS || size2index(usize_max) != + size2index(oldsize)) && (size > oldsize || usize_max < + oldsize)) + return (true); arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); - } else if (oldsize >= chunksize && usize_max >= chunksize) { + } else if (oldsize >= LARGE_MINCLASS && usize_max >= LARGE_MINCLASS) { return (huge_ralloc_no_move(tsdn, extent, usize_min, usize_max, zero)); } @@ -3129,14 +2503,14 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, if (unlikely(usize == 0 || size > HUGE_MAXCLASS)) return (NULL); - if (likely(usize <= large_maxclass)) { + if (likely(usize <= SMALL_MAXCLASS)) { /* Try to avoid moving the allocation. */ if (!arena_ralloc_no_move(tsdn, extent, ptr, oldsize, usize, 0, zero)) return (ptr); } - if (oldsize >= chunksize && usize >= chunksize) { + if (oldsize >= LARGE_MINCLASS && usize >= LARGE_MINCLASS) { return (huge_ralloc(tsdn, arena, extent, usize, alignment, zero, tcache)); } @@ -3252,8 +2626,7 @@ void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *lg_dirty_mult, ssize_t *decay_time, size_t *nactive, size_t *ndirty, arena_stats_t *astats, - malloc_bin_stats_t *bstats, malloc_large_stats_t *lstats, - malloc_huge_stats_t *hstats) + malloc_bin_stats_t *bstats, malloc_huge_stats_t *hstats) { unsigned i; @@ -3270,24 +2643,15 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, astats->purged += arena->stats.purged; astats->metadata_mapped += arena->stats.metadata_mapped; astats->metadata_allocated += arena_metadata_allocated_get(arena); - astats->allocated_large += arena->stats.allocated_large; - astats->nmalloc_large += arena->stats.nmalloc_large; - astats->ndalloc_large += arena->stats.ndalloc_large; - astats->nrequests_large += arena->stats.nrequests_large; astats->allocated_huge += arena->stats.allocated_huge; astats->nmalloc_huge += arena->stats.nmalloc_huge; astats->ndalloc_huge += arena->stats.ndalloc_huge; + astats->nrequests_huge += arena->stats.nrequests_huge; - for (i = 0; i < nlclasses; i++) { - lstats[i].nmalloc += arena->stats.lstats[i].nmalloc; - lstats[i].ndalloc += arena->stats.lstats[i].ndalloc; - lstats[i].nrequests += arena->stats.lstats[i].nrequests; - lstats[i].curruns += arena->stats.lstats[i].curruns; - } - - for (i = 0; i < nhclasses; i++) { + for (i = 0; i < NSIZES - NBINS; i++) { hstats[i].nmalloc += arena->stats.hstats[i].nmalloc; hstats[i].ndalloc += arena->stats.hstats[i].ndalloc; + hstats[i].nrequests += arena->stats.hstats[i].nrequests; hstats[i].curhchunks += arena->stats.hstats[i].curhchunks; } malloc_mutex_unlock(tsdn, &arena->lock); @@ -3338,17 +2702,7 @@ arena_new(tsdn_t *tsdn, unsigned ind) arena_t *arena; unsigned i; - /* - * Allocate arena, arena->lstats, and arena->hstats contiguously, mainly - * because there is no way to clean up if base_alloc() OOMs. - */ - if (config_stats) { - arena = (arena_t *)base_alloc(tsdn, - CACHELINE_CEILING(sizeof(arena_t)) + - QUANTUM_CEILING((nlclasses * sizeof(malloc_large_stats_t)) + - (nhclasses * sizeof(malloc_huge_stats_t)))); - } else - arena = (arena_t *)base_alloc(tsdn, sizeof(arena_t)); + arena = (arena_t *)base_alloc(tsdn, sizeof(arena_t)); if (arena == NULL) return (NULL); @@ -3357,20 +2711,8 @@ arena_new(tsdn_t *tsdn, unsigned ind) if (malloc_mutex_init(&arena->lock, "arena", WITNESS_RANK_ARENA)) return (NULL); - if (config_stats) { - memset(&arena->stats, 0, sizeof(arena_stats_t)); - arena->stats.lstats = (malloc_large_stats_t *)((uintptr_t)arena - + CACHELINE_CEILING(sizeof(arena_t))); - memset(arena->stats.lstats, 0, nlclasses * - sizeof(malloc_large_stats_t)); - arena->stats.hstats = (malloc_huge_stats_t *)((uintptr_t)arena - + CACHELINE_CEILING(sizeof(arena_t)) + - QUANTUM_CEILING(nlclasses * sizeof(malloc_large_stats_t))); - memset(arena->stats.hstats, 0, nhclasses * - sizeof(malloc_huge_stats_t)); - if (config_tcache) - ql_new(&arena->tcache_ql); - } + if (config_stats && config_tcache) + ql_new(&arena->tcache_ql); if (config_prof) arena->prof_accumbytes = 0; @@ -3476,18 +2818,6 @@ arena_boot(void) arena_maxrun = chunksize - (map_bias << LG_PAGE); assert(arena_maxrun > 0); - large_maxclass = index2size(size2index(chunksize)-1); - if (large_maxclass > arena_maxrun) { - /* - * For small chunk sizes it's possible for there to be fewer - * non-header pages available than are necessary to serve the - * size classes just below chunksize. - */ - large_maxclass = arena_maxrun; - } - assert(large_maxclass > 0); - nlclasses = size2index(large_maxclass) - size2index(SMALL_MAXCLASS); - nhclasses = NSIZES - nlclasses - NBINS; } void diff --git a/src/base.c b/src/base.c index 1e32d955..134018a8 100644 --- a/src/base.c +++ b/src/base.c @@ -74,7 +74,8 @@ base_chunk_alloc(tsdn_t *tsdn, size_t minsize) base_resident += PAGE_CEILING(nsize); } } - extent_init(extent, NULL, addr, csize, true, false, true, true, false); + extent_init(extent, NULL, addr, csize, 0, true, false, true, true, + false); return (extent); } diff --git a/src/chunk.c b/src/chunk.c index 4b213a90..8c4f741f 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -369,7 +369,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, if (leadsize != 0) { extent_t *lead = extent; extent = chunk_split_wrapper(tsdn, arena, chunk_hooks, lead, - leadsize, size + trailsize); + leadsize, leadsize, size + trailsize, usize + trailsize); if (extent == NULL) { chunk_leak(tsdn, arena, chunk_hooks, cache, lead); malloc_mutex_unlock(tsdn, &arena->chunks_mtx); @@ -382,7 +382,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, /* Split the trail. */ if (trailsize != 0) { extent_t *trail = chunk_split_wrapper(tsdn, arena, chunk_hooks, - extent, size, trailsize); + extent, size, usize, trailsize, trailsize); if (trail == NULL) { chunk_leak(tsdn, arena, chunk_hooks, cache, extent); malloc_mutex_unlock(tsdn, &arena->chunks_mtx); @@ -390,6 +390,12 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } extent_heaps_insert(extent_heaps, trail); arena_chunk_cache_maybe_insert(arena, trail, cache); + } else if (leadsize == 0) { + /* + * Splitting causes usize to be set as a side effect, but no + * splitting occurred. + */ + extent_usize_set(extent, usize); } if (!extent_committed_get(extent) && @@ -552,7 +558,8 @@ chunk_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, extent_dalloc(tsdn, arena, extent); return (NULL); } - extent_init(extent, arena, addr, size, true, false, zero, commit, slab); + extent_init(extent, arena, addr, size, usize, true, false, zero, commit, + slab); if (pad != 0) extent_addr_randomize(tsdn, extent, alignment); if (chunk_register(tsdn, extent)) { @@ -635,6 +642,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, malloc_mutex_lock(tsdn, &arena->chunks_mtx); chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); + extent_usize_set(extent, 0); extent_active_set(extent, false); extent_zeroed_set(extent, !cache && extent_zeroed_get(extent)); if (extent_slab_get(extent)) { @@ -801,7 +809,8 @@ chunk_split_default(void *chunk, size_t size, size_t size_a, size_t size_b, extent_t * chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - extent_t *extent, size_t size_a, size_t size_b) + extent_t *extent, size_t size_a, size_t usize_a, size_t size_b, + size_t usize_b) { extent_t *trail; rtree_elm_t *lead_elm_a, *lead_elm_b, *trail_elm_a, *trail_elm_b; @@ -818,9 +827,9 @@ chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_t lead; extent_init(&lead, arena, extent_addr_get(extent), size_a, - extent_active_get(extent), extent_dirty_get(extent), - extent_zeroed_get(extent), extent_committed_get(extent), - extent_slab_get(extent)); + usize_a, extent_active_get(extent), + extent_dirty_get(extent), extent_zeroed_get(extent), + extent_committed_get(extent), extent_slab_get(extent)); if (extent_rtree_acquire(tsdn, &lead, false, true, &lead_elm_a, &lead_elm_b)) @@ -828,7 +837,7 @@ chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) + - size_a), size_b, extent_active_get(extent), + size_a), size_b, usize_b, extent_active_get(extent), extent_dirty_get(extent), extent_zeroed_get(extent), extent_committed_get(extent), extent_slab_get(extent)); if (extent_rtree_acquire(tsdn, trail, false, true, &trail_elm_a, @@ -840,6 +849,7 @@ chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, goto label_error_d; extent_size_set(extent, size_a); + extent_usize_set(extent, usize_a); extent_rtree_write_acquired(tsdn, lead_elm_a, lead_elm_b, extent); extent_rtree_write_acquired(tsdn, trail_elm_a, trail_elm_b, trail); @@ -905,6 +915,7 @@ chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, b_elm_b = b_elm_a; extent_size_set(a, extent_size_get(a) + extent_size_get(b)); + extent_usize_set(a, extent_usize_get(a) + extent_usize_get(b)); extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b)); extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a); diff --git a/src/chunk_dss.c b/src/chunk_dss.c index 0119c12b..e92fda72 100644 --- a/src/chunk_dss.c +++ b/src/chunk_dss.c @@ -121,7 +121,7 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, pad_size = (uintptr_t)ret - (uintptr_t)pad_addr; if (pad_size != 0) { extent_init(pad, arena, pad_addr, pad_size, - false, true, false, true, false); + pad_size, false, true, false, true, false); } dss_next = (void *)((uintptr_t)ret + size); if ((uintptr_t)ret < (uintptr_t)dss_max || diff --git a/src/ctl.c b/src/ctl.c index 908a2850..26bc1750 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -49,7 +49,6 @@ static int n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \ static const ctl_named_node_t *n##_index(tsdn_t *tsdn, \ const size_t *mib, size_t miblen, size_t i); -static bool ctl_arena_init(ctl_arena_stats_t *astats); static void ctl_arena_clear(ctl_arena_stats_t *astats); static void ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_stats_t *cstats, arena_t *arena); @@ -127,8 +126,6 @@ CTL_PROTO(arenas_bin_i_size) CTL_PROTO(arenas_bin_i_nregs) CTL_PROTO(arenas_bin_i_run_size) INDEX_PROTO(arenas_bin_i) -CTL_PROTO(arenas_lrun_i_size) -INDEX_PROTO(arenas_lrun_i) CTL_PROTO(arenas_hchunk_i_size) INDEX_PROTO(arenas_hchunk_i) CTL_PROTO(arenas_narenas) @@ -140,7 +137,6 @@ CTL_PROTO(arenas_page) CTL_PROTO(arenas_tcache_max) CTL_PROTO(arenas_nbins) CTL_PROTO(arenas_nhbins) -CTL_PROTO(arenas_nlruns) CTL_PROTO(arenas_nhchunks) CTL_PROTO(arenas_extend) CTL_PROTO(prof_thread_active_init) @@ -154,10 +150,6 @@ CTL_PROTO(stats_arenas_i_small_allocated) CTL_PROTO(stats_arenas_i_small_nmalloc) CTL_PROTO(stats_arenas_i_small_ndalloc) CTL_PROTO(stats_arenas_i_small_nrequests) -CTL_PROTO(stats_arenas_i_large_allocated) -CTL_PROTO(stats_arenas_i_large_nmalloc) -CTL_PROTO(stats_arenas_i_large_ndalloc) -CTL_PROTO(stats_arenas_i_large_nrequests) CTL_PROTO(stats_arenas_i_huge_allocated) CTL_PROTO(stats_arenas_i_huge_nmalloc) CTL_PROTO(stats_arenas_i_huge_ndalloc) @@ -172,11 +164,6 @@ CTL_PROTO(stats_arenas_i_bins_j_nruns) CTL_PROTO(stats_arenas_i_bins_j_nreruns) CTL_PROTO(stats_arenas_i_bins_j_curruns) INDEX_PROTO(stats_arenas_i_bins_j) -CTL_PROTO(stats_arenas_i_lruns_j_nmalloc) -CTL_PROTO(stats_arenas_i_lruns_j_ndalloc) -CTL_PROTO(stats_arenas_i_lruns_j_nrequests) -CTL_PROTO(stats_arenas_i_lruns_j_curruns) -INDEX_PROTO(stats_arenas_i_lruns_j) CTL_PROTO(stats_arenas_i_hchunks_j_nmalloc) CTL_PROTO(stats_arenas_i_hchunks_j_ndalloc) CTL_PROTO(stats_arenas_i_hchunks_j_nrequests) @@ -323,17 +310,6 @@ static const ctl_indexed_node_t arenas_bin_node[] = { {INDEX(arenas_bin_i)} }; -static const ctl_named_node_t arenas_lrun_i_node[] = { - {NAME("size"), CTL(arenas_lrun_i_size)} -}; -static const ctl_named_node_t super_arenas_lrun_i_node[] = { - {NAME(""), CHILD(named, arenas_lrun_i)} -}; - -static const ctl_indexed_node_t arenas_lrun_node[] = { - {INDEX(arenas_lrun_i)} -}; - static const ctl_named_node_t arenas_hchunk_i_node[] = { {NAME("size"), CTL(arenas_hchunk_i_size)} }; @@ -356,8 +332,6 @@ static const ctl_named_node_t arenas_node[] = { {NAME("nbins"), CTL(arenas_nbins)}, {NAME("nhbins"), CTL(arenas_nhbins)}, {NAME("bin"), CHILD(indexed, arenas_bin)}, - {NAME("nlruns"), CTL(arenas_nlruns)}, - {NAME("lrun"), CHILD(indexed, arenas_lrun)}, {NAME("nhchunks"), CTL(arenas_nhchunks)}, {NAME("hchunk"), CHILD(indexed, arenas_hchunk)}, {NAME("extend"), CTL(arenas_extend)} @@ -385,13 +359,6 @@ static const ctl_named_node_t stats_arenas_i_small_node[] = { {NAME("nrequests"), CTL(stats_arenas_i_small_nrequests)} }; -static const ctl_named_node_t stats_arenas_i_large_node[] = { - {NAME("allocated"), CTL(stats_arenas_i_large_allocated)}, - {NAME("nmalloc"), CTL(stats_arenas_i_large_nmalloc)}, - {NAME("ndalloc"), CTL(stats_arenas_i_large_ndalloc)}, - {NAME("nrequests"), CTL(stats_arenas_i_large_nrequests)} -}; - static const ctl_named_node_t stats_arenas_i_huge_node[] = { {NAME("allocated"), CTL(stats_arenas_i_huge_allocated)}, {NAME("nmalloc"), CTL(stats_arenas_i_huge_nmalloc)}, @@ -418,20 +385,6 @@ static const ctl_indexed_node_t stats_arenas_i_bins_node[] = { {INDEX(stats_arenas_i_bins_j)} }; -static const ctl_named_node_t stats_arenas_i_lruns_j_node[] = { - {NAME("nmalloc"), CTL(stats_arenas_i_lruns_j_nmalloc)}, - {NAME("ndalloc"), CTL(stats_arenas_i_lruns_j_ndalloc)}, - {NAME("nrequests"), CTL(stats_arenas_i_lruns_j_nrequests)}, - {NAME("curruns"), CTL(stats_arenas_i_lruns_j_curruns)} -}; -static const ctl_named_node_t super_stats_arenas_i_lruns_j_node[] = { - {NAME(""), CHILD(named, stats_arenas_i_lruns_j)} -}; - -static const ctl_indexed_node_t stats_arenas_i_lruns_node[] = { - {INDEX(stats_arenas_i_lruns_j)} -}; - static const ctl_named_node_t stats_arenas_i_hchunks_j_node[] = { {NAME("nmalloc"), CTL(stats_arenas_i_hchunks_j_nmalloc)}, {NAME("ndalloc"), CTL(stats_arenas_i_hchunks_j_ndalloc)}, @@ -460,10 +413,8 @@ static const ctl_named_node_t stats_arenas_i_node[] = { {NAME("purged"), CTL(stats_arenas_i_purged)}, {NAME("metadata"), CHILD(named, stats_arenas_i_metadata)}, {NAME("small"), CHILD(named, stats_arenas_i_small)}, - {NAME("large"), CHILD(named, stats_arenas_i_large)}, {NAME("huge"), CHILD(named, stats_arenas_i_huge)}, {NAME("bins"), CHILD(indexed, stats_arenas_i_bins)}, - {NAME("lruns"), CHILD(indexed, stats_arenas_i_lruns)}, {NAME("hchunks"), CHILD(indexed, stats_arenas_i_hchunks)} }; static const ctl_named_node_t super_stats_arenas_i_node[] = { @@ -508,27 +459,6 @@ static const ctl_named_node_t super_root_node[] = { /******************************************************************************/ -static bool -ctl_arena_init(ctl_arena_stats_t *astats) -{ - - if (astats->lstats == NULL) { - astats->lstats = (malloc_large_stats_t *)a0malloc(nlclasses * - sizeof(malloc_large_stats_t)); - if (astats->lstats == NULL) - return (true); - } - - if (astats->hstats == NULL) { - astats->hstats = (malloc_huge_stats_t *)a0malloc(nhclasses * - sizeof(malloc_huge_stats_t)); - if (astats->hstats == NULL) - return (true); - } - - return (false); -} - static void ctl_arena_clear(ctl_arena_stats_t *astats) { @@ -546,9 +476,7 @@ ctl_arena_clear(ctl_arena_stats_t *astats) astats->ndalloc_small = 0; astats->nrequests_small = 0; memset(astats->bstats, 0, NBINS * sizeof(malloc_bin_stats_t)); - memset(astats->lstats, 0, nlclasses * - sizeof(malloc_large_stats_t)); - memset(astats->hstats, 0, nhclasses * + memset(astats->hstats, 0, (NSIZES - NBINS) * sizeof(malloc_huge_stats_t)); } } @@ -562,7 +490,7 @@ ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_stats_t *cstats, arena_t *arena) arena_stats_merge(tsdn, arena, &cstats->nthreads, &cstats->dss, &cstats->lg_dirty_mult, &cstats->decay_time, &cstats->pactive, &cstats->pdirty, &cstats->astats, - cstats->bstats, cstats->lstats, cstats->hstats); + cstats->bstats, cstats->hstats); for (i = 0; i < NBINS; i++) { cstats->allocated_small += cstats->bstats[i].curregs * @@ -604,16 +532,10 @@ ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats) sstats->ndalloc_small += astats->ndalloc_small; sstats->nrequests_small += astats->nrequests_small; - sstats->astats.allocated_large += - astats->astats.allocated_large; - sstats->astats.nmalloc_large += astats->astats.nmalloc_large; - sstats->astats.ndalloc_large += astats->astats.ndalloc_large; - sstats->astats.nrequests_large += - astats->astats.nrequests_large; - sstats->astats.allocated_huge += astats->astats.allocated_huge; sstats->astats.nmalloc_huge += astats->astats.nmalloc_huge; sstats->astats.ndalloc_huge += astats->astats.ndalloc_huge; + sstats->astats.nrequests_huge += astats->astats.nrequests_huge; for (i = 0; i < NBINS; i++) { sstats->bstats[i].nmalloc += astats->bstats[i].nmalloc; @@ -632,17 +554,11 @@ ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats) sstats->bstats[i].curruns += astats->bstats[i].curruns; } - for (i = 0; i < nlclasses; i++) { - sstats->lstats[i].nmalloc += astats->lstats[i].nmalloc; - sstats->lstats[i].ndalloc += astats->lstats[i].ndalloc; - sstats->lstats[i].nrequests += - astats->lstats[i].nrequests; - sstats->lstats[i].curruns += astats->lstats[i].curruns; - } - - for (i = 0; i < nhclasses; i++) { + for (i = 0; i < NSIZES - NBINS; i++) { sstats->hstats[i].nmalloc += astats->hstats[i].nmalloc; sstats->hstats[i].ndalloc += astats->hstats[i].ndalloc; + sstats->hstats[i].nrequests += + astats->hstats[i].nrequests; sstats->hstats[i].curhchunks += astats->hstats[i].curhchunks; } @@ -680,10 +596,6 @@ ctl_grow(tsdn_t *tsdn) memcpy(astats, ctl_stats.arenas, (ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t)); memset(&astats[ctl_stats.narenas + 1], 0, sizeof(ctl_arena_stats_t)); - if (ctl_arena_init(&astats[ctl_stats.narenas + 1])) { - a0dalloc(astats); - return (true); - } /* Swap merged stats to their new location. */ { ctl_arena_stats_t tstats; @@ -730,7 +642,6 @@ ctl_refresh(tsdn_t *tsdn) &base_mapped); ctl_stats.allocated = ctl_stats.arenas[ctl_stats.narenas].allocated_small + - ctl_stats.arenas[ctl_stats.narenas].astats.allocated_large + ctl_stats.arenas[ctl_stats.narenas].astats.allocated_huge; ctl_stats.active = (ctl_stats.arenas[ctl_stats.narenas].pactive << LG_PAGE); @@ -771,30 +682,6 @@ ctl_init(tsdn_t *tsdn) } memset(ctl_stats.arenas, 0, (ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t)); - - /* - * Initialize all stats structures, regardless of whether they - * ever get used. Lazy initialization would allow errors to - * cause inconsistent state to be viewable by the application. - */ - if (config_stats) { - unsigned i; - for (i = 0; i <= ctl_stats.narenas; i++) { - if (ctl_arena_init(&ctl_stats.arenas[i])) { - unsigned j; - for (j = 0; j < i; j++) { - a0dalloc( - ctl_stats.arenas[j].lstats); - a0dalloc( - ctl_stats.arenas[j].hstats); - } - a0dalloc(ctl_stats.arenas); - ctl_stats.arenas = NULL; - ret = true; - goto label_return; - } - } - } ctl_stats.arenas[ctl_stats.narenas].initialized = true; ctl_epoch = 0; @@ -1924,25 +1811,13 @@ arenas_bin_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) return (super_arenas_bin_i_node); } -CTL_RO_NL_GEN(arenas_nlruns, nlclasses, unsigned) -CTL_RO_NL_GEN(arenas_lrun_i_size, index2size(NBINS+(szind_t)mib[2]), size_t) -static const ctl_named_node_t * -arenas_lrun_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) -{ - - if (i > nlclasses) - return (NULL); - return (super_arenas_lrun_i_node); -} - -CTL_RO_NL_GEN(arenas_nhchunks, nhclasses, unsigned) -CTL_RO_NL_GEN(arenas_hchunk_i_size, index2size(NBINS+nlclasses+(szind_t)mib[2]), - size_t) +CTL_RO_NL_GEN(arenas_nhchunks, NSIZES - NBINS, unsigned) +CTL_RO_NL_GEN(arenas_hchunk_i_size, index2size(NBINS+(szind_t)mib[2]), size_t) static const ctl_named_node_t * arenas_hchunk_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { - if (i > nhclasses) + if (i > NSIZES - NBINS) return (NULL); return (super_arenas_hchunk_i_node); } @@ -2136,14 +2011,6 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc, ctl_stats.arenas[mib[2]].ndalloc_small, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests, ctl_stats.arenas[mib[2]].nrequests_small, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated, - ctl_stats.arenas[mib[2]].astats.allocated_large, size_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc, - ctl_stats.arenas[mib[2]].astats.nmalloc_large, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc, - ctl_stats.arenas[mib[2]].astats.ndalloc_large, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests, - ctl_stats.arenas[mib[2]].astats.nrequests_large, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_huge_allocated, ctl_stats.arenas[mib[2]].astats.allocated_huge, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_huge_nmalloc, @@ -2182,32 +2049,12 @@ stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, return (super_stats_arenas_i_bins_j_node); } -CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nmalloc, - ctl_stats.arenas[mib[2]].lstats[mib[4]].nmalloc, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_ndalloc, - ctl_stats.arenas[mib[2]].lstats[mib[4]].ndalloc, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nrequests, - ctl_stats.arenas[mib[2]].lstats[mib[4]].nrequests, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_curruns, - ctl_stats.arenas[mib[2]].lstats[mib[4]].curruns, size_t) - -static const ctl_named_node_t * -stats_arenas_i_lruns_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, - size_t j) -{ - - if (j > nlclasses) - return (NULL); - return (super_stats_arenas_i_lruns_j_node); -} - CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_nmalloc, ctl_stats.arenas[mib[2]].hstats[mib[4]].nmalloc, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_ndalloc, ctl_stats.arenas[mib[2]].hstats[mib[4]].ndalloc, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_nrequests, - ctl_stats.arenas[mib[2]].hstats[mib[4]].nmalloc, /* Intentional. */ - uint64_t) + ctl_stats.arenas[mib[2]].hstats[mib[4]].nrequests, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_curhchunks, ctl_stats.arenas[mib[2]].hstats[mib[4]].curhchunks, size_t) @@ -2216,7 +2063,7 @@ stats_arenas_i_hchunks_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t j) { - if (j > nhclasses) + if (j > NSIZES - NBINS) return (NULL); return (super_stats_arenas_i_hchunks_j_node); } diff --git a/src/extent.c b/src/extent.c index d7f3b6cc..757a6e21 100644 --- a/src/extent.c +++ b/src/extent.c @@ -40,7 +40,7 @@ extent_size_quantize_floor(size_t size) pszind_t pind; assert(size > 0); - assert(size <= HUGE_MAXCLASS); + assert(size - large_pad <= HUGE_MAXCLASS); assert((size & PAGE_MASK) == 0); assert(size != 0); @@ -77,7 +77,7 @@ extent_size_quantize_ceil(size_t size) size_t ret; assert(size > 0); - assert(size <= HUGE_MAXCLASS); + assert(size - large_pad <= HUGE_MAXCLASS); assert((size & PAGE_MASK) == 0); ret = extent_size_quantize_floor(size); diff --git a/src/huge.c b/src/huge.c index b00be904..5375b59f 100644 --- a/src/huge.c +++ b/src/huge.c @@ -19,6 +19,7 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, size_t ausize; extent_t *extent; bool is_zeroed; + UNUSED bool idump JEMALLOC_CC_SILENCE_INIT(false); assert(!tsdn_null(tsdn) || arena != NULL); @@ -42,6 +43,8 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, ql_elm_new(extent, ql_link); ql_tail_insert(&arena->huge, extent, ql_link); malloc_mutex_unlock(tsdn, &arena->huge_mtx); + if (config_prof && arena_prof_accum(tsdn, arena, usize)) + prof_idump(tsdn); if (zero || (config_fill && unlikely(opt_zero))) { if (!is_zeroed) { @@ -61,8 +64,20 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, #undef huge_dalloc_junk #define huge_dalloc_junk JEMALLOC_N(huge_dalloc_junk_impl) #endif +void +huge_dalloc_junk(void *ptr, size_t usize) +{ + + memset(ptr, JEMALLOC_FREE_JUNK, usize); +} +#ifdef JEMALLOC_JET +#undef huge_dalloc_junk +#define huge_dalloc_junk JEMALLOC_N(huge_dalloc_junk) +huge_dalloc_junk_t *huge_dalloc_junk = JEMALLOC_N(huge_dalloc_junk_impl); +#endif + static void -huge_dalloc_junk(tsdn_t *tsdn, void *ptr, size_t usize) +huge_dalloc_maybe_junk(tsdn_t *tsdn, void *ptr, size_t usize) { if (config_fill && have_dss && unlikely(opt_junk_free)) { @@ -71,14 +86,10 @@ huge_dalloc_junk(tsdn_t *tsdn, void *ptr, size_t usize) * unmapped. */ if (!config_munmap || (have_dss && chunk_in_dss(tsdn, ptr))) + huge_dalloc_junk(ptr, usize); memset(ptr, JEMALLOC_FREE_JUNK, usize); } } -#ifdef JEMALLOC_JET -#undef huge_dalloc_junk -#define huge_dalloc_junk JEMALLOC_N(huge_dalloc_junk) -huge_dalloc_junk_t *huge_dalloc_junk = JEMALLOC_N(huge_dalloc_junk_impl); -#endif static bool huge_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) @@ -93,12 +104,12 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) /* Split excess pages. */ if (diff != 0) { extent_t *trail = chunk_split_wrapper(tsdn, arena, &chunk_hooks, - extent, usize + large_pad, diff); + extent, usize + large_pad, usize, diff, diff); if (trail == NULL) return (true); if (config_fill && unlikely(opt_junk_free)) { - huge_dalloc_junk(tsdn, extent_addr_get(trail), + huge_dalloc_maybe_junk(tsdn, extent_addr_get(trail), extent_usize_get(trail)); } @@ -176,7 +187,8 @@ huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, /* The following should have been caught by callers. */ assert(usize_min > 0 && usize_max <= HUGE_MAXCLASS); /* Both allocation sizes must be huge to avoid a move. */ - assert(extent_usize_get(extent) >= chunksize && usize_max >= chunksize); + assert(extent_usize_get(extent) >= LARGE_MINCLASS && usize_max >= + LARGE_MINCLASS); if (usize_max > extent_usize_get(extent)) { /* Attempt to expand the allocation in-place. */ @@ -234,7 +246,8 @@ huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, /* The following should have been caught by callers. */ assert(usize > 0 && usize <= HUGE_MAXCLASS); /* Both allocation sizes must be huge to avoid a move. */ - assert(extent_usize_get(extent) >= chunksize && usize >= chunksize); + assert(extent_usize_get(extent) >= LARGE_MINCLASS && usize >= + LARGE_MINCLASS); /* Try to avoid moving the allocation. */ if (!huge_ralloc_no_move(tsdn, extent, usize, usize, zero)) @@ -257,21 +270,39 @@ huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, return (ret); } -void -huge_dalloc(tsdn_t *tsdn, extent_t *extent) +static void +huge_dalloc_impl(tsdn_t *tsdn, extent_t *extent, bool junked_locked) { arena_t *arena; arena = extent_arena_get(extent); - malloc_mutex_lock(tsdn, &arena->huge_mtx); + if (!junked_locked) + malloc_mutex_lock(tsdn, &arena->huge_mtx); ql_remove(&arena->huge, extent, ql_link); - malloc_mutex_unlock(tsdn, &arena->huge_mtx); + if (!junked_locked) { + malloc_mutex_unlock(tsdn, &arena->huge_mtx); - huge_dalloc_junk(tsdn, extent_addr_get(extent), - extent_usize_get(extent)); - arena_chunk_dalloc_huge(tsdn, extent_arena_get(extent), extent); + huge_dalloc_maybe_junk(tsdn, extent_addr_get(extent), + extent_usize_get(extent)); + } + arena_chunk_dalloc_huge(tsdn, arena, extent, junked_locked); - arena_decay_tick(tsdn, arena); + if (!junked_locked) + arena_decay_tick(tsdn, arena); +} + +void +huge_dalloc_junked_locked(tsdn_t *tsdn, extent_t *extent) +{ + + huge_dalloc_impl(tsdn, extent, true); +} + +void +huge_dalloc(tsdn_t *tsdn, extent_t *extent) +{ + + huge_dalloc_impl(tsdn, extent, false); } size_t diff --git a/src/jemalloc.c b/src/jemalloc.c index 479d8319..9f8bd01e 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1401,7 +1401,7 @@ ialloc_prof_sample(tsd_t *tsd, size_t usize, szind_t ind, bool zero, p = ialloc(tsd, LARGE_MINCLASS, ind_large, zero, slow_path); if (p == NULL) return (NULL); - arena_prof_promoted(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, + arena_prof_promote(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, usize); } else p = ialloc(tsd, usize, ind, zero, slow_path); @@ -1483,8 +1483,7 @@ ialloc_post_check(void *ret, tsdn_t *tsdn, size_t usize, const char *func, set_errno(ENOMEM); } if (config_stats && likely(ret != NULL)) { - assert(usize == isalloc(tsdn, iealloc(tsdn, ret), ret, - config_prof)); + assert(usize == isalloc(tsdn, iealloc(tsdn, ret), ret)); *tsd_thread_allocatedp_get(tsdn_tsd(tsdn)) += usize; } witness_assert_lockless(tsdn); @@ -1527,7 +1526,7 @@ imemalign_prof_sample(tsd_t *tsd, size_t alignment, size_t usize, p = ipalloc(tsd, LARGE_MINCLASS, alignment, false); if (p == NULL) return (NULL); - arena_prof_promoted(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, + arena_prof_promote(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, usize); } else p = ipalloc(tsd, usize, alignment, false); @@ -1608,7 +1607,7 @@ imemalign(void **memptr, size_t alignment, size_t size, size_t min_alignment) label_return: if (config_stats && likely(result != NULL)) { assert(usize == isalloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), - result), result, config_prof)); + result), result)); *tsd_thread_allocatedp_get(tsd) += usize; } UTRACE(0, size, result); @@ -1699,7 +1698,7 @@ irealloc_prof_sample(tsd_t *tsd, extent_t *extent, void *old_ptr, false); if (p == NULL) return (NULL); - arena_prof_promoted(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, + arena_prof_promote(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, usize); } else p = iralloc(tsd, extent, old_ptr, old_usize, usize, 0, false); @@ -1748,10 +1747,10 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) extent = iealloc(tsd_tsdn(tsd), ptr); if (config_prof && opt_prof) { - usize = isalloc(tsd_tsdn(tsd), extent, ptr, config_prof); + usize = isalloc(tsd_tsdn(tsd), extent, ptr); prof_free(tsd, extent, ptr, usize); } else if (config_stats) - usize = isalloc(tsd_tsdn(tsd), extent, ptr, config_prof); + usize = isalloc(tsd_tsdn(tsd), extent, ptr); if (config_stats) *tsd_thread_deallocatedp_get(tsd) += usize; @@ -1815,7 +1814,7 @@ je_realloc(void *ptr, size_t size) witness_assert_lockless(tsd_tsdn(tsd)); extent = iealloc(tsd_tsdn(tsd), ptr); - old_usize = isalloc(tsd_tsdn(tsd), extent, ptr, config_prof); + old_usize = isalloc(tsd_tsdn(tsd), extent, ptr); if (config_prof && opt_prof) { usize = s2u(size); ret = unlikely(usize == 0 || usize > HUGE_MAXCLASS) ? @@ -1848,8 +1847,7 @@ je_realloc(void *ptr, size_t size) if (config_stats && likely(ret != NULL)) { tsd_t *tsd; - assert(usize == isalloc(tsdn, iealloc(tsdn, ret), ret, - config_prof)); + assert(usize == isalloc(tsdn, iealloc(tsdn, ret), ret)); tsd = tsdn_tsd(tsdn); *tsd_thread_allocatedp_get(tsd) += usize; *tsd_thread_deallocatedp_get(tsd) += old_usize; @@ -2003,7 +2001,7 @@ imallocx_prof_sample(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, tcache, arena, slow_path); if (p == NULL) return (NULL); - arena_prof_promoted(tsdn, iealloc(tsdn, p), p, usize); + arena_prof_promote(tsdn, iealloc(tsdn, p), p, usize); } else p = imallocx_flags(tsdn, usize, alignment, zero, tcache, arena, slow_path); @@ -2138,7 +2136,7 @@ irallocx_prof_sample(tsdn_t *tsdn, extent_t *extent, void *old_ptr, alignment, zero, tcache, arena); if (p == NULL) return (NULL); - arena_prof_promoted(tsdn, iealloc(tsdn, p), p, usize); + arena_prof_promote(tsdn, iealloc(tsdn, p), p, usize); } else { p = iralloct(tsdn, extent, old_ptr, old_usize, usize, alignment, zero, tcache, arena); @@ -2182,7 +2180,7 @@ irallocx_prof(tsd_t *tsd, extent_t *extent, void *old_ptr, size_t old_usize, * reallocation. Therefore, query the actual value of usize. */ e = extent; - *usize = isalloc(tsd_tsdn(tsd), e, p, config_prof); + *usize = isalloc(tsd_tsdn(tsd), e, p); } else e = iealloc(tsd_tsdn(tsd), p); prof_realloc(tsd, e, p, *usize, tctx, prof_active, true, old_ptr, @@ -2229,7 +2227,7 @@ je_rallocx(void *ptr, size_t size, int flags) } else tcache = tcache_get(tsd, true); - old_usize = isalloc(tsd_tsdn(tsd), extent, ptr, config_prof); + old_usize = isalloc(tsd_tsdn(tsd), extent, ptr); if (config_prof && opt_prof) { usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment); @@ -2246,7 +2244,7 @@ je_rallocx(void *ptr, size_t size, int flags) goto label_oom; if (config_stats) { usize = isalloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), - p), p, config_prof); + p), p); } } assert(alignment == 0 || ((uintptr_t)p & (alignment - 1)) == ZU(0)); @@ -2276,7 +2274,7 @@ ixallocx_helper(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t old_usize, if (ixalloc(tsdn, extent, ptr, old_usize, size, extra, alignment, zero)) return (old_usize); - usize = isalloc(tsdn, extent, ptr, config_prof); + usize = isalloc(tsdn, extent, ptr); return (usize); } @@ -2363,7 +2361,7 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) witness_assert_lockless(tsd_tsdn(tsd)); extent = iealloc(tsd_tsdn(tsd), ptr); - old_usize = isalloc(tsd_tsdn(tsd), extent, ptr, config_prof); + old_usize = isalloc(tsd_tsdn(tsd), extent, ptr); /* * The API explicitly absolves itself of protecting against (size + @@ -2414,9 +2412,9 @@ je_sallocx(const void *ptr, int flags) witness_assert_lockless(tsdn); if (config_ivsalloc) - usize = ivsalloc(tsdn, ptr, config_prof); + usize = ivsalloc(tsdn, ptr); else - usize = isalloc(tsdn, iealloc(tsdn, ptr), ptr, config_prof); + usize = isalloc(tsdn, iealloc(tsdn, ptr), ptr); witness_assert_lockless(tsdn); return (usize); @@ -2477,7 +2475,7 @@ je_sdallocx(void *ptr, size_t size, int flags) tsd = tsd_fetch(); extent = iealloc(tsd_tsdn(tsd), ptr); usize = inallocx(tsd_tsdn(tsd), size, flags); - assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr, config_prof)); + assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr)); witness_assert_lockless(tsd_tsdn(tsd)); if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { @@ -2593,10 +2591,10 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) witness_assert_lockless(tsdn); if (config_ivsalloc) - ret = ivsalloc(tsdn, ptr, config_prof); + ret = ivsalloc(tsdn, ptr); else { - ret = (ptr == NULL) ? 0 : isalloc(tsdn, iealloc(tsdn, ptr), ptr, - config_prof); + ret = (ptr == NULL) ? 0 : isalloc(tsdn, iealloc(tsdn, ptr), + ptr); } witness_assert_lockless(tsdn); diff --git a/src/stats.c b/src/stats.c index 0e1442ed..4dc48d5b 100644 --- a/src/stats.c +++ b/src/stats.c @@ -37,12 +37,10 @@ size_t stats_cactive = 0; static void stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, unsigned i); -static void stats_arena_lruns_print(void (*write_cb)(void *, const char *), - void *cbopaque, unsigned i); static void stats_arena_hchunks_print( void (*write_cb)(void *, const char *), void *cbopaque, unsigned i); static void stats_arena_print(void (*write_cb)(void *, const char *), - void *cbopaque, unsigned i, bool bins, bool large, bool huge); + void *cbopaque, unsigned i, bool bins, bool huge); /******************************************************************************/ @@ -157,64 +155,17 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, } } -static void -stats_arena_lruns_print(void (*write_cb)(void *, const char *), void *cbopaque, - unsigned i) -{ - unsigned nbins, nlruns, j; - bool in_gap; - - malloc_cprintf(write_cb, cbopaque, - "large: size ind allocated nmalloc ndalloc" - " nrequests curruns\n"); - CTL_GET("arenas.nbins", &nbins, unsigned); - CTL_GET("arenas.nlruns", &nlruns, unsigned); - for (j = 0, in_gap = false; j < nlruns; j++) { - uint64_t nmalloc, ndalloc, nrequests; - size_t run_size, curruns; - - CTL_M2_M4_GET("stats.arenas.0.lruns.0.nmalloc", i, j, &nmalloc, - uint64_t); - CTL_M2_M4_GET("stats.arenas.0.lruns.0.ndalloc", i, j, &ndalloc, - uint64_t); - CTL_M2_M4_GET("stats.arenas.0.lruns.0.nrequests", i, j, - &nrequests, uint64_t); - if (nrequests == 0) - in_gap = true; - else { - CTL_M2_GET("arenas.lrun.0.size", j, &run_size, size_t); - CTL_M2_M4_GET("stats.arenas.0.lruns.0.curruns", i, j, - &curruns, size_t); - if (in_gap) { - malloc_cprintf(write_cb, cbopaque, - " ---\n"); - in_gap = false; - } - malloc_cprintf(write_cb, cbopaque, - "%20zu %3u %12zu %12"FMTu64" %12"FMTu64 - " %12"FMTu64" %12zu\n", - run_size, nbins + j, curruns * run_size, nmalloc, - ndalloc, nrequests, curruns); - } - } - if (in_gap) { - malloc_cprintf(write_cb, cbopaque, - " ---\n"); - } -} - static void stats_arena_hchunks_print(void (*write_cb)(void *, const char *), void *cbopaque, unsigned i) { - unsigned nbins, nlruns, nhchunks, j; + unsigned nbins, nhchunks, j; bool in_gap; malloc_cprintf(write_cb, cbopaque, "huge: size ind allocated nmalloc ndalloc" " nrequests curhchunks\n"); CTL_GET("arenas.nbins", &nbins, unsigned); - CTL_GET("arenas.nlruns", &nlruns, unsigned); CTL_GET("arenas.nhchunks", &nhchunks, unsigned); for (j = 0, in_gap = false; j < nhchunks; j++) { uint64_t nmalloc, ndalloc, nrequests; @@ -241,7 +192,7 @@ stats_arena_hchunks_print(void (*write_cb)(void *, const char *), malloc_cprintf(write_cb, cbopaque, "%20zu %3u %12zu %12"FMTu64" %12"FMTu64 " %12"FMTu64" %12zu\n", - hchunk_size, nbins + nlruns + j, + hchunk_size, nbins + j, curhchunks * hchunk_size, nmalloc, ndalloc, nrequests, curhchunks); } @@ -254,7 +205,7 @@ stats_arena_hchunks_print(void (*write_cb)(void *, const char *), static void stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, - unsigned i, bool bins, bool large, bool huge) + unsigned i, bool bins, bool huge) { unsigned nthreads; const char *dss; @@ -264,8 +215,6 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, uint64_t npurge, nmadvise, purged; size_t small_allocated; uint64_t small_nmalloc, small_ndalloc, small_nrequests; - size_t large_allocated; - uint64_t large_nmalloc, large_ndalloc, large_nrequests; size_t huge_allocated; uint64_t huge_nmalloc, huge_ndalloc, huge_nrequests; @@ -318,16 +267,6 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, "small: %12zu %12"FMTu64" %12"FMTu64 " %12"FMTu64"\n", small_allocated, small_nmalloc, small_ndalloc, small_nrequests); - CTL_M2_GET("stats.arenas.0.large.allocated", i, &large_allocated, - size_t); - CTL_M2_GET("stats.arenas.0.large.nmalloc", i, &large_nmalloc, uint64_t); - CTL_M2_GET("stats.arenas.0.large.ndalloc", i, &large_ndalloc, uint64_t); - CTL_M2_GET("stats.arenas.0.large.nrequests", i, &large_nrequests, - uint64_t); - malloc_cprintf(write_cb, cbopaque, - "large: %12zu %12"FMTu64" %12"FMTu64 - " %12"FMTu64"\n", - large_allocated, large_nmalloc, large_ndalloc, large_nrequests); CTL_M2_GET("stats.arenas.0.huge.allocated", i, &huge_allocated, size_t); CTL_M2_GET("stats.arenas.0.huge.nmalloc", i, &huge_nmalloc, uint64_t); CTL_M2_GET("stats.arenas.0.huge.ndalloc", i, &huge_ndalloc, uint64_t); @@ -340,10 +279,8 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "total: %12zu %12"FMTu64" %12"FMTu64 " %12"FMTu64"\n", - small_allocated + large_allocated + huge_allocated, - small_nmalloc + large_nmalloc + huge_nmalloc, - small_ndalloc + large_ndalloc + huge_ndalloc, - small_nrequests + large_nrequests + huge_nrequests); + small_allocated + huge_allocated, small_nmalloc + huge_nmalloc, + small_ndalloc + huge_ndalloc, small_nrequests + huge_nrequests); malloc_cprintf(write_cb, cbopaque, "active: %12zu\n", pactive * page); CTL_M2_GET("stats.arenas.0.mapped", i, &mapped, size_t); @@ -362,8 +299,6 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, if (bins) stats_arena_bins_print(write_cb, cbopaque, i); - if (large) - stats_arena_lruns_print(write_cb, cbopaque, i); if (huge) stats_arena_hchunks_print(write_cb, cbopaque, i); } @@ -379,7 +314,6 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, bool merged = true; bool unmerged = true; bool bins = true; - bool large = true; bool huge = true; /* @@ -421,9 +355,6 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, bins = false; break; case 'l': - large = false; - break; - case 'h': huge = false; break; default:; @@ -636,7 +567,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "\nMerged arenas stats:\n"); stats_arena_print(write_cb, cbopaque, - narenas, bins, large, huge); + narenas, bins, huge); } } } @@ -662,8 +593,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, cbopaque, "\narenas[%u]:\n", i); stats_arena_print(write_cb, - cbopaque, i, bins, large, - huge); + cbopaque, i, bins, huge); } } } diff --git a/src/tcache.c b/src/tcache.c index d3ef9992..41074d34 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -27,7 +27,7 @@ size_t tcache_salloc(tsdn_t *tsdn, const void *ptr) { - return (arena_salloc(tsdn, iealloc(tsdn, ptr), ptr, false)); + return (arena_salloc(tsdn, iealloc(tsdn, ptr), ptr)); } void @@ -46,7 +46,7 @@ tcache_event_hard(tsd_t *tsd, tcache_t *tcache) tbin->ncached - tbin->low_water + (tbin->low_water >> 2)); } else { - tcache_bin_flush_large(tsd, tbin, binind, tbin->ncached + tcache_bin_flush_huge(tsd, tbin, binind, tbin->ncached - tbin->low_water + (tbin->low_water >> 2), tcache); } /* @@ -170,7 +170,7 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, } void -tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, +tcache_bin_flush_huge(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, unsigned rem, tcache_t *tcache) { arena_t *arena; @@ -200,9 +200,9 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, } if (config_stats) { merged_stats = true; - arena->stats.nrequests_large += + arena->stats.nrequests_huge += tbin->tstats.nrequests; - arena->stats.lstats[binind - NBINS].nrequests += + arena->stats.hstats[binind - NBINS].nrequests += tbin->tstats.nrequests; tbin->tstats.nrequests = 0; } @@ -213,10 +213,8 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, assert(ptr != NULL); extent = iealloc(tsd_tsdn(tsd), ptr); if (extent_arena_get(extent) == locked_arena) { - arena_chunk_t *chunk = - (arena_chunk_t *)extent_base_get(extent); - arena_dalloc_large_junked_locked(tsd_tsdn(tsd), - locked_arena, chunk, extent, ptr); + huge_dalloc_junked_locked(tsd_tsdn(tsd), + extent); } else { /* * This object was allocated via a different @@ -240,8 +238,8 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, * arena, so the stats didn't get merged. Manually do so now. */ malloc_mutex_lock(tsd_tsdn(tsd), &arena->lock); - arena->stats.nrequests_large += tbin->tstats.nrequests; - arena->stats.lstats[binind - NBINS].nrequests += + arena->stats.nrequests_huge += tbin->tstats.nrequests; + arena->stats.hstats[binind - NBINS].nrequests += tbin->tstats.nrequests; tbin->tstats.nrequests = 0; malloc_mutex_unlock(tsd_tsdn(tsd), &arena->lock); @@ -379,12 +377,12 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache) for (; i < nhbins; i++) { tcache_bin_t *tbin = &tcache->tbins[i]; - tcache_bin_flush_large(tsd, tbin, i, 0, tcache); + tcache_bin_flush_huge(tsd, tbin, i, 0, tcache); if (config_stats && tbin->tstats.nrequests != 0) { malloc_mutex_lock(tsd_tsdn(tsd), &arena->lock); - arena->stats.nrequests_large += tbin->tstats.nrequests; - arena->stats.lstats[i - NBINS].nrequests += + arena->stats.nrequests_huge += tbin->tstats.nrequests; + arena->stats.hstats[i - NBINS].nrequests += tbin->tstats.nrequests; malloc_mutex_unlock(tsd_tsdn(tsd), &arena->lock); } @@ -439,10 +437,10 @@ tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) } for (; i < nhbins; i++) { - malloc_large_stats_t *lstats = &arena->stats.lstats[i - NBINS]; + malloc_huge_stats_t *hstats = &arena->stats.hstats[i - NBINS]; tcache_bin_t *tbin = &tcache->tbins[i]; - arena->stats.nrequests_large += tbin->tstats.nrequests; - lstats->nrequests += tbin->tstats.nrequests; + arena->stats.nrequests_huge += tbin->tstats.nrequests; + hstats->nrequests += tbin->tstats.nrequests; tbin->tstats.nrequests = 0; } } @@ -516,14 +514,9 @@ tcache_boot(tsdn_t *tsdn) { unsigned i; - /* - * If necessary, clamp opt_lg_tcache_max, now that large_maxclass is - * known. - */ + /* If necessary, clamp opt_lg_tcache_max. */ if (opt_lg_tcache_max < 0 || (1U << opt_lg_tcache_max) < SMALL_MAXCLASS) tcache_maxclass = SMALL_MAXCLASS; - else if ((1U << opt_lg_tcache_max) > large_maxclass) - tcache_maxclass = large_maxclass; else tcache_maxclass = (1U << opt_lg_tcache_max); @@ -550,7 +543,7 @@ tcache_boot(tsdn_t *tsdn) stack_nelms += tcache_bin_info[i].ncached_max; } for (; i < nhbins; i++) { - tcache_bin_info[i].ncached_max = TCACHE_NSLOTS_LARGE; + tcache_bin_info[i].ncached_max = TCACHE_NSLOTS_HUGE; stack_nelms += tcache_bin_info[i].ncached_max; } diff --git a/src/zone.c b/src/zone.c index 2c17123a..4609503a 100644 --- a/src/zone.c +++ b/src/zone.c @@ -56,7 +56,7 @@ zone_size(malloc_zone_t *zone, void *ptr) * not work in practice, we must check all pointers to assure that they * reside within a mapped chunk before determining size. */ - return (ivsalloc(tsdn_fetch(), ptr, config_prof)); + return (ivsalloc(tsdn_fetch(), ptr)); } static void * @@ -87,7 +87,7 @@ static void zone_free(malloc_zone_t *zone, void *ptr) { - if (ivsalloc(tsdn_fetch(), ptr, config_prof) != 0) { + if (ivsalloc(tsdn_fetch(), ptr) != 0) { je_free(ptr); return; } @@ -99,7 +99,7 @@ static void * zone_realloc(malloc_zone_t *zone, void *ptr, size_t size) { - if (ivsalloc(tsdn_fetch(), ptr, config_prof) != 0) + if (ivsalloc(tsdn_fetch(), ptr) != 0) return (je_realloc(ptr, size)); return (realloc(ptr, size)); @@ -123,7 +123,7 @@ zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size) { size_t alloc_size; - alloc_size = ivsalloc(tsdn_fetch(), ptr, config_prof); + alloc_size = ivsalloc(tsdn_fetch(), ptr); if (alloc_size != 0) { assert(alloc_size == size); je_free(ptr); diff --git a/test/integration/chunk.c b/test/integration/chunk.c index 092472c6..3aad7a8a 100644 --- a/test/integration/chunk.c +++ b/test/integration/chunk.c @@ -120,7 +120,7 @@ chunk_merge(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b, TEST_BEGIN(test_chunk) { void *p; - size_t old_size, new_size, large0, large1, huge0, huge1, huge2, sz; + size_t old_size, new_size, huge0, huge1, huge2, sz; unsigned arena_ind; int flags; size_t hooks_mib[3], purge_mib[3]; @@ -162,14 +162,8 @@ TEST_BEGIN(test_chunk) assert_ptr_ne(old_hooks.split, chunk_split, "Unexpected split error"); assert_ptr_ne(old_hooks.merge, chunk_merge, "Unexpected merge error"); - /* Get large size classes. */ - sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.lrun.0.size", &large0, &sz, NULL, 0), 0, - "Unexpected arenas.lrun.0.size failure"); - assert_d_eq(mallctl("arenas.lrun.1.size", &large1, &sz, NULL, 0), 0, - "Unexpected arenas.lrun.1.size failure"); - /* Get huge size classes. */ + sz = sizeof(size_t); assert_d_eq(mallctl("arenas.hchunk.0.size", &huge0, &sz, NULL, 0), 0, "Unexpected arenas.hchunk.0.size failure"); assert_d_eq(mallctl("arenas.hchunk.1.size", &huge1, &sz, NULL, 0), 0, @@ -224,24 +218,6 @@ TEST_BEGIN(test_chunk) do_dalloc = true; do_decommit = false; - /* Test decommit for large allocations. */ - do_decommit = true; - p = mallocx(large1, flags); - assert_ptr_not_null(p, "Unexpected mallocx() error"); - assert_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0), - 0, "Unexpected arena.%u.purge error", arena_ind); - did_decommit = false; - assert_zu_eq(xallocx(p, large0, 0, flags), large0, - "Unexpected xallocx() failure"); - assert_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0), - 0, "Unexpected arena.%u.purge error", arena_ind); - did_commit = false; - assert_zu_eq(xallocx(p, large1, 0, flags), large1, - "Unexpected xallocx() failure"); - assert_b_eq(did_decommit, did_commit, "Expected decommit/commit match"); - dallocx(p, flags); - do_decommit = false; - /* Make sure non-huge allocation succeeds. */ p = mallocx(42, flags); assert_ptr_not_null(p, "Unexpected mallocx() error"); diff --git a/test/integration/xallocx.c b/test/integration/xallocx.c index ad292bb5..7af1b194 100644 --- a/test/integration/xallocx.c +++ b/test/integration/xallocx.c @@ -91,13 +91,6 @@ get_nsmall(void) return (get_nsizes_impl("arenas.nbins")); } -static unsigned -get_nlarge(void) -{ - - return (get_nsizes_impl("arenas.nlruns")); -} - static unsigned get_nhuge(void) { @@ -131,13 +124,6 @@ get_small_size(size_t ind) return (get_size_impl("arenas.bin.0.size", ind)); } -static size_t -get_large_size(size_t ind) -{ - - return (get_size_impl("arenas.lrun.0.size", ind)); -} - static size_t get_huge_size(size_t ind) { @@ -239,81 +225,14 @@ TEST_BEGIN(test_extra_small) } TEST_END -TEST_BEGIN(test_extra_large) -{ - int flags = MALLOCX_ARENA(arena_ind()); - size_t smallmax, large0, large1, large2, huge0, hugemax; - void *p; - - /* Get size classes. */ - smallmax = get_small_size(get_nsmall()-1); - large0 = get_large_size(0); - large1 = get_large_size(1); - large2 = get_large_size(2); - huge0 = get_huge_size(0); - hugemax = get_huge_size(get_nhuge()-1); - - p = mallocx(large2, flags); - assert_ptr_not_null(p, "Unexpected mallocx() error"); - - assert_zu_eq(xallocx(p, large2, 0, flags), large2, - "Unexpected xallocx() behavior"); - /* Test size decrease with zero extra. */ - assert_zu_eq(xallocx(p, large0, 0, flags), large0, - "Unexpected xallocx() behavior"); - assert_zu_eq(xallocx(p, smallmax, 0, flags), large0, - "Unexpected xallocx() behavior"); - - assert_zu_eq(xallocx(p, large2, 0, flags), large2, - "Unexpected xallocx() behavior"); - /* Test size decrease with non-zero extra. */ - assert_zu_eq(xallocx(p, large0, large2 - large0, flags), large2, - "Unexpected xallocx() behavior"); - assert_zu_eq(xallocx(p, large1, large2 - large1, flags), large2, - "Unexpected xallocx() behavior"); - assert_zu_eq(xallocx(p, large0, large1 - large0, flags), large1, - "Unexpected xallocx() behavior"); - assert_zu_eq(xallocx(p, smallmax, large0 - smallmax, flags), large0, - "Unexpected xallocx() behavior"); - - assert_zu_eq(xallocx(p, large0, 0, flags), large0, - "Unexpected xallocx() behavior"); - /* Test size increase with zero extra. */ - assert_zu_eq(xallocx(p, large2, 0, flags), large2, - "Unexpected xallocx() behavior"); - assert_zu_eq(xallocx(p, huge0, 0, flags), large2, - "Unexpected xallocx() behavior"); - - assert_zu_eq(xallocx(p, large0, 0, flags), large0, - "Unexpected xallocx() behavior"); - /* Test size increase with non-zero extra. */ - assert_zu_lt(xallocx(p, large0, huge0 - large0, flags), huge0, - "Unexpected xallocx() behavior"); - - assert_zu_eq(xallocx(p, large0, 0, flags), large0, - "Unexpected xallocx() behavior"); - /* Test size increase with non-zero extra. */ - assert_zu_eq(xallocx(p, large0, large2 - large0, flags), large2, - "Unexpected xallocx() behavior"); - - assert_zu_eq(xallocx(p, large2, 0, flags), large2, - "Unexpected xallocx() behavior"); - /* Test size+extra overflow. */ - assert_zu_lt(xallocx(p, large2, hugemax - large2 + 1, flags), huge0, - "Unexpected xallocx() behavior"); - - dallocx(p, flags); -} -TEST_END - TEST_BEGIN(test_extra_huge) { int flags = MALLOCX_ARENA(arena_ind()); - size_t largemax, huge1, huge2, huge3, hugemax; + size_t smallmax, huge1, huge2, huge3, hugemax; void *p; /* Get size classes. */ - largemax = get_large_size(get_nlarge()-1); + smallmax = get_small_size(get_nsmall()-1); huge1 = get_huge_size(1); huge2 = get_huge_size(2); huge3 = get_huge_size(3); @@ -327,7 +246,7 @@ TEST_BEGIN(test_extra_huge) /* Test size decrease with zero extra. */ assert_zu_ge(xallocx(p, huge1, 0, flags), huge1, "Unexpected xallocx() behavior"); - assert_zu_ge(xallocx(p, largemax, 0, flags), huge1, + assert_zu_ge(xallocx(p, smallmax, 0, flags), huge1, "Unexpected xallocx() behavior"); assert_zu_eq(xallocx(p, huge3, 0, flags), huge3, @@ -339,7 +258,7 @@ TEST_BEGIN(test_extra_huge) "Unexpected xallocx() behavior"); assert_zu_eq(xallocx(p, huge1, huge2 - huge1, flags), huge2, "Unexpected xallocx() behavior"); - assert_zu_ge(xallocx(p, largemax, huge1 - largemax, flags), huge1, + assert_zu_ge(xallocx(p, smallmax, huge1 - smallmax, flags), huge1, "Unexpected xallocx() behavior"); assert_zu_ge(xallocx(p, huge1, 0, flags), huge1, @@ -455,18 +374,6 @@ test_zero(size_t szmin, size_t szmax) dallocx(p, flags); } -TEST_BEGIN(test_zero_large) -{ - size_t large0, largemax; - - /* Get size classes. */ - large0 = get_large_size(0); - largemax = get_large_size(get_nlarge()-1); - - test_zero(large0, largemax); -} -TEST_END - TEST_BEGIN(test_zero_huge) { size_t huge0, huge1; @@ -490,8 +397,6 @@ main(void) test_size, test_size_extra_overflow, test_extra_small, - test_extra_large, test_extra_huge, - test_zero_large, test_zero_huge)); } diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index fa2c5cd5..546d3cc8 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -24,13 +24,6 @@ get_nsmall(void) return (get_nsizes_impl("arenas.nbins")); } -static unsigned -get_nlarge(void) -{ - - return (get_nsizes_impl("arenas.nlruns")); -} - static unsigned get_nhuge(void) { @@ -64,13 +57,6 @@ get_small_size(size_t ind) return (get_size_impl("arenas.bin.0.size", ind)); } -static size_t -get_large_size(size_t ind) -{ - - return (get_size_impl("arenas.lrun.0.size", ind)); -} - static size_t get_huge_size(size_t ind) { @@ -90,13 +76,13 @@ vsalloc(tsdn_t *tsdn, const void *ptr) if (!extent_active_get(extent)) return (0); - return (isalloc(tsdn, extent, ptr, false)); + return (isalloc(tsdn, extent, ptr)); } TEST_BEGIN(test_arena_reset) { -#define NHUGE 4 - unsigned arena_ind, nsmall, nlarge, nhuge, nptrs, i; +#define NHUGE 32 + unsigned arena_ind, nsmall, nhuge, nptrs, i; size_t sz, miblen; void **ptrs; int flags; @@ -110,9 +96,8 @@ TEST_BEGIN(test_arena_reset) flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; nsmall = get_nsmall(); - nlarge = get_nlarge(); nhuge = get_nhuge() > NHUGE ? NHUGE : get_nhuge(); - nptrs = nsmall + nlarge + nhuge; + nptrs = nsmall + nhuge; ptrs = (void **)malloc(nptrs * sizeof(void *)); assert_ptr_not_null(ptrs, "Unexpected malloc() failure"); @@ -123,15 +108,9 @@ TEST_BEGIN(test_arena_reset) assert_ptr_not_null(ptrs[i], "Unexpected mallocx(%zu, %#x) failure", sz, flags); } - for (i = 0; i < nlarge; i++) { - sz = get_large_size(i); - ptrs[nsmall + i] = mallocx(sz, flags); - assert_ptr_not_null(ptrs[i], - "Unexpected mallocx(%zu, %#x) failure", sz, flags); - } for (i = 0; i < nhuge; i++) { sz = get_huge_size(i); - ptrs[nsmall + nlarge + i] = mallocx(sz, flags); + ptrs[nsmall + i] = mallocx(sz, flags); assert_ptr_not_null(ptrs[i], "Unexpected mallocx(%zu, %#x) failure", sz, flags); } @@ -140,7 +119,7 @@ TEST_BEGIN(test_arena_reset) /* Verify allocations. */ for (i = 0; i < nptrs; i++) { - assert_zu_gt(ivsalloc(tsdn, ptrs[i], false), 0, + assert_zu_gt(ivsalloc(tsdn, ptrs[i]), 0, "Allocation should have queryable size"); } diff --git a/test/unit/decay.c b/test/unit/decay.c index 70a2e67a..786cc934 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -1,6 +1,6 @@ #include "test/jemalloc_test.h" -const char *malloc_conf = "purge:decay,decay_time:1"; +const char *malloc_conf = "purge:decay,decay_time:1,lg_tcache_max:0"; static nstime_update_t *nstime_update_orig; @@ -22,7 +22,7 @@ TEST_BEGIN(test_decay_ticks) { ticker_t *decay_ticker; unsigned tick0, tick1; - size_t sz, huge0, large0; + size_t sz, huge0; void *p; test_skip_if(opt_purge != purge_mode_decay); @@ -34,13 +34,11 @@ TEST_BEGIN(test_decay_ticks) sz = sizeof(size_t); assert_d_eq(mallctl("arenas.hchunk.0.size", &huge0, &sz, NULL, 0), 0, "Unexpected mallctl failure"); - assert_d_eq(mallctl("arenas.lrun.0.size", &large0, &sz, NULL, 0), 0, - "Unexpected mallctl failure"); /* * Test the standard APIs using a huge size class, since we can't - * control tcache interactions (except by completely disabling tcache - * for the entire test program). + * control tcache interactions for small size classes (except by + * completely disabling tcache for the entire test program). */ /* malloc(). */ @@ -101,15 +99,14 @@ TEST_BEGIN(test_decay_ticks) assert_u32_ne(tick1, tick0, "Expected ticker to tick during realloc()"); /* - * Test the *allocx() APIs using huge, large, and small size classes, - * with tcache explicitly disabled. + * Test the *allocx() APIs using huge and small size classes, with + * tcache explicitly disabled. */ { unsigned i; - size_t allocx_sizes[3]; + size_t allocx_sizes[2]; allocx_sizes[0] = huge0; - allocx_sizes[1] = large0; - allocx_sizes[2] = 1; + allocx_sizes[1] = 1; for (i = 0; i < sizeof(allocx_sizes) / sizeof(size_t); i++) { sz = allocx_sizes[i]; @@ -157,13 +154,13 @@ TEST_BEGIN(test_decay_ticks) } /* - * Test tcache fill/flush interactions for large and small size classes, + * Test tcache fill/flush interactions for huge and small size classes, * using an explicit tcache. */ if (config_tcache) { unsigned tcache_ind, i; size_t tcache_sizes[2]; - tcache_sizes[0] = large0; + tcache_sizes[0] = huge0; tcache_sizes[1] = 1; sz = sizeof(unsigned); @@ -204,14 +201,14 @@ TEST_BEGIN(test_decay_ticker) uint64_t epoch; uint64_t npurge0 = 0; uint64_t npurge1 = 0; - size_t sz, large; + size_t sz, huge; unsigned i, nupdates0; nstime_t time, decay_time, deadline; test_skip_if(opt_purge != purge_mode_decay); /* - * Allocate a bunch of large objects, pause the clock, deallocate the + * Allocate a bunch of huge objects, pause the clock, deallocate the * objects, restore the clock, then [md]allocx() in a tight loop to * verify the ticker triggers purging. */ @@ -222,11 +219,11 @@ TEST_BEGIN(test_decay_ticker) sz = sizeof(size_t); assert_d_eq(mallctl("arenas.tcache_max", &tcache_max, &sz, NULL, 0), 0, "Unexpected mallctl failure"); - large = nallocx(tcache_max + 1, flags); + huge = nallocx(tcache_max + 1, flags); } else { sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.lrun.0.size", &large, &sz, NULL, 0), - 0, "Unexpected mallctl failure"); + assert_d_eq(mallctl("arenas.hchunk.0.size", &huge, &sz, NULL, + 0), 0, "Unexpected mallctl failure"); } assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, @@ -238,7 +235,7 @@ TEST_BEGIN(test_decay_ticker) config_stats ? 0 : ENOENT, "Unexpected mallctl result"); for (i = 0; i < NPS; i++) { - ps[i] = mallocx(large, flags); + ps[i] = mallocx(huge, flags); assert_ptr_not_null(ps[i], "Unexpected mallocx() failure"); } @@ -296,13 +293,13 @@ TEST_BEGIN(test_decay_nonmonotonic) uint64_t epoch; uint64_t npurge0 = 0; uint64_t npurge1 = 0; - size_t sz, large0; + size_t sz, huge0; unsigned i, nupdates0; test_skip_if(opt_purge != purge_mode_decay); sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.lrun.0.size", &large0, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arenas.hchunk.0.size", &huge0, &sz, NULL, 0), 0, "Unexpected mallctl failure"); assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, @@ -322,7 +319,7 @@ TEST_BEGIN(test_decay_nonmonotonic) nstime_update = nstime_update_mock; for (i = 0; i < NPS; i++) { - ps[i] = mallocx(large0, flags); + ps[i] = mallocx(huge0, flags); assert_ptr_not_null(ps[i], "Unexpected mallocx() failure"); } diff --git a/test/unit/extent_quantize.c b/test/unit/extent_quantize.c index d8846db4..98c9fde4 100644 --- a/test/unit/extent_quantize.c +++ b/test/unit/extent_quantize.c @@ -35,16 +35,16 @@ TEST_BEGIN(test_small_extent_size) } TEST_END -TEST_BEGIN(test_large_extent_size) +TEST_BEGIN(test_huge_extent_size) { bool cache_oblivious; - unsigned nlruns, i; + unsigned nhchunks, i; size_t sz, extent_size_prev, ceil_prev; size_t mib[4]; size_t miblen = sizeof(mib) / sizeof(size_t); /* - * Iterate over all large size classes, get their extent sizes, and + * Iterate over all huge size classes, get their extent sizes, and * verify that the quantized size is the same as the extent size. */ @@ -53,12 +53,12 @@ TEST_BEGIN(test_large_extent_size) NULL, 0), 0, "Unexpected mallctl failure"); sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.nlruns", &nlruns, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arenas.nhchunks", &nhchunks, &sz, NULL, 0), 0, "Unexpected mallctl failure"); - assert_d_eq(mallctlnametomib("arenas.lrun.0.size", mib, &miblen), 0, + assert_d_eq(mallctlnametomib("arenas.hchunk.0.size", mib, &miblen), 0, "Unexpected mallctlnametomib failure"); - for (i = 0; i < nlruns; i++) { + for (i = 0; i < nhchunks; i++) { size_t lextent_size, extent_size, floor, ceil; mib[2] = i; @@ -91,33 +91,24 @@ TEST_BEGIN(test_large_extent_size) ceil_prev, extent_size); } } - extent_size_prev = floor; - ceil_prev = extent_size_quantize_ceil(extent_size + PAGE); + if (i + 1 < nhchunks) { + extent_size_prev = floor; + ceil_prev = extent_size_quantize_ceil(extent_size + + PAGE); + } } } TEST_END TEST_BEGIN(test_monotonic) { - unsigned nbins, nlruns, i; - size_t sz, floor_prev, ceil_prev; - - /* - * Iterate over all extent sizes and verify that - * extent_size_quantize_{floor,ceil}() are monotonic. - */ - - sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.nbins", &nbins, &sz, NULL, 0), 0, - "Unexpected mallctl failure"); - - sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.nlruns", &nlruns, &sz, NULL, 0), 0, - "Unexpected mallctl failure"); +#define SZ_MAX ZU(4 * 1024 * 1024) + unsigned i; + size_t floor_prev, ceil_prev; floor_prev = 0; ceil_prev = 0; - for (i = 1; i <= large_maxclass >> LG_PAGE; i++) { + for (i = 1; i <= SZ_MAX >> LG_PAGE; i++) { size_t extent_size, floor, ceil; extent_size = i << LG_PAGE; @@ -150,6 +141,6 @@ main(void) return (test( test_small_extent_size, - test_large_extent_size, + test_huge_extent_size, test_monotonic)); } diff --git a/test/unit/junk.c b/test/unit/junk.c index 82eddf4c..cdf8fb3c 100644 --- a/test/unit/junk.c +++ b/test/unit/junk.c @@ -9,7 +9,6 @@ const char *malloc_conf = #endif static arena_dalloc_junk_small_t *arena_dalloc_junk_small_orig; -static arena_dalloc_junk_large_t *arena_dalloc_junk_large_orig; static huge_dalloc_junk_t *huge_dalloc_junk_orig; static void *watch_for_junking; static bool saw_junking; @@ -38,25 +37,10 @@ arena_dalloc_junk_small_intercept(void *ptr, const arena_bin_info_t *bin_info) } static void -arena_dalloc_junk_large_intercept(void *ptr, size_t usize) +huge_dalloc_junk_intercept(void *ptr, size_t usize) { - size_t i; - - arena_dalloc_junk_large_orig(ptr, usize); - for (i = 0; i < usize; i++) { - assert_u_eq(((uint8_t *)ptr)[i], JEMALLOC_FREE_JUNK, - "Missing junk fill for byte %zu/%zu of deallocated region", - i, usize); - } - if (ptr == watch_for_junking) - saw_junking = true; -} -static void -huge_dalloc_junk_intercept(tsdn_t *tsdn, void *ptr, size_t usize) -{ - - huge_dalloc_junk_orig(tsdn, ptr, usize); + huge_dalloc_junk_orig(ptr, usize); /* * The conditions under which junk filling actually occurs are nuanced * enough that it doesn't make sense to duplicate the decision logic in @@ -75,8 +59,6 @@ test_junk(size_t sz_min, size_t sz_max) if (opt_junk_free) { arena_dalloc_junk_small_orig = arena_dalloc_junk_small; arena_dalloc_junk_small = arena_dalloc_junk_small_intercept; - arena_dalloc_junk_large_orig = arena_dalloc_junk_large; - arena_dalloc_junk_large = arena_dalloc_junk_large_intercept; huge_dalloc_junk_orig = huge_dalloc_junk; huge_dalloc_junk = huge_dalloc_junk_intercept; } @@ -106,13 +88,18 @@ test_junk(size_t sz_min, size_t sz_max) } if (xallocx(s, sz+1, 0, 0) == sz) { + uint8_t *t; watch_junking(s); - s = (uint8_t *)rallocx(s, sz+1, 0); - assert_ptr_not_null((void *)s, + t = (uint8_t *)rallocx(s, sz+1, 0); + assert_ptr_not_null((void *)t, "Unexpected rallocx() failure"); + assert_ptr_ne(s, t, "Unexpected in-place rallocx()"); + assert_zu_ge(sallocx(t, 0), sz+1, + "Unexpectedly small rallocx() result"); assert_true(!opt_junk_free || saw_junking, "Expected region of size %zu to be junk-filled", sz); + s = t; } } @@ -123,7 +110,6 @@ test_junk(size_t sz_min, size_t sz_max) if (opt_junk_free) { arena_dalloc_junk_small = arena_dalloc_junk_small_orig; - arena_dalloc_junk_large = arena_dalloc_junk_large_orig; huge_dalloc_junk = huge_dalloc_junk_orig; } } @@ -136,64 +122,11 @@ TEST_BEGIN(test_junk_small) } TEST_END -TEST_BEGIN(test_junk_large) -{ - - test_skip_if(!config_fill); - test_junk(SMALL_MAXCLASS+1, large_maxclass); -} -TEST_END - TEST_BEGIN(test_junk_huge) { test_skip_if(!config_fill); - test_junk(large_maxclass+1, chunksize*2); -} -TEST_END - -arena_ralloc_junk_large_t *arena_ralloc_junk_large_orig; -static void *most_recently_trimmed; - -static size_t -shrink_size(size_t size) -{ - size_t shrink_size; - - for (shrink_size = size - 1; nallocx(shrink_size, 0) == size; - shrink_size--) - ; /* Do nothing. */ - - return (shrink_size); -} - -static void -arena_ralloc_junk_large_intercept(void *ptr, size_t old_usize, size_t usize) -{ - - arena_ralloc_junk_large_orig(ptr, old_usize, usize); - assert_zu_eq(old_usize, large_maxclass, "Unexpected old_usize"); - assert_zu_eq(usize, shrink_size(large_maxclass), "Unexpected usize"); - most_recently_trimmed = ptr; -} - -TEST_BEGIN(test_junk_large_ralloc_shrink) -{ - void *p1, *p2; - - p1 = mallocx(large_maxclass, 0); - assert_ptr_not_null(p1, "Unexpected mallocx() failure"); - - arena_ralloc_junk_large_orig = arena_ralloc_junk_large; - arena_ralloc_junk_large = arena_ralloc_junk_large_intercept; - - p2 = rallocx(p1, shrink_size(large_maxclass), 0); - assert_ptr_eq(p1, p2, "Unexpected move during shrink"); - - arena_ralloc_junk_large = arena_ralloc_junk_large_orig; - - assert_ptr_eq(most_recently_trimmed, p1, - "Expected trimmed portion of region to be junk-filled"); + test_junk(SMALL_MAXCLASS+1, chunksize*2); } TEST_END @@ -203,7 +136,5 @@ main(void) return (test( test_junk_small, - test_junk_large, - test_junk_huge, - test_junk_large_ralloc_shrink)); + test_junk_huge)); } diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 79c5147c..9ba730a6 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -596,8 +596,7 @@ TEST_BEGIN(test_arenas_constants) TEST_ARENAS_CONSTANT(size_t, quantum, QUANTUM); TEST_ARENAS_CONSTANT(size_t, page, PAGE); TEST_ARENAS_CONSTANT(unsigned, nbins, NBINS); - TEST_ARENAS_CONSTANT(unsigned, nlruns, nlclasses); - TEST_ARENAS_CONSTANT(unsigned, nhchunks, nhclasses); + TEST_ARENAS_CONSTANT(unsigned, nhchunks, NSIZES - NBINS); #undef TEST_ARENAS_CONSTANT } @@ -622,23 +621,6 @@ TEST_BEGIN(test_arenas_bin_constants) } TEST_END -TEST_BEGIN(test_arenas_lrun_constants) -{ - -#define TEST_ARENAS_LRUN_CONSTANT(t, name, expected) do { \ - t name; \ - size_t sz = sizeof(t); \ - assert_d_eq(mallctl("arenas.lrun.0."#name, &name, &sz, NULL, \ - 0), 0, "Unexpected mallctl() failure"); \ - assert_zu_eq(name, expected, "Incorrect "#name" size"); \ -} while (0) - - TEST_ARENAS_LRUN_CONSTANT(size_t, size, LARGE_MINCLASS); - -#undef TEST_ARENAS_LRUN_CONSTANT -} -TEST_END - TEST_BEGIN(test_arenas_hchunk_constants) { @@ -650,7 +632,7 @@ TEST_BEGIN(test_arenas_hchunk_constants) assert_zu_eq(name, expected, "Incorrect "#name" size"); \ } while (0) - TEST_ARENAS_HCHUNK_CONSTANT(size_t, size, chunksize); + TEST_ARENAS_HCHUNK_CONSTANT(size_t, size, LARGE_MINCLASS); #undef TEST_ARENAS_HCHUNK_CONSTANT } @@ -721,7 +703,6 @@ main(void) test_arenas_decay_time, test_arenas_constants, test_arenas_bin_constants, - test_arenas_lrun_constants, test_arenas_hchunk_constants, test_arenas_extend, test_stats_arenas)); diff --git a/test/unit/prof_idump.c b/test/unit/prof_idump.c index bdea53ec..2b0639d8 100644 --- a/test/unit/prof_idump.c +++ b/test/unit/prof_idump.c @@ -1,10 +1,17 @@ #include "test/jemalloc_test.h" +const char *malloc_conf = "" #ifdef JEMALLOC_PROF -const char *malloc_conf = - "prof:true,prof_accum:true,prof_active:false,lg_prof_sample:0," - "lg_prof_interval:0"; + "prof:true,prof_accum:true,prof_active:false,lg_prof_sample:0" + ",lg_prof_interval:0" +# ifdef JEMALLOC_TCACHE + "," +# endif #endif +#ifdef JEMALLOC_TCACHE + "tcache:false" +#endif + ; static bool did_prof_dump_open; diff --git a/test/unit/run_quantize.c b/test/unit/run_quantize.c deleted file mode 100644 index 45f32018..00000000 --- a/test/unit/run_quantize.c +++ /dev/null @@ -1,149 +0,0 @@ -#include "test/jemalloc_test.h" - -TEST_BEGIN(test_small_run_size) -{ - unsigned nbins, i; - size_t sz, run_size; - size_t mib[4]; - size_t miblen = sizeof(mib) / sizeof(size_t); - - /* - * Iterate over all small size classes, get their run sizes, and verify - * that the quantized size is the same as the run size. - */ - - sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.nbins", &nbins, &sz, NULL, 0), 0, - "Unexpected mallctl failure"); - - assert_d_eq(mallctlnametomib("arenas.bin.0.run_size", mib, &miblen), 0, - "Unexpected mallctlnametomib failure"); - for (i = 0; i < nbins; i++) { - mib[2] = i; - sz = sizeof(size_t); - assert_d_eq(mallctlbymib(mib, miblen, &run_size, &sz, NULL, 0), - 0, "Unexpected mallctlbymib failure"); - assert_zu_eq(run_size, run_quantize_floor(run_size), - "Small run quantization should be a no-op (run_size=%zu)", - run_size); - assert_zu_eq(run_size, run_quantize_ceil(run_size), - "Small run quantization should be a no-op (run_size=%zu)", - run_size); - } -} -TEST_END - -TEST_BEGIN(test_large_run_size) -{ - bool cache_oblivious; - unsigned nlruns, i; - size_t sz, run_size_prev, ceil_prev; - size_t mib[4]; - size_t miblen = sizeof(mib) / sizeof(size_t); - - /* - * Iterate over all large size classes, get their run sizes, and verify - * that the quantized size is the same as the run size. - */ - - sz = sizeof(bool); - assert_d_eq(mallctl("config.cache_oblivious", &cache_oblivious, &sz, - NULL, 0), 0, "Unexpected mallctl failure"); - - sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.nlruns", &nlruns, &sz, NULL, 0), 0, - "Unexpected mallctl failure"); - - assert_d_eq(mallctlnametomib("arenas.lrun.0.size", mib, &miblen), 0, - "Unexpected mallctlnametomib failure"); - for (i = 0; i < nlruns; i++) { - size_t lrun_size, run_size, floor, ceil; - - mib[2] = i; - sz = sizeof(size_t); - assert_d_eq(mallctlbymib(mib, miblen, &lrun_size, &sz, NULL, 0), - 0, "Unexpected mallctlbymib failure"); - run_size = cache_oblivious ? lrun_size + PAGE : lrun_size; - floor = run_quantize_floor(run_size); - ceil = run_quantize_ceil(run_size); - - assert_zu_eq(run_size, floor, - "Large run quantization should be a no-op for precise " - "size (lrun_size=%zu, run_size=%zu)", lrun_size, run_size); - assert_zu_eq(run_size, ceil, - "Large run quantization should be a no-op for precise " - "size (lrun_size=%zu, run_size=%zu)", lrun_size, run_size); - - if (i > 0) { - assert_zu_eq(run_size_prev, run_quantize_floor(run_size - - PAGE), "Floor should be a precise size"); - if (run_size_prev < ceil_prev) { - assert_zu_eq(ceil_prev, run_size, - "Ceiling should be a precise size " - "(run_size_prev=%zu, ceil_prev=%zu, " - "run_size=%zu)", run_size_prev, ceil_prev, - run_size); - } - } - run_size_prev = floor; - ceil_prev = run_quantize_ceil(run_size + PAGE); - } -} -TEST_END - -TEST_BEGIN(test_monotonic) -{ - unsigned nbins, nlruns, i; - size_t sz, floor_prev, ceil_prev; - - /* - * Iterate over all run sizes and verify that - * run_quantize_{floor,ceil}() are monotonic. - */ - - sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.nbins", &nbins, &sz, NULL, 0), 0, - "Unexpected mallctl failure"); - - sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.nlruns", &nlruns, &sz, NULL, 0), 0, - "Unexpected mallctl failure"); - - floor_prev = 0; - ceil_prev = 0; - for (i = 1; i <= large_maxclass >> LG_PAGE; i++) { - size_t run_size, floor, ceil; - - run_size = i << LG_PAGE; - floor = run_quantize_floor(run_size); - ceil = run_quantize_ceil(run_size); - - assert_zu_le(floor, run_size, - "Floor should be <= (floor=%zu, run_size=%zu, ceil=%zu)", - floor, run_size, ceil); - assert_zu_ge(ceil, run_size, - "Ceiling should be >= (floor=%zu, run_size=%zu, ceil=%zu)", - floor, run_size, ceil); - - assert_zu_le(floor_prev, floor, "Floor should be monotonic " - "(floor_prev=%zu, floor=%zu, run_size=%zu, ceil=%zu)", - floor_prev, floor, run_size, ceil); - assert_zu_le(ceil_prev, ceil, "Ceiling should be monotonic " - "(floor=%zu, run_size=%zu, ceil_prev=%zu, ceil=%zu)", - floor, run_size, ceil_prev, ceil); - - floor_prev = floor; - ceil_prev = ceil; - } -} -TEST_END - -int -main(void) -{ - - return (test( - test_small_run_size, - test_large_run_size, - test_monotonic)); -} diff --git a/test/unit/stats.c b/test/unit/stats.c index a9a3981f..b0e318a5 100644 --- a/test/unit/stats.c +++ b/test/unit/stats.c @@ -42,7 +42,7 @@ TEST_BEGIN(test_stats_huge) size_t sz; int expected = config_stats ? 0 : ENOENT; - p = mallocx(large_maxclass+1, 0); + p = mallocx(SMALL_MAXCLASS+1, 0); assert_ptr_not_null(p, "Unexpected mallocx() failure"); assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, @@ -75,7 +75,7 @@ TEST_END TEST_BEGIN(test_stats_arenas_summary) { unsigned arena; - void *little, *large, *huge; + void *little, *huge; uint64_t epoch; size_t sz; int expected = config_stats ? 0 : ENOENT; @@ -88,13 +88,10 @@ TEST_BEGIN(test_stats_arenas_summary) little = mallocx(SMALL_MAXCLASS, 0); assert_ptr_not_null(little, "Unexpected mallocx() failure"); - large = mallocx(large_maxclass, 0); - assert_ptr_not_null(large, "Unexpected mallocx() failure"); huge = mallocx(chunksize, 0); assert_ptr_not_null(huge, "Unexpected mallocx() failure"); dallocx(little, 0); - dallocx(large, 0); dallocx(huge, 0); assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, @@ -188,50 +185,6 @@ TEST_BEGIN(test_stats_arenas_small) } TEST_END -TEST_BEGIN(test_stats_arenas_large) -{ - unsigned arena; - void *p; - size_t sz, allocated; - uint64_t epoch, nmalloc, ndalloc, nrequests; - int expected = config_stats ? 0 : ENOENT; - - arena = 0; - assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)), - 0, "Unexpected mallctl() failure"); - - p = mallocx(large_maxclass, 0); - assert_ptr_not_null(p, "Unexpected mallocx() failure"); - - assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, - "Unexpected mallctl() failure"); - - sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.large.allocated", &allocated, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.large.nmalloc", &nmalloc, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.large.ndalloc", &ndalloc, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.large.nrequests", &nrequests, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - - if (config_stats) { - assert_zu_gt(allocated, 0, - "allocated should be greater than zero"); - assert_u64_gt(nmalloc, 0, - "nmalloc should be greater than zero"); - assert_u64_ge(nmalloc, ndalloc, - "nmalloc should be at least as large as ndalloc"); - assert_u64_gt(nrequests, 0, - "nrequests should be greater than zero"); - } - - dallocx(p, 0); -} -TEST_END - TEST_BEGIN(test_stats_arenas_huge) { unsigned arena; @@ -346,63 +299,23 @@ TEST_BEGIN(test_stats_arenas_bins) } TEST_END -TEST_BEGIN(test_stats_arenas_lruns) -{ - unsigned arena; - void *p; - uint64_t epoch, nmalloc, ndalloc, nrequests; - size_t curruns, sz; - int expected = config_stats ? 0 : ENOENT; - - arena = 0; - assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)), - 0, "Unexpected mallctl() failure"); - - p = mallocx(LARGE_MINCLASS, 0); - assert_ptr_not_null(p, "Unexpected mallocx() failure"); - - assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, - "Unexpected mallctl() failure"); - - sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.lruns.0.nmalloc", &nmalloc, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.lruns.0.ndalloc", &ndalloc, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.lruns.0.nrequests", &nrequests, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.lruns.0.curruns", &curruns, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - - if (config_stats) { - assert_u64_gt(nmalloc, 0, - "nmalloc should be greater than zero"); - assert_u64_ge(nmalloc, ndalloc, - "nmalloc should be at least as large as ndalloc"); - assert_u64_gt(nrequests, 0, - "nrequests should be greater than zero"); - assert_u64_gt(curruns, 0, - "At least one run should be currently allocated"); - } - - dallocx(p, 0); -} -TEST_END - TEST_BEGIN(test_stats_arenas_hchunks) { unsigned arena; void *p; uint64_t epoch, nmalloc, ndalloc; - size_t curhchunks, sz; + size_t curhchunks, sz, hsize; int expected = config_stats ? 0 : ENOENT; arena = 0; assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)), 0, "Unexpected mallctl() failure"); - p = mallocx(chunksize, 0); + sz = sizeof(size_t); + assert_d_eq(mallctl("arenas.hchunk.0.size", &hsize, &sz, NULL, 0), 0, + "Unexpected mallctl() failure"); + + p = mallocx(hsize, 0); assert_ptr_not_null(p, "Unexpected mallocx() failure"); assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, @@ -439,9 +352,7 @@ main(void) test_stats_huge, test_stats_arenas_summary, test_stats_arenas_small, - test_stats_arenas_large, test_stats_arenas_huge, test_stats_arenas_bins, - test_stats_arenas_lruns, test_stats_arenas_hchunks)); } diff --git a/test/unit/zero.c b/test/unit/zero.c index 123f0e03..2da288ac 100644 --- a/test/unit/zero.c +++ b/test/unit/zero.c @@ -53,19 +53,11 @@ TEST_BEGIN(test_zero_small) } TEST_END -TEST_BEGIN(test_zero_large) -{ - - test_skip_if(!config_fill); - test_zero(SMALL_MAXCLASS+1, large_maxclass); -} -TEST_END - TEST_BEGIN(test_zero_huge) { test_skip_if(!config_fill); - test_zero(large_maxclass+1, chunksize*2); + test_zero(SMALL_MAXCLASS+1, chunksize*2); } TEST_END @@ -75,6 +67,5 @@ main(void) return (test( test_zero_small, - test_zero_large, test_zero_huge)); } -- GitLab From d28e5a6696fd59a45c156b5c4dc183bb9ed21596 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 28 May 2016 17:29:03 -0700 Subject: [PATCH 042/544] Improve interval-based profile dump triggering. When an allocation is large enough to trigger multiple dumps, use modular math rather than subtraction to reset the interval counter. Prior to this change, it was possible for a single allocation to cause many subsequent allocations to all trigger profile dumps. When updating usable size for a sampled object, try to cancel out the difference between LARGE_MINCLASS and usable size from the interval counter. --- include/jemalloc/internal/arena.h | 2 +- src/arena.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index bf16e8e9..b0c4b5f3 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -984,7 +984,7 @@ arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes) arena->prof_accumbytes += accumbytes; if (arena->prof_accumbytes >= prof_interval) { - arena->prof_accumbytes -= prof_interval; + arena->prof_accumbytes %= prof_interval; return (true); } return (false); diff --git a/src/arena.c b/src/arena.c index d9882a45..0b98ec5d 100644 --- a/src/arena.c +++ b/src/arena.c @@ -2258,6 +2258,7 @@ void arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize) { + arena_t *arena = extent_arena_get(extent); cassert(config_prof); assert(ptr != NULL); @@ -2266,6 +2267,19 @@ arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, extent_usize_set(extent, usize); + /* + * Cancel out as much of the excessive prof_accumbytes increase as + * possible without underflowing. Interval-triggered dumps occur + * slightly more often than intended as a result of incomplete + * canceling. + */ + malloc_mutex_lock(tsdn, &arena->lock); + if (arena->prof_accumbytes >= LARGE_MINCLASS - usize) + arena->prof_accumbytes -= LARGE_MINCLASS - usize; + else + arena->prof_accumbytes = 0; + malloc_mutex_unlock(tsdn, &arena->lock); + assert(isalloc(tsdn, extent, ptr) == usize); } -- GitLab From 498856f44a30b31fe713a18eb2fc7c6ecf3a9f63 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 29 May 2016 18:34:50 -0700 Subject: [PATCH 043/544] Move slabs out of chunks. --- doc/jemalloc.xml.in | 102 +- include/jemalloc/internal/arena.h | 795 +------- include/jemalloc/internal/bitmap.h | 2 +- include/jemalloc/internal/extent.h | 86 +- include/jemalloc/internal/private_symbols.txt | 45 +- include/jemalloc/internal/prof.h | 44 +- include/jemalloc/internal/size_classes.sh | 22 +- include/jemalloc/internal/stats.h | 14 +- include/jemalloc/internal/tcache.h | 2 +- src/arena.c | 1619 ++++------------- src/base.c | 3 +- src/chunk.c | 11 +- src/chunk_dss.c | 2 +- src/ctl.c | 37 +- src/huge.c | 4 +- src/jemalloc.c | 46 +- src/stats.c | 45 +- src/tcache.c | 8 +- test/unit/extent_quantize.c | 10 +- test/unit/mallctl.c | 3 +- test/unit/stats.c | 18 +- 21 files changed, 591 insertions(+), 2327 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index efb4bfe4..923097d4 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -509,26 +509,20 @@ for (i = 0; i < nbins; i++) { In addition to multiple arenas, unless is specified during configuration, this - allocator supports thread-specific caching for small and large objects, in - order to make it possible to completely avoid synchronization for most - allocation requests. Such caching allows very fast allocation in the - common case, but it increases memory usage and fragmentation, since a - bounded number of objects can remain allocated in each thread cache. - - Memory is conceptually broken into equal-sized chunks, where the chunk - size is a power of two that is greater than the page size. Chunks are - always aligned to multiples of the chunk size. This alignment makes it - possible to find metadata for user objects very quickly. User objects are - broken into three categories according to size: small, large, and huge. - Multiple small and large objects can reside within a single chunk, whereas - huge objects each have one or more chunks backing them. Each chunk that - contains small and/or large objects tracks its contents as runs of - contiguous pages (unused, backing a set of small objects, or backing one - large object). The combination of chunk alignment and chunk page maps makes - it possible to determine all metadata regarding small and large allocations - in constant time. - - Small objects are managed in groups by page runs. Each run maintains + allocator supports thread-specific caching, in order to make it possible to + completely avoid synchronization for most allocation requests. Such caching + allows very fast allocation in the common case, but it increases memory + usage and fragmentation, since a bounded number of objects can remain + allocated in each thread cache. + + Memory is conceptually broken into extents. Extents are always + aligned to multiples of the page size. This alignment makes it possible to + find metadata for user objects quickly. User objects are broken into two + categories according to size: small and large. Contiguous small objects + comprise a slab, which resides within a single extent, whereas large objects + each have their own extents backing them. + + Small objects are managed in groups by slabs. Each slab maintains a bitmap to track which regions are in use. Allocation requests that are no more than half the quantum (8 or 16, depending on architecture) are rounded up to the nearest power of two that is at least opt.lg_chunk option), and - huge size classes extend from the chunk size up to the largest size class - that does not exceed PTRDIFF_MAX. + are smaller than four times the page size, and large size classes extend + from four times the page size up to the largest size class that does not + exceed PTRDIFF_MAX. Allocations are packed tightly together, which can be an issue for multi-threaded applications. If you need to assure that allocations do not @@ -560,18 +552,16 @@ for (i = 0; i < nbins; i++) { trivially succeeds in place as long as the pre-size and post-size both round up to the same size class. No other API guarantees are made regarding in-place resizing, but the current implementation also tries to resize large - and huge allocations in place, as long as the pre-size and post-size are - both large or both huge. In such cases shrinkage always succeeds for large - size classes, but for huge size classes the chunk allocator must support - splitting (see arena.<i>.chunk_hooks). - Growth only succeeds if the trailing memory is currently available, and - additionally for huge size classes the chunk allocator must support - merging. + Growth only succeeds if the trailing memory is currently available, and the + extent allocator supports merging. - Assuming 2 MiB chunks, 4 KiB pages, and a 16-byte quantum on a - 64-bit system, the size classes in each category are as shown in . + Assuming 4 KiB pages and a 16-byte quantum on a 64-bit system, the + size classes in each category are as shown in . Size classes @@ -625,7 +615,7 @@ for (i = 0; i < nbins; i++) { [10 KiB, 12 KiB, 14 KiB] - Large + Large 2 KiB [16 KiB] @@ -655,12 +645,7 @@ for (i = 0; i < nbins; i++) { 256 KiB - [1280 KiB, 1536 KiB, 1792 KiB] - - - Huge - 256 KiB - [2 MiB] + [1280 KiB, 1536 KiB, 1792 KiB, 2 MiB] 512 KiB @@ -1875,16 +1860,16 @@ typedef struct { (uint32_t) r- - Number of regions per page run. + Number of regions per slab. - + - arenas.bin.<i>.run_size + arenas.bin.<i>.slab_size (size_t) r- - Number of bytes per page run. + Number of bytes per slab. @@ -2185,7 +2170,7 @@ typedef struct { (size_t) r- - Number of pages in active runs. + Number of pages in active extents. @@ -2194,8 +2179,9 @@ typedef struct { (size_t) r- - Number of pages within unused runs that are potentially - dirty, and for which madvise... + Number of pages within unused extents that are + potentially dirty, and for which + madvise... MADV_DONTNEED or similar has not been called. @@ -2483,35 +2469,35 @@ typedef struct { Cumulative number of tcache flushes. - + - stats.arenas.<i>.bins.<j>.nruns + stats.arenas.<i>.bins.<j>.nslabs (uint64_t) r- [] - Cumulative number of runs created. + Cumulative number of slabs created. - + - stats.arenas.<i>.bins.<j>.nreruns + stats.arenas.<i>.bins.<j>.nreslabs (uint64_t) r- [] - Cumulative number of times the current run from which + Cumulative number of times the current slab from which to allocate changed. - + - stats.arenas.<i>.bins.<j>.curruns + stats.arenas.<i>.bins.<j>.curslabs (size_t) r- [] - Current number of runs. + Current number of slabs. diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index b0c4b5f3..d66548f2 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -3,9 +3,9 @@ #define LARGE_MINCLASS (ZU(1) << LG_LARGE_MINCLASS) -/* Maximum number of regions in one run. */ -#define LG_RUN_MAXREGS (LG_PAGE - LG_TINY_MIN) -#define RUN_MAXREGS (1U << LG_RUN_MAXREGS) +/* Maximum number of regions in one slab. */ +#define LG_SLAB_MAXREGS (LG_PAGE - LG_TINY_MIN) +#define SLAB_MAXREGS (1U << LG_SLAB_MAXREGS) /* * The minimum ratio of active:dirty pages per arena is computed as: @@ -29,12 +29,7 @@ typedef enum { /* Number of event ticks between time checks. */ #define DECAY_NTICKS_PER_UPDATE 1000 -typedef struct arena_runs_dirty_link_s arena_runs_dirty_link_t; -typedef struct arena_avail_links_s arena_avail_links_t; -typedef struct arena_run_s arena_run_t; -typedef struct arena_chunk_map_bits_s arena_chunk_map_bits_t; -typedef struct arena_chunk_map_misc_s arena_chunk_map_misc_t; -typedef struct arena_chunk_s arena_chunk_t; +typedef struct arena_slab_data_s arena_slab_data_t; typedef struct arena_bin_info_s arena_bin_info_t; typedef struct arena_bin_s arena_bin_t; typedef struct arena_s arena_t; @@ -45,152 +40,25 @@ typedef struct arena_tdata_s arena_tdata_t; #ifdef JEMALLOC_H_STRUCTS #ifdef JEMALLOC_ARENA_STRUCTS_A -struct arena_run_s { - /* Index of bin this run is associated with. */ +struct arena_slab_data_s { + /* Index of bin this slab is associated with. */ szind_t binind; - /* Number of free regions in run. */ + /* Number of free regions in slab. */ unsigned nfree; /* Per region allocated/deallocated bitmap. */ bitmap_t bitmap[BITMAP_GROUPS_MAX]; }; - -/* Each element of the chunk map corresponds to one page within the chunk. */ -struct arena_chunk_map_bits_s { - /* - * Run address (or size) and various flags are stored together. The bit - * layout looks like (assuming 32-bit system): - * - * ???????? ???????? ???nnnnn nnndumla - * - * ? : Unallocated: Run address for first/last pages, unset for internal - * pages. - * Small: Run page offset. - * Large: Run page count for first page, unset for trailing pages. - * n : binind for small size class, BININD_INVALID for large size class. - * d : dirty? - * u : unzeroed? - * m : decommitted? - * l : large? - * a : allocated? - * - * Following are example bit patterns for the three types of runs. - * - * p : run page offset - * s : run size - * n : binind for size class; large objects set these to BININD_INVALID - * x : don't care - * - : 0 - * + : 1 - * [DUMLA] : bit set - * [dumla] : bit unset - * - * Unallocated (clean): - * ssssssss ssssssss sss+++++ +++dum-a - * xxxxxxxx xxxxxxxx xxxxxxxx xxx-Uxxx - * ssssssss ssssssss sss+++++ +++dUm-a - * - * Unallocated (dirty): - * ssssssss ssssssss sss+++++ +++D-m-a - * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - * ssssssss ssssssss sss+++++ +++D-m-a - * - * Small: - * pppppppp pppppppp pppnnnnn nnnd---A - * pppppppp pppppppp pppnnnnn nnn----A - * pppppppp pppppppp pppnnnnn nnnd---A - * - * Large: - * ssssssss ssssssss sss+++++ +++D--LA - * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - * -------- -------- ---+++++ +++D--LA - * - * Large (sampled, size <= LARGE_MINCLASS): - * ssssssss ssssssss sssnnnnn nnnD--LA - * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - * -------- -------- ---+++++ +++D--LA - * - * Large (not sampled, size == LARGE_MINCLASS): - * ssssssss ssssssss sss+++++ +++D--LA - * xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx - * -------- -------- ---+++++ +++D--LA - */ - size_t bits; -#define CHUNK_MAP_ALLOCATED ((size_t)0x01U) -#define CHUNK_MAP_LARGE ((size_t)0x02U) -#define CHUNK_MAP_STATE_MASK ((size_t)0x3U) - -#define CHUNK_MAP_DECOMMITTED ((size_t)0x04U) -#define CHUNK_MAP_UNZEROED ((size_t)0x08U) -#define CHUNK_MAP_DIRTY ((size_t)0x10U) -#define CHUNK_MAP_FLAGS_MASK ((size_t)0x1cU) - -#define CHUNK_MAP_BININD_SHIFT 5 -#define BININD_INVALID ((size_t)0xffU) -#define CHUNK_MAP_BININD_MASK (BININD_INVALID << CHUNK_MAP_BININD_SHIFT) -#define CHUNK_MAP_BININD_INVALID CHUNK_MAP_BININD_MASK - -#define CHUNK_MAP_RUNIND_SHIFT (CHUNK_MAP_BININD_SHIFT + 8) -#define CHUNK_MAP_SIZE_SHIFT (CHUNK_MAP_RUNIND_SHIFT - LG_PAGE) -#define CHUNK_MAP_SIZE_MASK \ - (~(CHUNK_MAP_BININD_MASK | CHUNK_MAP_FLAGS_MASK | CHUNK_MAP_STATE_MASK)) -}; - -struct arena_runs_dirty_link_s { - qr(arena_runs_dirty_link_t) rd_link; -}; - -/* - * Each arena_chunk_map_misc_t corresponds to one page within the chunk, just - * like arena_chunk_map_bits_t. Two separate arrays are stored within each - * chunk header in order to improve cache locality. - */ -struct arena_chunk_map_misc_s { - /* - * Linkage for run heaps. There are two disjoint uses: - * - * 1) arena_t's runs_avail heaps. - * 2) arena_run_t conceptually uses this linkage for in-use non-full - * runs, rather than directly embedding linkage. - */ - phn(arena_chunk_map_misc_t) ph_link; - - union { - /* Linkage for list of dirty runs. */ - arena_runs_dirty_link_t rd; - - /* Profile counters, used for large object runs. */ - union { - void *prof_tctx_pun; - prof_tctx_t *prof_tctx; - }; - - /* Small region run metadata. */ - arena_run_t run; - }; -}; -typedef ph(arena_chunk_map_misc_t) arena_run_heap_t; #endif /* JEMALLOC_ARENA_STRUCTS_A */ #ifdef JEMALLOC_ARENA_STRUCTS_B -/* Arena chunk header. */ -struct arena_chunk_s { - /* - * Map of pages within chunk that keeps track of free/large/small. The - * first map_bias entries are omitted, since the chunk header does not - * need to be tracked in the map. This omission saves a header page - * for common chunk sizes (e.g. 4 MiB). - */ - arena_chunk_map_bits_t map_bits[1]; /* Dynamically sized. */ -}; - /* * Read-only information associated with each element of arena_t's bins array * is stored separately, partly to reduce memory usage (only one copy, rather * than one per arena), but mainly to avoid false cacheline sharing. * - * Each run has the following layout: + * Each slab has the following layout: * * /--------------------\ * | region 0 | @@ -205,45 +73,42 @@ struct arena_chunk_s { * \--------------------/ */ struct arena_bin_info_s { - /* Size of regions in a run for this bin's size class. */ + /* Size of regions in a slab for this bin's size class. */ size_t reg_size; - /* Total size of a run for this bin's size class. */ - size_t run_size; + /* Total size of a slab for this bin's size class. */ + size_t slab_size; - /* Total number of regions in a run for this bin's size class. */ + /* Total number of regions in a slab for this bin's size class. */ uint32_t nregs; /* - * Metadata used to manipulate bitmaps for runs associated with this + * Metadata used to manipulate bitmaps for slabs associated with this * bin. */ bitmap_info_t bitmap_info; }; struct arena_bin_s { - /* - * All operations on runcur, runs, and stats require that lock be - * locked. Run allocation/deallocation are protected by the arena lock, - * which may be acquired while holding one or more bin locks, but not - * vise versa. - */ + /* All operations on arena_bin_t fields require lock ownership. */ malloc_mutex_t lock; /* - * Current run being used to service allocations of this bin's size - * class. + * Current slab being used to service allocations of this bin's size + * class. slabcur is independent of slabs_{nonfull,full}; whenever + * slabcur is reassigned, the previous slab must be deallocated or + * inserted into slabs_{nonfull,full}. */ - arena_run_t *runcur; + extent_t *slabcur; /* - * Heap of non-full runs. This heap is used when looking for an - * existing run when runcur is no longer usable. We choose the - * non-full run that is lowest in memory; this policy tends to keep - * objects packed well, and it can also help reduce the number of - * almost-empty chunks. + * Heap of non-full slabs. This heap is used to assure that new + * allocations come from the non-full slab that is lowest in memory. */ - arena_run_heap_t runs; + extent_heap_t slabs_nonfull; + + /* Ring sentinel used to track full slabs. */ + extent_t slabs_full; /* Bin statistics. */ malloc_bin_stats_t stats; @@ -272,7 +137,7 @@ struct arena_s { * perspective: * 1) Thread assignment (modifies nthreads) is synchronized via atomics. * 2) Bin-related operations are protected by bin locks. - * 3) Chunk- and run-related operations are protected by this mutex. + * 3) Chunk-related operations are protected by this mutex. */ malloc_mutex_t lock; @@ -294,32 +159,17 @@ struct arena_s { dss_prec_t dss_prec; - /* Extant arena chunks. */ - ql_head(extent_t) achunks; - - /* - * In order to avoid rapid chunk allocation/deallocation when an arena - * oscillates right on the cusp of needing a new chunk, cache the most - * recently freed chunk. The spare is left in the arena's chunk trees - * until it is deleted. - * - * There is one spare chunk per arena, rather than one spare total, in - * order to avoid interactions between multiple threads that could make - * a single spare inadequate. - */ - extent_t *spare; - /* Minimum ratio (log base 2) of nactive:ndirty. */ ssize_t lg_dirty_mult; /* True if a thread is currently executing arena_purge_to_limit(). */ bool purging; - /* Number of pages in active runs and huge regions. */ + /* Number of pages in active extents. */ size_t nactive; /* - * Current count of pages within unused runs that are potentially + * Current count of pages within unused extents that are potentially * dirty, and for which madvise(... MADV_DONTNEED) has not been called. * By tracking this, we can institute a limit on how much dirty unused * memory is mapped for each arena. @@ -327,35 +177,10 @@ struct arena_s { size_t ndirty; /* - * Unused dirty memory this arena manages. Dirty memory is conceptually - * tracked as an arbitrarily interleaved LRU of dirty runs and cached - * chunks, but the list linkage is actually semi-duplicated in order to - * avoid extra arena_chunk_map_misc_t space overhead. - * - * LRU-----------------------------------------------------------MRU - * - * /-- arena ---\ - * | | - * | | - * |------------| /-- chunk --\ - * ...->|chunks_cache|<--------------------------->| /------\ |<--... - * |------------| | |extent| | - * | | | | | | - * | | /- run -\ /- run -\ | | | | - * | | | | | | | | | | - * | | | | | | | | | | - * |------------| |-------| |-------| | |------| | - * ...->|runs_dirty |<-->|rd |<-->|rd |<---->|rd |<----... - * |------------| |-------| |-------| | |------| | - * | | | | | | | | | | - * | | | | | | | \------/ | - * | | \-------/ \-------/ | | - * | | | | - * | | | | - * \------------/ \-----------/ + * Ring sentinel used to track unused dirty memory. Dirty memory is + * managed as an LRU of cached extents. */ - arena_runs_dirty_link_t runs_dirty; - extent_t chunks_cache; + extent_t extents_dirty; /* * Approximate time in seconds from the creation of a set of unused @@ -424,16 +249,8 @@ struct arena_s { /* User-configurable chunk hook functions. */ chunk_hooks_t chunk_hooks; - /* bins is used to store trees of free regions. */ + /* bins is used to store heaps of free regions. */ arena_bin_t bins[NBINS]; - - /* - * Size-segregated address-ordered heaps of this arena's available runs, - * used for first-best-fit run allocation. Runs are quantized, i.e. - * they reside in the last heap which corresponds to a size class less - * than or equal to the run size. - */ - arena_run_heap_t runs_avail[NPSIZES]; }; /* Used in conjunction with tsd for fast arena-related context lookup. */ @@ -461,15 +278,6 @@ extern ssize_t opt_decay_time; extern const arena_bin_info_t arena_bin_info[NBINS]; -extern size_t map_bias; /* Number of arena chunk header pages. */ -extern size_t map_misc_offset; -extern size_t arena_maxrun; /* Max run size for arenas. */ - -#ifdef JEMALLOC_JET -typedef size_t (run_quantize_t)(size_t); -extern run_quantize_t *run_quantize_floor; -extern run_quantize_t *run_quantize_ceil; -#endif extent_t *arena_chunk_cache_alloc(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, bool *zero); @@ -514,10 +322,9 @@ void arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, void arena_dalloc_promoted(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, bool slow_path); void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, - arena_chunk_t *chunk, extent_t *extent, void *ptr, - arena_chunk_map_bits_t *bitselm); -void arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - extent_t *extent, void *ptr, size_t pageind); + extent_t *extent, void *ptr); +void arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + void *ptr); bool arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t extra, bool zero); void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, @@ -552,70 +359,19 @@ void arena_postfork_child(tsdn_t *tsdn, arena_t *arena); #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE -arena_chunk_map_bits_t *arena_bitselm_get_mutable(arena_chunk_t *chunk, - size_t pageind); -const arena_chunk_map_bits_t *arena_bitselm_get_const( - const arena_chunk_t *chunk, size_t pageind); -arena_chunk_map_misc_t *arena_miscelm_get_mutable(arena_chunk_t *chunk, - size_t pageind); -const arena_chunk_map_misc_t *arena_miscelm_get_const( - const arena_chunk_t *chunk, size_t pageind); -size_t arena_miscelm_to_pageind(const extent_t *extent, - const arena_chunk_map_misc_t *miscelm); -void *arena_miscelm_to_rpages(const extent_t *extent, - const arena_chunk_map_misc_t *miscelm); -arena_chunk_map_misc_t *arena_rd_to_miscelm(const extent_t *extent, - arena_runs_dirty_link_t *rd); -arena_chunk_map_misc_t *arena_run_to_miscelm(const extent_t *extent, - arena_run_t *run); -size_t *arena_mapbitsp_get_mutable(arena_chunk_t *chunk, size_t pageind); -const size_t *arena_mapbitsp_get_const(const arena_chunk_t *chunk, - size_t pageind); -size_t arena_mapbitsp_read(const size_t *mapbitsp); -size_t arena_mapbits_get(const arena_chunk_t *chunk, size_t pageind); -size_t arena_mapbits_size_decode(size_t mapbits); -size_t arena_mapbits_unallocated_size_get(const arena_chunk_t *chunk, - size_t pageind); -size_t arena_mapbits_large_size_get(const arena_chunk_t *chunk, - size_t pageind); -size_t arena_mapbits_small_runind_get(const arena_chunk_t *chunk, - size_t pageind); -szind_t arena_mapbits_binind_get(const arena_chunk_t *chunk, size_t pageind); -size_t arena_mapbits_dirty_get(const arena_chunk_t *chunk, size_t pageind); -size_t arena_mapbits_unzeroed_get(const arena_chunk_t *chunk, size_t pageind); -size_t arena_mapbits_decommitted_get(const arena_chunk_t *chunk, - size_t pageind); -size_t arena_mapbits_large_get(const arena_chunk_t *chunk, size_t pageind); -size_t arena_mapbits_allocated_get(const arena_chunk_t *chunk, size_t pageind); -void arena_mapbitsp_write(size_t *mapbitsp, size_t mapbits); -size_t arena_mapbits_size_encode(size_t size); -void arena_mapbits_unallocated_set(arena_chunk_t *chunk, size_t pageind, - size_t size, size_t flags); -void arena_mapbits_unallocated_size_set(arena_chunk_t *chunk, size_t pageind, - size_t size); -void arena_mapbits_internal_set(arena_chunk_t *chunk, size_t pageind, - size_t flags); -void arena_mapbits_large_set(arena_chunk_t *chunk, size_t pageind, - size_t size, size_t flags); -void arena_mapbits_large_binind_set(arena_chunk_t *chunk, size_t pageind, - szind_t binind); -void arena_mapbits_small_set(arena_chunk_t *chunk, size_t pageind, - size_t runind, szind_t binind, size_t flags); void arena_metadata_allocated_add(arena_t *arena, size_t size); void arena_metadata_allocated_sub(arena_t *arena, size_t size); size_t arena_metadata_allocated_get(arena_t *arena); bool arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes); bool arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes); bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes); -szind_t arena_ptr_small_binind_get(tsdn_t *tsdn, const void *ptr, - size_t mapbits); szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin); prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr); void arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, prof_tctx_t *tctx); void arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize, const void *old_ptr, prof_tctx_t *old_tctx); + prof_tctx_t *tctx); void arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks); void arena_decay_tick(tsdn_t *tsdn, arena_t *arena); void *arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, @@ -630,330 +386,6 @@ void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) # ifdef JEMALLOC_ARENA_INLINE_A -JEMALLOC_ALWAYS_INLINE arena_chunk_map_bits_t * -arena_bitselm_get_mutable(arena_chunk_t *chunk, size_t pageind) -{ - - assert(pageind >= map_bias); - assert(pageind < chunk_npages); - - return (&chunk->map_bits[pageind-map_bias]); -} - -JEMALLOC_ALWAYS_INLINE const arena_chunk_map_bits_t * -arena_bitselm_get_const(const arena_chunk_t *chunk, size_t pageind) -{ - - return (arena_bitselm_get_mutable((arena_chunk_t *)chunk, pageind)); -} - -JEMALLOC_ALWAYS_INLINE arena_chunk_map_misc_t * -arena_miscelm_get_mutable(arena_chunk_t *chunk, size_t pageind) -{ - - assert(pageind >= map_bias); - assert(pageind < chunk_npages); - - return ((arena_chunk_map_misc_t *)((uintptr_t)chunk + - (uintptr_t)map_misc_offset) + pageind-map_bias); -} - -JEMALLOC_ALWAYS_INLINE const arena_chunk_map_misc_t * -arena_miscelm_get_const(const arena_chunk_t *chunk, size_t pageind) -{ - - return (arena_miscelm_get_mutable((arena_chunk_t *)chunk, pageind)); -} - -JEMALLOC_ALWAYS_INLINE size_t -arena_miscelm_to_pageind(const extent_t *extent, - const arena_chunk_map_misc_t *miscelm) -{ - arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); - size_t pageind = ((uintptr_t)miscelm - ((uintptr_t)chunk + - map_misc_offset)) / sizeof(arena_chunk_map_misc_t) + map_bias; - - assert(pageind >= map_bias); - assert(pageind < chunk_npages); - - return (pageind); -} - -JEMALLOC_ALWAYS_INLINE void * -arena_miscelm_to_rpages(const extent_t *extent, - const arena_chunk_map_misc_t *miscelm) -{ - arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); - size_t pageind = arena_miscelm_to_pageind(extent, miscelm); - - return ((void *)((uintptr_t)chunk + (pageind << LG_PAGE))); -} - -JEMALLOC_ALWAYS_INLINE arena_chunk_map_misc_t * -arena_rd_to_miscelm(const extent_t *extent, arena_runs_dirty_link_t *rd) -{ - arena_chunk_map_misc_t *miscelm = (arena_chunk_map_misc_t - *)((uintptr_t)rd - offsetof(arena_chunk_map_misc_t, rd)); - - assert(arena_miscelm_to_pageind(extent, miscelm) >= map_bias); - assert(arena_miscelm_to_pageind(extent, miscelm) < chunk_npages); - - return (miscelm); -} - -JEMALLOC_ALWAYS_INLINE arena_chunk_map_misc_t * -arena_run_to_miscelm(const extent_t *extent, arena_run_t *run) -{ - arena_chunk_map_misc_t *miscelm = (arena_chunk_map_misc_t - *)((uintptr_t)run - offsetof(arena_chunk_map_misc_t, run)); - - assert(arena_miscelm_to_pageind(extent, miscelm) >= map_bias); - assert(arena_miscelm_to_pageind(extent, miscelm) < chunk_npages); - - return (miscelm); -} - -JEMALLOC_ALWAYS_INLINE size_t * -arena_mapbitsp_get_mutable(arena_chunk_t *chunk, size_t pageind) -{ - - return (&arena_bitselm_get_mutable(chunk, pageind)->bits); -} - -JEMALLOC_ALWAYS_INLINE const size_t * -arena_mapbitsp_get_const(const arena_chunk_t *chunk, size_t pageind) -{ - - return (arena_mapbitsp_get_mutable((arena_chunk_t *)chunk, pageind)); -} - -JEMALLOC_ALWAYS_INLINE size_t -arena_mapbitsp_read(const size_t *mapbitsp) -{ - - return (*mapbitsp); -} - -JEMALLOC_ALWAYS_INLINE size_t -arena_mapbits_get(const arena_chunk_t *chunk, size_t pageind) -{ - - return (arena_mapbitsp_read(arena_mapbitsp_get_const(chunk, pageind))); -} - -JEMALLOC_ALWAYS_INLINE size_t -arena_mapbits_size_decode(size_t mapbits) -{ - size_t size; - -#if CHUNK_MAP_SIZE_SHIFT > 0 - size = (mapbits & CHUNK_MAP_SIZE_MASK) >> CHUNK_MAP_SIZE_SHIFT; -#elif CHUNK_MAP_SIZE_SHIFT == 0 - size = mapbits & CHUNK_MAP_SIZE_MASK; -#else - size = (mapbits & CHUNK_MAP_SIZE_MASK) << -CHUNK_MAP_SIZE_SHIFT; -#endif - - return (size); -} - -JEMALLOC_ALWAYS_INLINE size_t -arena_mapbits_unallocated_size_get(const arena_chunk_t *chunk, size_t pageind) -{ - size_t mapbits; - - mapbits = arena_mapbits_get(chunk, pageind); - assert((mapbits & (CHUNK_MAP_LARGE|CHUNK_MAP_ALLOCATED)) == 0); - return (arena_mapbits_size_decode(mapbits)); -} - -JEMALLOC_ALWAYS_INLINE size_t -arena_mapbits_large_size_get(const arena_chunk_t *chunk, size_t pageind) -{ - size_t mapbits; - - mapbits = arena_mapbits_get(chunk, pageind); - assert((mapbits & (CHUNK_MAP_LARGE|CHUNK_MAP_ALLOCATED)) == - (CHUNK_MAP_LARGE|CHUNK_MAP_ALLOCATED)); - return (arena_mapbits_size_decode(mapbits)); -} - -JEMALLOC_ALWAYS_INLINE size_t -arena_mapbits_small_runind_get(const arena_chunk_t *chunk, size_t pageind) -{ - size_t mapbits; - - mapbits = arena_mapbits_get(chunk, pageind); - assert((mapbits & (CHUNK_MAP_LARGE|CHUNK_MAP_ALLOCATED)) == - CHUNK_MAP_ALLOCATED); - return (mapbits >> CHUNK_MAP_RUNIND_SHIFT); -} - -JEMALLOC_ALWAYS_INLINE szind_t -arena_mapbits_binind_get(const arena_chunk_t *chunk, size_t pageind) -{ - size_t mapbits; - szind_t binind; - - mapbits = arena_mapbits_get(chunk, pageind); - binind = (mapbits & CHUNK_MAP_BININD_MASK) >> CHUNK_MAP_BININD_SHIFT; - assert(binind < NBINS || binind == BININD_INVALID); - return (binind); -} - -JEMALLOC_ALWAYS_INLINE size_t -arena_mapbits_dirty_get(const arena_chunk_t *chunk, size_t pageind) -{ - size_t mapbits; - - mapbits = arena_mapbits_get(chunk, pageind); - assert((mapbits & CHUNK_MAP_DECOMMITTED) == 0 || (mapbits & - (CHUNK_MAP_DIRTY|CHUNK_MAP_UNZEROED)) == 0); - return (mapbits & CHUNK_MAP_DIRTY); -} - -JEMALLOC_ALWAYS_INLINE size_t -arena_mapbits_unzeroed_get(const arena_chunk_t *chunk, size_t pageind) -{ - size_t mapbits; - - mapbits = arena_mapbits_get(chunk, pageind); - assert((mapbits & CHUNK_MAP_DECOMMITTED) == 0 || (mapbits & - (CHUNK_MAP_DIRTY|CHUNK_MAP_UNZEROED)) == 0); - return (mapbits & CHUNK_MAP_UNZEROED); -} - -JEMALLOC_ALWAYS_INLINE size_t -arena_mapbits_decommitted_get(const arena_chunk_t *chunk, size_t pageind) -{ - size_t mapbits; - - mapbits = arena_mapbits_get(chunk, pageind); - assert((mapbits & CHUNK_MAP_DECOMMITTED) == 0 || (mapbits & - (CHUNK_MAP_DIRTY|CHUNK_MAP_UNZEROED)) == 0); - return (mapbits & CHUNK_MAP_DECOMMITTED); -} - -JEMALLOC_ALWAYS_INLINE size_t -arena_mapbits_large_get(const arena_chunk_t *chunk, size_t pageind) -{ - size_t mapbits; - - mapbits = arena_mapbits_get(chunk, pageind); - return (mapbits & CHUNK_MAP_LARGE); -} - -JEMALLOC_ALWAYS_INLINE size_t -arena_mapbits_allocated_get(const arena_chunk_t *chunk, size_t pageind) -{ - size_t mapbits; - - mapbits = arena_mapbits_get(chunk, pageind); - return (mapbits & CHUNK_MAP_ALLOCATED); -} - -JEMALLOC_ALWAYS_INLINE void -arena_mapbitsp_write(size_t *mapbitsp, size_t mapbits) -{ - - *mapbitsp = mapbits; -} - -JEMALLOC_ALWAYS_INLINE size_t -arena_mapbits_size_encode(size_t size) -{ - size_t mapbits; - -#if CHUNK_MAP_SIZE_SHIFT > 0 - mapbits = size << CHUNK_MAP_SIZE_SHIFT; -#elif CHUNK_MAP_SIZE_SHIFT == 0 - mapbits = size; -#else - mapbits = size >> -CHUNK_MAP_SIZE_SHIFT; -#endif - - assert((mapbits & ~CHUNK_MAP_SIZE_MASK) == 0); - return (mapbits); -} - -JEMALLOC_ALWAYS_INLINE void -arena_mapbits_unallocated_set(arena_chunk_t *chunk, size_t pageind, size_t size, - size_t flags) -{ - size_t *mapbitsp = arena_mapbitsp_get_mutable(chunk, pageind); - - assert((size & PAGE_MASK) == 0); - assert((flags & CHUNK_MAP_FLAGS_MASK) == flags); - assert((flags & CHUNK_MAP_DECOMMITTED) == 0 || (flags & - (CHUNK_MAP_DIRTY|CHUNK_MAP_UNZEROED)) == 0); - arena_mapbitsp_write(mapbitsp, arena_mapbits_size_encode(size) | - CHUNK_MAP_BININD_INVALID | flags); -} - -JEMALLOC_ALWAYS_INLINE void -arena_mapbits_unallocated_size_set(arena_chunk_t *chunk, size_t pageind, - size_t size) -{ - size_t *mapbitsp = arena_mapbitsp_get_mutable(chunk, pageind); - size_t mapbits = arena_mapbitsp_read(mapbitsp); - - assert((size & PAGE_MASK) == 0); - assert((mapbits & (CHUNK_MAP_LARGE|CHUNK_MAP_ALLOCATED)) == 0); - arena_mapbitsp_write(mapbitsp, arena_mapbits_size_encode(size) | - (mapbits & ~CHUNK_MAP_SIZE_MASK)); -} - -JEMALLOC_ALWAYS_INLINE void -arena_mapbits_internal_set(arena_chunk_t *chunk, size_t pageind, size_t flags) -{ - size_t *mapbitsp = arena_mapbitsp_get_mutable(chunk, pageind); - - assert((flags & CHUNK_MAP_UNZEROED) == flags); - arena_mapbitsp_write(mapbitsp, flags); -} - -JEMALLOC_ALWAYS_INLINE void -arena_mapbits_large_set(arena_chunk_t *chunk, size_t pageind, size_t size, - size_t flags) -{ - size_t *mapbitsp = arena_mapbitsp_get_mutable(chunk, pageind); - - assert((size & PAGE_MASK) == 0); - assert((flags & CHUNK_MAP_FLAGS_MASK) == flags); - assert((flags & CHUNK_MAP_DECOMMITTED) == 0 || (flags & - (CHUNK_MAP_DIRTY|CHUNK_MAP_UNZEROED)) == 0); - arena_mapbitsp_write(mapbitsp, arena_mapbits_size_encode(size) | - CHUNK_MAP_BININD_INVALID | flags | CHUNK_MAP_LARGE | - CHUNK_MAP_ALLOCATED); -} - -JEMALLOC_ALWAYS_INLINE void -arena_mapbits_large_binind_set(arena_chunk_t *chunk, size_t pageind, - szind_t binind) -{ - size_t *mapbitsp = arena_mapbitsp_get_mutable(chunk, pageind); - size_t mapbits = arena_mapbitsp_read(mapbitsp); - - assert(binind <= BININD_INVALID); - assert(arena_mapbits_large_size_get(chunk, pageind) == LARGE_MINCLASS + - large_pad); - arena_mapbitsp_write(mapbitsp, (mapbits & ~CHUNK_MAP_BININD_MASK) | - (binind << CHUNK_MAP_BININD_SHIFT)); -} - -JEMALLOC_ALWAYS_INLINE void -arena_mapbits_small_set(arena_chunk_t *chunk, size_t pageind, size_t runind, - szind_t binind, size_t flags) -{ - size_t *mapbitsp = arena_mapbitsp_get_mutable(chunk, pageind); - - assert(binind < BININD_INVALID); - assert(pageind - runind >= map_bias); - assert((flags & CHUNK_MAP_UNZEROED) == flags); - arena_mapbitsp_write(mapbitsp, (runind << CHUNK_MAP_RUNIND_SHIFT) | - (binind << CHUNK_MAP_BININD_SHIFT) | flags | CHUNK_MAP_ALLOCATED); -} - JEMALLOC_INLINE void arena_metadata_allocated_add(arena_t *arena, size_t size) { @@ -1022,54 +454,6 @@ arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) # endif /* JEMALLOC_ARENA_INLINE_A */ # ifdef JEMALLOC_ARENA_INLINE_B -JEMALLOC_ALWAYS_INLINE szind_t -arena_ptr_small_binind_get(tsdn_t *tsdn, const void *ptr, size_t mapbits) -{ - szind_t binind; - - binind = (mapbits & CHUNK_MAP_BININD_MASK) >> CHUNK_MAP_BININD_SHIFT; - - if (config_debug) { - const extent_t *extent; - arena_chunk_t *chunk; - arena_t *arena; - size_t pageind; - size_t actual_mapbits; - size_t rpages_ind; - const arena_run_t *run; - arena_bin_t *bin; - szind_t run_binind, actual_binind; - const arena_bin_info_t *bin_info; - const arena_chunk_map_misc_t *miscelm; - const void *rpages; - - assert(binind != BININD_INVALID); - assert(binind < NBINS); - extent = iealloc(tsdn, ptr); - chunk = (arena_chunk_t *)extent_base_get(extent); - arena = extent_arena_get(extent); - pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - actual_mapbits = arena_mapbits_get(chunk, pageind); - assert(mapbits == actual_mapbits); - assert(arena_mapbits_large_get(chunk, pageind) == 0); - assert(arena_mapbits_allocated_get(chunk, pageind) != 0); - rpages_ind = pageind - arena_mapbits_small_runind_get(chunk, - pageind); - miscelm = arena_miscelm_get_const(chunk, rpages_ind); - run = &miscelm->run; - run_binind = run->binind; - bin = &arena->bins[run_binind]; - actual_binind = (szind_t)(bin - arena->bins); - assert(run_binind == actual_binind); - bin_info = &arena_bin_info[actual_binind]; - rpages = arena_miscelm_to_rpages(extent, miscelm); - assert(((uintptr_t)ptr - (uintptr_t)rpages) % bin_info->reg_size - == 0); - } - - return (binind); -} - JEMALLOC_INLINE szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin) { @@ -1081,27 +465,13 @@ arena_bin_index(arena_t *arena, arena_bin_t *bin) JEMALLOC_INLINE prof_tctx_t * arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { - prof_tctx_t *ret; cassert(config_prof); assert(ptr != NULL); - if (likely(extent_slab_get(extent))) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); - size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - size_t mapbits = arena_mapbits_get(chunk, pageind); - assert((mapbits & CHUNK_MAP_ALLOCATED) != 0); - if (likely((mapbits & CHUNK_MAP_LARGE) == 0)) - ret = (prof_tctx_t *)(uintptr_t)1U; - else { - arena_chunk_map_misc_t *elm = - arena_miscelm_get_mutable(chunk, pageind); - ret = atomic_read_p(&elm->prof_tctx_pun); - } - } else - ret = huge_prof_tctx_get(tsdn, extent); - - return (ret); + if (unlikely(!extent_slab_get(extent))) + return (huge_prof_tctx_get(tsdn, extent)); + return ((prof_tctx_t *)(uintptr_t)1U); } JEMALLOC_INLINE void @@ -1112,61 +482,20 @@ arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, cassert(config_prof); assert(ptr != NULL); - if (likely(extent_slab_get(extent))) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); - size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - - assert(arena_mapbits_allocated_get(chunk, pageind) != 0); - - if (unlikely(usize > SMALL_MAXCLASS || (uintptr_t)tctx > - (uintptr_t)1U)) { - arena_chunk_map_misc_t *elm; - - assert(arena_mapbits_large_get(chunk, pageind) != 0); - - elm = arena_miscelm_get_mutable(chunk, pageind); - atomic_write_p(&elm->prof_tctx_pun, tctx); - } else { - /* - * tctx must always be initialized for large runs. - * Assert that the surrounding conditional logic is - * equivalent to checking whether ptr refers to a large - * run. - */ - assert(arena_mapbits_large_get(chunk, pageind) == 0); - } - } else + if (unlikely(!extent_slab_get(extent))) huge_prof_tctx_set(tsdn, extent, tctx); } JEMALLOC_INLINE void arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize, const void *old_ptr, prof_tctx_t *old_tctx) + prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); + assert(!extent_slab_get(extent)); - if (unlikely(usize > SMALL_MAXCLASS || (ptr == old_ptr && - (uintptr_t)old_tctx > (uintptr_t)1U))) { - if (likely(extent_slab_get(extent))) { - arena_chunk_t *chunk = - (arena_chunk_t *)extent_base_get(extent); - size_t pageind; - arena_chunk_map_misc_t *elm; - - pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> - LG_PAGE; - assert(arena_mapbits_allocated_get(chunk, pageind) != - 0); - assert(arena_mapbits_large_get(chunk, pageind) != 0); - - elm = arena_miscelm_get_mutable(chunk, pageind); - atomic_write_p(&elm->prof_tctx_pun, - (prof_tctx_t *)(uintptr_t)1U); - } else - huge_prof_tctx_reset(tsdn, extent); - } + huge_prof_tctx_reset(tsdn, extent); } JEMALLOC_ALWAYS_INLINE void @@ -1231,20 +560,9 @@ arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) assert(ptr != NULL); - if (likely(extent_slab_get(extent))) { - const arena_chunk_t *chunk = - (const arena_chunk_t *)extent_base_get(extent); - size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - szind_t binind; - - assert(arena_mapbits_allocated_get(chunk, pageind) != 0); - binind = arena_mapbits_binind_get(chunk, pageind); - /* Small allocation. */ - assert(arena_mapbits_large_get(chunk, pageind) != 0 || - arena_ptr_small_binind_get(tsdn, ptr, - arena_mapbits_get(chunk, pageind)) == binind); - ret = index2size(binind); - } else + if (likely(extent_slab_get(extent))) + ret = index2size(extent_slab_data_get_const(extent)->binind); + else ret = huge_salloc(tsdn, extent); return (ret); @@ -1260,19 +578,13 @@ arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, if (likely(extent_slab_get(extent))) { /* Small allocation. */ - arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); - size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - size_t mapbits = arena_mapbits_get(chunk, pageind); - assert(arena_mapbits_allocated_get(chunk, pageind) != 0); - assert((mapbits & CHUNK_MAP_LARGE) == 0); if (likely(tcache != NULL)) { - szind_t binind = arena_ptr_small_binind_get(tsdn, ptr, - mapbits); + szind_t binind = extent_slab_data_get(extent)->binind; tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, binind, slow_path); } else { arena_dalloc_small(tsdn, extent_arena_get(extent), - chunk, extent, ptr, pageind); + extent, ptr); } } else { size_t usize = extent_usize_get(extent); @@ -1282,8 +594,8 @@ arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, arena_dalloc_promoted(tsdn, extent, ptr, tcache, slow_path); } else { - tcache_dalloc_huge(tsdn_tsd(tsdn), tcache, ptr, - usize, slow_path); + tcache_dalloc_huge(tsdn_tsd(tsdn), tcache, + ptr, usize, slow_path); } } else huge_dalloc(tsdn, extent); @@ -1302,15 +614,12 @@ arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, /* Small allocation. */ if (likely(tcache != NULL)) { szind_t binind = size2index(size); + assert(binind == extent_slab_data_get(extent)->binind); tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, binind, slow_path); } else { - arena_chunk_t *chunk = - (arena_chunk_t *)extent_base_get(extent); - size_t pageind = ((uintptr_t)ptr - - (uintptr_t)chunk) >> LG_PAGE; arena_dalloc_small(tsdn, extent_arena_get(extent), - chunk, extent, ptr, pageind); + extent, ptr); } } else { if (likely(tcache != NULL) && size <= tcache_maxclass) { diff --git a/include/jemalloc/internal/bitmap.h b/include/jemalloc/internal/bitmap.h index 0d456e2d..c2e34554 100644 --- a/include/jemalloc/internal/bitmap.h +++ b/include/jemalloc/internal/bitmap.h @@ -2,7 +2,7 @@ #ifdef JEMALLOC_H_TYPES /* Maximum bitmap bit count is 2^LG_BITMAP_MAXBITS. */ -#define LG_BITMAP_MAXBITS LG_RUN_MAXREGS +#define LG_BITMAP_MAXBITS LG_SLAB_MAXREGS #define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS) typedef struct bitmap_level_s bitmap_level_t; diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 4e1e97ea..bfe61811 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -27,9 +27,6 @@ struct extent_s { /* True if extent is active (in use). */ bool e_active; - /* True if extent is dirty (touched). */ - bool e_dirty; - /* * The zeroed flag is used by chunk recycling code to track whether * memory is zero-filled. @@ -50,21 +47,27 @@ struct extent_s { */ bool e_slab; - /* Profile counters, used for huge objects. */ union { - void *e_prof_tctx_pun; - prof_tctx_t *e_prof_tctx; + /* Small region slab metadata. */ + arena_slab_data_t e_slab_data; + + /* Profile counters, used for huge objects. */ + union { + void *e_prof_tctx_pun; + prof_tctx_t *e_prof_tctx; + }; }; - /* Linkage for arena's runs_dirty and chunks_cache rings. */ - arena_runs_dirty_link_t rd; - qr(extent_t) cc_link; + /* + * Linkage for arena's extents_dirty and arena_bin_t's slabs_full rings. + */ + qr(extent_t) qr_link; union { /* Linkage for per size class address-ordered heaps. */ phn(extent_t) ph_link; - /* Linkage for arena's achunks, huge, and node_cache lists. */ + /* Linkage for arena's huge and extent_cache lists. */ ql_elm(extent_t) ql_link; }; }; @@ -102,11 +105,12 @@ void *extent_before_get(const extent_t *extent); void *extent_last_get(const extent_t *extent); void *extent_past_get(const extent_t *extent); bool extent_active_get(const extent_t *extent); -bool extent_dirty_get(const extent_t *extent); bool extent_retained_get(const extent_t *extent); bool extent_zeroed_get(const extent_t *extent); bool extent_committed_get(const extent_t *extent); bool extent_slab_get(const extent_t *extent); +arena_slab_data_t *extent_slab_data_get(extent_t *extent); +const arena_slab_data_t *extent_slab_data_get_const(const extent_t *extent); prof_tctx_t *extent_prof_tctx_get(const extent_t *extent); void extent_arena_set(extent_t *extent, arena_t *arena); void extent_addr_set(extent_t *extent, void *addr); @@ -114,17 +118,15 @@ void extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment); void extent_size_set(extent_t *extent, size_t size); void extent_usize_set(extent_t *extent, size_t usize); void extent_active_set(extent_t *extent, bool active); -void extent_dirty_set(extent_t *extent, bool dirty); void extent_zeroed_set(extent_t *extent, bool zeroed); void extent_committed_set(extent_t *extent, bool committed); void extent_slab_set(extent_t *extent, bool slab); void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx); void extent_init(extent_t *extent, arena_t *arena, void *addr, - size_t size, size_t usize, bool active, bool dirty, bool zeroed, - bool committed, bool slab); -void extent_dirty_insert(extent_t *extent, - arena_runs_dirty_link_t *runs_dirty, extent_t *chunks_dirty); -void extent_dirty_remove(extent_t *extent); + size_t size, size_t usize, bool active, bool zeroed, bool committed, + bool slab); +void extent_ring_insert(extent_t *sentinel, extent_t *extent); +void extent_ring_remove(extent_t *extent); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_)) @@ -197,18 +199,11 @@ extent_active_get(const extent_t *extent) return (extent->e_active); } -JEMALLOC_INLINE bool -extent_dirty_get(const extent_t *extent) -{ - - return (extent->e_dirty); -} - JEMALLOC_INLINE bool extent_retained_get(const extent_t *extent) { - return (qr_next(&extent->rd, rd_link) == &extent->rd); + return (qr_next(extent, qr_link) == extent); } JEMALLOC_INLINE bool @@ -232,6 +227,22 @@ extent_slab_get(const extent_t *extent) return (extent->e_slab); } +JEMALLOC_INLINE arena_slab_data_t * +extent_slab_data_get(extent_t *extent) +{ + + assert(extent->e_slab); + return (&extent->e_slab_data); +} + +JEMALLOC_INLINE const arena_slab_data_t * +extent_slab_data_get_const(const extent_t *extent) +{ + + assert(extent->e_slab); + return (&extent->e_slab_data); +} + JEMALLOC_INLINE prof_tctx_t * extent_prof_tctx_get(const extent_t *extent) { @@ -296,13 +307,6 @@ extent_active_set(extent_t *extent, bool active) extent->e_active = active; } -JEMALLOC_INLINE void -extent_dirty_set(extent_t *extent, bool dirty) -{ - - extent->e_dirty = dirty; -} - JEMALLOC_INLINE void extent_zeroed_set(extent_t *extent, bool zeroed) { @@ -333,8 +337,7 @@ extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) JEMALLOC_INLINE void extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, - size_t usize, bool active, bool dirty, bool zeroed, bool committed, - bool slab) + size_t usize, bool active, bool zeroed, bool committed, bool slab) { assert(addr == PAGE_ADDR2BASE(addr) || !slab); @@ -344,31 +347,26 @@ extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, extent_size_set(extent, size); extent_usize_set(extent, usize); extent_active_set(extent, active); - extent_dirty_set(extent, dirty); extent_zeroed_set(extent, zeroed); extent_committed_set(extent, committed); extent_slab_set(extent, slab); if (config_prof) extent_prof_tctx_set(extent, NULL); - qr_new(&extent->rd, rd_link); - qr_new(extent, cc_link); + qr_new(extent, qr_link); } JEMALLOC_INLINE void -extent_dirty_insert(extent_t *extent, - arena_runs_dirty_link_t *runs_dirty, extent_t *chunks_dirty) +extent_ring_insert(extent_t *sentinel, extent_t *extent) { - qr_meld(runs_dirty, &extent->rd, rd_link); - qr_meld(chunks_dirty, extent, cc_link); + qr_meld(sentinel, extent, qr_link); } JEMALLOC_INLINE void -extent_dirty_remove(extent_t *extent) +extent_ring_remove(extent_t *extent) { - qr_remove(&extent->rd, rd_link); - qr_remove(extent, cc_link); + qr_remove(extent, qr_link); } #endif diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 5f94d2c2..676c2431 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -5,8 +5,6 @@ arena_alloc_junk_small arena_basic_stats_merge arena_bin_index arena_bin_info -arena_bitselm_get_const -arena_bitselm_get_mutable arena_boot arena_choose arena_choose_hard @@ -43,38 +41,11 @@ arena_lg_dirty_mult_get arena_lg_dirty_mult_set arena_malloc arena_malloc_hard -arena_mapbits_allocated_get -arena_mapbits_binind_get -arena_mapbits_decommitted_get -arena_mapbits_dirty_get -arena_mapbits_get -arena_mapbits_internal_set -arena_mapbits_large_binind_set -arena_mapbits_large_get -arena_mapbits_large_set -arena_mapbits_large_size_get -arena_mapbits_size_decode -arena_mapbits_size_encode -arena_mapbits_small_runind_get -arena_mapbits_small_set -arena_mapbits_unallocated_set -arena_mapbits_unallocated_size_get -arena_mapbits_unallocated_size_set -arena_mapbits_unzeroed_get -arena_mapbitsp_get_const -arena_mapbitsp_get_mutable -arena_mapbitsp_read -arena_mapbitsp_write -arena_maxrun arena_maybe_purge arena_metadata_allocated_add arena_metadata_allocated_get arena_metadata_allocated_sub arena_migrate -arena_miscelm_get_const -arena_miscelm_get_mutable -arena_miscelm_to_pageind -arena_miscelm_to_rpages arena_new arena_nthreads_dec arena_nthreads_get @@ -93,14 +64,11 @@ arena_prof_promote arena_prof_tctx_get arena_prof_tctx_reset arena_prof_tctx_set -arena_ptr_small_binind_get arena_purge arena_ralloc arena_ralloc_junk_large arena_ralloc_no_move -arena_rd_to_miscelm arena_reset -arena_run_to_miscelm arena_salloc arena_sdalloc arena_stats_merge @@ -213,22 +181,23 @@ extent_before_get extent_committed_get extent_committed_set extent_dalloc -extent_dirty_get -extent_dirty_insert -extent_dirty_remove -extent_dirty_set extent_init extent_last_get extent_past_get extent_prof_tctx_get extent_prof_tctx_set extent_retained_get +extent_ring_insert +extent_ring_remove extent_size_get extent_size_set extent_size_quantize_ceil extent_size_quantize_floor +extent_slab_data_get +extent_slab_data_get_const extent_slab_get extent_slab_set +extent_slab_data_get extent_usize_get extent_zeroed_get extent_zeroed_set @@ -309,8 +278,6 @@ malloc_tsd_no_cleanup malloc_vcprintf malloc_vsnprintf malloc_write -map_bias -map_misc_offset mb_write narenas_auto narenas_tdata_cleanup @@ -451,8 +418,6 @@ rtree_subtree_read rtree_subtree_read_hard rtree_subtree_tryread rtree_write -run_quantize_ceil -run_quantize_floor s2u s2u_compute s2u_lookup diff --git a/include/jemalloc/internal/prof.h b/include/jemalloc/internal/prof.h index 7da20ad0..8fdc27f6 100644 --- a/include/jemalloc/internal/prof.h +++ b/include/jemalloc/internal/prof.h @@ -335,8 +335,8 @@ prof_tctx_t *prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, void prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, prof_tctx_t *tctx); void prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize, const void *old_ptr, prof_tctx_t *tctx); -bool prof_sample_accum_update(tsd_t *tsd, size_t usize, bool commit, + prof_tctx_t *tctx); +bool prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update, prof_tdata_t **tdata_out); prof_tctx_t *prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update); @@ -344,7 +344,8 @@ void prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, prof_tctx_t *tctx); void prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, prof_tctx_t *tctx, bool prof_active, bool updated, - const void *old_ptr, size_t old_usize, prof_tctx_t *old_tctx); + extent_t *old_extent, const void *old_ptr, size_t old_usize, + prof_tctx_t *old_tctx); void prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, size_t usize); #endif @@ -421,14 +422,14 @@ prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, } JEMALLOC_ALWAYS_INLINE void -prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, - const void *old_ptr, prof_tctx_t *old_tctx) +prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, + prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); - arena_prof_tctx_reset(tsdn, extent, ptr, usize, old_ptr, old_tctx); + arena_prof_tctx_reset(tsdn, extent, ptr, tctx); } JEMALLOC_ALWAYS_INLINE bool @@ -501,10 +502,10 @@ prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, JEMALLOC_ALWAYS_INLINE void prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, - prof_tctx_t *tctx, bool prof_active, bool updated, const void *old_ptr, - size_t old_usize, prof_tctx_t *old_tctx) + prof_tctx_t *tctx, bool prof_active, bool updated, extent_t *old_extent, + const void *old_ptr, size_t old_usize, prof_tctx_t *old_tctx) { - bool sampled, old_sampled; + bool sampled, old_sampled, moved; cassert(config_prof); assert(ptr != NULL || (uintptr_t)tctx <= (uintptr_t)1U); @@ -523,19 +524,30 @@ prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, } } + /* + * The following code must differentiate among eight possible cases, + * based on three boolean conditions. + */ sampled = ((uintptr_t)tctx > (uintptr_t)1U); old_sampled = ((uintptr_t)old_tctx > (uintptr_t)1U); + moved = (ptr != old_ptr); + + /* + * The following block must only execute if this is a non-moving + * reallocation, because for moving reallocation the old allocation will + * be deallocated via a separate call. + */ + if (unlikely(old_sampled) && !moved) + prof_free_sampled_object(tsd, old_usize, old_tctx); if (unlikely(sampled)) { prof_malloc_sample_object(tsd_tsdn(tsd), extent, ptr, usize, tctx); - } else { - prof_tctx_reset(tsd_tsdn(tsd), extent, ptr, usize, old_ptr, - old_tctx); - } - - if (unlikely(old_sampled)) - prof_free_sampled_object(tsd, old_usize, old_tctx); + } else if (moved) { + prof_tctx_set(tsd_tsdn(tsd), extent, ptr, usize, + (prof_tctx_t *)(uintptr_t)1U); + } else if (unlikely(old_sampled)) + prof_tctx_reset(tsd_tsdn(tsd), extent, ptr, tctx); } JEMALLOC_ALWAYS_INLINE void diff --git a/include/jemalloc/internal/size_classes.sh b/include/jemalloc/internal/size_classes.sh index 440953ad..b73064d1 100755 --- a/include/jemalloc/internal/size_classes.sh +++ b/include/jemalloc/internal/size_classes.sh @@ -50,7 +50,7 @@ reg_size_compute() { reg_size=$((${grp} + ${delta}*${ndelta})) } -run_size() { +slab_size() { lg_p=$1 lg_grp=$2 lg_delta=$3 @@ -59,22 +59,22 @@ run_size() { pow2 ${lg_p}; p=${pow2_result} reg_size_compute ${lg_grp} ${lg_delta} ${ndelta} - # Compute smallest run size that is an integer multiple of reg_size. - try_run_size=${p} - try_nregs=$((${try_run_size} / ${reg_size})) + # Compute smallest slab size that is an integer multiple of reg_size. + try_slab_size=${p} + try_nregs=$((${try_slab_size} / ${reg_size})) perfect=0 while [ ${perfect} -eq 0 ] ; do - perfect_run_size=${try_run_size} + perfect_slab_size=${try_slab_size} perfect_nregs=${try_nregs} - try_run_size=$((${try_run_size} + ${p})) - try_nregs=$((${try_run_size} / ${reg_size})) - if [ ${perfect_run_size} -eq $((${perfect_nregs} * ${reg_size})) ] ; then + try_slab_size=$((${try_slab_size} + ${p})) + try_nregs=$((${try_slab_size} / ${reg_size})) + if [ ${perfect_slab_size} -eq $((${perfect_nregs} * ${reg_size})) ] ; then perfect=1 fi done - run_size_pgs=$((${perfect_run_size} / ${p})) + slab_size_pgs=$((${perfect_slab_size} / ${p})) } size_class() { @@ -117,7 +117,7 @@ size_class() { if [ ${lg_size} -lt $((${lg_p} + ${lg_g})) ] ; then bin="yes" - run_size ${lg_p} ${lg_grp} ${lg_delta} ${ndelta}; pgs=${run_size_pgs} + slab_size ${lg_p} ${lg_grp} ${lg_delta} ${ndelta}; pgs=${slab_size_pgs} else bin="no" pgs=0 @@ -278,7 +278,7 @@ cat < b_miscelm) - (a_miscelm < b_miscelm)); -} - -/* Generate pairing heap functions. */ -ph_gen(static UNUSED, arena_run_heap_, arena_run_heap_t, arena_chunk_map_misc_t, - ph_link, arena_run_addr_comp) - -#ifdef JEMALLOC_JET -#undef run_quantize_floor -#define run_quantize_floor JEMALLOC_N(n_run_quantize_floor) -#endif -static size_t -run_quantize_floor(size_t size) -{ - size_t ret; - pszind_t pind; - - assert(size > 0); - assert(size <= HUGE_MAXCLASS); - assert((size & PAGE_MASK) == 0); - - assert(size != 0); - assert(size == PAGE_CEILING(size)); - - pind = psz2ind(size - large_pad + 1); - if (pind == 0) { - /* - * Avoid underflow. This short-circuit would also do the right - * thing for all sizes in the range for which there are - * PAGE-spaced size classes, but it's simplest to just handle - * the one case that would cause erroneous results. - */ - return (size); - } - ret = pind2sz(pind - 1) + large_pad; - assert(ret <= size); - return (ret); -} -#ifdef JEMALLOC_JET -#undef run_quantize_floor -#define run_quantize_floor JEMALLOC_N(run_quantize_floor) -run_quantize_t *run_quantize_floor = JEMALLOC_N(n_run_quantize_floor); -#endif - -#ifdef JEMALLOC_JET -#undef run_quantize_ceil -#define run_quantize_ceil JEMALLOC_N(n_run_quantize_ceil) -#endif -static size_t -run_quantize_ceil(size_t size) -{ - size_t ret; - - assert(size > 0); - assert(size <= HUGE_MAXCLASS); - assert((size & PAGE_MASK) == 0); - - ret = run_quantize_floor(size); - if (ret < size) { - /* - * Skip a quantization that may have an adequately large run, - * because under-sized runs may be mixed in. This only happens - * when an unusual size is requested, i.e. for aligned - * allocation, and is just one of several places where linear - * search would potentially find sufficiently aligned available - * memory somewhere lower. - */ - ret = pind2sz(psz2ind(ret - large_pad + 1)) + large_pad; - } - return (ret); -} -#ifdef JEMALLOC_JET -#undef run_quantize_ceil -#define run_quantize_ceil JEMALLOC_N(run_quantize_ceil) -run_quantize_t *run_quantize_ceil = JEMALLOC_N(n_run_quantize_ceil); -#endif - -static void -arena_avail_insert(arena_t *arena, extent_t *extent, size_t pageind, - size_t npages) -{ - arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); - pszind_t pind = psz2ind(run_quantize_floor(arena_miscelm_size_get( - extent, arena_miscelm_get_const(chunk, pageind)))); - assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >> - LG_PAGE)); - arena_run_heap_insert(&arena->runs_avail[pind], - arena_miscelm_get_mutable(chunk, pageind)); -} - -static void -arena_avail_remove(arena_t *arena, extent_t *extent, size_t pageind, - size_t npages) -{ - arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); - pszind_t pind = psz2ind(run_quantize_floor(arena_miscelm_size_get( - extent, arena_miscelm_get_const(chunk, pageind)))); - assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >> - LG_PAGE)); - arena_run_heap_remove(&arena->runs_avail[pind], - arena_miscelm_get_mutable(chunk, pageind)); -} - -static void -arena_run_dirty_insert(arena_t *arena, arena_chunk_t *chunk, size_t pageind, - size_t npages) -{ - arena_chunk_map_misc_t *miscelm = arena_miscelm_get_mutable(chunk, - pageind); - - assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >> - LG_PAGE)); - assert(arena_mapbits_dirty_get(chunk, pageind) == CHUNK_MAP_DIRTY); - assert(arena_mapbits_dirty_get(chunk, pageind+npages-1) == - CHUNK_MAP_DIRTY); - - qr_new(&miscelm->rd, rd_link); - qr_meld(&arena->runs_dirty, &miscelm->rd, rd_link); - arena->ndirty += npages; -} - -static void -arena_run_dirty_remove(arena_t *arena, arena_chunk_t *chunk, size_t pageind, - size_t npages) -{ - arena_chunk_map_misc_t *miscelm = arena_miscelm_get_mutable(chunk, - pageind); - - assert(npages == (arena_mapbits_unallocated_size_get(chunk, pageind) >> - LG_PAGE)); - assert(arena_mapbits_dirty_get(chunk, pageind) == CHUNK_MAP_DIRTY); - assert(arena_mapbits_dirty_get(chunk, pageind+npages-1) == - CHUNK_MAP_DIRTY); - - qr_remove(&miscelm->rd, rd_link); - assert(arena->ndirty >= npages); - arena->ndirty -= npages; -} - static size_t arena_chunk_dirty_npages(const extent_t *extent) { @@ -269,8 +105,7 @@ arena_chunk_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache) { if (cache) { - extent_dirty_insert(extent, &arena->runs_dirty, - &arena->chunks_cache); + extent_ring_insert(&arena->extents_dirty, extent); arena->ndirty += arena_chunk_dirty_npages(extent); } } @@ -280,54 +115,49 @@ arena_chunk_cache_maybe_remove(arena_t *arena, extent_t *extent, bool dirty) { if (dirty) { - extent_dirty_remove(extent); + extent_ring_remove(extent); assert(arena->ndirty >= arena_chunk_dirty_npages(extent)); arena->ndirty -= arena_chunk_dirty_npages(extent); } } JEMALLOC_INLINE_C void * -arena_run_reg_alloc(tsdn_t *tsdn, arena_run_t *run, +arena_slab_reg_alloc(tsdn_t *tsdn, extent_t *slab, const arena_bin_info_t *bin_info) { void *ret; - extent_t *extent; + arena_slab_data_t *slab_data = extent_slab_data_get(slab); size_t regind; - arena_chunk_map_misc_t *miscelm; - void *rpages; - - assert(run->nfree > 0); - assert(!bitmap_full(run->bitmap, &bin_info->bitmap_info)); - - extent = iealloc(tsdn, run); - regind = (unsigned)bitmap_sfu(run->bitmap, &bin_info->bitmap_info); - miscelm = arena_run_to_miscelm(extent, run); - rpages = arena_miscelm_to_rpages(extent, miscelm); - ret = (void *)((uintptr_t)rpages + (uintptr_t)(bin_info->reg_size * - regind)); - run->nfree--; + + assert(slab_data->nfree > 0); + assert(!bitmap_full(slab_data->bitmap, &bin_info->bitmap_info)); + + regind = (unsigned)bitmap_sfu(slab_data->bitmap, + &bin_info->bitmap_info); + ret = (void *)((uintptr_t)extent_addr_get(slab) + + (uintptr_t)(bin_info->reg_size * regind)); + slab_data->nfree--; return (ret); } JEMALLOC_INLINE_C size_t -arena_run_regind(extent_t *extent, arena_run_t *run, - const arena_bin_info_t *bin_info, const void *ptr) +arena_slab_regind(extent_t *slab, const arena_bin_info_t *bin_info, + const void *ptr) { size_t diff, interval, shift, regind; - arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(extent, run); - void *rpages = arena_miscelm_to_rpages(extent, miscelm); - /* - * Freeing a pointer lower than region zero can cause assertion - * failure. - */ - assert((uintptr_t)ptr >= (uintptr_t)rpages); + /* Freeing a pointer outside the slab can cause assertion failure. */ + assert((uintptr_t)ptr >= (uintptr_t)extent_addr_get(slab)); + assert((uintptr_t)ptr < (uintptr_t)extent_past_get(slab)); + /* Freeing an interior pointer can cause assertion failure. */ + assert(((uintptr_t)ptr - (uintptr_t)extent_addr_get(slab)) % + (uintptr_t)bin_info->reg_size == 0); /* * Avoid doing division with a variable divisor if possible. Using * actual division here can reduce allocator throughput by over 20%! */ - diff = (size_t)((uintptr_t)ptr - (uintptr_t)rpages); + diff = (size_t)((uintptr_t)ptr - (uintptr_t)extent_addr_get(slab)); /* Rescale (factor powers of 2 out of the numerator and denominator). */ interval = bin_info->reg_size; @@ -353,7 +183,7 @@ arena_run_regind(extent_t *extent, arena_run_t *run, * divide by 0, and 1 and 2 are both powers of two, which are * handled above. */ -#define SIZE_INV_SHIFT ((sizeof(size_t) << 3) - LG_RUN_MAXREGS) +#define SIZE_INV_SHIFT ((sizeof(size_t) << 3) - LG_SLAB_MAXREGS) #define SIZE_INV(s) (((ZU(1) << SIZE_INV_SHIFT) / (s)) + 1) static const size_t interval_invs[] = { SIZE_INV(3), @@ -382,48 +212,19 @@ arena_run_regind(extent_t *extent, arena_run_t *run, } JEMALLOC_INLINE_C void -arena_run_reg_dalloc(tsdn_t *tsdn, arena_run_t *run, extent_t *extent, - void *ptr) +arena_slab_reg_dalloc(tsdn_t *tsdn, extent_t *slab, + arena_slab_data_t *slab_data, void *ptr) { - arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); - size_t pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - size_t mapbits = arena_mapbits_get(chunk, pageind); - szind_t binind = arena_ptr_small_binind_get(tsdn, ptr, mapbits); + szind_t binind = slab_data->binind; const arena_bin_info_t *bin_info = &arena_bin_info[binind]; - size_t regind = arena_run_regind(extent, run, bin_info, ptr); + size_t regind = arena_slab_regind(slab, bin_info, ptr); - assert(run->nfree < bin_info->nregs); - /* Freeing an interior pointer can cause assertion failure. */ - assert(((uintptr_t)ptr - - (uintptr_t)arena_miscelm_to_rpages(extent, - arena_run_to_miscelm(extent, run))) % (uintptr_t)bin_info->reg_size - == 0); - assert((uintptr_t)ptr >= - (uintptr_t)arena_miscelm_to_rpages(extent, - arena_run_to_miscelm(extent, run))); + assert(slab_data->nfree < bin_info->nregs); /* Freeing an unallocated pointer can cause assertion failure. */ - assert(bitmap_get(run->bitmap, &bin_info->bitmap_info, regind)); - - bitmap_unset(run->bitmap, &bin_info->bitmap_info, regind); - run->nfree++; -} - -JEMALLOC_INLINE_C void -arena_run_zero(arena_chunk_t *chunk, size_t run_ind, size_t npages) -{ - - memset((void *)((uintptr_t)chunk + (run_ind << LG_PAGE)), 0, - (npages << LG_PAGE)); -} + assert(bitmap_get(slab_data->bitmap, &bin_info->bitmap_info, regind)); -JEMALLOC_INLINE_C void -arena_run_page_validate_zeroed(arena_chunk_t *chunk, size_t run_ind) -{ - size_t i; - UNUSED size_t *p = (size_t *)((uintptr_t)chunk + (run_ind << LG_PAGE)); - - for (i = 0; i < PAGE / sizeof(size_t); i++) - assert(p[i] == 0); + bitmap_unset(slab_data->bitmap, &bin_info->bitmap_info, regind); + slab_data->nfree++; } static void @@ -454,373 +255,6 @@ arena_nactive_sub(arena_t *arena, size_t sub_pages) arena->nactive -= sub_pages; } -static void -arena_run_split_remove(arena_t *arena, extent_t *extent, size_t run_ind, - size_t flag_dirty, size_t flag_decommitted, size_t need_pages) -{ - arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); - size_t total_pages, rem_pages; - - assert(flag_dirty == 0 || flag_decommitted == 0); - - total_pages = arena_mapbits_unallocated_size_get(chunk, run_ind) >> - LG_PAGE; - assert(arena_mapbits_dirty_get(chunk, run_ind+total_pages-1) == - flag_dirty); - assert(need_pages <= total_pages); - rem_pages = total_pages - need_pages; - - arena_avail_remove(arena, extent, run_ind, total_pages); - if (flag_dirty != 0) - arena_run_dirty_remove(arena, chunk, run_ind, total_pages); - arena_nactive_add(arena, need_pages); - - /* Keep track of trailing unused pages for later use. */ - if (rem_pages > 0) { - size_t flags = flag_dirty | flag_decommitted; - size_t flag_unzeroed_mask = (flags == 0) ? CHUNK_MAP_UNZEROED : - 0; - - arena_mapbits_unallocated_set(chunk, run_ind+need_pages, - (rem_pages << LG_PAGE), flags | - (arena_mapbits_unzeroed_get(chunk, run_ind+need_pages) & - flag_unzeroed_mask)); - arena_mapbits_unallocated_set(chunk, run_ind+total_pages-1, - (rem_pages << LG_PAGE), flags | - (arena_mapbits_unzeroed_get(chunk, run_ind+total_pages-1) & - flag_unzeroed_mask)); - if (flag_dirty != 0) { - arena_run_dirty_insert(arena, chunk, run_ind+need_pages, - rem_pages); - } - arena_avail_insert(arena, extent, run_ind+need_pages, - rem_pages); - } -} - -static bool -arena_run_split_large_helper(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - arena_run_t *run, size_t size, bool remove, bool zero) -{ - arena_chunk_t *chunk; - arena_chunk_map_misc_t *miscelm; - size_t flag_dirty, flag_decommitted, run_ind, need_pages; - size_t flag_unzeroed_mask; - - chunk = (arena_chunk_t *)extent_base_get(extent); - miscelm = arena_run_to_miscelm(extent, run); - run_ind = arena_miscelm_to_pageind(extent, miscelm); - flag_dirty = arena_mapbits_dirty_get(chunk, run_ind); - flag_decommitted = arena_mapbits_decommitted_get(chunk, run_ind); - need_pages = (size >> LG_PAGE); - assert(need_pages > 0); - - if (flag_decommitted != 0 && chunk_commit_wrapper(tsdn, arena, - &arena->chunk_hooks, extent, run_ind << LG_PAGE, size)) - return (true); - - if (remove) { - arena_run_split_remove(arena, extent, run_ind, flag_dirty, - flag_decommitted, need_pages); - } - - if (zero) { - if (flag_decommitted != 0) - ; /* The run is untouched, and therefore zeroed. */ - else if (flag_dirty != 0) { - /* The run is dirty, so all pages must be zeroed. */ - arena_run_zero(chunk, run_ind, need_pages); - } else { - /* - * The run is clean, so some pages may be zeroed (i.e. - * never before touched). - */ - size_t i; - for (i = 0; i < need_pages; i++) { - if (arena_mapbits_unzeroed_get(chunk, run_ind+i) - != 0) - arena_run_zero(chunk, run_ind+i, 1); - else if (config_debug) { - arena_run_page_validate_zeroed(chunk, - run_ind+i); - } - } - } - } - - /* - * Set the last element first, in case the run only contains one page - * (i.e. both statements set the same element). - */ - flag_unzeroed_mask = (flag_dirty | flag_decommitted) == 0 ? - CHUNK_MAP_UNZEROED : 0; - arena_mapbits_large_set(chunk, run_ind+need_pages-1, 0, flag_dirty | - (flag_unzeroed_mask & arena_mapbits_unzeroed_get(chunk, - run_ind+need_pages-1))); - arena_mapbits_large_set(chunk, run_ind, size, flag_dirty | - (flag_unzeroed_mask & arena_mapbits_unzeroed_get(chunk, run_ind))); - return (false); -} - -static bool -arena_run_split_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - arena_run_t *run, size_t size, bool zero) -{ - - return (arena_run_split_large_helper(tsdn, arena, extent, run, size, - true, zero)); -} - -static bool -arena_run_split_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - arena_run_t *run, size_t size, szind_t binind) -{ - arena_chunk_t *chunk; - arena_chunk_map_misc_t *miscelm; - size_t flag_dirty, flag_decommitted, run_ind, need_pages, i; - - assert(binind != BININD_INVALID); - - chunk = (arena_chunk_t *)extent_base_get(extent); - miscelm = arena_run_to_miscelm(extent, run); - run_ind = arena_miscelm_to_pageind(extent, miscelm); - flag_dirty = arena_mapbits_dirty_get(chunk, run_ind); - flag_decommitted = arena_mapbits_decommitted_get(chunk, run_ind); - need_pages = (size >> LG_PAGE); - assert(need_pages > 0); - - if (flag_decommitted != 0 && chunk_commit_wrapper(tsdn, arena, - &arena->chunk_hooks, extent, run_ind << LG_PAGE, size)) - return (true); - - arena_run_split_remove(arena, extent, run_ind, flag_dirty, - flag_decommitted, need_pages); - - for (i = 0; i < need_pages; i++) { - size_t flag_unzeroed = arena_mapbits_unzeroed_get(chunk, - run_ind+i); - arena_mapbits_small_set(chunk, run_ind+i, i, binind, - flag_unzeroed); - if (config_debug && flag_dirty == 0 && flag_unzeroed == 0) - arena_run_page_validate_zeroed(chunk, run_ind+i); - } - return (false); -} - -static extent_t * -arena_chunk_init_spare(arena_t *arena) -{ - extent_t *extent; - - assert(arena->spare != NULL); - - extent = arena->spare; - arena->spare = NULL; - - assert(arena_mapbits_allocated_get((arena_chunk_t *) - extent_base_get(extent), map_bias) == 0); - assert(arena_mapbits_allocated_get((arena_chunk_t *) - extent_base_get(extent), chunk_npages-1) == 0); - assert(arena_mapbits_unallocated_size_get((arena_chunk_t *) - extent_base_get(extent), map_bias) == arena_maxrun); - assert(arena_mapbits_unallocated_size_get((arena_chunk_t *) - extent_base_get(extent), chunk_npages-1) == arena_maxrun); - assert(arena_mapbits_dirty_get((arena_chunk_t *) - extent_base_get(extent), map_bias) == - arena_mapbits_dirty_get((arena_chunk_t *)extent_base_get(extent), - chunk_npages-1)); - - return (extent); -} - -static extent_t * -arena_chunk_alloc_internal_hard(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, bool *zero, bool *commit) -{ - extent_t *extent; - - malloc_mutex_unlock(tsdn, &arena->lock); - - extent = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, chunksize, - 0, CACHELINE, zero, commit, true); - if (extent != NULL && !*commit) { - /* Commit header. */ - if (chunk_commit_wrapper(tsdn, arena, chunk_hooks, extent, 0, - map_bias << LG_PAGE)) { - chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, extent); - extent = NULL; - } - } - - malloc_mutex_lock(tsdn, &arena->lock); - - return (extent); -} - -static extent_t * -arena_chunk_alloc_internal(tsdn_t *tsdn, arena_t *arena, bool *zero, - bool *commit) -{ - extent_t *extent; - chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; - - extent = arena_chunk_cache_alloc_locked(tsdn, arena, &chunk_hooks, NULL, - chunksize, 0, CACHELINE, zero, true); - if (extent != NULL) - *commit = true; - if (extent == NULL) { - extent = arena_chunk_alloc_internal_hard(tsdn, arena, - &chunk_hooks, zero, commit); - if (extent == NULL) - return (NULL); - } - assert(extent_slab_get(extent)); - - if (config_stats) { - arena->stats.mapped += extent_size_get(extent); - arena->stats.metadata_mapped += (map_bias << LG_PAGE); - } - - return (extent); -} - -static extent_t * -arena_chunk_init_hard(tsdn_t *tsdn, arena_t *arena) -{ - extent_t *extent; - bool zero, commit; - size_t flag_unzeroed, flag_decommitted, i; - - assert(arena->spare == NULL); - - zero = false; - commit = false; - extent = arena_chunk_alloc_internal(tsdn, arena, &zero, &commit); - if (extent == NULL) - return (NULL); - - /* - * Initialize the map to contain one maximal free untouched run. Mark - * the pages as zeroed if arena_chunk_alloc_internal() returned a zeroed - * or decommitted chunk. - */ - flag_unzeroed = (zero || !commit) ? 0 : CHUNK_MAP_UNZEROED; - flag_decommitted = commit ? 0 : CHUNK_MAP_DECOMMITTED; - arena_mapbits_unallocated_set((arena_chunk_t *)extent_base_get(extent), - map_bias, arena_maxrun, flag_unzeroed | flag_decommitted); - /* - * There is no need to initialize the internal page map entries unless - * the chunk is not zeroed. - */ - if (!zero) { - for (i = map_bias+1; i < chunk_npages-1; i++) { - arena_mapbits_internal_set((arena_chunk_t *) - extent_base_get(extent), i, flag_unzeroed); - } - } else { - if (config_debug) { - for (i = map_bias+1; i < chunk_npages-1; i++) { - assert(arena_mapbits_unzeroed_get( - (arena_chunk_t *)extent_base_get(extent), i) - == flag_unzeroed); - } - } - } - arena_mapbits_unallocated_set((arena_chunk_t *)extent_base_get(extent), - chunk_npages-1, arena_maxrun, flag_unzeroed); - - return (extent); -} - -static extent_t * -arena_chunk_alloc(tsdn_t *tsdn, arena_t *arena) -{ - extent_t *extent; - - if (arena->spare != NULL) - extent = arena_chunk_init_spare(arena); - else { - extent = arena_chunk_init_hard(tsdn, arena); - if (extent == NULL) - return (NULL); - } - - ql_elm_new(extent, ql_link); - ql_tail_insert(&arena->achunks, extent, ql_link); - arena_avail_insert(arena, extent, map_bias, chunk_npages-map_bias); - - return (extent); -} - -static void -arena_chunk_discard(tsdn_t *tsdn, arena_t *arena, extent_t *extent) -{ - chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; - - extent_committed_set(extent, - (arena_mapbits_decommitted_get((arena_chunk_t *) - extent_base_get(extent), map_bias) == 0)); - if (!extent_committed_get(extent)) { - /* - * Decommit the header. Mark the chunk as decommitted even if - * header decommit fails, since treating a partially committed - * chunk as committed has a high potential for causing later - * access of decommitted memory. - */ - chunk_decommit_wrapper(tsdn, arena, &chunk_hooks, extent, 0, - map_bias << LG_PAGE); - } - - if (config_stats) { - arena->stats.mapped -= extent_size_get(extent); - arena->stats.metadata_mapped -= (map_bias << LG_PAGE); - } - - arena_chunk_cache_dalloc_locked(tsdn, arena, &chunk_hooks, extent); -} - -static void -arena_spare_discard(tsdn_t *tsdn, arena_t *arena, extent_t *spare) -{ - - assert(arena->spare != spare); - - if (arena_mapbits_dirty_get((arena_chunk_t *)extent_base_get(spare), - map_bias) != 0) { - arena_run_dirty_remove(arena, (arena_chunk_t *) - extent_base_get(spare), map_bias, chunk_npages-map_bias); - } - - arena_chunk_discard(tsdn, arena, spare); -} - -static void -arena_chunk_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) -{ - arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); - extent_t *spare; - - assert(arena_mapbits_allocated_get(chunk, map_bias) == 0); - assert(arena_mapbits_allocated_get(chunk, chunk_npages-1) == 0); - assert(arena_mapbits_unallocated_size_get(chunk, map_bias) == - arena_maxrun); - assert(arena_mapbits_unallocated_size_get(chunk, chunk_npages-1) == - arena_maxrun); - assert(arena_mapbits_dirty_get(chunk, map_bias) == - arena_mapbits_dirty_get(chunk, chunk_npages-1)); - assert(arena_mapbits_decommitted_get(chunk, map_bias) == - arena_mapbits_decommitted_get(chunk, chunk_npages-1)); - - /* Remove run from runs_avail, so that the arena does not use it. */ - arena_avail_remove(arena, extent, map_bias, chunk_npages-map_bias); - - ql_remove(&arena->achunks, extent, ql_link); - spare = arena->spare; - arena->spare = extent; - if (spare != NULL) - arena_spare_discard(tsdn, arena, spare); -} - static void arena_huge_malloc_stats_update(arena_t *arena, size_t usize) { @@ -986,77 +420,6 @@ arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, malloc_mutex_unlock(tsdn, &arena->lock); } -/* - * Do first-best-fit run selection, i.e. select the lowest run that best fits. - * Run sizes are indexed, so not all candidate runs are necessarily exactly the - * same size. - */ -static arena_run_t * -arena_run_first_best_fit(arena_t *arena, size_t size) -{ - pszind_t pind, i; - - pind = psz2ind(run_quantize_ceil(size)); - - for (i = pind; pind2sz(i) <= arena_maxrun; i++) { - arena_chunk_map_misc_t *miscelm = arena_run_heap_first( - &arena->runs_avail[i]); - if (miscelm != NULL) - return (&miscelm->run); - } - - return (NULL); -} - -static arena_run_t * -arena_run_alloc_small_helper(tsdn_t *tsdn, arena_t *arena, size_t size, - szind_t binind) -{ - arena_run_t *run = arena_run_first_best_fit(arena, size); - if (run != NULL) { - if (arena_run_split_small(tsdn, arena, iealloc(tsdn, run), run, - size, binind)) - run = NULL; - } - return (run); -} - -static arena_run_t * -arena_run_alloc_small(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t binind) -{ - arena_run_t *run; - extent_t *extent; - - assert(size <= arena_maxrun); - assert(size == PAGE_CEILING(size)); - assert(binind != BININD_INVALID); - - /* Search the arena's chunks for the lowest best fit. */ - run = arena_run_alloc_small_helper(tsdn, arena, size, binind); - if (run != NULL) - return (run); - - /* - * No usable runs. Create a new chunk from which to allocate the run. - */ - extent = arena_chunk_alloc(tsdn, arena); - if (extent != NULL) { - run = &arena_miscelm_get_mutable( - (arena_chunk_t *)extent_base_get(extent), map_bias)->run; - if (arena_run_split_small(tsdn, arena, iealloc(tsdn, run), run, - size, binind)) - run = NULL; - return (run); - } - - /* - * arena_chunk_alloc() failed, but another thread may have made - * sufficient memory available while this one dropped arena->lock in - * arena_chunk_alloc(), so search one more time. - */ - return (arena_run_alloc_small_helper(tsdn, arena, size, binind)); -} - static bool arena_lg_dirty_mult_valid(ssize_t lg_dirty_mult) { @@ -1360,120 +723,45 @@ arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) static size_t arena_dirty_count(tsdn_t *tsdn, arena_t *arena) { + extent_t *extent; size_t ndirty = 0; - arena_runs_dirty_link_t *rdelm; - extent_t *chunkselm; - for (rdelm = qr_next(&arena->runs_dirty, rd_link), - chunkselm = qr_next(&arena->chunks_cache, cc_link); - rdelm != &arena->runs_dirty; rdelm = qr_next(rdelm, rd_link)) { - size_t npages; - - if (rdelm == &chunkselm->rd) { - npages = extent_size_get(chunkselm) >> LG_PAGE; - chunkselm = qr_next(chunkselm, cc_link); - } else { - extent_t *extent = iealloc(tsdn, rdelm); - arena_chunk_t *chunk = - (arena_chunk_t *)extent_base_get(extent); - arena_chunk_map_misc_t *miscelm = - arena_rd_to_miscelm(extent, rdelm); - size_t pageind = arena_miscelm_to_pageind(extent, - miscelm); - assert(arena_mapbits_allocated_get(chunk, pageind) == - 0); - assert(arena_mapbits_large_get(chunk, pageind) == 0); - assert(arena_mapbits_dirty_get(chunk, pageind) != 0); - npages = arena_mapbits_unallocated_size_get(chunk, - pageind) >> LG_PAGE; - } - ndirty += npages; - } + for (extent = qr_next(&arena->extents_dirty, qr_link); extent != + &arena->extents_dirty; extent = qr_next(extent, qr_link)) + ndirty += extent_size_get(extent) >> LG_PAGE; return (ndirty); } static size_t arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - size_t ndirty_limit, arena_runs_dirty_link_t *purge_runs_sentinel, - extent_t *purge_chunks_sentinel) + size_t ndirty_limit, extent_t *purge_extents_sentinel) { - arena_runs_dirty_link_t *rdelm, *rdelm_next; - extent_t *chunkselm; + extent_t *extent, *next; size_t nstashed = 0; - /* Stash runs/chunks according to ndirty_limit. */ - for (rdelm = qr_next(&arena->runs_dirty, rd_link), - chunkselm = qr_next(&arena->chunks_cache, cc_link); - rdelm != &arena->runs_dirty; rdelm = rdelm_next) { + /* Stash extents according to ndirty_limit. */ + for (extent = qr_next(&arena->extents_dirty, qr_link); extent != + &arena->extents_dirty; extent = next) { size_t npages; - rdelm_next = qr_next(rdelm, rd_link); - - if (rdelm == &chunkselm->rd) { - extent_t *chunkselm_next; - bool zero; - UNUSED extent_t *extent; - - npages = extent_size_get(chunkselm) >> LG_PAGE; - if (opt_purge == purge_mode_decay && arena->ndirty - - (nstashed + npages) < ndirty_limit) - break; - - chunkselm_next = qr_next(chunkselm, cc_link); - /* Allocate. */ - zero = false; - extent = arena_chunk_cache_alloc_locked(tsdn, arena, - chunk_hooks, extent_base_get(chunkselm), - extent_size_get(chunkselm), 0, CACHELINE, &zero, - false); - assert(extent == chunkselm); - assert(zero == extent_zeroed_get(chunkselm)); - extent_dirty_insert(chunkselm, purge_runs_sentinel, - purge_chunks_sentinel); - assert(npages == (extent_size_get(chunkselm) >> - LG_PAGE)); - chunkselm = chunkselm_next; - } else { - extent_t *extent = iealloc(tsdn, rdelm); - arena_chunk_map_misc_t *miscelm = - arena_rd_to_miscelm(extent, rdelm); - size_t pageind = arena_miscelm_to_pageind(extent, - miscelm); - arena_run_t *run = &miscelm->run; - size_t run_size = - arena_mapbits_unallocated_size_get((arena_chunk_t *) - extent_base_get(extent), pageind); - - npages = run_size >> LG_PAGE; - if (opt_purge == purge_mode_decay && arena->ndirty - - (nstashed + npages) < ndirty_limit) - break; - - assert(pageind + npages <= chunk_npages); - assert(arena_mapbits_dirty_get((arena_chunk_t *) - extent_base_get(extent), pageind) == - arena_mapbits_dirty_get((arena_chunk_t *) - extent_base_get(extent), pageind+npages-1)); + bool zero; + UNUSED extent_t *textent; - /* - * If purging the spare chunk's run, make it available - * prior to allocation. - */ - if (extent == arena->spare) - arena_chunk_alloc(tsdn, arena); - - /* Temporarily allocate the free dirty run. */ - arena_run_split_large(tsdn, arena, extent, run, - run_size, false); - /* Stash. */ - if (false) - qr_new(rdelm, rd_link); /* Redundant. */ - else { - assert(qr_next(rdelm, rd_link) == rdelm); - assert(qr_prev(rdelm, rd_link) == rdelm); - } - qr_meld(purge_runs_sentinel, rdelm, rd_link); - } + npages = extent_size_get(extent) >> LG_PAGE; + if (opt_purge == purge_mode_decay && arena->ndirty - (nstashed + + npages) < ndirty_limit) + break; + + next = qr_next(extent, qr_link); + /* Allocate. */ + zero = false; + textent = arena_chunk_cache_alloc_locked(tsdn, arena, + chunk_hooks, extent_base_get(extent), + extent_size_get(extent), 0, CACHELINE, &zero, false); + assert(textent == extent); + assert(zero == extent_zeroed_get(extent)); + extent_ring_remove(extent); + extent_ring_insert(purge_extents_sentinel, extent); nstashed += npages; if (opt_purge == purge_mode_ratio && arena->ndirty - nstashed <= @@ -1486,90 +774,26 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, static size_t arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - arena_runs_dirty_link_t *purge_runs_sentinel, - extent_t *purge_chunks_sentinel) + extent_t *purge_extents_sentinel) { - size_t npurged, nmadvise; - arena_runs_dirty_link_t *rdelm; - extent_t *chunkselm; + UNUSED size_t nmadvise; + size_t npurged; + extent_t *extent, *next; if (config_stats) nmadvise = 0; npurged = 0; - malloc_mutex_unlock(tsdn, &arena->lock); - for (rdelm = qr_next(purge_runs_sentinel, rd_link), - chunkselm = qr_next(purge_chunks_sentinel, cc_link); - rdelm != purge_runs_sentinel; rdelm = qr_next(rdelm, rd_link)) { - size_t npages; - - if (rdelm == &chunkselm->rd) { - /* - * Don't actually purge the chunk here because 1) - * chunkselm is embedded in the chunk and must remain - * valid, and 2) we deallocate the chunk in - * arena_unstash_purged(), where it is destroyed, - * decommitted, or purged, depending on chunk - * deallocation policy. - */ - size_t size = extent_size_get(chunkselm); - npages = size >> LG_PAGE; - chunkselm = qr_next(chunkselm, cc_link); - } else { - size_t pageind, run_size, flag_unzeroed, flags, i; - bool decommitted; - extent_t *extent = iealloc(tsdn, rdelm); - arena_chunk_t *chunk = - (arena_chunk_t *)extent_base_get(extent); - arena_chunk_map_misc_t *miscelm = - arena_rd_to_miscelm(extent, rdelm); - pageind = arena_miscelm_to_pageind(extent, miscelm); - run_size = arena_mapbits_large_size_get(chunk, pageind); - npages = run_size >> LG_PAGE; - - assert(pageind + npages <= chunk_npages); - assert(!arena_mapbits_decommitted_get(chunk, pageind)); - assert(!arena_mapbits_decommitted_get(chunk, - pageind+npages-1)); - decommitted = !chunk_decommit_wrapper(tsdn, arena, - chunk_hooks, extent, pageind << LG_PAGE, npages << - LG_PAGE); - if (decommitted) { - flag_unzeroed = 0; - flags = CHUNK_MAP_DECOMMITTED; - } else { - flag_unzeroed = chunk_purge_wrapper(tsdn, arena, - chunk_hooks, extent, pageind << LG_PAGE, - run_size) ? CHUNK_MAP_UNZEROED : 0; - flags = flag_unzeroed; - } - arena_mapbits_large_set(chunk, pageind+npages-1, 0, - flags); - arena_mapbits_large_set(chunk, pageind, run_size, - flags); - - /* - * Set the unzeroed flag for internal pages, now that - * chunk_purge_wrapper() has returned whether the pages - * were zeroed as a side effect of purging. This chunk - * map modification is safe even though the arena mutex - * isn't currently owned by this thread, because the run - * is marked as allocated, thus protecting it from being - * modified by any other thread. As long as these - * writes don't perturb the first and last elements' - * CHUNK_MAP_ALLOCATED bits, behavior is well defined. - */ - for (i = 1; i < npages-1; i++) { - arena_mapbits_internal_set(chunk, pageind+i, - flag_unzeroed); - } - } - - npurged += npages; + for (extent = qr_next(purge_extents_sentinel, qr_link); extent != + purge_extents_sentinel; extent = next) { if (config_stats) nmadvise++; + npurged += extent_size_get(extent) >> LG_PAGE; + + next = qr_next(extent, qr_link); + extent_ring_remove(extent); + chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, extent); } - malloc_mutex_lock(tsdn, &arena->lock); if (config_stats) { arena->stats.nmadvise += nmadvise; @@ -1579,49 +803,12 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, return (npurged); } -static void -arena_unstash_purged(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - arena_runs_dirty_link_t *purge_runs_sentinel, - extent_t *purge_chunks_sentinel) -{ - arena_runs_dirty_link_t *rdelm, *rdelm_next; - extent_t *chunkselm; - - /* Deallocate chunks/runs. */ - for (rdelm = qr_next(purge_runs_sentinel, rd_link), - chunkselm = qr_next(purge_chunks_sentinel, cc_link); - rdelm != purge_runs_sentinel; rdelm = rdelm_next) { - rdelm_next = qr_next(rdelm, rd_link); - if (rdelm == &chunkselm->rd) { - extent_t *chunkselm_next = qr_next(chunkselm, cc_link); - extent_dirty_remove(chunkselm); - chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, - chunkselm); - chunkselm = chunkselm_next; - } else { - extent_t *extent = iealloc(tsdn, rdelm); - arena_chunk_t *chunk = - (arena_chunk_t *)extent_base_get(extent); - arena_chunk_map_misc_t *miscelm = - arena_rd_to_miscelm(extent, rdelm); - size_t pageind = arena_miscelm_to_pageind(extent, - miscelm); - bool decommitted = (arena_mapbits_decommitted_get(chunk, - pageind) != 0); - arena_run_t *run = &miscelm->run; - qr_remove(rdelm, rd_link); - arena_run_dalloc(tsdn, arena, extent, run, false, true, - decommitted); - } - } -} - /* * NB: ndirty_limit is interpreted differently depending on opt_purge: - * - purge_mode_ratio: Purge as few dirty run/chunks as possible to reach the + * - purge_mode_ratio: Purge as few dirty extents as possible to reach the * desired state: * (arena->ndirty <= ndirty_limit) - * - purge_mode_decay: Purge as many dirty runs/chunks as possible without + * - purge_mode_decay: Purge as many dirty extents as possible without * violating the invariant: * (arena->ndirty >= ndirty_limit) */ @@ -1630,8 +817,7 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) { chunk_hooks_t chunk_hooks = chunk_hooks_get(tsdn, arena); size_t npurge, npurged; - arena_runs_dirty_link_t purge_runs_sentinel; - extent_t purge_chunks_sentinel; + extent_t purge_extents_sentinel; arena->purging = true; @@ -1646,19 +832,16 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) assert(opt_purge != purge_mode_ratio || (arena->nactive >> arena->lg_dirty_mult) < arena->ndirty || ndirty_limit == 0); - qr_new(&purge_runs_sentinel, rd_link); - extent_init(&purge_chunks_sentinel, arena, NULL, 0, 0, false, false, - false, false, false); + extent_init(&purge_extents_sentinel, arena, NULL, 0, 0, false, false, + false, false); npurge = arena_stash_dirty(tsdn, arena, &chunk_hooks, ndirty_limit, - &purge_runs_sentinel, &purge_chunks_sentinel); + &purge_extents_sentinel); if (npurge == 0) goto label_return; npurged = arena_purge_stashed(tsdn, arena, &chunk_hooks, - &purge_runs_sentinel, &purge_chunks_sentinel); + &purge_extents_sentinel); assert(npurged == npurge); - arena_unstash_purged(tsdn, arena, &chunk_hooks, &purge_runs_sentinel, - &purge_chunks_sentinel); if (config_stats) arena->stats.npurge++; @@ -1679,6 +862,15 @@ arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) malloc_mutex_unlock(tsdn, &arena->lock); } +static void +arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) +{ + chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; + + arena_nactive_sub(arena, extent_size_get(slab) >> LG_PAGE); + arena_chunk_cache_dalloc_locked(tsdn, arena, &chunk_hooks, slab); +} + void arena_reset(tsd_t *tsd, arena_t *arena) { @@ -1724,367 +916,225 @@ arena_reset(tsd_t *tsd, arena_t *arena) /* Bins. */ for (i = 0; i < NBINS; i++) { + extent_t *slab, *next; arena_bin_t *bin = &arena->bins[i]; malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); - bin->runcur = NULL; - arena_run_heap_new(&bin->runs); + if (bin->slabcur != NULL) { + arena_slab_dalloc(tsd_tsdn(tsd), arena, bin->slabcur); + bin->slabcur = NULL; + } + while ((slab = extent_heap_remove_first(&bin->slabs_nonfull)) != + NULL) + arena_slab_dalloc(tsd_tsdn(tsd), arena, slab); + for (slab = qr_next(&bin->slabs_full, qr_link); slab != + &bin->slabs_full; slab = next) { + next = qr_next(slab, qr_link); + arena_slab_dalloc(tsd_tsdn(tsd), arena, slab); + } if (config_stats) { bin->stats.curregs = 0; - bin->stats.curruns = 0; + bin->stats.curslabs = 0; } malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); } - /* - * Re-initialize runs_dirty such that the chunks_cache and runs_dirty - * chains directly correspond. - */ - qr_new(&arena->runs_dirty, rd_link); - for (extent = qr_next(&arena->chunks_cache, cc_link); - extent != &arena->chunks_cache; extent = qr_next(extent, cc_link)) { - qr_new(&extent->rd, rd_link); - qr_meld(&arena->runs_dirty, &extent->rd, rd_link); - } - - /* Arena chunks. */ - for (extent = ql_last(&arena->achunks, ql_link); extent != NULL; extent - = ql_last(&arena->achunks, ql_link)) { - ql_remove(&arena->achunks, extent, ql_link); - arena_chunk_discard(tsd_tsdn(tsd), arena, extent); - } - - /* Spare. */ - if (arena->spare != NULL) { - arena_chunk_discard(tsd_tsdn(tsd), arena, arena->spare); - arena->spare = NULL; - } - assert(!arena->purging); arena->nactive = 0; - for (i = 0; i < sizeof(arena->runs_avail) / sizeof(arena_run_heap_t); - i++) - arena_run_heap_new(&arena->runs_avail[i]); - malloc_mutex_unlock(tsd_tsdn(tsd), &arena->lock); } static void -arena_run_coalesce(arena_t *arena, extent_t *extent, size_t *p_size, - size_t *p_run_ind, size_t *p_run_pages, size_t flag_dirty, - size_t flag_decommitted) -{ - arena_chunk_t *chunk = (arena_chunk_t *)extent_base_get(extent); - size_t size = *p_size; - size_t run_ind = *p_run_ind; - size_t run_pages = *p_run_pages; - - /* Try to coalesce forward. */ - if (run_ind + run_pages < chunk_npages && - arena_mapbits_allocated_get(chunk, run_ind+run_pages) == 0 && - arena_mapbits_dirty_get(chunk, run_ind+run_pages) == flag_dirty && - arena_mapbits_decommitted_get(chunk, run_ind+run_pages) == - flag_decommitted) { - size_t nrun_size = arena_mapbits_unallocated_size_get(chunk, - run_ind+run_pages); - size_t nrun_pages = nrun_size >> LG_PAGE; - - /* - * Remove successor from runs_avail; the coalesced run is - * inserted later. - */ - assert(arena_mapbits_unallocated_size_get(chunk, - run_ind+run_pages+nrun_pages-1) == nrun_size); - assert(arena_mapbits_dirty_get(chunk, - run_ind+run_pages+nrun_pages-1) == flag_dirty); - assert(arena_mapbits_decommitted_get(chunk, - run_ind+run_pages+nrun_pages-1) == flag_decommitted); - arena_avail_remove(arena, extent, run_ind+run_pages, - nrun_pages); - - /* - * If the successor is dirty, remove it from the set of dirty - * pages. - */ - if (flag_dirty != 0) { - arena_run_dirty_remove(arena, chunk, run_ind+run_pages, - nrun_pages); - } - - size += nrun_size; - run_pages += nrun_pages; - - arena_mapbits_unallocated_size_set(chunk, run_ind, size); - arena_mapbits_unallocated_size_set(chunk, run_ind+run_pages-1, - size); - } - - /* Try to coalesce backward. */ - if (run_ind > map_bias && arena_mapbits_allocated_get(chunk, - run_ind-1) == 0 && arena_mapbits_dirty_get(chunk, run_ind-1) == - flag_dirty && arena_mapbits_decommitted_get(chunk, run_ind-1) == - flag_decommitted) { - size_t prun_size = arena_mapbits_unallocated_size_get(chunk, - run_ind-1); - size_t prun_pages = prun_size >> LG_PAGE; - - run_ind -= prun_pages; - - /* - * Remove predecessor from runs_avail; the coalesced run is - * inserted later. - */ - assert(arena_mapbits_unallocated_size_get(chunk, run_ind) == - prun_size); - assert(arena_mapbits_dirty_get(chunk, run_ind) == flag_dirty); - assert(arena_mapbits_decommitted_get(chunk, run_ind) == - flag_decommitted); - arena_avail_remove(arena, extent, run_ind, prun_pages); - - /* - * If the predecessor is dirty, remove it from the set of dirty - * pages. - */ - if (flag_dirty != 0) { - arena_run_dirty_remove(arena, chunk, run_ind, - prun_pages); - } - - size += prun_size; - run_pages += prun_pages; - - arena_mapbits_unallocated_size_set(chunk, run_ind, size); - arena_mapbits_unallocated_size_set(chunk, run_ind+run_pages-1, - size); - } +arena_bin_slabs_nonfull_insert(arena_bin_t *bin, extent_t *slab) +{ - *p_size = size; - *p_run_ind = run_ind; - *p_run_pages = run_pages; + assert(extent_slab_data_get(slab)->nfree > 0); + extent_heap_insert(&bin->slabs_nonfull, slab); } -static size_t -arena_run_size_get(arena_t *arena, arena_chunk_t *chunk, arena_run_t *run, - size_t run_ind) +static void +arena_bin_slabs_nonfull_remove(arena_bin_t *bin, extent_t *slab) { - size_t size; - assert(run_ind >= map_bias); - assert(run_ind < chunk_npages); - - if (arena_mapbits_large_get(chunk, run_ind) != 0) { - size = arena_mapbits_large_size_get(chunk, run_ind); - assert(size == PAGE || arena_mapbits_large_size_get(chunk, - run_ind+(size>>LG_PAGE)-1) == 0); - } else { - const arena_bin_info_t *bin_info = &arena_bin_info[run->binind]; - size = bin_info->run_size; - } + extent_heap_remove(&bin->slabs_nonfull, slab); +} - return (size); +static extent_t * +arena_bin_slabs_nonfull_tryget(arena_bin_t *bin) +{ + extent_t *slab = extent_heap_remove_first(&bin->slabs_nonfull); + if (slab == NULL) + return (NULL); + if (config_stats) + bin->stats.reslabs++; + return (slab); } static void -arena_run_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - arena_run_t *run, bool dirty, bool cleaned, bool decommitted) -{ - arena_chunk_t *chunk; - arena_chunk_map_misc_t *miscelm; - size_t size, run_ind, run_pages, flag_dirty, flag_decommitted; - - chunk = (arena_chunk_t *)extent_base_get(extent); - miscelm = arena_run_to_miscelm(extent, run); - run_ind = arena_miscelm_to_pageind(extent, miscelm); - assert(run_ind >= map_bias); - assert(run_ind < chunk_npages); - size = arena_run_size_get(arena, chunk, run, run_ind); - run_pages = (size >> LG_PAGE); - arena_nactive_sub(arena, run_pages); +arena_bin_slabs_full_insert(arena_bin_t *bin, extent_t *slab) +{ - /* - * The run is dirty if the caller claims to have dirtied it, as well as - * if it was already dirty before being allocated and the caller - * doesn't claim to have cleaned it. - */ - assert(arena_mapbits_dirty_get(chunk, run_ind) == - arena_mapbits_dirty_get(chunk, run_ind+run_pages-1)); - if (!cleaned && !decommitted && arena_mapbits_dirty_get(chunk, run_ind) - != 0) - dirty = true; - flag_dirty = dirty ? CHUNK_MAP_DIRTY : 0; - flag_decommitted = decommitted ? CHUNK_MAP_DECOMMITTED : 0; - - /* Mark pages as unallocated in the chunk map. */ - if (dirty || decommitted) { - size_t flags = flag_dirty | flag_decommitted; - arena_mapbits_unallocated_set(chunk, run_ind, size, flags); - arena_mapbits_unallocated_set(chunk, run_ind+run_pages-1, size, - flags); - } else { - arena_mapbits_unallocated_set(chunk, run_ind, size, - arena_mapbits_unzeroed_get(chunk, run_ind)); - arena_mapbits_unallocated_set(chunk, run_ind+run_pages-1, size, - arena_mapbits_unzeroed_get(chunk, run_ind+run_pages-1)); - } + assert(extent_slab_data_get(slab)->nfree == 0); + extent_ring_insert(&bin->slabs_full, slab); +} - arena_run_coalesce(arena, extent, &size, &run_ind, &run_pages, - flag_dirty, flag_decommitted); - - /* Insert into runs_avail, now that coalescing is complete. */ - assert(arena_mapbits_unallocated_size_get(chunk, run_ind) == - arena_mapbits_unallocated_size_get(chunk, run_ind+run_pages-1)); - assert(arena_mapbits_dirty_get(chunk, run_ind) == - arena_mapbits_dirty_get(chunk, run_ind+run_pages-1)); - assert(arena_mapbits_decommitted_get(chunk, run_ind) == - arena_mapbits_decommitted_get(chunk, run_ind+run_pages-1)); - arena_avail_insert(arena, extent, run_ind, run_pages); - - if (dirty) - arena_run_dirty_insert(arena, chunk, run_ind, run_pages); - - /* Deallocate chunk if it is now completely unused. */ - if (size == arena_maxrun) { - assert(run_ind == map_bias); - assert(run_pages == (arena_maxrun >> LG_PAGE)); - arena_chunk_dalloc(tsdn, arena, extent); - } +static void +arena_bin_slabs_full_remove(extent_t *slab) +{ - /* - * It is okay to do dirty page processing here even if the chunk was - * deallocated above, since in that case it is the spare. Waiting - * until after possible chunk deallocation to do dirty processing - * allows for an old spare to be fully deallocated, thus decreasing the - * chances of spuriously crossing the dirty page purging threshold. - */ - if (dirty) - arena_maybe_purge(tsdn, arena); + extent_ring_remove(slab); } -static void -arena_bin_runs_insert(arena_bin_t *bin, extent_t *extent, arena_run_t *run) +static extent_t * +arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, + const arena_bin_info_t *bin_info) { - arena_chunk_map_misc_t *miscelm = arena_run_to_miscelm(extent, run); + extent_t *slab; + bool zero, commit; + + zero = false; + commit = true; + malloc_mutex_unlock(tsdn, &arena->lock); + slab = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, + bin_info->slab_size, 0, PAGE, &zero, &commit, true); + malloc_mutex_lock(tsdn, &arena->lock); - arena_run_heap_insert(&bin->runs, miscelm); + return (slab); } -static arena_run_t * -arena_bin_nonfull_run_tryget(arena_bin_t *bin) +static extent_t * +arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, + const arena_bin_info_t *bin_info) { - arena_chunk_map_misc_t *miscelm; + extent_t *slab; + arena_slab_data_t *slab_data; + chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; + bool zero; + + zero = false; + slab = arena_chunk_cache_alloc_locked(tsdn, arena, &chunk_hooks, NULL, + bin_info->slab_size, 0, PAGE, &zero, true); + if (slab == NULL) { + slab = arena_slab_alloc_hard(tsdn, arena, &chunk_hooks, + bin_info); + if (slab == NULL) + return (NULL); + } + assert(extent_slab_get(slab)); + + arena_nactive_add(arena, extent_size_get(slab) >> LG_PAGE); + + /* Initialize slab internals. */ + slab_data = extent_slab_data_get(slab); + slab_data->binind = binind; + slab_data->nfree = bin_info->nregs; + bitmap_init(slab_data->bitmap, &bin_info->bitmap_info); - miscelm = arena_run_heap_remove_first(&bin->runs); - if (miscelm == NULL) - return (NULL); if (config_stats) - bin->stats.reruns++; + arena->stats.mapped += extent_size_get(slab); - return (&miscelm->run); + return (slab); } -static arena_run_t * -arena_bin_nonfull_run_get(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin) +static extent_t * +arena_bin_nonfull_slab_get(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, + szind_t binind) { - arena_run_t *run; - szind_t binind; + extent_t *slab; const arena_bin_info_t *bin_info; - /* Look for a usable run. */ - run = arena_bin_nonfull_run_tryget(bin); - if (run != NULL) - return (run); - /* No existing runs have any space available. */ + /* Look for a usable slab. */ + slab = arena_bin_slabs_nonfull_tryget(bin); + if (slab != NULL) + return (slab); + /* No existing slabs have any space available. */ - binind = arena_bin_index(arena, bin); bin_info = &arena_bin_info[binind]; - /* Allocate a new run. */ + /* Allocate a new slab. */ malloc_mutex_unlock(tsdn, &bin->lock); /******************************/ malloc_mutex_lock(tsdn, &arena->lock); - run = arena_run_alloc_small(tsdn, arena, bin_info->run_size, binind); - if (run != NULL) { - /* Initialize run internals. */ - run->binind = binind; - run->nfree = bin_info->nregs; - bitmap_init(run->bitmap, &bin_info->bitmap_info); - } + slab = arena_slab_alloc(tsdn, arena, binind, bin_info); malloc_mutex_unlock(tsdn, &arena->lock); /********************************/ malloc_mutex_lock(tsdn, &bin->lock); - if (run != NULL) { + if (slab != NULL) { if (config_stats) { - bin->stats.nruns++; - bin->stats.curruns++; + bin->stats.nslabs++; + bin->stats.curslabs++; } - return (run); + return (slab); } /* - * arena_run_alloc_small() failed, but another thread may have made + * arena_slab_alloc() failed, but another thread may have made * sufficient memory available while this one dropped bin->lock above, * so search one more time. */ - run = arena_bin_nonfull_run_tryget(bin); - if (run != NULL) - return (run); + slab = arena_bin_slabs_nonfull_tryget(bin); + if (slab != NULL) + return (slab); return (NULL); } -/* Re-fill bin->runcur, then call arena_run_reg_alloc(). */ +/* Re-fill bin->slabcur, then call arena_slab_reg_alloc(). */ static void * -arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin) +arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, + szind_t binind) { - szind_t binind; const arena_bin_info_t *bin_info; - arena_run_t *run; + extent_t *slab; + - binind = arena_bin_index(arena, bin); bin_info = &arena_bin_info[binind]; - bin->runcur = NULL; - run = arena_bin_nonfull_run_get(tsdn, arena, bin); - if (bin->runcur != NULL && bin->runcur->nfree > 0) { + if (bin->slabcur != NULL) { + arena_bin_slabs_full_insert(bin, bin->slabcur); + bin->slabcur = NULL; + } + slab = arena_bin_nonfull_slab_get(tsdn, arena, bin, binind); + if (bin->slabcur != NULL) { /* - * Another thread updated runcur while this one ran without the - * bin lock in arena_bin_nonfull_run_get(). + * Another thread updated slabcur while this one ran without the + * bin lock in arena_bin_nonfull_slab_get(). */ - void *ret; - assert(bin->runcur->nfree > 0); - ret = arena_run_reg_alloc(tsdn, bin->runcur, bin_info); - if (run != NULL) { - extent_t *extent; - arena_chunk_t *chunk; - - /* - * arena_run_alloc_small() may have allocated run, or - * it may have pulled run from the bin's run tree. - * Therefore it is unsafe to make any assumptions about - * how run has previously been used, and - * arena_bin_lower_run() must be called, as if a region - * were just deallocated from the run. - */ - extent = iealloc(tsdn, run); - chunk = (arena_chunk_t *)extent_base_get(extent); - if (run->nfree == bin_info->nregs) { - arena_dalloc_bin_run(tsdn, arena, chunk, extent, - run, bin); - } else { - arena_bin_lower_run(tsdn, arena, extent, run, - bin); + if (extent_slab_data_get(bin->slabcur)->nfree > 0) { + void *ret = arena_slab_reg_alloc(tsdn, bin->slabcur, + bin_info); + if (slab != NULL) { + /* + * arena_slab_alloc() may have allocated slab, + * or it may have been pulled from + * slabs_nonfull. Therefore it is unsafe to + * make any assumptions about how slab has + * previously been used, and + * arena_bin_lower_slab() must be called, as if + * a region were just deallocated from the slab. + */ + if (extent_slab_data_get(slab)->nfree == + bin_info->nregs) { + arena_dalloc_bin_slab(tsdn, arena, slab, + bin); + } else { + arena_bin_lower_slab(tsdn, arena, slab, + bin); + } } + return (ret); } - return (ret); + + arena_bin_slabs_full_insert(bin, bin->slabcur); + bin->slabcur = NULL; } - if (run == NULL) + if (slab == NULL) return (NULL); + bin->slabcur = slab; - bin->runcur = run; - - assert(bin->runcur->nfree > 0); + assert(extent_slab_data_get(bin->slabcur)->nfree > 0); - return (arena_run_reg_alloc(tsdn, bin->runcur, bin_info)); + return (arena_slab_reg_alloc(tsdn, slab, bin_info)); } void @@ -2102,13 +1152,14 @@ arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_bin_t *tbin, malloc_mutex_lock(tsdn, &bin->lock); for (i = 0, nfill = (tcache_bin_info[binind].ncached_max >> tbin->lg_fill_div); i < nfill; i++) { - arena_run_t *run; + extent_t *slab; void *ptr; - if ((run = bin->runcur) != NULL && run->nfree > 0) { - ptr = arena_run_reg_alloc(tsdn, run, + if ((slab = bin->slabcur) != NULL && + extent_slab_data_get(slab)->nfree > 0) { + ptr = arena_slab_reg_alloc(tsdn, slab, &arena_bin_info[binind]); } else - ptr = arena_bin_malloc_hard(tsdn, arena, bin); + ptr = arena_bin_malloc_hard(tsdn, arena, bin, binind); if (ptr == NULL) { /* * OOM. tbin->avail isn't yet filled down to its first @@ -2171,17 +1222,18 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) void *ret; arena_bin_t *bin; size_t usize; - arena_run_t *run; + extent_t *slab; assert(binind < NBINS); bin = &arena->bins[binind]; usize = index2size(binind); malloc_mutex_lock(tsdn, &bin->lock); - if ((run = bin->runcur) != NULL && run->nfree > 0) - ret = arena_run_reg_alloc(tsdn, run, &arena_bin_info[binind]); + if ((slab = bin->slabcur) != NULL && extent_slab_data_get(slab)->nfree > + 0) + ret = arena_slab_reg_alloc(tsdn, slab, &arena_bin_info[binind]); else - ret = arena_bin_malloc_hard(tsdn, arena, bin); + ret = arena_bin_malloc_hard(tsdn, arena, bin, binind); if (ret == NULL) { malloc_mutex_unlock(tsdn, &bin->lock); @@ -2242,7 +1294,7 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, if (usize <= SMALL_MAXCLASS && (alignment < PAGE || (alignment == PAGE && (usize & PAGE_MASK) == 0))) { - /* Small; alignment doesn't require special run placement. */ + /* Small; alignment doesn't require special slab placement. */ ret = arena_malloc(tsdn, arena, usize, size2index(usize), zero, tcache, true); } else { @@ -2315,97 +1367,92 @@ arena_dalloc_promoted(tsdn_t *tsdn, extent_t *extent, void *ptr, } static void -arena_dissociate_bin_run(extent_t *extent, arena_run_t *run, arena_bin_t *bin) +arena_dissociate_bin_slab(extent_t *slab, arena_bin_t *bin) { - /* Dissociate run from bin. */ - if (run == bin->runcur) - bin->runcur = NULL; + /* Dissociate slab from bin. */ + if (slab == bin->slabcur) + bin->slabcur = NULL; else { - szind_t binind = arena_bin_index(extent_arena_get(extent), bin); + szind_t binind = extent_slab_data_get(slab)->binind; const arena_bin_info_t *bin_info = &arena_bin_info[binind]; /* * The following block's conditional is necessary because if the - * run only contains one region, then it never gets inserted - * into the non-full runs tree. + * slab only contains one region, then it never gets inserted + * into the non-full slabs heap. */ - if (bin_info->nregs != 1) { - arena_chunk_map_misc_t *miscelm = - arena_run_to_miscelm(extent, run); - - arena_run_heap_remove(&bin->runs, miscelm); - } + if (bin_info->nregs == 1) + arena_bin_slabs_full_remove(slab); + else + arena_bin_slabs_nonfull_remove(bin, slab); } } static void -arena_dalloc_bin_run(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - extent_t *extent, arena_run_t *run, arena_bin_t *bin) +arena_dalloc_bin_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, + arena_bin_t *bin) { - assert(run != bin->runcur); + assert(slab != bin->slabcur); malloc_mutex_unlock(tsdn, &bin->lock); /******************************/ malloc_mutex_lock(tsdn, &arena->lock); - arena_run_dalloc(tsdn, arena, extent, run, true, false, false); + arena_slab_dalloc(tsdn, arena, slab); malloc_mutex_unlock(tsdn, &arena->lock); /****************************/ malloc_mutex_lock(tsdn, &bin->lock); if (config_stats) - bin->stats.curruns--; + bin->stats.curslabs--; } static void -arena_bin_lower_run(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - arena_run_t *run, arena_bin_t *bin) +arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, + arena_bin_t *bin) { + assert(extent_slab_data_get(slab)->nfree > 0); + /* - * Make sure that if bin->runcur is non-NULL, it refers to the lowest - * non-full run. It is okay to NULL runcur out rather than proactively - * keeping it pointing at the lowest non-full run. + * Make sure that if bin->slabcur is non-NULL, it refers to the lowest + * non-full slab. It is okay to NULL slabcur out rather than + * proactively keeping it pointing at the lowest non-full slab. */ - if ((uintptr_t)run < (uintptr_t)bin->runcur) { - /* Switch runcur. */ - if (bin->runcur->nfree > 0) { - arena_bin_runs_insert(bin, iealloc(tsdn, bin->runcur), - bin->runcur); - } - bin->runcur = run; + if (bin->slabcur != NULL && (uintptr_t)extent_addr_get(slab) < + (uintptr_t)extent_addr_get(bin->slabcur)) { + /* Switch slabcur. */ + if (extent_slab_data_get(bin->slabcur)->nfree > 0) + arena_bin_slabs_nonfull_insert(bin, bin->slabcur); + else + arena_bin_slabs_full_insert(bin, bin->slabcur); + bin->slabcur = slab; if (config_stats) - bin->stats.reruns++; + bin->stats.reslabs++; } else - arena_bin_runs_insert(bin, extent, run); + arena_bin_slabs_nonfull_insert(bin, slab); } static void -arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - extent_t *extent, void *ptr, arena_chunk_map_bits_t *bitselm, bool junked) +arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, extent_t *slab, + void *ptr, bool junked) { - size_t pageind, rpages_ind; - arena_run_t *run; - arena_bin_t *bin; - const arena_bin_info_t *bin_info; - szind_t binind; - - pageind = ((uintptr_t)ptr - (uintptr_t)chunk) >> LG_PAGE; - rpages_ind = pageind - arena_mapbits_small_runind_get(chunk, pageind); - run = &arena_miscelm_get_mutable(chunk, rpages_ind)->run; - binind = run->binind; - bin = &arena->bins[binind]; - bin_info = &arena_bin_info[binind]; + arena_slab_data_t *slab_data = extent_slab_data_get(slab); + szind_t binind = slab_data->binind; + arena_bin_t *bin = &arena->bins[binind]; + const arena_bin_info_t *bin_info = &arena_bin_info[binind]; if (!junked && config_fill && unlikely(opt_junk_free)) arena_dalloc_junk_small(ptr, bin_info); - arena_run_reg_dalloc(tsdn, run, extent, ptr); - if (run->nfree == bin_info->nregs) { - arena_dissociate_bin_run(extent, run, bin); - arena_dalloc_bin_run(tsdn, arena, chunk, extent, run, bin); - } else if (run->nfree == 1 && run != bin->runcur) - arena_bin_lower_run(tsdn, arena, extent, run, bin); + arena_slab_reg_dalloc(tsdn, slab, slab_data, ptr); + if (slab_data->nfree == bin_info->nregs) { + arena_dissociate_bin_slab(slab, bin); + arena_dalloc_bin_slab(tsdn, arena, slab, bin); + } else if (slab_data->nfree == 1 && slab != bin->slabcur) { + arena_bin_slabs_full_remove(slab); + arena_bin_lower_slab(tsdn, arena, slab, bin); + } if (config_stats) { bin->stats.ndalloc++; @@ -2414,45 +1461,28 @@ arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, } void -arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, - arena_chunk_t *chunk, extent_t *extent, void *ptr, - arena_chunk_map_bits_t *bitselm) +arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + void *ptr) { - arena_dalloc_bin_locked_impl(tsdn, arena, chunk, extent, ptr, bitselm, - true); + arena_dalloc_bin_locked_impl(tsdn, arena, extent, ptr, true); } static void -arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - extent_t *extent, void *ptr, size_t pageind, arena_chunk_map_bits_t *bitselm) +arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) { - arena_run_t *run; - arena_bin_t *bin; - size_t rpages_ind; + arena_bin_t *bin = &arena->bins[extent_slab_data_get(extent)->binind]; - rpages_ind = pageind - arena_mapbits_small_runind_get(chunk, pageind); - run = &arena_miscelm_get_mutable(chunk, rpages_ind)->run; - bin = &arena->bins[run->binind]; malloc_mutex_lock(tsdn, &bin->lock); - arena_dalloc_bin_locked_impl(tsdn, arena, chunk, extent, ptr, bitselm, - false); + arena_dalloc_bin_locked_impl(tsdn, arena, extent, ptr, false); malloc_mutex_unlock(tsdn, &bin->lock); } void -arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, arena_chunk_t *chunk, - extent_t *extent, void *ptr, size_t pageind) +arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) { - arena_chunk_map_bits_t *bitselm; - if (config_debug) { - /* arena_ptr_small_binind_get() does extra sanity checking. */ - assert(arena_ptr_small_binind_get(tsdn, ptr, - arena_mapbits_get(chunk, pageind)) != BININD_INVALID); - } - bitselm = arena_bitselm_get_mutable(chunk, pageind); - arena_dalloc_bin(tsdn, arena, chunk, extent, ptr, pageind, bitselm); + arena_dalloc_bin(tsdn, arena, extent, ptr); arena_decay_tick(tsdn, arena); } @@ -2682,9 +1712,9 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, bstats[i].nfills += bin->stats.nfills; bstats[i].nflushes += bin->stats.nflushes; } - bstats[i].nruns += bin->stats.nruns; - bstats[i].reruns += bin->stats.reruns; - bstats[i].curruns += bin->stats.curruns; + bstats[i].nslabs += bin->stats.nslabs; + bstats[i].reslabs += bin->stats.reslabs; + bstats[i].curslabs += bin->stats.curslabs; malloc_mutex_unlock(tsdn, &bin->lock); } } @@ -2745,17 +1775,13 @@ arena_new(tsdn_t *tsdn, unsigned ind) arena->dss_prec = chunk_dss_prec_get(tsdn); - ql_new(&arena->achunks); - - arena->spare = NULL; - arena->lg_dirty_mult = arena_lg_dirty_mult_default_get(); arena->purging = false; arena->nactive = 0; arena->ndirty = 0; - qr_new(&arena->runs_dirty, rd_link); - qr_new(&arena->chunks_cache, cc_link); + extent_init(&arena->extents_dirty, arena, NULL, 0, 0, false, false, + false, false); if (opt_purge == purge_mode_decay) arena_decay_init(arena, arena_decay_time_default_get()); @@ -2786,52 +1812,23 @@ arena_new(tsdn_t *tsdn, unsigned ind) if (malloc_mutex_init(&bin->lock, "arena_bin", WITNESS_RANK_ARENA_BIN)) return (NULL); - bin->runcur = NULL; - arena_run_heap_new(&bin->runs); + bin->slabcur = NULL; + extent_heap_new(&bin->slabs_nonfull); + extent_init(&bin->slabs_full, arena, NULL, 0, 0, false, false, + false, false); if (config_stats) memset(&bin->stats, 0, sizeof(malloc_bin_stats_t)); } - for (i = 0; i < NPSIZES; i++) - arena_run_heap_new(&arena->runs_avail[i]); - return (arena); } void arena_boot(void) { - unsigned i; arena_lg_dirty_mult_default_set(opt_lg_dirty_mult); arena_decay_time_default_set(opt_decay_time); - - /* - * Compute the header size such that it is large enough to contain the - * page map. The page map is biased to omit entries for the header - * itself, so some iteration is necessary to compute the map bias. - * - * 1) Compute safe header_size and map_bias values that include enough - * space for an unbiased page map. - * 2) Refine map_bias based on (1) to omit the header pages in the page - * map. The resulting map_bias may be one too small. - * 3) Refine map_bias based on (2). The result will be >= the result - * from (2), and will always be correct. - */ - map_bias = 0; - for (i = 0; i < 3; i++) { - size_t header_size = offsetof(arena_chunk_t, map_bits) + - ((sizeof(arena_chunk_map_bits_t) + - sizeof(arena_chunk_map_misc_t)) * (chunk_npages-map_bias)); - map_bias = (header_size + PAGE_MASK) >> LG_PAGE; - } - assert(map_bias > 0); - - map_misc_offset = offsetof(arena_chunk_t, map_bits) + - sizeof(arena_chunk_map_bits_t) * (chunk_npages-map_bias); - - arena_maxrun = chunksize - (map_bias << LG_PAGE); - assert(arena_maxrun > 0); } void diff --git a/src/base.c b/src/base.c index 134018a8..3807422c 100644 --- a/src/base.c +++ b/src/base.c @@ -74,8 +74,7 @@ base_chunk_alloc(tsdn_t *tsdn, size_t minsize) base_resident += PAGE_CEILING(nsize); } } - extent_init(extent, NULL, addr, csize, 0, true, false, true, true, - false); + extent_init(extent, NULL, addr, csize, 0, true, true, true, false); return (extent); } diff --git a/src/chunk.c b/src/chunk.c index 8c4f741f..e2e9de03 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -558,8 +558,7 @@ chunk_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, extent_dalloc(tsdn, arena, extent); return (NULL); } - extent_init(extent, arena, addr, size, usize, true, false, zero, commit, - slab); + extent_init(extent, arena, addr, size, usize, true, zero, commit, slab); if (pad != 0) extent_addr_randomize(tsdn, extent, alignment); if (chunk_register(tsdn, extent)) { @@ -828,8 +827,8 @@ chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_init(&lead, arena, extent_addr_get(extent), size_a, usize_a, extent_active_get(extent), - extent_dirty_get(extent), extent_zeroed_get(extent), - extent_committed_get(extent), extent_slab_get(extent)); + extent_zeroed_get(extent), extent_committed_get(extent), + extent_slab_get(extent)); if (extent_rtree_acquire(tsdn, &lead, false, true, &lead_elm_a, &lead_elm_b)) @@ -838,8 +837,8 @@ chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) + size_a), size_b, usize_b, extent_active_get(extent), - extent_dirty_get(extent), extent_zeroed_get(extent), - extent_committed_get(extent), extent_slab_get(extent)); + extent_zeroed_get(extent), extent_committed_get(extent), + extent_slab_get(extent)); if (extent_rtree_acquire(tsdn, trail, false, true, &trail_elm_a, &trail_elm_b)) goto label_error_c; diff --git a/src/chunk_dss.c b/src/chunk_dss.c index e92fda72..f890a5cd 100644 --- a/src/chunk_dss.c +++ b/src/chunk_dss.c @@ -121,7 +121,7 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, pad_size = (uintptr_t)ret - (uintptr_t)pad_addr; if (pad_size != 0) { extent_init(pad, arena, pad_addr, pad_size, - pad_size, false, true, false, true, false); + pad_size, false, false, true, false); } dss_next = (void *)((uintptr_t)ret + size); if ((uintptr_t)ret < (uintptr_t)dss_max || diff --git a/src/ctl.c b/src/ctl.c index 26bc1750..34c7e1bd 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -124,7 +124,7 @@ CTL_PROTO(arena_i_chunk_hooks) INDEX_PROTO(arena_i) CTL_PROTO(arenas_bin_i_size) CTL_PROTO(arenas_bin_i_nregs) -CTL_PROTO(arenas_bin_i_run_size) +CTL_PROTO(arenas_bin_i_slab_size) INDEX_PROTO(arenas_bin_i) CTL_PROTO(arenas_hchunk_i_size) INDEX_PROTO(arenas_hchunk_i) @@ -160,9 +160,9 @@ CTL_PROTO(stats_arenas_i_bins_j_nrequests) CTL_PROTO(stats_arenas_i_bins_j_curregs) CTL_PROTO(stats_arenas_i_bins_j_nfills) CTL_PROTO(stats_arenas_i_bins_j_nflushes) -CTL_PROTO(stats_arenas_i_bins_j_nruns) -CTL_PROTO(stats_arenas_i_bins_j_nreruns) -CTL_PROTO(stats_arenas_i_bins_j_curruns) +CTL_PROTO(stats_arenas_i_bins_j_nslabs) +CTL_PROTO(stats_arenas_i_bins_j_nreslabs) +CTL_PROTO(stats_arenas_i_bins_j_curslabs) INDEX_PROTO(stats_arenas_i_bins_j) CTL_PROTO(stats_arenas_i_hchunks_j_nmalloc) CTL_PROTO(stats_arenas_i_hchunks_j_ndalloc) @@ -300,7 +300,7 @@ static const ctl_indexed_node_t arena_node[] = { static const ctl_named_node_t arenas_bin_i_node[] = { {NAME("size"), CTL(arenas_bin_i_size)}, {NAME("nregs"), CTL(arenas_bin_i_nregs)}, - {NAME("run_size"), CTL(arenas_bin_i_run_size)} + {NAME("slab_size"), CTL(arenas_bin_i_slab_size)} }; static const ctl_named_node_t super_arenas_bin_i_node[] = { {NAME(""), CHILD(named, arenas_bin_i)} @@ -373,9 +373,9 @@ static const ctl_named_node_t stats_arenas_i_bins_j_node[] = { {NAME("curregs"), CTL(stats_arenas_i_bins_j_curregs)}, {NAME("nfills"), CTL(stats_arenas_i_bins_j_nfills)}, {NAME("nflushes"), CTL(stats_arenas_i_bins_j_nflushes)}, - {NAME("nruns"), CTL(stats_arenas_i_bins_j_nruns)}, - {NAME("nreruns"), CTL(stats_arenas_i_bins_j_nreruns)}, - {NAME("curruns"), CTL(stats_arenas_i_bins_j_curruns)} + {NAME("nslabs"), CTL(stats_arenas_i_bins_j_nslabs)}, + {NAME("nreslabs"), CTL(stats_arenas_i_bins_j_nreslabs)}, + {NAME("curslabs"), CTL(stats_arenas_i_bins_j_curslabs)} }; static const ctl_named_node_t super_stats_arenas_i_bins_j_node[] = { {NAME(""), CHILD(named, stats_arenas_i_bins_j)} @@ -549,9 +549,10 @@ ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats) sstats->bstats[i].nflushes += astats->bstats[i].nflushes; } - sstats->bstats[i].nruns += astats->bstats[i].nruns; - sstats->bstats[i].reruns += astats->bstats[i].reruns; - sstats->bstats[i].curruns += astats->bstats[i].curruns; + sstats->bstats[i].nslabs += astats->bstats[i].nslabs; + sstats->bstats[i].reslabs += astats->bstats[i].reslabs; + sstats->bstats[i].curslabs += + astats->bstats[i].curslabs; } for (i = 0; i < NSIZES - NBINS; i++) { @@ -1801,7 +1802,7 @@ CTL_RO_NL_GEN(arenas_nbins, NBINS, unsigned) CTL_RO_NL_CGEN(config_tcache, arenas_nhbins, nhbins, unsigned) CTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[2]].reg_size, size_t) CTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t) -CTL_RO_NL_GEN(arenas_bin_i_run_size, arena_bin_info[mib[2]].run_size, size_t) +CTL_RO_NL_GEN(arenas_bin_i_slab_size, arena_bin_info[mib[2]].slab_size, size_t) static const ctl_named_node_t * arenas_bin_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { @@ -2032,12 +2033,12 @@ CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nfills, ctl_stats.arenas[mib[2]].bstats[mib[4]].nfills, uint64_t) CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nflushes, ctl_stats.arenas[mib[2]].bstats[mib[4]].nflushes, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nruns, - ctl_stats.arenas[mib[2]].bstats[mib[4]].nruns, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreruns, - ctl_stats.arenas[mib[2]].bstats[mib[4]].reruns, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curruns, - ctl_stats.arenas[mib[2]].bstats[mib[4]].curruns, size_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nslabs, + ctl_stats.arenas[mib[2]].bstats[mib[4]].nslabs, uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreslabs, + ctl_stats.arenas[mib[2]].bstats[mib[4]].reslabs, uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curslabs, + ctl_stats.arenas[mib[2]].bstats[mib[4]].curslabs, size_t) static const ctl_named_node_t * stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, diff --git a/src/huge.c b/src/huge.c index 5375b59f..5f758140 100644 --- a/src/huge.c +++ b/src/huge.c @@ -153,8 +153,8 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, * Zero the trailing bytes of the original allocation's * last page, since they are in an indeterminate state. * There will always be trailing bytes, because ptr's - * offset from the beginning of the run is a multiple of - * CACHELINE in [0 .. PAGE). + * offset from the beginning of the extent is a multiple + * of CACHELINE in [0 .. PAGE). */ void *zbase = (void *) ((uintptr_t)extent_addr_get(extent) + oldusize); diff --git a/src/jemalloc.c b/src/jemalloc.c index 9f8bd01e..429667f6 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1707,28 +1707,30 @@ irealloc_prof_sample(tsd_t *tsd, extent_t *extent, void *old_ptr, } JEMALLOC_ALWAYS_INLINE_C void * -irealloc_prof(tsd_t *tsd, extent_t *extent, void *old_ptr, size_t old_usize, +irealloc_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, size_t usize) { void *p; - extent_t *e; + extent_t *extent; bool prof_active; prof_tctx_t *old_tctx, *tctx; prof_active = prof_active_get_unlocked(); - old_tctx = prof_tctx_get(tsd_tsdn(tsd), extent, old_ptr); + old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_extent, old_ptr); tctx = prof_alloc_prep(tsd, usize, prof_active, true); if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { - p = irealloc_prof_sample(tsd, extent, old_ptr, old_usize, usize, - tctx); - } else - p = iralloc(tsd, extent, old_ptr, old_usize, usize, 0, false); + p = irealloc_prof_sample(tsd, old_extent, old_ptr, old_usize, + usize, tctx); + } else { + p = iralloc(tsd, old_extent, old_ptr, old_usize, usize, 0, + false); + } if (unlikely(p == NULL)) { prof_alloc_rollback(tsd, tctx, true); return (NULL); } - e = (p == old_ptr) ? extent : iealloc(tsd_tsdn(tsd), p); - prof_realloc(tsd, e, p, usize, tctx, prof_active, true, + extent = (p == old_ptr) ? old_extent : iealloc(tsd_tsdn(tsd), p); + prof_realloc(tsd, extent, p, usize, tctx, prof_active, true, old_extent, old_ptr, old_usize, old_tctx); return (p); @@ -2146,24 +2148,24 @@ irallocx_prof_sample(tsdn_t *tsdn, extent_t *extent, void *old_ptr, } JEMALLOC_ALWAYS_INLINE_C void * -irallocx_prof(tsd_t *tsd, extent_t *extent, void *old_ptr, size_t old_usize, +irallocx_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, size_t size, size_t alignment, size_t *usize, bool zero, tcache_t *tcache, arena_t *arena) { void *p; - extent_t *e; + extent_t *extent; bool prof_active; prof_tctx_t *old_tctx, *tctx; prof_active = prof_active_get_unlocked(); - old_tctx = prof_tctx_get(tsd_tsdn(tsd), extent, old_ptr); + old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_extent, old_ptr); tctx = prof_alloc_prep(tsd, *usize, prof_active, true); if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { - p = irallocx_prof_sample(tsd_tsdn(tsd), extent, old_ptr, + p = irallocx_prof_sample(tsd_tsdn(tsd), old_extent, old_ptr, old_usize, *usize, alignment, zero, tcache, arena, tctx); } else { - p = iralloct(tsd_tsdn(tsd), extent, old_ptr, old_usize, size, - alignment, zero, tcache, arena); + p = iralloct(tsd_tsdn(tsd), old_extent, old_ptr, old_usize, + size, alignment, zero, tcache, arena); } if (unlikely(p == NULL)) { prof_alloc_rollback(tsd, tctx, true); @@ -2179,12 +2181,12 @@ irallocx_prof(tsd_t *tsd, extent_t *extent, void *old_ptr, size_t old_usize, * be the same as the current usize because of in-place large * reallocation. Therefore, query the actual value of usize. */ - e = extent; - *usize = isalloc(tsd_tsdn(tsd), e, p); + extent = old_extent; + *usize = isalloc(tsd_tsdn(tsd), extent, p); } else - e = iealloc(tsd_tsdn(tsd), p); - prof_realloc(tsd, e, p, *usize, tctx, prof_active, true, old_ptr, - old_usize, old_tctx); + extent = iealloc(tsd_tsdn(tsd), p); + prof_realloc(tsd, extent, p, *usize, tctx, prof_active, true, + old_extent, old_ptr, old_usize, old_tctx); return (p); } @@ -2338,8 +2340,8 @@ ixallocx_prof(tsd_t *tsd, extent_t *extent, void *ptr, size_t old_usize, prof_alloc_rollback(tsd, tctx, false); return (usize); } - prof_realloc(tsd, extent, ptr, usize, tctx, prof_active, false, ptr, - old_usize, old_tctx); + prof_realloc(tsd, extent, ptr, usize, tctx, prof_active, false, extent, + ptr, old_usize, old_tctx); return (usize); } diff --git a/src/stats.c b/src/stats.c index 4dc48d5b..599e377d 100644 --- a/src/stats.c +++ b/src/stats.c @@ -58,29 +58,29 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, if (config_tcache) { malloc_cprintf(write_cb, cbopaque, "bins: size ind allocated nmalloc" - " ndalloc nrequests curregs curruns regs" - " pgs util nfills nflushes newruns" - " reruns\n"); + " ndalloc nrequests curregs curslabs regs" + " pgs util nfills nflushes newslabs" + " reslabs\n"); } else { malloc_cprintf(write_cb, cbopaque, "bins: size ind allocated nmalloc" - " ndalloc nrequests curregs curruns regs" - " pgs util newruns reruns\n"); + " ndalloc nrequests curregs curslabs regs" + " pgs util newslabs reslabs\n"); } CTL_GET("arenas.nbins", &nbins, unsigned); for (j = 0, in_gap = false; j < nbins; j++) { - uint64_t nruns; + uint64_t nslabs; - CTL_M2_M4_GET("stats.arenas.0.bins.0.nruns", i, j, &nruns, + CTL_M2_M4_GET("stats.arenas.0.bins.0.nslabs", i, j, &nslabs, uint64_t); - if (nruns == 0) + if (nslabs == 0) in_gap = true; else { - size_t reg_size, run_size, curregs, availregs, milli; - size_t curruns; + size_t reg_size, slab_size, curregs, availregs, milli; + size_t curslabs; uint32_t nregs; uint64_t nmalloc, ndalloc, nrequests, nfills, nflushes; - uint64_t reruns; + uint64_t reslabs; char util[6]; /* "x.yyy". */ if (in_gap) { @@ -90,7 +90,7 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, } CTL_M2_GET("arenas.bin.0.size", j, ®_size, size_t); CTL_M2_GET("arenas.bin.0.nregs", j, &nregs, uint32_t); - CTL_M2_GET("arenas.bin.0.run_size", j, &run_size, + CTL_M2_GET("arenas.bin.0.slab_size", j, &slab_size, size_t); CTL_M2_M4_GET("stats.arenas.0.bins.0.nmalloc", i, j, &nmalloc, uint64_t); @@ -106,12 +106,12 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, CTL_M2_M4_GET("stats.arenas.0.bins.0.nflushes", i, j, &nflushes, uint64_t); } - CTL_M2_M4_GET("stats.arenas.0.bins.0.nreruns", i, j, - &reruns, uint64_t); - CTL_M2_M4_GET("stats.arenas.0.bins.0.curruns", i, j, - &curruns, size_t); + CTL_M2_M4_GET("stats.arenas.0.bins.0.nreslabs", i, j, + &reslabs, uint64_t); + CTL_M2_M4_GET("stats.arenas.0.bins.0.curslabs", i, j, + &curslabs, size_t); - availregs = nregs * curruns; + availregs = nregs * curslabs; milli = (availregs != 0) ? (1000 * curregs) / availregs : 1000; assert(milli <= 1000); @@ -134,9 +134,9 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, " %12zu %4u %3zu %-5s %12"FMTu64 " %12"FMTu64" %12"FMTu64" %12"FMTu64"\n", reg_size, j, curregs * reg_size, nmalloc, - ndalloc, nrequests, curregs, curruns, nregs, - run_size / page, util, nfills, nflushes, - nruns, reruns); + ndalloc, nrequests, curregs, curslabs, + nregs, slab_size / page, util, nfills, + nflushes, nslabs, reslabs); } else { malloc_cprintf(write_cb, cbopaque, "%20zu %3u %12zu %12"FMTu64 @@ -144,8 +144,9 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, " %12zu %4u %3zu %-5s %12"FMTu64 " %12"FMTu64"\n", reg_size, j, curregs * reg_size, nmalloc, - ndalloc, nrequests, curregs, curruns, nregs, - run_size / page, util, nruns, reruns); + ndalloc, nrequests, curregs, curslabs, + nregs, slab_size / page, util, nslabs, + reslabs); } } } diff --git a/src/tcache.c b/src/tcache.c index 41074d34..02015227 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -127,14 +127,8 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, extent = iealloc(tsd_tsdn(tsd), ptr); if (extent_arena_get(extent) == bin_arena) { - arena_chunk_t *chunk = - (arena_chunk_t *)extent_base_get(extent); - size_t pageind = ((uintptr_t)ptr - - (uintptr_t)chunk) >> LG_PAGE; - arena_chunk_map_bits_t *bitselm = - arena_bitselm_get_mutable(chunk, pageind); arena_dalloc_bin_junked_locked(tsd_tsdn(tsd), - bin_arena, chunk, extent, ptr, bitselm); + bin_arena, extent, ptr); } else { /* * This object was allocated via a different diff --git a/test/unit/extent_quantize.c b/test/unit/extent_quantize.c index 98c9fde4..a165aece 100644 --- a/test/unit/extent_quantize.c +++ b/test/unit/extent_quantize.c @@ -16,7 +16,7 @@ TEST_BEGIN(test_small_extent_size) assert_d_eq(mallctl("arenas.nbins", &nbins, &sz, NULL, 0), 0, "Unexpected mallctl failure"); - assert_d_eq(mallctlnametomib("arenas.bin.0.run_size", mib, &miblen), 0, + assert_d_eq(mallctlnametomib("arenas.bin.0.slab_size", mib, &miblen), 0, "Unexpected mallctlnametomib failure"); for (i = 0; i < nbins; i++) { mib[2] = i; @@ -71,12 +71,12 @@ TEST_BEGIN(test_huge_extent_size) ceil = extent_size_quantize_ceil(extent_size); assert_zu_eq(extent_size, floor, - "Large run quantization should be a no-op for precise " - "size (lextent_size=%zu, extent_size=%zu)", lextent_size, + "Extent quantization should be a no-op for precise size " + "(lextent_size=%zu, extent_size=%zu)", lextent_size, extent_size); assert_zu_eq(extent_size, ceil, - "Large run quantization should be a no-op for precise " - "size (lextent_size=%zu, extent_size=%zu)", lextent_size, + "Extent quantization should be a no-op for precise size " + "(lextent_size=%zu, extent_size=%zu)", lextent_size, extent_size); if (i > 0) { diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 9ba730a6..872aeaa0 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -615,7 +615,8 @@ TEST_BEGIN(test_arenas_bin_constants) TEST_ARENAS_BIN_CONSTANT(size_t, size, arena_bin_info[0].reg_size); TEST_ARENAS_BIN_CONSTANT(uint32_t, nregs, arena_bin_info[0].nregs); - TEST_ARENAS_BIN_CONSTANT(size_t, run_size, arena_bin_info[0].run_size); + TEST_ARENAS_BIN_CONSTANT(size_t, slab_size, + arena_bin_info[0].slab_size); #undef TEST_ARENAS_BIN_CONSTANT } diff --git a/test/unit/stats.c b/test/unit/stats.c index b0e318a5..f524c005 100644 --- a/test/unit/stats.c +++ b/test/unit/stats.c @@ -229,9 +229,9 @@ TEST_BEGIN(test_stats_arenas_bins) { unsigned arena; void *p; - size_t sz, curruns, curregs; + size_t sz, curslabs, curregs; uint64_t epoch, nmalloc, ndalloc, nrequests, nfills, nflushes; - uint64_t nruns, nreruns; + uint64_t nslabs, nreslabs; int expected = config_stats ? 0 : ENOENT; arena = 0; @@ -266,12 +266,12 @@ TEST_BEGIN(test_stats_arenas_bins) NULL, 0), config_tcache ? expected : ENOENT, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.bins.0.nruns", &nruns, &sz, + assert_d_eq(mallctl("stats.arenas.0.bins.0.nslabs", &nslabs, &sz, NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.bins.0.nreruns", &nreruns, &sz, + assert_d_eq(mallctl("stats.arenas.0.bins.0.nreslabs", &nreslabs, &sz, NULL, 0), expected, "Unexpected mallctl() result"); sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.bins.0.curruns", &curruns, &sz, + assert_d_eq(mallctl("stats.arenas.0.bins.0.curslabs", &curslabs, &sz, NULL, 0), expected, "Unexpected mallctl() result"); if (config_stats) { @@ -289,10 +289,10 @@ TEST_BEGIN(test_stats_arenas_bins) assert_u64_gt(nflushes, 0, "At least one flush should have occurred"); } - assert_u64_gt(nruns, 0, - "At least one run should have been allocated"); - assert_zu_gt(curruns, 0, - "At least one run should be currently allocated"); + assert_u64_gt(nslabs, 0, + "At least one slab should have been allocated"); + assert_zu_gt(curslabs, 0, + "At least one slab should be currently allocated"); } dallocx(p, 0); -- GitLab From 714d1640f30726a21898b34ac64b8f2fddb502c7 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 31 May 2016 14:14:03 -0700 Subject: [PATCH 044/544] Update private symbols. --- include/jemalloc/internal/private_symbols.txt | 30 ++++++++++++------- src/huge.c | 4 +-- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 676c2431..b8ed4341 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -19,7 +19,6 @@ arena_chunk_ralloc_huge_expand arena_chunk_ralloc_huge_shrink arena_cleanup arena_dalloc -arena_dalloc_bin arena_dalloc_bin_junked_locked arena_dalloc_junk_small arena_dalloc_promoted @@ -66,7 +65,6 @@ arena_prof_tctx_reset arena_prof_tctx_set arena_purge arena_ralloc -arena_ralloc_junk_large arena_ralloc_no_move arena_reset arena_salloc @@ -181,6 +179,12 @@ extent_before_get extent_committed_get extent_committed_set extent_dalloc +extent_heap_empty +extent_heap_first +extent_heap_insert +extent_heap_new +extent_heap_remove +extent_heap_remove_first extent_init extent_last_get extent_past_get @@ -190,15 +194,15 @@ extent_retained_get extent_ring_insert extent_ring_remove extent_size_get -extent_size_set extent_size_quantize_ceil extent_size_quantize_floor +extent_size_set extent_slab_data_get extent_slab_data_get_const extent_slab_get extent_slab_set -extent_slab_data_get extent_usize_get +extent_usize_set extent_zeroed_get extent_zeroed_set ffs_llu @@ -333,6 +337,7 @@ pages_unmap pind2sz pind2sz_compute pind2sz_lookup +pind2sz_tab pow2_ceil_u32 pow2_ceil_u64 pow2_ceil_zu @@ -396,10 +401,6 @@ rtree_child_read_hard rtree_child_tryread rtree_clear rtree_delete -rtree_new -rtree_node_alloc -rtree_node_dalloc -rtree_node_valid rtree_elm_acquire rtree_elm_lookup rtree_elm_read @@ -411,6 +412,10 @@ rtree_elm_witness_release rtree_elm_witnesses_cleanup rtree_elm_write rtree_elm_write_acquired +rtree_new +rtree_node_alloc +rtree_node_dalloc +rtree_node_valid rtree_read rtree_start_level rtree_subkey @@ -433,17 +438,17 @@ stats_cactive_get stats_cactive_sub stats_print tcache_alloc_easy -tcache_alloc_large +tcache_alloc_huge tcache_alloc_small tcache_alloc_small_hard tcache_arena_reassociate -tcache_bin_flush_large +tcache_bin_flush_huge tcache_bin_flush_small tcache_bin_info tcache_boot tcache_cleanup tcache_create -tcache_dalloc_large +tcache_dalloc_huge tcache_dalloc_small tcache_enabled_cleanup tcache_enabled_get @@ -502,6 +507,9 @@ tsd_nominal tsd_prof_tdata_get tsd_prof_tdata_set tsd_prof_tdatap_get +tsd_rtree_elm_witnesses_get +tsd_rtree_elm_witnesses_set +tsd_rtree_elm_witnessesp_get tsd_set tsd_tcache_enabled_get tsd_tcache_enabled_set diff --git a/src/huge.c b/src/huge.c index 5f758140..8aa3dfd2 100644 --- a/src/huge.c +++ b/src/huge.c @@ -62,7 +62,7 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, #ifdef JEMALLOC_JET #undef huge_dalloc_junk -#define huge_dalloc_junk JEMALLOC_N(huge_dalloc_junk_impl) +#define huge_dalloc_junk JEMALLOC_N(n_huge_dalloc_junk) #endif void huge_dalloc_junk(void *ptr, size_t usize) @@ -73,7 +73,7 @@ huge_dalloc_junk(void *ptr, size_t usize) #ifdef JEMALLOC_JET #undef huge_dalloc_junk #define huge_dalloc_junk JEMALLOC_N(huge_dalloc_junk) -huge_dalloc_junk_t *huge_dalloc_junk = JEMALLOC_N(huge_dalloc_junk_impl); +huge_dalloc_junk_t *huge_dalloc_junk = JEMALLOC_N(n_huge_dalloc_junk); #endif static void -- GitLab From 7d63fed0fd0bb10bd250e40c35558f67f26469cd Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 31 May 2016 14:50:21 -0700 Subject: [PATCH 045/544] Rename huge to large. --- Makefile.in | 2 +- doc/jemalloc.xml.in | 74 ++------- include/jemalloc/internal/arena.h | 36 ++--- include/jemalloc/internal/ctl.h | 2 +- include/jemalloc/internal/extent.h | 4 +- include/jemalloc/internal/huge.h | 37 ----- .../jemalloc/internal/jemalloc_internal.h.in | 26 ++-- include/jemalloc/internal/large.h | 37 +++++ include/jemalloc/internal/private_symbols.txt | 36 ++--- include/jemalloc/internal/size_classes.sh | 8 +- include/jemalloc/internal/stats.h | 18 +-- include/jemalloc/internal/tcache.h | 24 +-- include/jemalloc/internal/witness.h | 2 +- .../projects/vc2015/jemalloc/jemalloc.vcxproj | 4 +- .../vc2015/jemalloc/jemalloc.vcxproj.filters | 10 +- src/arena.c | 143 ++++++++--------- src/chunk_dss.c | 2 +- src/ckh.c | 6 +- src/ctl.c | 146 +++++++++--------- src/extent.c | 4 +- src/jemalloc.c | 32 ++-- src/{huge.c => large.c} | 119 +++++++------- src/stats.c | 71 ++++----- src/tcache.c | 28 ++-- test/integration/chunk.c | 28 ++-- test/integration/mallocx.c | 24 +-- test/integration/overflow.c | 8 +- test/integration/rallocx.c | 16 +- test/integration/xallocx.c | 104 ++++++------- test/unit/arena_reset.c | 20 +-- test/unit/decay.c | 42 ++--- test/unit/extent_quantize.c | 16 +- test/unit/junk.c | 16 +- test/unit/mallctl.c | 8 +- test/unit/size_classes.c | 8 +- test/unit/stats.c | 48 +++--- test/unit/zero.c | 4 +- 37 files changed, 587 insertions(+), 626 deletions(-) delete mode 100644 include/jemalloc/internal/huge.h create mode 100644 include/jemalloc/internal/large.h rename src/{huge.c => large.c} (66%) diff --git a/Makefile.in b/Makefile.in index 2e9bbbc2..f90e2a4f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -88,7 +88,7 @@ C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/ctl.c \ $(srcroot)src/extent.c \ $(srcroot)src/hash.c \ - $(srcroot)src/huge.c \ + $(srcroot)src/large.c \ $(srcroot)src/mb.c \ $(srcroot)src/mutex.c \ $(srcroot)src/nstime.c \ diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 923097d4..7613c24c 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -1872,22 +1872,22 @@ typedef struct { Number of bytes per slab. - + - arenas.nhchunks + arenas.nlextents (unsigned) r- - Total number of huge size classes. + Total number of large size classes. - + - arenas.hchunk.<i>.size + arenas.lextent.<i>.size (size_t) r- - Maximum size supported by this huge size + Maximum size supported by this large size class. @@ -2361,50 +2361,6 @@ typedef struct { - - - stats.arenas.<i>.huge.allocated - (size_t) - r- - [] - - Number of bytes currently allocated by huge objects. - - - - - - stats.arenas.<i>.huge.nmalloc - (uint64_t) - r- - [] - - Cumulative number of huge allocation requests served - directly by the arena. - - - - - stats.arenas.<i>.huge.ndalloc - (uint64_t) - r- - [] - - Cumulative number of huge deallocation requests served - directly by the arena. - - - - - stats.arenas.<i>.huge.nrequests - (uint64_t) - r- - [] - - Cumulative number of huge allocation requests. - - - stats.arenas.<i>.bins.<j>.nmalloc @@ -2500,9 +2456,9 @@ typedef struct { Current number of slabs. - + - stats.arenas.<i>.hchunks.<j>.nmalloc + stats.arenas.<i>.lextents.<j>.nmalloc (uint64_t) r- [] @@ -2511,9 +2467,9 @@ typedef struct { class served directly by the arena. - + - stats.arenas.<i>.hchunks.<j>.ndalloc + stats.arenas.<i>.lextents.<j>.ndalloc (uint64_t) r- [] @@ -2522,9 +2478,9 @@ typedef struct { size class served directly by the arena. - + - stats.arenas.<i>.hchunks.<j>.nrequests + stats.arenas.<i>.lextents.<j>.nrequests (uint64_t) r- [] @@ -2533,14 +2489,14 @@ typedef struct { class. - + - stats.arenas.<i>.hchunks.<j>.curhchunks + stats.arenas.<i>.lextents.<j>.curlextents (size_t) r- [] - Current number of huge allocations for this size class. + Current number of large allocations for this size class. diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index d66548f2..56f78571 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -229,10 +229,10 @@ struct arena_s { */ size_t decay_backlog[SMOOTHSTEP_NSTEPS]; - /* Extant huge allocations. */ - ql_head(extent_t) huge; - /* Synchronizes all huge allocation/update/deallocation. */ - malloc_mutex_t huge_mtx; + /* Extant large allocations. */ + ql_head(extent_t) large; + /* Synchronizes all large allocation/update/deallocation. */ + malloc_mutex_t large_mtx; /* * Heaps of chunks that were previously allocated. These are used when @@ -287,13 +287,13 @@ void arena_chunk_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache); void arena_chunk_cache_maybe_remove(arena_t *arena, extent_t *extent, bool cache); -extent_t *arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, +extent_t *arena_chunk_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero); -void arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, extent_t *extent, +void arena_chunk_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, bool locked); -void arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, +void arena_chunk_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); -void arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, +void arena_chunk_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); ssize_t arena_lg_dirty_mult_get(tsdn_t *tsdn, arena_t *arena); bool arena_lg_dirty_mult_set(tsdn_t *tsdn, arena_t *arena, @@ -341,7 +341,7 @@ void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *lg_dirty_mult, ssize_t *decay_time, size_t *nactive, size_t *ndirty, arena_stats_t *astats, - malloc_bin_stats_t *bstats, malloc_huge_stats_t *hstats); + malloc_bin_stats_t *bstats, malloc_large_stats_t *lstats); unsigned arena_nthreads_get(arena_t *arena, bool internal); void arena_nthreads_inc(arena_t *arena, bool internal); void arena_nthreads_dec(arena_t *arena, bool internal); @@ -470,7 +470,7 @@ arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) assert(ptr != NULL); if (unlikely(!extent_slab_get(extent))) - return (huge_prof_tctx_get(tsdn, extent)); + return (large_prof_tctx_get(tsdn, extent)); return ((prof_tctx_t *)(uintptr_t)1U); } @@ -483,7 +483,7 @@ arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, assert(ptr != NULL); if (unlikely(!extent_slab_get(extent))) - huge_prof_tctx_set(tsdn, extent, tctx); + large_prof_tctx_set(tsdn, extent, tctx); } JEMALLOC_INLINE void @@ -495,7 +495,7 @@ arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, assert(ptr != NULL); assert(!extent_slab_get(extent)); - huge_prof_tctx_reset(tsdn, extent); + large_prof_tctx_reset(tsdn, extent); } JEMALLOC_ALWAYS_INLINE void @@ -535,7 +535,7 @@ arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, tcache, size, ind, zero, slow_path)); } if (likely(size <= tcache_maxclass)) { - return (tcache_alloc_huge(tsdn_tsd(tsdn), arena, + return (tcache_alloc_large(tsdn_tsd(tsdn), arena, tcache, size, ind, zero, slow_path)); } /* (size > tcache_maxclass) case falls through. */ @@ -563,7 +563,7 @@ arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) if (likely(extent_slab_get(extent))) ret = index2size(extent_slab_data_get_const(extent)->binind); else - ret = huge_salloc(tsdn, extent); + ret = large_salloc(tsdn, extent); return (ret); } @@ -594,11 +594,11 @@ arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, arena_dalloc_promoted(tsdn, extent, ptr, tcache, slow_path); } else { - tcache_dalloc_huge(tsdn_tsd(tsdn), tcache, + tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, usize, slow_path); } } else - huge_dalloc(tsdn, extent); + large_dalloc(tsdn, extent); } } @@ -627,11 +627,11 @@ arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, arena_dalloc_promoted(tsdn, extent, ptr, tcache, slow_path); } else { - tcache_dalloc_huge(tsdn_tsd(tsdn), tcache, ptr, + tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, size, slow_path); } } else - huge_dalloc(tsdn, extent); + large_dalloc(tsdn, extent); } } # endif /* JEMALLOC_ARENA_INLINE_B */ diff --git a/include/jemalloc/internal/ctl.h b/include/jemalloc/internal/ctl.h index 00deeb8a..3fbac205 100644 --- a/include/jemalloc/internal/ctl.h +++ b/include/jemalloc/internal/ctl.h @@ -51,7 +51,7 @@ struct ctl_arena_stats_s { uint64_t nrequests_small; malloc_bin_stats_t bstats[NBINS]; - malloc_huge_stats_t hstats[NSIZES - NBINS]; + malloc_large_stats_t lstats[NSIZES - NBINS]; }; struct ctl_stats_s { diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index bfe61811..cf717d9e 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -51,7 +51,7 @@ struct extent_s { /* Small region slab metadata. */ arena_slab_data_t e_slab_data; - /* Profile counters, used for huge objects. */ + /* Profile counters, used for large objects. */ union { void *e_prof_tctx_pun; prof_tctx_t *e_prof_tctx; @@ -67,7 +67,7 @@ struct extent_s { /* Linkage for per size class address-ordered heaps. */ phn(extent_t) ph_link; - /* Linkage for arena's huge and extent_cache lists. */ + /* Linkage for arena's large and extent_cache lists. */ ql_elm(extent_t) ql_link; }; }; diff --git a/include/jemalloc/internal/huge.h b/include/jemalloc/internal/huge.h deleted file mode 100644 index 836f1b50..00000000 --- a/include/jemalloc/internal/huge.h +++ /dev/null @@ -1,37 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -void *huge_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero); -void *huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, - size_t alignment, bool zero); -bool huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, - size_t usize_max, bool zero); -void *huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - size_t usize, size_t alignment, bool zero, tcache_t *tcache); -#ifdef JEMALLOC_JET -typedef void (huge_dalloc_junk_t)(void *, size_t); -extern huge_dalloc_junk_t *huge_dalloc_junk; -#else -void huge_dalloc_junk(void *ptr, size_t usize); -#endif -void huge_dalloc_junked_locked(tsdn_t *tsdn, extent_t *extent); -void huge_dalloc(tsdn_t *tsdn, extent_t *extent); -size_t huge_salloc(tsdn_t *tsdn, const extent_t *extent); -prof_tctx_t *huge_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent); -void huge_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx); -void huge_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index f4d26beb..58a18ae5 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -362,7 +362,7 @@ typedef unsigned szind_t; #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/pages.h" #include "jemalloc/internal/chunk.h" -#include "jemalloc/internal/huge.h" +#include "jemalloc/internal/large.h" #include "jemalloc/internal/tcache.h" #include "jemalloc/internal/hash.h" #include "jemalloc/internal/prof.h" @@ -396,7 +396,7 @@ typedef unsigned szind_t; #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/pages.h" #include "jemalloc/internal/chunk.h" -#include "jemalloc/internal/huge.h" +#include "jemalloc/internal/large.h" #include "jemalloc/internal/tcache.h" #include "jemalloc/internal/hash.h" #include "jemalloc/internal/prof.h" @@ -486,7 +486,7 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/pages.h" #include "jemalloc/internal/chunk.h" -#include "jemalloc/internal/huge.h" +#include "jemalloc/internal/large.h" #include "jemalloc/internal/tcache.h" #include "jemalloc/internal/hash.h" #include "jemalloc/internal/prof.h" @@ -515,7 +515,7 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/pages.h" #include "jemalloc/internal/chunk.h" -#include "jemalloc/internal/huge.h" +#include "jemalloc/internal/large.h" #ifndef JEMALLOC_ENABLE_INLINE pszind_t psz2ind(size_t psz); @@ -547,7 +547,7 @@ JEMALLOC_INLINE pszind_t psz2ind(size_t psz) { - if (unlikely(psz > HUGE_MAXCLASS)) + if (unlikely(psz > LARGE_MAXCLASS)) return (NPSIZES); { pszind_t x = lg_floor((psz<<1)-1); @@ -608,7 +608,7 @@ JEMALLOC_INLINE size_t psz2u(size_t psz) { - if (unlikely(psz > HUGE_MAXCLASS)) + if (unlikely(psz > LARGE_MAXCLASS)) return (0); { size_t x = lg_floor((psz<<1)-1); @@ -625,7 +625,7 @@ JEMALLOC_INLINE szind_t size2index_compute(size_t size) { - if (unlikely(size > HUGE_MAXCLASS)) + if (unlikely(size > LARGE_MAXCLASS)) return (NSIZES); #if (NTBINS != 0) if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { @@ -721,7 +721,7 @@ JEMALLOC_ALWAYS_INLINE size_t s2u_compute(size_t size) { - if (unlikely(size > HUGE_MAXCLASS)) + if (unlikely(size > LARGE_MAXCLASS)) return (0); #if (NTBINS > 0) if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { @@ -797,9 +797,9 @@ sa2u(size_t size, size_t alignment) return (usize); } - /* Huge size class. Beware of overflow. */ + /* Large size class. Beware of overflow. */ - if (unlikely(alignment > HUGE_MAXCLASS)) + if (unlikely(alignment > LARGE_MAXCLASS)) return (0); /* Make sure result is a large size class. */ @@ -814,7 +814,7 @@ sa2u(size_t size, size_t alignment) } /* - * Calculate the multi-page mapping that huge_palloc() would need in + * Calculate the multi-page mapping that large_palloc() would need in * order to guarantee the alignment. */ if (usize + large_pad + PAGE_CEILING(alignment) < usize) { @@ -1113,7 +1113,7 @@ iralloct_realign(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t usize, copysize; usize = sa2u(size + extra, alignment); - if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) return (NULL); p = ipalloct(tsdn, usize, alignment, zero, tcache, arena); if (p == NULL) { @@ -1121,7 +1121,7 @@ iralloct_realign(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, return (NULL); /* Try again, without extra this time. */ usize = sa2u(size, alignment); - if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) return (NULL); p = ipalloct(tsdn, usize, alignment, zero, tcache, arena); if (p == NULL) diff --git a/include/jemalloc/internal/large.h b/include/jemalloc/internal/large.h new file mode 100644 index 00000000..afaa6c3c --- /dev/null +++ b/include/jemalloc/internal/large.h @@ -0,0 +1,37 @@ +/******************************************************************************/ +#ifdef JEMALLOC_H_TYPES + +#endif /* JEMALLOC_H_TYPES */ +/******************************************************************************/ +#ifdef JEMALLOC_H_STRUCTS + +#endif /* JEMALLOC_H_STRUCTS */ +/******************************************************************************/ +#ifdef JEMALLOC_H_EXTERNS + +void *large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero); +void *large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, + size_t alignment, bool zero); +bool large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, + size_t usize_max, bool zero); +void *large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + size_t usize, size_t alignment, bool zero, tcache_t *tcache); +#ifdef JEMALLOC_JET +typedef void (large_dalloc_junk_t)(void *, size_t); +extern large_dalloc_junk_t *large_dalloc_junk; +#else +void large_dalloc_junk(void *ptr, size_t usize); +#endif +void large_dalloc_junked_locked(tsdn_t *tsdn, extent_t *extent); +void large_dalloc(tsdn_t *tsdn, extent_t *extent); +size_t large_salloc(tsdn_t *tsdn, const extent_t *extent); +prof_tctx_t *large_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent); +void large_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx); +void large_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent); + +#endif /* JEMALLOC_H_EXTERNS */ +/******************************************************************************/ +#ifdef JEMALLOC_H_INLINES + +#endif /* JEMALLOC_H_INLINES */ +/******************************************************************************/ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index b8ed4341..cab0fc54 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -9,14 +9,14 @@ arena_boot arena_choose arena_choose_hard arena_choose_impl -arena_chunk_alloc_huge +arena_chunk_alloc_large arena_chunk_cache_alloc arena_chunk_cache_dalloc arena_chunk_cache_maybe_insert arena_chunk_cache_maybe_remove -arena_chunk_dalloc_huge -arena_chunk_ralloc_huge_expand -arena_chunk_ralloc_huge_shrink +arena_chunk_dalloc_large +arena_chunk_ralloc_large_expand +arena_chunk_ralloc_large_shrink arena_cleanup arena_dalloc arena_dalloc_bin_junked_locked @@ -222,17 +222,6 @@ hash_rotl_64 hash_x64_128 hash_x86_128 hash_x86_32 -huge_dalloc -huge_dalloc_junk -huge_dalloc_junked_locked -huge_malloc -huge_palloc -huge_prof_tctx_get -huge_prof_tctx_reset -huge_prof_tctx_set -huge_ralloc -huge_ralloc_no_move -huge_salloc iaalloc ialloc iallocztm @@ -258,6 +247,17 @@ ixalloc jemalloc_postfork_child jemalloc_postfork_parent jemalloc_prefork +large_dalloc +large_dalloc_junk +large_dalloc_junked_locked +large_malloc +large_palloc +large_prof_tctx_get +large_prof_tctx_reset +large_prof_tctx_set +large_ralloc +large_ralloc_no_move +large_salloc lg_floor lg_prof_sample malloc_cprintf @@ -438,17 +438,17 @@ stats_cactive_get stats_cactive_sub stats_print tcache_alloc_easy -tcache_alloc_huge +tcache_alloc_large tcache_alloc_small tcache_alloc_small_hard tcache_arena_reassociate -tcache_bin_flush_huge +tcache_bin_flush_large tcache_bin_flush_small tcache_bin_info tcache_boot tcache_cleanup tcache_create -tcache_dalloc_huge +tcache_dalloc_large tcache_dalloc_small tcache_enabled_cleanup tcache_enabled_get diff --git a/include/jemalloc/internal/size_classes.sh b/include/jemalloc/internal/size_classes.sh index b73064d1..38fe4902 100755 --- a/include/jemalloc/internal/size_classes.sh +++ b/include/jemalloc/internal/size_classes.sh @@ -237,7 +237,7 @@ size_classes() { fi fi # Final written value is correct: - huge_maxclass="((((size_t)1) << ${lg_grp}) + (((size_t)${ndelta}) << ${lg_delta}))" + large_maxclass="((((size_t)1) << ${lg_grp}) + (((size_t)${ndelta}) << ${lg_delta}))" index=$((${index} + 1)) ndelta=$((${ndelta} + 1)) done @@ -257,7 +257,7 @@ size_classes() { # - lookup_maxclass # - small_maxclass # - lg_large_minclass - # - huge_maxclass + # - large_maxclass } cat <tbins[binind]; tbin_info = &tcache_bin_info[binind]; if (unlikely(tbin->ncached == tbin_info->ncached_max)) { - tcache_bin_flush_huge(tsd, tbin, binind, + tcache_bin_flush_large(tsd, tbin, binind, (tbin_info->ncached_max >> 1), tcache); } assert(tbin->ncached < tbin_info->ncached_max); diff --git a/include/jemalloc/internal/witness.h b/include/jemalloc/internal/witness.h index f15665bc..8c56c21a 100644 --- a/include/jemalloc/internal/witness.h +++ b/include/jemalloc/internal/witness.h @@ -32,7 +32,7 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *, #define WITNESS_RANK_LEAF 0xffffffffU #define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF -#define WITNESS_RANK_ARENA_HUGE WITNESS_RANK_LEAF +#define WITNESS_RANK_ARENA_LARGE WITNESS_RANK_LEAF #define WITNESS_RANK_DSS WITNESS_RANK_LEAF #define WITNESS_RANK_PROF_ACTIVE WITNESS_RANK_LEAF #define WITNESS_RANK_PROF_DUMP_SEQ WITNESS_RANK_LEAF diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj index 537cb6ab..91c949aa 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj @@ -47,11 +47,11 @@ - + @@ -98,8 +98,8 @@ - + diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters index d2b5595f..09d4cb20 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters @@ -80,9 +80,6 @@ Header Files\internal - - Header Files\internal - Header Files\internal @@ -95,6 +92,9 @@ Header Files\internal + + Header Files\internal + Header Files\internal @@ -205,10 +205,10 @@ Source Files - + Source Files - + Source Files diff --git a/src/arena.c b/src/arena.c index ffde2e31..8194ced7 100644 --- a/src/arena.c +++ b/src/arena.c @@ -256,71 +256,71 @@ arena_nactive_sub(arena_t *arena, size_t sub_pages) } static void -arena_huge_malloc_stats_update(arena_t *arena, size_t usize) +arena_large_malloc_stats_update(arena_t *arena, size_t usize) { szind_t index = size2index(usize); szind_t hindex = (index >= NBINS) ? index - NBINS : 0; cassert(config_stats); - arena->stats.nmalloc_huge++; - arena->stats.allocated_huge += usize; - arena->stats.hstats[hindex].nmalloc++; - arena->stats.hstats[hindex].nrequests++; - arena->stats.hstats[hindex].curhchunks++; + arena->stats.nmalloc_large++; + arena->stats.allocated_large += usize; + arena->stats.lstats[hindex].nmalloc++; + arena->stats.lstats[hindex].nrequests++; + arena->stats.lstats[hindex].curlextents++; } static void -arena_huge_malloc_stats_update_undo(arena_t *arena, size_t usize) +arena_large_malloc_stats_update_undo(arena_t *arena, size_t usize) { szind_t index = size2index(usize); szind_t hindex = (index >= NBINS) ? index - NBINS : 0; cassert(config_stats); - arena->stats.nmalloc_huge--; - arena->stats.allocated_huge -= usize; - arena->stats.hstats[hindex].nmalloc--; - arena->stats.hstats[hindex].nrequests--; - arena->stats.hstats[hindex].curhchunks--; + arena->stats.nmalloc_large--; + arena->stats.allocated_large -= usize; + arena->stats.lstats[hindex].nmalloc--; + arena->stats.lstats[hindex].nrequests--; + arena->stats.lstats[hindex].curlextents--; } static void -arena_huge_dalloc_stats_update(arena_t *arena, size_t usize) +arena_large_dalloc_stats_update(arena_t *arena, size_t usize) { szind_t index = size2index(usize); szind_t hindex = (index >= NBINS) ? index - NBINS : 0; cassert(config_stats); - arena->stats.ndalloc_huge++; - arena->stats.allocated_huge -= usize; - arena->stats.hstats[hindex].ndalloc++; - arena->stats.hstats[hindex].curhchunks--; + arena->stats.ndalloc_large++; + arena->stats.allocated_large -= usize; + arena->stats.lstats[hindex].ndalloc++; + arena->stats.lstats[hindex].curlextents--; } static void -arena_huge_reset_stats_cancel(arena_t *arena, size_t usize) +arena_large_reset_stats_cancel(arena_t *arena, size_t usize) { szind_t index = size2index(usize); szind_t hindex = (index >= NBINS) ? index - NBINS : 0; cassert(config_stats); - arena->stats.ndalloc_huge++; - arena->stats.hstats[hindex].ndalloc--; + arena->stats.ndalloc_large++; + arena->stats.lstats[hindex].ndalloc--; } static void -arena_huge_ralloc_stats_update(arena_t *arena, size_t oldusize, size_t usize) +arena_large_ralloc_stats_update(arena_t *arena, size_t oldusize, size_t usize) { - arena_huge_dalloc_stats_update(arena, oldusize); - arena_huge_malloc_stats_update(arena, usize); + arena_large_dalloc_stats_update(arena, oldusize); + arena_large_malloc_stats_update(arena, usize); } static extent_t * -arena_chunk_alloc_huge_hard(tsdn_t *tsdn, arena_t *arena, +arena_chunk_alloc_large_hard(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, size_t usize, size_t alignment, bool *zero) { extent_t *extent; @@ -332,7 +332,7 @@ arena_chunk_alloc_huge_hard(tsdn_t *tsdn, arena_t *arena, /* Revert optimistic stats updates. */ malloc_mutex_lock(tsdn, &arena->lock); if (config_stats) { - arena_huge_malloc_stats_update_undo(arena, usize); + arena_large_malloc_stats_update_undo(arena, usize); arena->stats.mapped -= usize; } arena_nactive_sub(arena, (usize + large_pad) >> LG_PAGE); @@ -343,7 +343,7 @@ arena_chunk_alloc_huge_hard(tsdn_t *tsdn, arena_t *arena, } extent_t * -arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, +arena_chunk_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero) { extent_t *extent; @@ -353,7 +353,7 @@ arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, /* Optimistically update stats. */ if (config_stats) { - arena_huge_malloc_stats_update(arena, usize); + arena_large_malloc_stats_update(arena, usize); arena->stats.mapped += usize; } arena_nactive_add(arena, (usize + large_pad) >> LG_PAGE); @@ -362,7 +362,7 @@ arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, usize, large_pad, alignment, zero, false); malloc_mutex_unlock(tsdn, &arena->lock); if (extent == NULL) { - extent = arena_chunk_alloc_huge_hard(tsdn, arena, &chunk_hooks, + extent = arena_chunk_alloc_large_hard(tsdn, arena, &chunk_hooks, usize, alignment, zero); } @@ -370,7 +370,7 @@ arena_chunk_alloc_huge(tsdn_t *tsdn, arena_t *arena, size_t usize, } void -arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, extent_t *extent, +arena_chunk_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, bool locked) { chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; @@ -378,7 +378,8 @@ arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, extent_t *extent, if (!locked) malloc_mutex_lock(tsdn, &arena->lock); if (config_stats) { - arena_huge_dalloc_stats_update(arena, extent_usize_get(extent)); + arena_large_dalloc_stats_update(arena, + extent_usize_get(extent)); arena->stats.mapped -= extent_size_get(extent); } arena_nactive_sub(arena, extent_size_get(extent) >> LG_PAGE); @@ -389,7 +390,7 @@ arena_chunk_dalloc_huge(tsdn_t *tsdn, arena_t *arena, extent_t *extent, } void -arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, +arena_chunk_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldusize) { size_t usize = extent_usize_get(extent); @@ -397,7 +398,7 @@ arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, malloc_mutex_lock(tsdn, &arena->lock); if (config_stats) { - arena_huge_ralloc_stats_update(arena, oldusize, usize); + arena_large_ralloc_stats_update(arena, oldusize, usize); arena->stats.mapped -= udiff; } arena_nactive_sub(arena, udiff >> LG_PAGE); @@ -405,7 +406,7 @@ arena_chunk_ralloc_huge_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, } void -arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, +arena_chunk_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldusize) { size_t usize = extent_usize_get(extent); @@ -413,7 +414,7 @@ arena_chunk_ralloc_huge_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, malloc_mutex_lock(tsdn, &arena->lock); if (config_stats) { - arena_huge_ralloc_stats_update(arena, oldusize, usize); + arena_large_ralloc_stats_update(arena, oldusize, usize); arena->stats.mapped += udiff; } arena_nactive_add(arena, udiff >> LG_PAGE); @@ -891,26 +892,26 @@ arena_reset(tsd_t *tsd, arena_t *arena) * stats refreshes would impose an inconvenient burden. */ - /* Huge allocations. */ - malloc_mutex_lock(tsd_tsdn(tsd), &arena->huge_mtx); - for (extent = ql_last(&arena->huge, ql_link); extent != NULL; extent = - ql_last(&arena->huge, ql_link)) { + /* Large allocations. */ + malloc_mutex_lock(tsd_tsdn(tsd), &arena->large_mtx); + for (extent = ql_last(&arena->large, ql_link); extent != NULL; extent = + ql_last(&arena->large, ql_link)) { void *ptr = extent_base_get(extent); size_t usize; - malloc_mutex_unlock(tsd_tsdn(tsd), &arena->huge_mtx); + malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx); if (config_stats || (config_prof && opt_prof)) usize = isalloc(tsd_tsdn(tsd), extent, ptr); - /* Remove huge allocation from prof sample set. */ + /* Remove large allocation from prof sample set. */ if (config_prof && opt_prof) prof_free(tsd, extent, ptr, usize); - huge_dalloc(tsd_tsdn(tsd), extent); - malloc_mutex_lock(tsd_tsdn(tsd), &arena->huge_mtx); + large_dalloc(tsd_tsdn(tsd), extent); + malloc_mutex_lock(tsd_tsdn(tsd), &arena->large_mtx); /* Cancel out unwanted effects on stats. */ if (config_stats) - arena_huge_reset_stats_cancel(arena, usize); + arena_large_reset_stats_cancel(arena, usize); } - malloc_mutex_unlock(tsd_tsdn(tsd), &arena->huge_mtx); + malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx); malloc_mutex_lock(tsd_tsdn(tsd), &arena->lock); @@ -1283,7 +1284,7 @@ arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, if (likely(size <= SMALL_MAXCLASS)) return (arena_malloc_small(tsdn, arena, ind, zero)); - return (huge_malloc(tsdn, arena, index2size(ind), zero)); + return (large_malloc(tsdn, arena, index2size(ind), zero)); } void * @@ -1299,9 +1300,9 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, tcache, true); } else { if (likely(alignment <= CACHELINE)) - ret = huge_malloc(tsdn, arena, usize, zero); + ret = large_malloc(tsdn, arena, usize, zero); else - ret = huge_palloc(tsdn, arena, usize, alignment, zero); + ret = large_palloc(tsdn, arena, usize, alignment, zero); } return (ret); } @@ -1360,10 +1361,10 @@ arena_dalloc_promoted(tsdn_t *tsdn, extent_t *extent, void *ptr, usize = arena_prof_demote(tsdn, extent, ptr); if (usize <= tcache_maxclass) { - tcache_dalloc_huge(tsdn_tsd(tsdn), tcache, ptr, usize, + tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, usize, slow_path); } else - huge_dalloc(tsdn, extent); + large_dalloc(tsdn, extent); } static void @@ -1493,9 +1494,9 @@ arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t usize_min, usize_max; /* Calls with non-zero extra had to clamp extra. */ - assert(extra == 0 || size + extra <= HUGE_MAXCLASS); + assert(extra == 0 || size + extra <= LARGE_MAXCLASS); - if (unlikely(size > HUGE_MAXCLASS)) + if (unlikely(size > LARGE_MAXCLASS)) return (true); usize_min = s2u(size); @@ -1515,7 +1516,7 @@ arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } else if (oldsize >= LARGE_MINCLASS && usize_max >= LARGE_MINCLASS) { - return (huge_ralloc_no_move(tsdn, extent, usize_min, usize_max, + return (large_ralloc_no_move(tsdn, extent, usize_min, usize_max, zero)); } @@ -1531,7 +1532,7 @@ arena_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, return (arena_malloc(tsdn, arena, usize, size2index(usize), zero, tcache, true)); usize = sa2u(usize, alignment); - if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) return (NULL); return (ipalloct(tsdn, usize, alignment, zero, tcache, arena)); } @@ -1544,7 +1545,7 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, size_t usize, copysize; usize = s2u(size); - if (unlikely(usize == 0 || size > HUGE_MAXCLASS)) + if (unlikely(usize == 0 || size > LARGE_MAXCLASS)) return (NULL); if (likely(usize <= SMALL_MAXCLASS)) { @@ -1555,8 +1556,8 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, } if (oldsize >= LARGE_MINCLASS && usize >= LARGE_MINCLASS) { - return (huge_ralloc(tsdn, arena, extent, usize, alignment, zero, - tcache)); + return (large_ralloc(tsdn, arena, extent, usize, alignment, + zero, tcache)); } /* @@ -1670,7 +1671,7 @@ void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *lg_dirty_mult, ssize_t *decay_time, size_t *nactive, size_t *ndirty, arena_stats_t *astats, - malloc_bin_stats_t *bstats, malloc_huge_stats_t *hstats) + malloc_bin_stats_t *bstats, malloc_large_stats_t *lstats) { unsigned i; @@ -1687,16 +1688,16 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, astats->purged += arena->stats.purged; astats->metadata_mapped += arena->stats.metadata_mapped; astats->metadata_allocated += arena_metadata_allocated_get(arena); - astats->allocated_huge += arena->stats.allocated_huge; - astats->nmalloc_huge += arena->stats.nmalloc_huge; - astats->ndalloc_huge += arena->stats.ndalloc_huge; - astats->nrequests_huge += arena->stats.nrequests_huge; + astats->allocated_large += arena->stats.allocated_large; + astats->nmalloc_large += arena->stats.nmalloc_large; + astats->ndalloc_large += arena->stats.ndalloc_large; + astats->nrequests_large += arena->stats.nrequests_large; for (i = 0; i < NSIZES - NBINS; i++) { - hstats[i].nmalloc += arena->stats.hstats[i].nmalloc; - hstats[i].ndalloc += arena->stats.hstats[i].ndalloc; - hstats[i].nrequests += arena->stats.hstats[i].nrequests; - hstats[i].curhchunks += arena->stats.hstats[i].curhchunks; + lstats[i].nmalloc += arena->stats.lstats[i].nmalloc; + lstats[i].ndalloc += arena->stats.lstats[i].ndalloc; + lstats[i].nrequests += arena->stats.lstats[i].nrequests; + lstats[i].curlextents += arena->stats.lstats[i].curlextents; } malloc_mutex_unlock(tsdn, &arena->lock); @@ -1786,9 +1787,9 @@ arena_new(tsdn_t *tsdn, unsigned ind) if (opt_purge == purge_mode_decay) arena_decay_init(arena, arena_decay_time_default_get()); - ql_new(&arena->huge); - if (malloc_mutex_init(&arena->huge_mtx, "arena_huge", - WITNESS_RANK_ARENA_HUGE)) + ql_new(&arena->large); + if (malloc_mutex_init(&arena->large_mtx, "arena_large", + WITNESS_RANK_ARENA_LARGE)) return (NULL); for (i = 0; i < NPSIZES; i++) { @@ -1859,7 +1860,7 @@ arena_prefork3(tsdn_t *tsdn, arena_t *arena) for (i = 0; i < NBINS; i++) malloc_mutex_prefork(tsdn, &arena->bins[i].lock); - malloc_mutex_prefork(tsdn, &arena->huge_mtx); + malloc_mutex_prefork(tsdn, &arena->large_mtx); } void @@ -1867,7 +1868,7 @@ arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) { unsigned i; - malloc_mutex_postfork_parent(tsdn, &arena->huge_mtx); + malloc_mutex_postfork_parent(tsdn, &arena->large_mtx); for (i = 0; i < NBINS; i++) malloc_mutex_postfork_parent(tsdn, &arena->bins[i].lock); malloc_mutex_postfork_parent(tsdn, &arena->extent_cache_mtx); @@ -1880,7 +1881,7 @@ arena_postfork_child(tsdn_t *tsdn, arena_t *arena) { unsigned i; - malloc_mutex_postfork_child(tsdn, &arena->huge_mtx); + malloc_mutex_postfork_child(tsdn, &arena->large_mtx); for (i = 0; i < NBINS; i++) malloc_mutex_postfork_child(tsdn, &arena->bins[i].lock); malloc_mutex_postfork_child(tsdn, &arena->extent_cache_mtx); diff --git a/src/chunk_dss.c b/src/chunk_dss.c index f890a5cd..f8c968b3 100644 --- a/src/chunk_dss.c +++ b/src/chunk_dss.c @@ -78,7 +78,7 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, /* * sbrk() uses a signed increment argument, so take care not to - * interpret a huge allocation request as a negative increment. + * interpret a large allocation request as a negative increment. */ if ((intptr_t)size < 0) return (NULL); diff --git a/src/ckh.c b/src/ckh.c index 5ec0f60a..90a81155 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -267,7 +267,7 @@ ckh_grow(tsdn_t *tsdn, ckh_t *ckh) lg_curcells++; usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); - if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) { + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { ret = true; goto label_return; } @@ -315,7 +315,7 @@ ckh_shrink(tsdn_t *tsdn, ckh_t *ckh) lg_prevbuckets = ckh->lg_curbuckets; lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 1; usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); - if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) return; tab = (ckhc_t *)ipallocztm(tsdn, usize, CACHELINE, true, NULL, true, arena_ichoose(tsdn, NULL)); @@ -390,7 +390,7 @@ ckh_new(tsdn_t *tsdn, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh->keycomp = keycomp; usize = sa2u(sizeof(ckhc_t) << lg_mincells, CACHELINE); - if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) { + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { ret = true; goto label_return; } diff --git a/src/ctl.c b/src/ctl.c index 34c7e1bd..85ca2e86 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -126,8 +126,8 @@ CTL_PROTO(arenas_bin_i_size) CTL_PROTO(arenas_bin_i_nregs) CTL_PROTO(arenas_bin_i_slab_size) INDEX_PROTO(arenas_bin_i) -CTL_PROTO(arenas_hchunk_i_size) -INDEX_PROTO(arenas_hchunk_i) +CTL_PROTO(arenas_lextent_i_size) +INDEX_PROTO(arenas_lextent_i) CTL_PROTO(arenas_narenas) CTL_PROTO(arenas_initialized) CTL_PROTO(arenas_lg_dirty_mult) @@ -137,7 +137,7 @@ CTL_PROTO(arenas_page) CTL_PROTO(arenas_tcache_max) CTL_PROTO(arenas_nbins) CTL_PROTO(arenas_nhbins) -CTL_PROTO(arenas_nhchunks) +CTL_PROTO(arenas_nlextents) CTL_PROTO(arenas_extend) CTL_PROTO(prof_thread_active_init) CTL_PROTO(prof_active) @@ -150,10 +150,10 @@ CTL_PROTO(stats_arenas_i_small_allocated) CTL_PROTO(stats_arenas_i_small_nmalloc) CTL_PROTO(stats_arenas_i_small_ndalloc) CTL_PROTO(stats_arenas_i_small_nrequests) -CTL_PROTO(stats_arenas_i_huge_allocated) -CTL_PROTO(stats_arenas_i_huge_nmalloc) -CTL_PROTO(stats_arenas_i_huge_ndalloc) -CTL_PROTO(stats_arenas_i_huge_nrequests) +CTL_PROTO(stats_arenas_i_large_allocated) +CTL_PROTO(stats_arenas_i_large_nmalloc) +CTL_PROTO(stats_arenas_i_large_ndalloc) +CTL_PROTO(stats_arenas_i_large_nrequests) CTL_PROTO(stats_arenas_i_bins_j_nmalloc) CTL_PROTO(stats_arenas_i_bins_j_ndalloc) CTL_PROTO(stats_arenas_i_bins_j_nrequests) @@ -164,11 +164,11 @@ CTL_PROTO(stats_arenas_i_bins_j_nslabs) CTL_PROTO(stats_arenas_i_bins_j_nreslabs) CTL_PROTO(stats_arenas_i_bins_j_curslabs) INDEX_PROTO(stats_arenas_i_bins_j) -CTL_PROTO(stats_arenas_i_hchunks_j_nmalloc) -CTL_PROTO(stats_arenas_i_hchunks_j_ndalloc) -CTL_PROTO(stats_arenas_i_hchunks_j_nrequests) -CTL_PROTO(stats_arenas_i_hchunks_j_curhchunks) -INDEX_PROTO(stats_arenas_i_hchunks_j) +CTL_PROTO(stats_arenas_i_lextents_j_nmalloc) +CTL_PROTO(stats_arenas_i_lextents_j_ndalloc) +CTL_PROTO(stats_arenas_i_lextents_j_nrequests) +CTL_PROTO(stats_arenas_i_lextents_j_curlextents) +INDEX_PROTO(stats_arenas_i_lextents_j) CTL_PROTO(stats_arenas_i_nthreads) CTL_PROTO(stats_arenas_i_dss) CTL_PROTO(stats_arenas_i_lg_dirty_mult) @@ -310,15 +310,15 @@ static const ctl_indexed_node_t arenas_bin_node[] = { {INDEX(arenas_bin_i)} }; -static const ctl_named_node_t arenas_hchunk_i_node[] = { - {NAME("size"), CTL(arenas_hchunk_i_size)} +static const ctl_named_node_t arenas_lextent_i_node[] = { + {NAME("size"), CTL(arenas_lextent_i_size)} }; -static const ctl_named_node_t super_arenas_hchunk_i_node[] = { - {NAME(""), CHILD(named, arenas_hchunk_i)} +static const ctl_named_node_t super_arenas_lextent_i_node[] = { + {NAME(""), CHILD(named, arenas_lextent_i)} }; -static const ctl_indexed_node_t arenas_hchunk_node[] = { - {INDEX(arenas_hchunk_i)} +static const ctl_indexed_node_t arenas_lextent_node[] = { + {INDEX(arenas_lextent_i)} }; static const ctl_named_node_t arenas_node[] = { @@ -332,8 +332,8 @@ static const ctl_named_node_t arenas_node[] = { {NAME("nbins"), CTL(arenas_nbins)}, {NAME("nhbins"), CTL(arenas_nhbins)}, {NAME("bin"), CHILD(indexed, arenas_bin)}, - {NAME("nhchunks"), CTL(arenas_nhchunks)}, - {NAME("hchunk"), CHILD(indexed, arenas_hchunk)}, + {NAME("nlextents"), CTL(arenas_nlextents)}, + {NAME("lextent"), CHILD(indexed, arenas_lextent)}, {NAME("extend"), CTL(arenas_extend)} }; @@ -359,11 +359,11 @@ static const ctl_named_node_t stats_arenas_i_small_node[] = { {NAME("nrequests"), CTL(stats_arenas_i_small_nrequests)} }; -static const ctl_named_node_t stats_arenas_i_huge_node[] = { - {NAME("allocated"), CTL(stats_arenas_i_huge_allocated)}, - {NAME("nmalloc"), CTL(stats_arenas_i_huge_nmalloc)}, - {NAME("ndalloc"), CTL(stats_arenas_i_huge_ndalloc)}, - {NAME("nrequests"), CTL(stats_arenas_i_huge_nrequests)} +static const ctl_named_node_t stats_arenas_i_large_node[] = { + {NAME("allocated"), CTL(stats_arenas_i_large_allocated)}, + {NAME("nmalloc"), CTL(stats_arenas_i_large_nmalloc)}, + {NAME("ndalloc"), CTL(stats_arenas_i_large_ndalloc)}, + {NAME("nrequests"), CTL(stats_arenas_i_large_nrequests)} }; static const ctl_named_node_t stats_arenas_i_bins_j_node[] = { @@ -385,18 +385,18 @@ static const ctl_indexed_node_t stats_arenas_i_bins_node[] = { {INDEX(stats_arenas_i_bins_j)} }; -static const ctl_named_node_t stats_arenas_i_hchunks_j_node[] = { - {NAME("nmalloc"), CTL(stats_arenas_i_hchunks_j_nmalloc)}, - {NAME("ndalloc"), CTL(stats_arenas_i_hchunks_j_ndalloc)}, - {NAME("nrequests"), CTL(stats_arenas_i_hchunks_j_nrequests)}, - {NAME("curhchunks"), CTL(stats_arenas_i_hchunks_j_curhchunks)} +static const ctl_named_node_t stats_arenas_i_lextents_j_node[] = { + {NAME("nmalloc"), CTL(stats_arenas_i_lextents_j_nmalloc)}, + {NAME("ndalloc"), CTL(stats_arenas_i_lextents_j_ndalloc)}, + {NAME("nrequests"), CTL(stats_arenas_i_lextents_j_nrequests)}, + {NAME("curlextents"), CTL(stats_arenas_i_lextents_j_curlextents)} }; -static const ctl_named_node_t super_stats_arenas_i_hchunks_j_node[] = { - {NAME(""), CHILD(named, stats_arenas_i_hchunks_j)} +static const ctl_named_node_t super_stats_arenas_i_lextents_j_node[] = { + {NAME(""), CHILD(named, stats_arenas_i_lextents_j)} }; -static const ctl_indexed_node_t stats_arenas_i_hchunks_node[] = { - {INDEX(stats_arenas_i_hchunks_j)} +static const ctl_indexed_node_t stats_arenas_i_lextents_node[] = { + {INDEX(stats_arenas_i_lextents_j)} }; static const ctl_named_node_t stats_arenas_i_node[] = { @@ -413,9 +413,9 @@ static const ctl_named_node_t stats_arenas_i_node[] = { {NAME("purged"), CTL(stats_arenas_i_purged)}, {NAME("metadata"), CHILD(named, stats_arenas_i_metadata)}, {NAME("small"), CHILD(named, stats_arenas_i_small)}, - {NAME("huge"), CHILD(named, stats_arenas_i_huge)}, + {NAME("large"), CHILD(named, stats_arenas_i_large)}, {NAME("bins"), CHILD(indexed, stats_arenas_i_bins)}, - {NAME("hchunks"), CHILD(indexed, stats_arenas_i_hchunks)} + {NAME("lextents"), CHILD(indexed, stats_arenas_i_lextents)} }; static const ctl_named_node_t super_stats_arenas_i_node[] = { {NAME(""), CHILD(named, stats_arenas_i)} @@ -476,8 +476,8 @@ ctl_arena_clear(ctl_arena_stats_t *astats) astats->ndalloc_small = 0; astats->nrequests_small = 0; memset(astats->bstats, 0, NBINS * sizeof(malloc_bin_stats_t)); - memset(astats->hstats, 0, (NSIZES - NBINS) * - sizeof(malloc_huge_stats_t)); + memset(astats->lstats, 0, (NSIZES - NBINS) * + sizeof(malloc_large_stats_t)); } } @@ -490,7 +490,7 @@ ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_stats_t *cstats, arena_t *arena) arena_stats_merge(tsdn, arena, &cstats->nthreads, &cstats->dss, &cstats->lg_dirty_mult, &cstats->decay_time, &cstats->pactive, &cstats->pdirty, &cstats->astats, - cstats->bstats, cstats->hstats); + cstats->bstats, cstats->lstats); for (i = 0; i < NBINS; i++) { cstats->allocated_small += cstats->bstats[i].curregs * @@ -532,10 +532,12 @@ ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats) sstats->ndalloc_small += astats->ndalloc_small; sstats->nrequests_small += astats->nrequests_small; - sstats->astats.allocated_huge += astats->astats.allocated_huge; - sstats->astats.nmalloc_huge += astats->astats.nmalloc_huge; - sstats->astats.ndalloc_huge += astats->astats.ndalloc_huge; - sstats->astats.nrequests_huge += astats->astats.nrequests_huge; + sstats->astats.allocated_large += + astats->astats.allocated_large; + sstats->astats.nmalloc_large += astats->astats.nmalloc_large; + sstats->astats.ndalloc_large += astats->astats.ndalloc_large; + sstats->astats.nrequests_large += + astats->astats.nrequests_large; for (i = 0; i < NBINS; i++) { sstats->bstats[i].nmalloc += astats->bstats[i].nmalloc; @@ -556,12 +558,12 @@ ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats) } for (i = 0; i < NSIZES - NBINS; i++) { - sstats->hstats[i].nmalloc += astats->hstats[i].nmalloc; - sstats->hstats[i].ndalloc += astats->hstats[i].ndalloc; - sstats->hstats[i].nrequests += - astats->hstats[i].nrequests; - sstats->hstats[i].curhchunks += - astats->hstats[i].curhchunks; + sstats->lstats[i].nmalloc += astats->lstats[i].nmalloc; + sstats->lstats[i].ndalloc += astats->lstats[i].ndalloc; + sstats->lstats[i].nrequests += + astats->lstats[i].nrequests; + sstats->lstats[i].curlextents += + astats->lstats[i].curlextents; } } } @@ -643,7 +645,7 @@ ctl_refresh(tsdn_t *tsdn) &base_mapped); ctl_stats.allocated = ctl_stats.arenas[ctl_stats.narenas].allocated_small + - ctl_stats.arenas[ctl_stats.narenas].astats.allocated_huge; + ctl_stats.arenas[ctl_stats.narenas].astats.allocated_large; ctl_stats.active = (ctl_stats.arenas[ctl_stats.narenas].pactive << LG_PAGE); ctl_stats.metadata = base_allocated + @@ -1812,15 +1814,15 @@ arenas_bin_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) return (super_arenas_bin_i_node); } -CTL_RO_NL_GEN(arenas_nhchunks, NSIZES - NBINS, unsigned) -CTL_RO_NL_GEN(arenas_hchunk_i_size, index2size(NBINS+(szind_t)mib[2]), size_t) +CTL_RO_NL_GEN(arenas_nlextents, NSIZES - NBINS, unsigned) +CTL_RO_NL_GEN(arenas_lextent_i_size, index2size(NBINS+(szind_t)mib[2]), size_t) static const ctl_named_node_t * -arenas_hchunk_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) +arenas_lextent_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { if (i > NSIZES - NBINS) return (NULL); - return (super_arenas_hchunk_i_node); + return (super_arenas_lextent_i_node); } static int @@ -2012,14 +2014,14 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc, ctl_stats.arenas[mib[2]].ndalloc_small, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests, ctl_stats.arenas[mib[2]].nrequests_small, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_huge_allocated, - ctl_stats.arenas[mib[2]].astats.allocated_huge, size_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_huge_nmalloc, - ctl_stats.arenas[mib[2]].astats.nmalloc_huge, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_huge_ndalloc, - ctl_stats.arenas[mib[2]].astats.ndalloc_huge, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_huge_nrequests, - ctl_stats.arenas[mib[2]].astats.nmalloc_huge, uint64_t) /* Intentional. */ +CTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated, + ctl_stats.arenas[mib[2]].astats.allocated_large, size_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc, + ctl_stats.arenas[mib[2]].astats.nmalloc_large, uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc, + ctl_stats.arenas[mib[2]].astats.ndalloc_large, uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests, + ctl_stats.arenas[mib[2]].astats.nmalloc_large, uint64_t) /* Intentional. */ CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc, ctl_stats.arenas[mib[2]].bstats[mib[4]].nmalloc, uint64_t) @@ -2050,23 +2052,23 @@ stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, return (super_stats_arenas_i_bins_j_node); } -CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_nmalloc, - ctl_stats.arenas[mib[2]].hstats[mib[4]].nmalloc, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_ndalloc, - ctl_stats.arenas[mib[2]].hstats[mib[4]].ndalloc, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_nrequests, - ctl_stats.arenas[mib[2]].hstats[mib[4]].nrequests, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_curhchunks, - ctl_stats.arenas[mib[2]].hstats[mib[4]].curhchunks, size_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nmalloc, + ctl_stats.arenas[mib[2]].lstats[mib[4]].nmalloc, uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_ndalloc, + ctl_stats.arenas[mib[2]].lstats[mib[4]].ndalloc, uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nrequests, + ctl_stats.arenas[mib[2]].lstats[mib[4]].nrequests, uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_curlextents, + ctl_stats.arenas[mib[2]].lstats[mib[4]].curlextents, size_t) static const ctl_named_node_t * -stats_arenas_i_hchunks_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, +stats_arenas_i_lextents_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t j) { if (j > NSIZES - NBINS) return (NULL); - return (super_stats_arenas_i_hchunks_j_node); + return (super_stats_arenas_i_lextents_j_node); } static const ctl_named_node_t * diff --git a/src/extent.c b/src/extent.c index 757a6e21..2f929a83 100644 --- a/src/extent.c +++ b/src/extent.c @@ -40,7 +40,7 @@ extent_size_quantize_floor(size_t size) pszind_t pind; assert(size > 0); - assert(size - large_pad <= HUGE_MAXCLASS); + assert(size - large_pad <= LARGE_MAXCLASS); assert((size & PAGE_MASK) == 0); assert(size != 0); @@ -77,7 +77,7 @@ extent_size_quantize_ceil(size_t size) size_t ret; assert(size > 0); - assert(size - large_pad <= HUGE_MAXCLASS); + assert(size - large_pad <= LARGE_MAXCLASS); assert((size & PAGE_MASK) == 0); ret = extent_size_quantize_floor(size); diff --git a/src/jemalloc.c b/src/jemalloc.c index 429667f6..85a592e9 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1457,7 +1457,7 @@ ialloc_body(size_t size, bool zero, tsdn_t **tsdn, size_t *usize, if (config_stats || (config_prof && opt_prof)) { *usize = index2size(ind); - assert(*usize > 0 && *usize <= HUGE_MAXCLASS); + assert(*usize > 0 && *usize <= LARGE_MAXCLASS); } if (config_prof && opt_prof) @@ -1589,7 +1589,7 @@ imemalign(void **memptr, size_t alignment, size_t size, size_t min_alignment) } usize = sa2u(size, alignment); - if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) { + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { result = NULL; goto label_oom; } @@ -1663,7 +1663,7 @@ je_calloc(size_t num, size_t size) if (num == 0 || size == 0) num_size = 1; else - num_size = HUGE_MAXCLASS + 1; /* Trigger OOM. */ + num_size = LARGE_MAXCLASS + 1; /* Trigger OOM. */ /* * Try to avoid division here. We know that it isn't possible to * overflow during multiplication if neither operand uses any of the @@ -1671,7 +1671,7 @@ je_calloc(size_t num, size_t size) */ } else if (unlikely(((num | size) & (SIZE_T_MAX << (sizeof(size_t) << 2))) && (num_size / size != num))) - num_size = HUGE_MAXCLASS + 1; /* size_t overflow. */ + num_size = LARGE_MAXCLASS + 1; /* size_t overflow. */ if (likely(!malloc_slow)) { ret = ialloc_body(num_size, true, &tsdn, &usize, false); @@ -1819,7 +1819,7 @@ je_realloc(void *ptr, size_t size) old_usize = isalloc(tsd_tsdn(tsd), extent, ptr); if (config_prof && opt_prof) { usize = s2u(size); - ret = unlikely(usize == 0 || usize > HUGE_MAXCLASS) ? + ret = unlikely(usize == 0 || usize > LARGE_MAXCLASS) ? NULL : irealloc_prof(tsd, extent, ptr, old_usize, usize); } else { @@ -1956,7 +1956,7 @@ imallocx_flags_decode(tsd_t *tsd, size_t size, int flags, size_t *usize, *alignment = MALLOCX_ALIGN_GET_SPECIFIED(flags); *usize = sa2u(size, *alignment); } - if (unlikely(*usize == 0 || *usize > HUGE_MAXCLASS)) + if (unlikely(*usize == 0 || *usize > LARGE_MAXCLASS)) return (true); *zero = MALLOCX_ZERO_GET(flags); if ((flags & MALLOCX_TCACHE_MASK) != 0) { @@ -2084,7 +2084,7 @@ imallocx_body(size_t size, int flags, tsdn_t **tsdn, size_t *usize, return (NULL); if (config_stats || (config_prof && opt_prof)) { *usize = index2size(ind); - assert(*usize > 0 && *usize <= HUGE_MAXCLASS); + assert(*usize > 0 && *usize <= LARGE_MAXCLASS); } if (config_prof && opt_prof) { @@ -2233,7 +2233,7 @@ je_rallocx(void *ptr, size_t size, int flags) if (config_prof && opt_prof) { usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment); - if (unlikely(usize == 0 || usize > HUGE_MAXCLASS)) + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) goto label_oom; p = irallocx_prof(tsd, extent, ptr, old_usize, size, alignment, &usize, zero, tcache, arena); @@ -2314,17 +2314,17 @@ ixallocx_prof(tsd_t *tsd, extent_t *extent, void *ptr, size_t old_usize, */ if (alignment == 0) { usize_max = s2u(size+extra); - assert(usize_max > 0 && usize_max <= HUGE_MAXCLASS); + assert(usize_max > 0 && usize_max <= LARGE_MAXCLASS); } else { usize_max = sa2u(size+extra, alignment); - if (unlikely(usize_max == 0 || usize_max > HUGE_MAXCLASS)) { + if (unlikely(usize_max == 0 || usize_max > LARGE_MAXCLASS)) { /* * usize_max is out of range, and chances are that * allocation will fail, but use the maximum possible * value and carry on with prof_alloc_prep(), just in * case allocation succeeds. */ - usize_max = HUGE_MAXCLASS; + usize_max = LARGE_MAXCLASS; } } tctx = prof_alloc_prep(tsd, usize_max, prof_active, false); @@ -2368,18 +2368,18 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) /* * The API explicitly absolves itself of protecting against (size + * extra) numerical overflow, but we may need to clamp extra to avoid - * exceeding HUGE_MAXCLASS. + * exceeding LARGE_MAXCLASS. * * Ordinarily, size limit checking is handled deeper down, but here we * have to check as part of (size + extra) clamping, since we need the * clamped value in the above helper functions. */ - if (unlikely(size > HUGE_MAXCLASS)) { + if (unlikely(size > LARGE_MAXCLASS)) { usize = old_usize; goto label_not_resized; } - if (unlikely(HUGE_MAXCLASS - size < extra)) - extra = HUGE_MAXCLASS - size; + if (unlikely(LARGE_MAXCLASS - size < extra)) + extra = LARGE_MAXCLASS - size; if (config_prof && opt_prof) { usize = ixallocx_prof(tsd, extent, ptr, old_usize, size, extra, @@ -2512,7 +2512,7 @@ je_nallocx(size_t size, int flags) witness_assert_lockless(tsdn); usize = inallocx(tsdn, size, flags); - if (unlikely(usize > HUGE_MAXCLASS)) + if (unlikely(usize > LARGE_MAXCLASS)) return (0); witness_assert_lockless(tsdn); diff --git a/src/huge.c b/src/large.c similarity index 66% rename from src/huge.c rename to src/large.c index 8aa3dfd2..43bfb284 100644 --- a/src/huge.c +++ b/src/large.c @@ -1,19 +1,19 @@ -#define JEMALLOC_HUGE_C_ +#define JEMALLOC_LARGE_C_ #include "jemalloc/internal/jemalloc_internal.h" /******************************************************************************/ void * -huge_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero) +large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero) { assert(usize == s2u(usize)); - return (huge_palloc(tsdn, arena, usize, CACHELINE, zero)); + return (large_palloc(tsdn, arena, usize, CACHELINE, zero)); } void * -huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, +large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero) { size_t ausize; @@ -24,7 +24,7 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, assert(!tsdn_null(tsdn) || arena != NULL); ausize = sa2u(usize, alignment); - if (unlikely(ausize == 0 || ausize > HUGE_MAXCLASS)) + if (unlikely(ausize == 0 || ausize > LARGE_MAXCLASS)) return (NULL); /* @@ -34,15 +34,15 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, is_zeroed = zero; if (likely(!tsdn_null(tsdn))) arena = arena_choose(tsdn_tsd(tsdn), arena); - if (unlikely(arena == NULL) || (extent = arena_chunk_alloc_huge(tsdn, + if (unlikely(arena == NULL) || (extent = arena_chunk_alloc_large(tsdn, arena, usize, alignment, &is_zeroed)) == NULL) return (NULL); - /* Insert extent into huge. */ - malloc_mutex_lock(tsdn, &arena->huge_mtx); + /* Insert extent into large. */ + malloc_mutex_lock(tsdn, &arena->large_mtx); ql_elm_new(extent, ql_link); - ql_tail_insert(&arena->huge, extent, ql_link); - malloc_mutex_unlock(tsdn, &arena->huge_mtx); + ql_tail_insert(&arena->large, extent, ql_link); + malloc_mutex_unlock(tsdn, &arena->large_mtx); if (config_prof && arena_prof_accum(tsdn, arena, usize)) prof_idump(tsdn); @@ -61,23 +61,23 @@ huge_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, } #ifdef JEMALLOC_JET -#undef huge_dalloc_junk -#define huge_dalloc_junk JEMALLOC_N(n_huge_dalloc_junk) +#undef large_dalloc_junk +#define large_dalloc_junk JEMALLOC_N(n_large_dalloc_junk) #endif void -huge_dalloc_junk(void *ptr, size_t usize) +large_dalloc_junk(void *ptr, size_t usize) { memset(ptr, JEMALLOC_FREE_JUNK, usize); } #ifdef JEMALLOC_JET -#undef huge_dalloc_junk -#define huge_dalloc_junk JEMALLOC_N(huge_dalloc_junk) -huge_dalloc_junk_t *huge_dalloc_junk = JEMALLOC_N(n_huge_dalloc_junk); +#undef large_dalloc_junk +#define large_dalloc_junk JEMALLOC_N(large_dalloc_junk) +large_dalloc_junk_t *large_dalloc_junk = JEMALLOC_N(n_large_dalloc_junk); #endif static void -huge_dalloc_maybe_junk(tsdn_t *tsdn, void *ptr, size_t usize) +large_dalloc_maybe_junk(tsdn_t *tsdn, void *ptr, size_t usize) { if (config_fill && have_dss && unlikely(opt_junk_free)) { @@ -86,13 +86,13 @@ huge_dalloc_maybe_junk(tsdn_t *tsdn, void *ptr, size_t usize) * unmapped. */ if (!config_munmap || (have_dss && chunk_in_dss(tsdn, ptr))) - huge_dalloc_junk(ptr, usize); + large_dalloc_junk(ptr, usize); memset(ptr, JEMALLOC_FREE_JUNK, usize); } } static bool -huge_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) +large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { arena_t *arena = extent_arena_get(extent); size_t oldusize = extent_usize_get(extent); @@ -109,20 +109,20 @@ huge_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) return (true); if (config_fill && unlikely(opt_junk_free)) { - huge_dalloc_maybe_junk(tsdn, extent_addr_get(trail), + large_dalloc_maybe_junk(tsdn, extent_addr_get(trail), extent_usize_get(trail)); } arena_chunk_cache_dalloc(tsdn, arena, &chunk_hooks, trail); } - arena_chunk_ralloc_huge_shrink(tsdn, arena, extent, oldusize); + arena_chunk_ralloc_large_shrink(tsdn, arena, extent, oldusize); return (false); } static bool -huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, +large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, bool zero) { arena_t *arena = extent_arena_get(extent); @@ -173,34 +173,35 @@ huge_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, JEMALLOC_ALLOC_JUNK, usize - oldusize); } - arena_chunk_ralloc_huge_expand(tsdn, arena, extent, oldusize); + arena_chunk_ralloc_large_expand(tsdn, arena, extent, oldusize); return (false); } bool -huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, +large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, size_t usize_max, bool zero) { assert(s2u(extent_usize_get(extent)) == extent_usize_get(extent)); /* The following should have been caught by callers. */ - assert(usize_min > 0 && usize_max <= HUGE_MAXCLASS); - /* Both allocation sizes must be huge to avoid a move. */ + assert(usize_min > 0 && usize_max <= LARGE_MAXCLASS); + /* Both allocation sizes must be large to avoid a move. */ assert(extent_usize_get(extent) >= LARGE_MINCLASS && usize_max >= LARGE_MINCLASS); if (usize_max > extent_usize_get(extent)) { /* Attempt to expand the allocation in-place. */ - if (!huge_ralloc_no_move_expand(tsdn, extent, usize_max, + if (!large_ralloc_no_move_expand(tsdn, extent, usize_max, zero)) { arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } /* Try again, this time with usize_min. */ if (usize_min < usize_max && usize_min > - extent_usize_get(extent) && huge_ralloc_no_move_expand(tsdn, - extent, usize_min, zero)) { + extent_usize_get(extent) && + large_ralloc_no_move_expand(tsdn, extent, usize_min, + zero)) { arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } @@ -218,7 +219,7 @@ huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, /* Attempt to shrink the allocation in-place. */ if (extent_usize_get(extent) > usize_max) { - if (!huge_ralloc_no_move_shrink(tsdn, extent, usize_max)) { + if (!large_ralloc_no_move_shrink(tsdn, extent, usize_max)) { arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); } @@ -227,30 +228,30 @@ huge_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, } static void * -huge_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, +large_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero) { if (alignment <= CACHELINE) - return (huge_malloc(tsdn, arena, usize, zero)); - return (huge_palloc(tsdn, arena, usize, alignment, zero)); + return (large_malloc(tsdn, arena, usize, zero)); + return (large_palloc(tsdn, arena, usize, alignment, zero)); } void * -huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, +large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, size_t alignment, bool zero, tcache_t *tcache) { void *ret; size_t copysize; /* The following should have been caught by callers. */ - assert(usize > 0 && usize <= HUGE_MAXCLASS); - /* Both allocation sizes must be huge to avoid a move. */ + assert(usize > 0 && usize <= LARGE_MAXCLASS); + /* Both allocation sizes must be large to avoid a move. */ assert(extent_usize_get(extent) >= LARGE_MINCLASS && usize >= LARGE_MINCLASS); /* Try to avoid moving the allocation. */ - if (!huge_ralloc_no_move(tsdn, extent, usize, usize, zero)) + if (!large_ralloc_no_move(tsdn, extent, usize, usize, zero)) return (extent_addr_get(extent)); /* @@ -258,7 +259,7 @@ huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, * different size class. In that case, fall back to allocating new * space and copying. */ - ret = huge_ralloc_move_helper(tsdn, arena, usize, alignment, zero); + ret = large_ralloc_move_helper(tsdn, arena, usize, alignment, zero); if (ret == NULL) return (NULL); @@ -271,82 +272,82 @@ huge_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, } static void -huge_dalloc_impl(tsdn_t *tsdn, extent_t *extent, bool junked_locked) +large_dalloc_impl(tsdn_t *tsdn, extent_t *extent, bool junked_locked) { arena_t *arena; arena = extent_arena_get(extent); if (!junked_locked) - malloc_mutex_lock(tsdn, &arena->huge_mtx); - ql_remove(&arena->huge, extent, ql_link); + malloc_mutex_lock(tsdn, &arena->large_mtx); + ql_remove(&arena->large, extent, ql_link); if (!junked_locked) { - malloc_mutex_unlock(tsdn, &arena->huge_mtx); + malloc_mutex_unlock(tsdn, &arena->large_mtx); - huge_dalloc_maybe_junk(tsdn, extent_addr_get(extent), + large_dalloc_maybe_junk(tsdn, extent_addr_get(extent), extent_usize_get(extent)); } - arena_chunk_dalloc_huge(tsdn, arena, extent, junked_locked); + arena_chunk_dalloc_large(tsdn, arena, extent, junked_locked); if (!junked_locked) arena_decay_tick(tsdn, arena); } void -huge_dalloc_junked_locked(tsdn_t *tsdn, extent_t *extent) +large_dalloc_junked_locked(tsdn_t *tsdn, extent_t *extent) { - huge_dalloc_impl(tsdn, extent, true); + large_dalloc_impl(tsdn, extent, true); } void -huge_dalloc(tsdn_t *tsdn, extent_t *extent) +large_dalloc(tsdn_t *tsdn, extent_t *extent) { - huge_dalloc_impl(tsdn, extent, false); + large_dalloc_impl(tsdn, extent, false); } size_t -huge_salloc(tsdn_t *tsdn, const extent_t *extent) +large_salloc(tsdn_t *tsdn, const extent_t *extent) { size_t usize; arena_t *arena; arena = extent_arena_get(extent); - malloc_mutex_lock(tsdn, &arena->huge_mtx); + malloc_mutex_lock(tsdn, &arena->large_mtx); usize = extent_usize_get(extent); - malloc_mutex_unlock(tsdn, &arena->huge_mtx); + malloc_mutex_unlock(tsdn, &arena->large_mtx); return (usize); } prof_tctx_t * -huge_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent) +large_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent) { prof_tctx_t *tctx; arena_t *arena; arena = extent_arena_get(extent); - malloc_mutex_lock(tsdn, &arena->huge_mtx); + malloc_mutex_lock(tsdn, &arena->large_mtx); tctx = extent_prof_tctx_get(extent); - malloc_mutex_unlock(tsdn, &arena->huge_mtx); + malloc_mutex_unlock(tsdn, &arena->large_mtx); return (tctx); } void -huge_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx) +large_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx) { arena_t *arena; arena = extent_arena_get(extent); - malloc_mutex_lock(tsdn, &arena->huge_mtx); + malloc_mutex_lock(tsdn, &arena->large_mtx); extent_prof_tctx_set(extent, tctx); - malloc_mutex_unlock(tsdn, &arena->huge_mtx); + malloc_mutex_unlock(tsdn, &arena->large_mtx); } void -huge_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent) +large_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent) { - huge_prof_tctx_set(tsdn, extent, (prof_tctx_t *)(uintptr_t)1U); + large_prof_tctx_set(tsdn, extent, (prof_tctx_t *)(uintptr_t)1U); } diff --git a/src/stats.c b/src/stats.c index 599e377d..493e409a 100644 --- a/src/stats.c +++ b/src/stats.c @@ -37,10 +37,10 @@ size_t stats_cactive = 0; static void stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, unsigned i); -static void stats_arena_hchunks_print( +static void stats_arena_lextents_print( void (*write_cb)(void *, const char *), void *cbopaque, unsigned i); static void stats_arena_print(void (*write_cb)(void *, const char *), - void *cbopaque, unsigned i, bool bins, bool huge); + void *cbopaque, unsigned i, bool bins, bool large); /******************************************************************************/ @@ -157,34 +157,34 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, } static void -stats_arena_hchunks_print(void (*write_cb)(void *, const char *), +stats_arena_lextents_print(void (*write_cb)(void *, const char *), void *cbopaque, unsigned i) { - unsigned nbins, nhchunks, j; + unsigned nbins, nlextents, j; bool in_gap; malloc_cprintf(write_cb, cbopaque, - "huge: size ind allocated nmalloc ndalloc" - " nrequests curhchunks\n"); + "large: size ind allocated nmalloc ndalloc" + " nrequests curlextents\n"); CTL_GET("arenas.nbins", &nbins, unsigned); - CTL_GET("arenas.nhchunks", &nhchunks, unsigned); - for (j = 0, in_gap = false; j < nhchunks; j++) { + CTL_GET("arenas.nlextents", &nlextents, unsigned); + for (j = 0, in_gap = false; j < nlextents; j++) { uint64_t nmalloc, ndalloc, nrequests; - size_t hchunk_size, curhchunks; + size_t lextent_size, curlextents; - CTL_M2_M4_GET("stats.arenas.0.hchunks.0.nmalloc", i, j, + CTL_M2_M4_GET("stats.arenas.0.lextents.0.nmalloc", i, j, &nmalloc, uint64_t); - CTL_M2_M4_GET("stats.arenas.0.hchunks.0.ndalloc", i, j, + CTL_M2_M4_GET("stats.arenas.0.lextents.0.ndalloc", i, j, &ndalloc, uint64_t); - CTL_M2_M4_GET("stats.arenas.0.hchunks.0.nrequests", i, j, + CTL_M2_M4_GET("stats.arenas.0.lextents.0.nrequests", i, j, &nrequests, uint64_t); if (nrequests == 0) in_gap = true; else { - CTL_M2_GET("arenas.hchunk.0.size", j, &hchunk_size, + CTL_M2_GET("arenas.lextent.0.size", j, &lextent_size, size_t); - CTL_M2_M4_GET("stats.arenas.0.hchunks.0.curhchunks", i, - j, &curhchunks, size_t); + CTL_M2_M4_GET("stats.arenas.0.lextents.0.curlextents", + i, j, &curlextents, size_t); if (in_gap) { malloc_cprintf(write_cb, cbopaque, " ---\n"); @@ -193,9 +193,9 @@ stats_arena_hchunks_print(void (*write_cb)(void *, const char *), malloc_cprintf(write_cb, cbopaque, "%20zu %3u %12zu %12"FMTu64" %12"FMTu64 " %12"FMTu64" %12zu\n", - hchunk_size, nbins + j, - curhchunks * hchunk_size, nmalloc, ndalloc, - nrequests, curhchunks); + lextent_size, nbins + j, + curlextents * lextent_size, nmalloc, ndalloc, + nrequests, curlextents); } } if (in_gap) { @@ -206,7 +206,7 @@ stats_arena_hchunks_print(void (*write_cb)(void *, const char *), static void stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, - unsigned i, bool bins, bool huge) + unsigned i, bool bins, bool large) { unsigned nthreads; const char *dss; @@ -216,8 +216,8 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, uint64_t npurge, nmadvise, purged; size_t small_allocated; uint64_t small_nmalloc, small_ndalloc, small_nrequests; - size_t huge_allocated; - uint64_t huge_nmalloc, huge_ndalloc, huge_nrequests; + size_t large_allocated; + uint64_t large_nmalloc, large_ndalloc, large_nrequests; CTL_GET("arenas.page", &page, size_t); @@ -268,20 +268,21 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, "small: %12zu %12"FMTu64" %12"FMTu64 " %12"FMTu64"\n", small_allocated, small_nmalloc, small_ndalloc, small_nrequests); - CTL_M2_GET("stats.arenas.0.huge.allocated", i, &huge_allocated, size_t); - CTL_M2_GET("stats.arenas.0.huge.nmalloc", i, &huge_nmalloc, uint64_t); - CTL_M2_GET("stats.arenas.0.huge.ndalloc", i, &huge_ndalloc, uint64_t); - CTL_M2_GET("stats.arenas.0.huge.nrequests", i, &huge_nrequests, + CTL_M2_GET("stats.arenas.0.large.allocated", i, &large_allocated, + size_t); + CTL_M2_GET("stats.arenas.0.large.nmalloc", i, &large_nmalloc, uint64_t); + CTL_M2_GET("stats.arenas.0.large.ndalloc", i, &large_ndalloc, uint64_t); + CTL_M2_GET("stats.arenas.0.large.nrequests", i, &large_nrequests, uint64_t); malloc_cprintf(write_cb, cbopaque, - "huge: %12zu %12"FMTu64" %12"FMTu64 + "large: %12zu %12"FMTu64" %12"FMTu64 " %12"FMTu64"\n", - huge_allocated, huge_nmalloc, huge_ndalloc, huge_nrequests); + large_allocated, large_nmalloc, large_ndalloc, large_nrequests); malloc_cprintf(write_cb, cbopaque, "total: %12zu %12"FMTu64" %12"FMTu64 " %12"FMTu64"\n", - small_allocated + huge_allocated, small_nmalloc + huge_nmalloc, - small_ndalloc + huge_ndalloc, small_nrequests + huge_nrequests); + small_allocated + large_allocated, small_nmalloc + large_nmalloc, + small_ndalloc + large_ndalloc, small_nrequests + large_nrequests); malloc_cprintf(write_cb, cbopaque, "active: %12zu\n", pactive * page); CTL_M2_GET("stats.arenas.0.mapped", i, &mapped, size_t); @@ -300,8 +301,8 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, if (bins) stats_arena_bins_print(write_cb, cbopaque, i); - if (huge) - stats_arena_hchunks_print(write_cb, cbopaque, i); + if (large) + stats_arena_lextents_print(write_cb, cbopaque, i); } void @@ -315,7 +316,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, bool merged = true; bool unmerged = true; bool bins = true; - bool huge = true; + bool large = true; /* * Refresh stats, in case mallctl() was called by the application. @@ -356,7 +357,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, bins = false; break; case 'l': - huge = false; + large = false; break; default:; } @@ -568,7 +569,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "\nMerged arenas stats:\n"); stats_arena_print(write_cb, cbopaque, - narenas, bins, huge); + narenas, bins, large); } } } @@ -594,7 +595,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, cbopaque, "\narenas[%u]:\n", i); stats_arena_print(write_cb, - cbopaque, i, bins, huge); + cbopaque, i, bins, large); } } } diff --git a/src/tcache.c b/src/tcache.c index 02015227..69444fac 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -46,7 +46,7 @@ tcache_event_hard(tsd_t *tsd, tcache_t *tcache) tbin->ncached - tbin->low_water + (tbin->low_water >> 2)); } else { - tcache_bin_flush_huge(tsd, tbin, binind, tbin->ncached + tcache_bin_flush_large(tsd, tbin, binind, tbin->ncached - tbin->low_water + (tbin->low_water >> 2), tcache); } /* @@ -164,7 +164,7 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, } void -tcache_bin_flush_huge(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, +tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, unsigned rem, tcache_t *tcache) { arena_t *arena; @@ -194,9 +194,9 @@ tcache_bin_flush_huge(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, } if (config_stats) { merged_stats = true; - arena->stats.nrequests_huge += + arena->stats.nrequests_large += tbin->tstats.nrequests; - arena->stats.hstats[binind - NBINS].nrequests += + arena->stats.lstats[binind - NBINS].nrequests += tbin->tstats.nrequests; tbin->tstats.nrequests = 0; } @@ -207,7 +207,7 @@ tcache_bin_flush_huge(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, assert(ptr != NULL); extent = iealloc(tsd_tsdn(tsd), ptr); if (extent_arena_get(extent) == locked_arena) { - huge_dalloc_junked_locked(tsd_tsdn(tsd), + large_dalloc_junked_locked(tsd_tsdn(tsd), extent); } else { /* @@ -232,8 +232,8 @@ tcache_bin_flush_huge(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, * arena, so the stats didn't get merged. Manually do so now. */ malloc_mutex_lock(tsd_tsdn(tsd), &arena->lock); - arena->stats.nrequests_huge += tbin->tstats.nrequests; - arena->stats.hstats[binind - NBINS].nrequests += + arena->stats.nrequests_large += tbin->tstats.nrequests; + arena->stats.lstats[binind - NBINS].nrequests += tbin->tstats.nrequests; tbin->tstats.nrequests = 0; malloc_mutex_unlock(tsd_tsdn(tsd), &arena->lock); @@ -371,12 +371,12 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache) for (; i < nhbins; i++) { tcache_bin_t *tbin = &tcache->tbins[i]; - tcache_bin_flush_huge(tsd, tbin, i, 0, tcache); + tcache_bin_flush_large(tsd, tbin, i, 0, tcache); if (config_stats && tbin->tstats.nrequests != 0) { malloc_mutex_lock(tsd_tsdn(tsd), &arena->lock); - arena->stats.nrequests_huge += tbin->tstats.nrequests; - arena->stats.hstats[i - NBINS].nrequests += + arena->stats.nrequests_large += tbin->tstats.nrequests; + arena->stats.lstats[i - NBINS].nrequests += tbin->tstats.nrequests; malloc_mutex_unlock(tsd_tsdn(tsd), &arena->lock); } @@ -431,10 +431,10 @@ tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) } for (; i < nhbins; i++) { - malloc_huge_stats_t *hstats = &arena->stats.hstats[i - NBINS]; + malloc_large_stats_t *lstats = &arena->stats.lstats[i - NBINS]; tcache_bin_t *tbin = &tcache->tbins[i]; - arena->stats.nrequests_huge += tbin->tstats.nrequests; - hstats->nrequests += tbin->tstats.nrequests; + arena->stats.nrequests_large += tbin->tstats.nrequests; + lstats->nrequests += tbin->tstats.nrequests; tbin->tstats.nrequests = 0; } } @@ -537,7 +537,7 @@ tcache_boot(tsdn_t *tsdn) stack_nelms += tcache_bin_info[i].ncached_max; } for (; i < nhbins; i++) { - tcache_bin_info[i].ncached_max = TCACHE_NSLOTS_HUGE; + tcache_bin_info[i].ncached_max = TCACHE_NSLOTS_LARGE; stack_nelms += tcache_bin_info[i].ncached_max; } diff --git a/test/integration/chunk.c b/test/integration/chunk.c index 3aad7a8a..ca87e80f 100644 --- a/test/integration/chunk.c +++ b/test/integration/chunk.c @@ -120,7 +120,7 @@ chunk_merge(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b, TEST_BEGIN(test_chunk) { void *p; - size_t old_size, new_size, huge0, huge1, huge2, sz; + size_t old_size, new_size, large0, large1, large2, sz; unsigned arena_ind; int flags; size_t hooks_mib[3], purge_mib[3]; @@ -162,14 +162,14 @@ TEST_BEGIN(test_chunk) assert_ptr_ne(old_hooks.split, chunk_split, "Unexpected split error"); assert_ptr_ne(old_hooks.merge, chunk_merge, "Unexpected merge error"); - /* Get huge size classes. */ + /* Get large size classes. */ sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.hchunk.0.size", &huge0, &sz, NULL, 0), 0, - "Unexpected arenas.hchunk.0.size failure"); - assert_d_eq(mallctl("arenas.hchunk.1.size", &huge1, &sz, NULL, 0), 0, - "Unexpected arenas.hchunk.1.size failure"); - assert_d_eq(mallctl("arenas.hchunk.2.size", &huge2, &sz, NULL, 0), 0, - "Unexpected arenas.hchunk.2.size failure"); + assert_d_eq(mallctl("arenas.lextent.0.size", &large0, &sz, NULL, 0), 0, + "Unexpected arenas.lextent.0.size failure"); + assert_d_eq(mallctl("arenas.lextent.1.size", &large1, &sz, NULL, 0), 0, + "Unexpected arenas.lextent.1.size failure"); + assert_d_eq(mallctl("arenas.lextent.2.size", &large2, &sz, NULL, 0), 0, + "Unexpected arenas.lextent.2.size failure"); /* Test dalloc/decommit/purge cascade. */ purge_miblen = sizeof(purge_mib)/sizeof(size_t); @@ -178,13 +178,13 @@ TEST_BEGIN(test_chunk) purge_mib[1] = (size_t)arena_ind; do_dalloc = false; do_decommit = false; - p = mallocx(huge0 * 2, flags); + p = mallocx(large0 * 2, flags); assert_ptr_not_null(p, "Unexpected mallocx() error"); did_dalloc = false; did_decommit = false; did_purge = false; did_split = false; - xallocx_success_a = (xallocx(p, huge0, 0, flags) == huge0); + xallocx_success_a = (xallocx(p, large0, 0, flags) == large0); assert_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0), 0, "Unexpected arena.%u.purge error", arena_ind); if (xallocx_success_a) { @@ -199,18 +199,18 @@ TEST_BEGIN(test_chunk) /* Test decommit/commit and observe split/merge. */ do_dalloc = false; do_decommit = true; - p = mallocx(huge0 * 2, flags); + p = mallocx(large0 * 2, flags); assert_ptr_not_null(p, "Unexpected mallocx() error"); did_decommit = false; did_commit = false; did_split = false; did_merge = false; - xallocx_success_b = (xallocx(p, huge0, 0, flags) == huge0); + xallocx_success_b = (xallocx(p, large0, 0, flags) == large0); assert_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0), 0, "Unexpected arena.%u.purge error", arena_ind); if (xallocx_success_b) assert_true(did_split, "Expected split"); - xallocx_success_c = (xallocx(p, huge0 * 2, 0, flags) == huge0 * 2); + xallocx_success_c = (xallocx(p, large0 * 2, 0, flags) == large0 * 2); assert_b_eq(did_decommit, did_commit, "Expected decommit/commit match"); if (xallocx_success_b && xallocx_success_c) assert_true(did_merge, "Expected merge"); @@ -218,7 +218,7 @@ TEST_BEGIN(test_chunk) do_dalloc = true; do_decommit = false; - /* Make sure non-huge allocation succeeds. */ + /* Make sure non-large allocation succeeds. */ p = mallocx(42, flags); assert_ptr_not_null(p, "Unexpected mallocx() error"); dallocx(p, flags); diff --git a/test/integration/mallocx.c b/test/integration/mallocx.c index 55e1a090..9d623eb7 100644 --- a/test/integration/mallocx.c +++ b/test/integration/mallocx.c @@ -18,10 +18,10 @@ get_nsizes_impl(const char *cmd) } static unsigned -get_nhuge(void) +get_nlarge(void) { - return (get_nsizes_impl("arenas.nhchunks")); + return (get_nsizes_impl("arenas.nlextents")); } static size_t @@ -44,20 +44,20 @@ get_size_impl(const char *cmd, size_t ind) } static size_t -get_huge_size(size_t ind) +get_large_size(size_t ind) { - return (get_size_impl("arenas.hchunk.0.size", ind)); + return (get_size_impl("arenas.lextent.0.size", ind)); } TEST_BEGIN(test_overflow) { - size_t hugemax; + size_t largemax; - hugemax = get_huge_size(get_nhuge()-1); + largemax = get_large_size(get_nlarge()-1); - assert_ptr_null(mallocx(hugemax+1, 0), - "Expected OOM for mallocx(size=%#zx, 0)", hugemax+1); + assert_ptr_null(mallocx(largemax+1, 0), + "Expected OOM for mallocx(size=%#zx, 0)", largemax+1); assert_ptr_null(mallocx(ZU(PTRDIFF_MAX)+1, 0), "Expected OOM for mallocx(size=%#zx, 0)", ZU(PTRDIFF_MAX)+1); @@ -73,7 +73,7 @@ TEST_END TEST_BEGIN(test_oom) { - size_t hugemax; + size_t largemax; bool oom; void *ptrs[3]; unsigned i; @@ -82,16 +82,16 @@ TEST_BEGIN(test_oom) * It should be impossible to allocate three objects that each consume * nearly half the virtual address space. */ - hugemax = get_huge_size(get_nhuge()-1); + largemax = get_large_size(get_nlarge()-1); oom = false; for (i = 0; i < sizeof(ptrs) / sizeof(void *); i++) { - ptrs[i] = mallocx(hugemax, 0); + ptrs[i] = mallocx(largemax, 0); if (ptrs[i] == NULL) oom = true; } assert_true(oom, "Expected OOM during series of calls to mallocx(size=%zu, 0)", - hugemax); + largemax); for (i = 0; i < sizeof(ptrs) / sizeof(void *); i++) { if (ptrs[i] != NULL) dallocx(ptrs[i], 0); diff --git a/test/integration/overflow.c b/test/integration/overflow.c index 303d9b2d..8dea1c95 100644 --- a/test/integration/overflow.c +++ b/test/integration/overflow.c @@ -2,19 +2,19 @@ TEST_BEGIN(test_overflow) { - unsigned nhchunks; + unsigned nlextents; size_t mib[4]; size_t sz, miblen, max_size_class; void *p; sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.nhchunks", &nhchunks, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arenas.nlextents", &nlextents, &sz, NULL, 0), 0, "Unexpected mallctl() error"); miblen = sizeof(mib) / sizeof(size_t); - assert_d_eq(mallctlnametomib("arenas.hchunk.0.size", mib, &miblen), 0, + assert_d_eq(mallctlnametomib("arenas.lextent.0.size", mib, &miblen), 0, "Unexpected mallctlnametomib() error"); - mib[2] = nhchunks - 1; + mib[2] = nlextents - 1; sz = sizeof(size_t); assert_d_eq(mallctlbymib(mib, miblen, &max_size_class, &sz, NULL, 0), 0, diff --git a/test/integration/rallocx.c b/test/integration/rallocx.c index 66ad8660..6278a490 100644 --- a/test/integration/rallocx.c +++ b/test/integration/rallocx.c @@ -14,10 +14,10 @@ get_nsizes_impl(const char *cmd) } static unsigned -get_nhuge(void) +get_nlarge(void) { - return (get_nsizes_impl("arenas.nhchunks")); + return (get_nsizes_impl("arenas.nlextents")); } static size_t @@ -40,10 +40,10 @@ get_size_impl(const char *cmd, size_t ind) } static size_t -get_huge_size(size_t ind) +get_large_size(size_t ind) { - return (get_size_impl("arenas.hchunk.0.size", ind)); + return (get_size_impl("arenas.lextent.0.size", ind)); } TEST_BEGIN(test_grow_and_shrink) @@ -221,16 +221,16 @@ TEST_END TEST_BEGIN(test_overflow) { - size_t hugemax; + size_t largemax; void *p; - hugemax = get_huge_size(get_nhuge()-1); + largemax = get_large_size(get_nlarge()-1); p = mallocx(1, 0); assert_ptr_not_null(p, "Unexpected mallocx() failure"); - assert_ptr_null(rallocx(p, hugemax+1, 0), - "Expected OOM for rallocx(p, size=%#zx, 0)", hugemax+1); + assert_ptr_null(rallocx(p, largemax+1, 0), + "Expected OOM for rallocx(p, size=%#zx, 0)", largemax+1); assert_ptr_null(rallocx(p, ZU(PTRDIFF_MAX)+1, 0), "Expected OOM for rallocx(p, size=%#zx, 0)", ZU(PTRDIFF_MAX)+1); diff --git a/test/integration/xallocx.c b/test/integration/xallocx.c index 7af1b194..4ff099f8 100644 --- a/test/integration/xallocx.c +++ b/test/integration/xallocx.c @@ -92,10 +92,10 @@ get_nsmall(void) } static unsigned -get_nhuge(void) +get_nlarge(void) { - return (get_nsizes_impl("arenas.nhchunks")); + return (get_nsizes_impl("arenas.nlextents")); } static size_t @@ -125,20 +125,20 @@ get_small_size(size_t ind) } static size_t -get_huge_size(size_t ind) +get_large_size(size_t ind) { - return (get_size_impl("arenas.hchunk.0.size", ind)); + return (get_size_impl("arenas.lextent.0.size", ind)); } TEST_BEGIN(test_size) { - size_t small0, hugemax; + size_t small0, largemax; void *p; /* Get size classes. */ small0 = get_small_size(0); - hugemax = get_huge_size(get_nhuge()-1); + largemax = get_large_size(get_nlarge()-1); p = mallocx(small0, 0); assert_ptr_not_null(p, "Unexpected mallocx() error"); @@ -148,13 +148,13 @@ TEST_BEGIN(test_size) "Unexpected xallocx() behavior"); /* Test largest supported size. */ - assert_zu_le(xallocx(p, hugemax, 0, 0), hugemax, + assert_zu_le(xallocx(p, largemax, 0, 0), largemax, "Unexpected xallocx() behavior"); /* Test size overflow. */ - assert_zu_le(xallocx(p, hugemax+1, 0, 0), hugemax, + assert_zu_le(xallocx(p, largemax+1, 0, 0), largemax, "Unexpected xallocx() behavior"); - assert_zu_le(xallocx(p, SIZE_T_MAX, 0, 0), hugemax, + assert_zu_le(xallocx(p, SIZE_T_MAX, 0, 0), largemax, "Unexpected xallocx() behavior"); dallocx(p, 0); @@ -163,30 +163,30 @@ TEST_END TEST_BEGIN(test_size_extra_overflow) { - size_t small0, hugemax; + size_t small0, largemax; void *p; /* Get size classes. */ small0 = get_small_size(0); - hugemax = get_huge_size(get_nhuge()-1); + largemax = get_large_size(get_nlarge()-1); p = mallocx(small0, 0); assert_ptr_not_null(p, "Unexpected mallocx() error"); /* Test overflows that can be resolved by clamping extra. */ - assert_zu_le(xallocx(p, hugemax-1, 2, 0), hugemax, + assert_zu_le(xallocx(p, largemax-1, 2, 0), largemax, "Unexpected xallocx() behavior"); - assert_zu_le(xallocx(p, hugemax, 1, 0), hugemax, + assert_zu_le(xallocx(p, largemax, 1, 0), largemax, "Unexpected xallocx() behavior"); - /* Test overflow such that hugemax-size underflows. */ - assert_zu_le(xallocx(p, hugemax+1, 2, 0), hugemax, + /* Test overflow such that largemax-size underflows. */ + assert_zu_le(xallocx(p, largemax+1, 2, 0), largemax, "Unexpected xallocx() behavior"); - assert_zu_le(xallocx(p, hugemax+2, 3, 0), hugemax, + assert_zu_le(xallocx(p, largemax+2, 3, 0), largemax, "Unexpected xallocx() behavior"); - assert_zu_le(xallocx(p, SIZE_T_MAX-2, 2, 0), hugemax, + assert_zu_le(xallocx(p, SIZE_T_MAX-2, 2, 0), largemax, "Unexpected xallocx() behavior"); - assert_zu_le(xallocx(p, SIZE_T_MAX-1, 1, 0), hugemax, + assert_zu_le(xallocx(p, SIZE_T_MAX-1, 1, 0), largemax, "Unexpected xallocx() behavior"); dallocx(p, 0); @@ -195,13 +195,13 @@ TEST_END TEST_BEGIN(test_extra_small) { - size_t small0, small1, hugemax; + size_t small0, small1, largemax; void *p; /* Get size classes. */ small0 = get_small_size(0); small1 = get_small_size(1); - hugemax = get_huge_size(get_nhuge()-1); + largemax = get_large_size(get_nlarge()-1); p = mallocx(small0, 0); assert_ptr_not_null(p, "Unexpected mallocx() error"); @@ -216,7 +216,7 @@ TEST_BEGIN(test_extra_small) "Unexpected xallocx() behavior"); /* Test size+extra overflow. */ - assert_zu_eq(xallocx(p, small0, hugemax - small0 + 1, 0), small0, + assert_zu_eq(xallocx(p, small0, largemax - small0 + 1, 0), small0, "Unexpected xallocx() behavior"); assert_zu_eq(xallocx(p, small0, SIZE_T_MAX - small0, 0), small0, "Unexpected xallocx() behavior"); @@ -225,66 +225,66 @@ TEST_BEGIN(test_extra_small) } TEST_END -TEST_BEGIN(test_extra_huge) +TEST_BEGIN(test_extra_large) { int flags = MALLOCX_ARENA(arena_ind()); - size_t smallmax, huge1, huge2, huge3, hugemax; + size_t smallmax, large1, large2, large3, largemax; void *p; /* Get size classes. */ smallmax = get_small_size(get_nsmall()-1); - huge1 = get_huge_size(1); - huge2 = get_huge_size(2); - huge3 = get_huge_size(3); - hugemax = get_huge_size(get_nhuge()-1); + large1 = get_large_size(1); + large2 = get_large_size(2); + large3 = get_large_size(3); + largemax = get_large_size(get_nlarge()-1); - p = mallocx(huge3, flags); + p = mallocx(large3, flags); assert_ptr_not_null(p, "Unexpected mallocx() error"); - assert_zu_eq(xallocx(p, huge3, 0, flags), huge3, + assert_zu_eq(xallocx(p, large3, 0, flags), large3, "Unexpected xallocx() behavior"); /* Test size decrease with zero extra. */ - assert_zu_ge(xallocx(p, huge1, 0, flags), huge1, + assert_zu_ge(xallocx(p, large1, 0, flags), large1, "Unexpected xallocx() behavior"); - assert_zu_ge(xallocx(p, smallmax, 0, flags), huge1, + assert_zu_ge(xallocx(p, smallmax, 0, flags), large1, "Unexpected xallocx() behavior"); - assert_zu_eq(xallocx(p, huge3, 0, flags), huge3, + assert_zu_eq(xallocx(p, large3, 0, flags), large3, "Unexpected xallocx() behavior"); /* Test size decrease with non-zero extra. */ - assert_zu_eq(xallocx(p, huge1, huge3 - huge1, flags), huge3, + assert_zu_eq(xallocx(p, large1, large3 - large1, flags), large3, "Unexpected xallocx() behavior"); - assert_zu_eq(xallocx(p, huge2, huge3 - huge2, flags), huge3, + assert_zu_eq(xallocx(p, large2, large3 - large2, flags), large3, "Unexpected xallocx() behavior"); - assert_zu_eq(xallocx(p, huge1, huge2 - huge1, flags), huge2, + assert_zu_eq(xallocx(p, large1, large2 - large1, flags), large2, "Unexpected xallocx() behavior"); - assert_zu_ge(xallocx(p, smallmax, huge1 - smallmax, flags), huge1, + assert_zu_ge(xallocx(p, smallmax, large1 - smallmax, flags), large1, "Unexpected xallocx() behavior"); - assert_zu_ge(xallocx(p, huge1, 0, flags), huge1, + assert_zu_ge(xallocx(p, large1, 0, flags), large1, "Unexpected xallocx() behavior"); /* Test size increase with zero extra. */ - assert_zu_le(xallocx(p, huge3, 0, flags), huge3, + assert_zu_le(xallocx(p, large3, 0, flags), large3, "Unexpected xallocx() behavior"); - assert_zu_le(xallocx(p, hugemax+1, 0, flags), huge3, + assert_zu_le(xallocx(p, largemax+1, 0, flags), large3, "Unexpected xallocx() behavior"); - assert_zu_ge(xallocx(p, huge1, 0, flags), huge1, + assert_zu_ge(xallocx(p, large1, 0, flags), large1, "Unexpected xallocx() behavior"); /* Test size increase with non-zero extra. */ - assert_zu_le(xallocx(p, huge1, SIZE_T_MAX - huge1, flags), hugemax, + assert_zu_le(xallocx(p, large1, SIZE_T_MAX - large1, flags), largemax, "Unexpected xallocx() behavior"); - assert_zu_ge(xallocx(p, huge1, 0, flags), huge1, + assert_zu_ge(xallocx(p, large1, 0, flags), large1, "Unexpected xallocx() behavior"); /* Test size increase with non-zero extra. */ - assert_zu_le(xallocx(p, huge1, huge3 - huge1, flags), huge3, + assert_zu_le(xallocx(p, large1, large3 - large1, flags), large3, "Unexpected xallocx() behavior"); - assert_zu_eq(xallocx(p, huge3, 0, flags), huge3, + assert_zu_eq(xallocx(p, large3, 0, flags), large3, "Unexpected xallocx() behavior"); /* Test size+extra overflow. */ - assert_zu_le(xallocx(p, huge3, hugemax - huge3 + 1, flags), hugemax, + assert_zu_le(xallocx(p, large3, largemax - large3 + 1, flags), largemax, "Unexpected xallocx() behavior"); dallocx(p, flags); @@ -374,15 +374,15 @@ test_zero(size_t szmin, size_t szmax) dallocx(p, flags); } -TEST_BEGIN(test_zero_huge) +TEST_BEGIN(test_zero_large) { - size_t huge0, huge1; + size_t large0, large1; /* Get size classes. */ - huge0 = get_huge_size(0); - huge1 = get_huge_size(1); + large0 = get_large_size(0); + large1 = get_large_size(1); - test_zero(huge1, huge0 * 2); + test_zero(large1, large0 * 2); } TEST_END @@ -397,6 +397,6 @@ main(void) test_size, test_size_extra_overflow, test_extra_small, - test_extra_huge, - test_zero_huge)); + test_extra_large, + test_zero_large)); } diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 546d3cc8..a9476b89 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -25,10 +25,10 @@ get_nsmall(void) } static unsigned -get_nhuge(void) +get_nlarge(void) { - return (get_nsizes_impl("arenas.nhchunks")); + return (get_nsizes_impl("arenas.nlextents")); } static size_t @@ -58,10 +58,10 @@ get_small_size(size_t ind) } static size_t -get_huge_size(size_t ind) +get_large_size(size_t ind) { - return (get_size_impl("arenas.hchunk.0.size", ind)); + return (get_size_impl("arenas.lextent.0.size", ind)); } /* Like ivsalloc(), but safe to call on discarded allocations. */ @@ -81,8 +81,8 @@ vsalloc(tsdn_t *tsdn, const void *ptr) TEST_BEGIN(test_arena_reset) { -#define NHUGE 32 - unsigned arena_ind, nsmall, nhuge, nptrs, i; +#define NLARGE 32 + unsigned arena_ind, nsmall, nlarge, nptrs, i; size_t sz, miblen; void **ptrs; int flags; @@ -96,8 +96,8 @@ TEST_BEGIN(test_arena_reset) flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; nsmall = get_nsmall(); - nhuge = get_nhuge() > NHUGE ? NHUGE : get_nhuge(); - nptrs = nsmall + nhuge; + nlarge = get_nlarge() > NLARGE ? NLARGE : get_nlarge(); + nptrs = nsmall + nlarge; ptrs = (void **)malloc(nptrs * sizeof(void *)); assert_ptr_not_null(ptrs, "Unexpected malloc() failure"); @@ -108,8 +108,8 @@ TEST_BEGIN(test_arena_reset) assert_ptr_not_null(ptrs[i], "Unexpected mallocx(%zu, %#x) failure", sz, flags); } - for (i = 0; i < nhuge; i++) { - sz = get_huge_size(i); + for (i = 0; i < nlarge; i++) { + sz = get_large_size(i); ptrs[nsmall + i] = mallocx(sz, flags); assert_ptr_not_null(ptrs[i], "Unexpected mallocx(%zu, %#x) failure", sz, flags); diff --git a/test/unit/decay.c b/test/unit/decay.c index 786cc934..592935d3 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -22,7 +22,7 @@ TEST_BEGIN(test_decay_ticks) { ticker_t *decay_ticker; unsigned tick0, tick1; - size_t sz, huge0; + size_t sz, large0; void *p; test_skip_if(opt_purge != purge_mode_decay); @@ -32,18 +32,18 @@ TEST_BEGIN(test_decay_ticks) "Unexpected failure getting decay ticker"); sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.hchunk.0.size", &huge0, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arenas.lextent.0.size", &large0, &sz, NULL, 0), 0, "Unexpected mallctl failure"); /* - * Test the standard APIs using a huge size class, since we can't + * Test the standard APIs using a large size class, since we can't * control tcache interactions for small size classes (except by * completely disabling tcache for the entire test program). */ /* malloc(). */ tick0 = ticker_read(decay_ticker); - p = malloc(huge0); + p = malloc(large0); assert_ptr_not_null(p, "Unexpected malloc() failure"); tick1 = ticker_read(decay_ticker); assert_u32_ne(tick1, tick0, "Expected ticker to tick during malloc()"); @@ -55,7 +55,7 @@ TEST_BEGIN(test_decay_ticks) /* calloc(). */ tick0 = ticker_read(decay_ticker); - p = calloc(1, huge0); + p = calloc(1, large0); assert_ptr_not_null(p, "Unexpected calloc() failure"); tick1 = ticker_read(decay_ticker); assert_u32_ne(tick1, tick0, "Expected ticker to tick during calloc()"); @@ -63,7 +63,7 @@ TEST_BEGIN(test_decay_ticks) /* posix_memalign(). */ tick0 = ticker_read(decay_ticker); - assert_d_eq(posix_memalign(&p, sizeof(size_t), huge0), 0, + assert_d_eq(posix_memalign(&p, sizeof(size_t), large0), 0, "Unexpected posix_memalign() failure"); tick1 = ticker_read(decay_ticker); assert_u32_ne(tick1, tick0, @@ -72,7 +72,7 @@ TEST_BEGIN(test_decay_ticks) /* aligned_alloc(). */ tick0 = ticker_read(decay_ticker); - p = aligned_alloc(sizeof(size_t), huge0); + p = aligned_alloc(sizeof(size_t), large0); assert_ptr_not_null(p, "Unexpected aligned_alloc() failure"); tick1 = ticker_read(decay_ticker); assert_u32_ne(tick1, tick0, @@ -82,13 +82,13 @@ TEST_BEGIN(test_decay_ticks) /* realloc(). */ /* Allocate. */ tick0 = ticker_read(decay_ticker); - p = realloc(NULL, huge0); + p = realloc(NULL, large0); assert_ptr_not_null(p, "Unexpected realloc() failure"); tick1 = ticker_read(decay_ticker); assert_u32_ne(tick1, tick0, "Expected ticker to tick during realloc()"); /* Reallocate. */ tick0 = ticker_read(decay_ticker); - p = realloc(p, huge0); + p = realloc(p, large0); assert_ptr_not_null(p, "Unexpected realloc() failure"); tick1 = ticker_read(decay_ticker); assert_u32_ne(tick1, tick0, "Expected ticker to tick during realloc()"); @@ -99,13 +99,13 @@ TEST_BEGIN(test_decay_ticks) assert_u32_ne(tick1, tick0, "Expected ticker to tick during realloc()"); /* - * Test the *allocx() APIs using huge and small size classes, with + * Test the *allocx() APIs using large and small size classes, with * tcache explicitly disabled. */ { unsigned i; size_t allocx_sizes[2]; - allocx_sizes[0] = huge0; + allocx_sizes[0] = large0; allocx_sizes[1] = 1; for (i = 0; i < sizeof(allocx_sizes) / sizeof(size_t); i++) { @@ -154,13 +154,13 @@ TEST_BEGIN(test_decay_ticks) } /* - * Test tcache fill/flush interactions for huge and small size classes, + * Test tcache fill/flush interactions for large and small size classes, * using an explicit tcache. */ if (config_tcache) { unsigned tcache_ind, i; size_t tcache_sizes[2]; - tcache_sizes[0] = huge0; + tcache_sizes[0] = large0; tcache_sizes[1] = 1; sz = sizeof(unsigned); @@ -201,14 +201,14 @@ TEST_BEGIN(test_decay_ticker) uint64_t epoch; uint64_t npurge0 = 0; uint64_t npurge1 = 0; - size_t sz, huge; + size_t sz, large; unsigned i, nupdates0; nstime_t time, decay_time, deadline; test_skip_if(opt_purge != purge_mode_decay); /* - * Allocate a bunch of huge objects, pause the clock, deallocate the + * Allocate a bunch of large objects, pause the clock, deallocate the * objects, restore the clock, then [md]allocx() in a tight loop to * verify the ticker triggers purging. */ @@ -219,10 +219,10 @@ TEST_BEGIN(test_decay_ticker) sz = sizeof(size_t); assert_d_eq(mallctl("arenas.tcache_max", &tcache_max, &sz, NULL, 0), 0, "Unexpected mallctl failure"); - huge = nallocx(tcache_max + 1, flags); + large = nallocx(tcache_max + 1, flags); } else { sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.hchunk.0.size", &huge, &sz, NULL, + assert_d_eq(mallctl("arenas.lextent.0.size", &large, &sz, NULL, 0), 0, "Unexpected mallctl failure"); } @@ -235,7 +235,7 @@ TEST_BEGIN(test_decay_ticker) config_stats ? 0 : ENOENT, "Unexpected mallctl result"); for (i = 0; i < NPS; i++) { - ps[i] = mallocx(huge, flags); + ps[i] = mallocx(large, flags); assert_ptr_not_null(ps[i], "Unexpected mallocx() failure"); } @@ -293,13 +293,13 @@ TEST_BEGIN(test_decay_nonmonotonic) uint64_t epoch; uint64_t npurge0 = 0; uint64_t npurge1 = 0; - size_t sz, huge0; + size_t sz, large0; unsigned i, nupdates0; test_skip_if(opt_purge != purge_mode_decay); sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.hchunk.0.size", &huge0, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arenas.lextent.0.size", &large0, &sz, NULL, 0), 0, "Unexpected mallctl failure"); assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, @@ -319,7 +319,7 @@ TEST_BEGIN(test_decay_nonmonotonic) nstime_update = nstime_update_mock; for (i = 0; i < NPS; i++) { - ps[i] = mallocx(huge0, flags); + ps[i] = mallocx(large0, flags); assert_ptr_not_null(ps[i], "Unexpected mallocx() failure"); } diff --git a/test/unit/extent_quantize.c b/test/unit/extent_quantize.c index a165aece..d8928da0 100644 --- a/test/unit/extent_quantize.c +++ b/test/unit/extent_quantize.c @@ -35,16 +35,16 @@ TEST_BEGIN(test_small_extent_size) } TEST_END -TEST_BEGIN(test_huge_extent_size) +TEST_BEGIN(test_large_extent_size) { bool cache_oblivious; - unsigned nhchunks, i; + unsigned nlextents, i; size_t sz, extent_size_prev, ceil_prev; size_t mib[4]; size_t miblen = sizeof(mib) / sizeof(size_t); /* - * Iterate over all huge size classes, get their extent sizes, and + * Iterate over all large size classes, get their extent sizes, and * verify that the quantized size is the same as the extent size. */ @@ -53,12 +53,12 @@ TEST_BEGIN(test_huge_extent_size) NULL, 0), 0, "Unexpected mallctl failure"); sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.nhchunks", &nhchunks, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arenas.nlextents", &nlextents, &sz, NULL, 0), 0, "Unexpected mallctl failure"); - assert_d_eq(mallctlnametomib("arenas.hchunk.0.size", mib, &miblen), 0, + assert_d_eq(mallctlnametomib("arenas.lextent.0.size", mib, &miblen), 0, "Unexpected mallctlnametomib failure"); - for (i = 0; i < nhchunks; i++) { + for (i = 0; i < nlextents; i++) { size_t lextent_size, extent_size, floor, ceil; mib[2] = i; @@ -91,7 +91,7 @@ TEST_BEGIN(test_huge_extent_size) ceil_prev, extent_size); } } - if (i + 1 < nhchunks) { + if (i + 1 < nlextents) { extent_size_prev = floor; ceil_prev = extent_size_quantize_ceil(extent_size + PAGE); @@ -141,6 +141,6 @@ main(void) return (test( test_small_extent_size, - test_huge_extent_size, + test_large_extent_size, test_monotonic)); } diff --git a/test/unit/junk.c b/test/unit/junk.c index cdf8fb3c..7a923509 100644 --- a/test/unit/junk.c +++ b/test/unit/junk.c @@ -9,7 +9,7 @@ const char *malloc_conf = #endif static arena_dalloc_junk_small_t *arena_dalloc_junk_small_orig; -static huge_dalloc_junk_t *huge_dalloc_junk_orig; +static large_dalloc_junk_t *large_dalloc_junk_orig; static void *watch_for_junking; static bool saw_junking; @@ -37,10 +37,10 @@ arena_dalloc_junk_small_intercept(void *ptr, const arena_bin_info_t *bin_info) } static void -huge_dalloc_junk_intercept(void *ptr, size_t usize) +large_dalloc_junk_intercept(void *ptr, size_t usize) { - huge_dalloc_junk_orig(ptr, usize); + large_dalloc_junk_orig(ptr, usize); /* * The conditions under which junk filling actually occurs are nuanced * enough that it doesn't make sense to duplicate the decision logic in @@ -59,8 +59,8 @@ test_junk(size_t sz_min, size_t sz_max) if (opt_junk_free) { arena_dalloc_junk_small_orig = arena_dalloc_junk_small; arena_dalloc_junk_small = arena_dalloc_junk_small_intercept; - huge_dalloc_junk_orig = huge_dalloc_junk; - huge_dalloc_junk = huge_dalloc_junk_intercept; + large_dalloc_junk_orig = large_dalloc_junk; + large_dalloc_junk = large_dalloc_junk_intercept; } sz_prev = 0; @@ -110,7 +110,7 @@ test_junk(size_t sz_min, size_t sz_max) if (opt_junk_free) { arena_dalloc_junk_small = arena_dalloc_junk_small_orig; - huge_dalloc_junk = huge_dalloc_junk_orig; + large_dalloc_junk = large_dalloc_junk_orig; } } @@ -122,7 +122,7 @@ TEST_BEGIN(test_junk_small) } TEST_END -TEST_BEGIN(test_junk_huge) +TEST_BEGIN(test_junk_large) { test_skip_if(!config_fill); @@ -136,5 +136,5 @@ main(void) return (test( test_junk_small, - test_junk_huge)); + test_junk_large)); } diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 872aeaa0..8eb5a60c 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -596,7 +596,7 @@ TEST_BEGIN(test_arenas_constants) TEST_ARENAS_CONSTANT(size_t, quantum, QUANTUM); TEST_ARENAS_CONSTANT(size_t, page, PAGE); TEST_ARENAS_CONSTANT(unsigned, nbins, NBINS); - TEST_ARENAS_CONSTANT(unsigned, nhchunks, NSIZES - NBINS); + TEST_ARENAS_CONSTANT(unsigned, nlextents, NSIZES - NBINS); #undef TEST_ARENAS_CONSTANT } @@ -622,13 +622,13 @@ TEST_BEGIN(test_arenas_bin_constants) } TEST_END -TEST_BEGIN(test_arenas_hchunk_constants) +TEST_BEGIN(test_arenas_lextent_constants) { #define TEST_ARENAS_HCHUNK_CONSTANT(t, name, expected) do { \ t name; \ size_t sz = sizeof(t); \ - assert_d_eq(mallctl("arenas.hchunk.0."#name, &name, &sz, NULL, \ + assert_d_eq(mallctl("arenas.lextent.0."#name, &name, &sz, NULL, \ 0), 0, "Unexpected mallctl() failure"); \ assert_zu_eq(name, expected, "Incorrect "#name" size"); \ } while (0) @@ -704,7 +704,7 @@ main(void) test_arenas_decay_time, test_arenas_constants, test_arenas_bin_constants, - test_arenas_hchunk_constants, + test_arenas_lextent_constants, test_arenas_extend, test_stats_arenas)); } diff --git a/test/unit/size_classes.c b/test/unit/size_classes.c index 4e1e0ce4..f5a5873d 100644 --- a/test/unit/size_classes.c +++ b/test/unit/size_classes.c @@ -3,18 +3,18 @@ static size_t get_max_size_class(void) { - unsigned nhchunks; + unsigned nlextents; size_t mib[4]; size_t sz, miblen, max_size_class; sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.nhchunks", &nhchunks, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arenas.nlextents", &nlextents, &sz, NULL, 0), 0, "Unexpected mallctl() error"); miblen = sizeof(mib) / sizeof(size_t); - assert_d_eq(mallctlnametomib("arenas.hchunk.0.size", mib, &miblen), 0, + assert_d_eq(mallctlnametomib("arenas.lextent.0.size", mib, &miblen), 0, "Unexpected mallctlnametomib() error"); - mib[2] = nhchunks - 1; + mib[2] = nlextents - 1; sz = sizeof(size_t); assert_d_eq(mallctlbymib(mib, miblen, &max_size_class, &sz, NULL, 0), 0, diff --git a/test/unit/stats.c b/test/unit/stats.c index f524c005..9fa9cead 100644 --- a/test/unit/stats.c +++ b/test/unit/stats.c @@ -33,7 +33,7 @@ TEST_BEGIN(test_stats_summary) } TEST_END -TEST_BEGIN(test_stats_huge) +TEST_BEGIN(test_stats_large) { void *p; uint64_t epoch; @@ -49,14 +49,14 @@ TEST_BEGIN(test_stats_huge) "Unexpected mallctl() failure"); sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.huge.allocated", &allocated, &sz, + assert_d_eq(mallctl("stats.arenas.0.large.allocated", &allocated, &sz, NULL, 0), expected, "Unexpected mallctl() result"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.huge.nmalloc", &nmalloc, &sz, NULL, + assert_d_eq(mallctl("stats.arenas.0.large.nmalloc", &nmalloc, &sz, NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.huge.ndalloc", &ndalloc, &sz, NULL, + assert_d_eq(mallctl("stats.arenas.0.large.ndalloc", &ndalloc, &sz, NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.huge.nrequests", &nrequests, &sz, + assert_d_eq(mallctl("stats.arenas.0.large.nrequests", &nrequests, &sz, NULL, 0), expected, "Unexpected mallctl() result"); if (config_stats) { @@ -75,7 +75,7 @@ TEST_END TEST_BEGIN(test_stats_arenas_summary) { unsigned arena; - void *little, *huge; + void *little, *large; uint64_t epoch; size_t sz; int expected = config_stats ? 0 : ENOENT; @@ -88,11 +88,11 @@ TEST_BEGIN(test_stats_arenas_summary) little = mallocx(SMALL_MAXCLASS, 0); assert_ptr_not_null(little, "Unexpected mallocx() failure"); - huge = mallocx(chunksize, 0); - assert_ptr_not_null(huge, "Unexpected mallocx() failure"); + large = mallocx(chunksize, 0); + assert_ptr_not_null(large, "Unexpected mallocx() failure"); dallocx(little, 0); - dallocx(huge, 0); + dallocx(large, 0); assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl() failure"); @@ -185,7 +185,7 @@ TEST_BEGIN(test_stats_arenas_small) } TEST_END -TEST_BEGIN(test_stats_arenas_huge) +TEST_BEGIN(test_stats_arenas_large) { unsigned arena; void *p; @@ -204,12 +204,12 @@ TEST_BEGIN(test_stats_arenas_huge) "Unexpected mallctl() failure"); sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.huge.allocated", &allocated, &sz, + assert_d_eq(mallctl("stats.arenas.0.large.allocated", &allocated, &sz, NULL, 0), expected, "Unexpected mallctl() result"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.huge.nmalloc", &nmalloc, &sz, + assert_d_eq(mallctl("stats.arenas.0.large.nmalloc", &nmalloc, &sz, NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.huge.ndalloc", &ndalloc, &sz, + assert_d_eq(mallctl("stats.arenas.0.large.ndalloc", &ndalloc, &sz, NULL, 0), expected, "Unexpected mallctl() result"); if (config_stats) { @@ -299,12 +299,12 @@ TEST_BEGIN(test_stats_arenas_bins) } TEST_END -TEST_BEGIN(test_stats_arenas_hchunks) +TEST_BEGIN(test_stats_arenas_lextents) { unsigned arena; void *p; uint64_t epoch, nmalloc, ndalloc; - size_t curhchunks, sz, hsize; + size_t curlextents, sz, hsize; int expected = config_stats ? 0 : ENOENT; arena = 0; @@ -312,7 +312,7 @@ TEST_BEGIN(test_stats_arenas_hchunks) 0, "Unexpected mallctl() failure"); sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.hchunk.0.size", &hsize, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arenas.lextent.0.size", &hsize, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); p = mallocx(hsize, 0); @@ -322,20 +322,20 @@ TEST_BEGIN(test_stats_arenas_hchunks) "Unexpected mallctl() failure"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.hchunks.0.nmalloc", &nmalloc, &sz, + assert_d_eq(mallctl("stats.arenas.0.lextents.0.nmalloc", &nmalloc, &sz, NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.hchunks.0.ndalloc", &ndalloc, &sz, + assert_d_eq(mallctl("stats.arenas.0.lextents.0.ndalloc", &ndalloc, &sz, NULL, 0), expected, "Unexpected mallctl() result"); sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.hchunks.0.curhchunks", &curhchunks, - &sz, NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.lextents.0.curlextents", + &curlextents, &sz, NULL, 0), expected, "Unexpected mallctl() result"); if (config_stats) { assert_u64_gt(nmalloc, 0, "nmalloc should be greater than zero"); assert_u64_ge(nmalloc, ndalloc, "nmalloc should be at least as large as ndalloc"); - assert_u64_gt(curhchunks, 0, + assert_u64_gt(curlextents, 0, "At least one chunk should be currently allocated"); } @@ -349,10 +349,10 @@ main(void) return (test( test_stats_summary, - test_stats_huge, + test_stats_large, test_stats_arenas_summary, test_stats_arenas_small, - test_stats_arenas_huge, + test_stats_arenas_large, test_stats_arenas_bins, - test_stats_arenas_hchunks)); + test_stats_arenas_lextents)); } diff --git a/test/unit/zero.c b/test/unit/zero.c index 2da288ac..3c35f4bd 100644 --- a/test/unit/zero.c +++ b/test/unit/zero.c @@ -53,7 +53,7 @@ TEST_BEGIN(test_zero_small) } TEST_END -TEST_BEGIN(test_zero_huge) +TEST_BEGIN(test_zero_large) { test_skip_if(!config_fill); @@ -67,5 +67,5 @@ main(void) return (test( test_zero_small, - test_zero_huge)); + test_zero_large)); } -- GitLab From 9c305c9e5c485c09100a17106c6562f8352a760d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 31 May 2016 15:03:51 -0700 Subject: [PATCH 046/544] s/chunk_hook/extent_hook/g --- doc/jemalloc.xml.in | 18 +- include/jemalloc/internal/arena.h | 8 +- include/jemalloc/internal/chunk.h | 31 ++-- include/jemalloc/internal/private_symbols.txt | 6 +- include/jemalloc/jemalloc_typedefs.h.in | 2 +- src/arena.c | 66 +++---- src/chunk.c | 175 +++++++++--------- src/chunk_dss.c | 4 +- src/ctl.c | 22 +-- src/jemalloc.c | 18 +- src/large.c | 19 +- test/integration/chunk.c | 22 +-- 12 files changed, 200 insertions(+), 191 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 7613c24c..801fd497 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -555,7 +555,7 @@ for (i = 0; i < nbins; i++) { allocations in place, as long as the pre-size and post-size are both large. For shrinkage to succeed, the extent allocator must support splitting (see arena.<i>.chunk_hooks). + linkend="arena.i.extent_hooks">arena.<i>.extent_hooks). Growth only succeeds if the trailing memory is currently available, and the extent allocator supports merging. @@ -1548,10 +1548,10 @@ malloc_conf = "xmalloc:true";]]> additional information. - + - arena.<i>.chunk_hooks - (chunk_hooks_t) + arena.<i>.extent_hooks + (extent_hooks_t) rw Get or set the chunk management hook functions for arena @@ -1561,7 +1561,7 @@ malloc_conf = "xmalloc:true";]]> control allocation for arenas created via arenas.extend such that all chunks originate from an application-supplied chunk allocator - (by setting custom chunk hook functions just after arena creation), but + (by setting custom extent hook functions just after arena creation), but the automatically created arenas may have already created chunks prior to the application having an opportunity to take over chunk allocation. @@ -1575,8 +1575,8 @@ typedef struct { chunk_purge_t *purge; chunk_split_t *split; chunk_merge_t *merge; -} chunk_hooks_t;]]> - The chunk_hooks_t structure comprises function +} extent_hooks_t;]]> + The extent_hooks_t structure comprises function pointers which are described individually below. jemalloc uses these functions to manage chunk lifetime, which starts off with allocation of mapped committed memory, in the simplest case followed by deallocation. @@ -2109,8 +2109,8 @@ typedef struct { 2. Retained virtual memory is typically untouched, decommitted, or purged, so it has no strongly associated physical memory (see chunk hooks for details). Retained - memory is excluded from mapped memory statistics, e.g. extent hooks for details). + Retained memory is excluded from mapped memory statistics, e.g. stats.mapped. diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 56f78571..f60b9d60 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -246,8 +246,8 @@ struct arena_s { ql_head(extent_t) extent_cache; malloc_mutex_t extent_cache_mtx; - /* User-configurable chunk hook functions. */ - chunk_hooks_t chunk_hooks; + /* User-configurable extent hook functions. */ + extent_hooks_t extent_hooks; /* bins is used to store heaps of free regions. */ arena_bin_t bins[NBINS]; @@ -279,10 +279,10 @@ extern ssize_t opt_decay_time; extern const arena_bin_info_t arena_bin_info[NBINS]; extent_t *arena_chunk_cache_alloc(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, + extent_hooks_t *extent_hooks, void *new_addr, size_t size, size_t alignment, bool *zero); void arena_chunk_cache_dalloc(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, extent_t *extent); + extent_hooks_t *extent_hooks, extent_t *extent); void arena_chunk_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache); void arena_chunk_cache_maybe_remove(arena_t *arena, extent_t *extent, diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index 6f50302e..10f2ae72 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -38,33 +38,36 @@ extern size_t chunksize; extern size_t chunksize_mask; /* (chunksize - 1). */ extern size_t chunk_npages; -extern const chunk_hooks_t chunk_hooks_default; +extern const extent_hooks_t extent_hooks_default; -chunk_hooks_t chunk_hooks_get(tsdn_t *tsdn, arena_t *arena); -chunk_hooks_t chunk_hooks_set(tsdn_t *tsdn, arena_t *arena, - const chunk_hooks_t *chunk_hooks); +extent_hooks_t extent_hooks_get(tsdn_t *tsdn, arena_t *arena); +extent_hooks_t extent_hooks_set(tsdn_t *tsdn, arena_t *arena, + const extent_hooks_t *extent_hooks); extent_t *chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *new_addr, size_t usize, size_t pad, + extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool slab); extent_t *chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *new_addr, size_t usize, size_t pad, + extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab); void chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, extent_t *extent); + extent_hooks_t *extent_hooks, extent_t *extent); void chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, extent_t *extent); + extent_hooks_t *extent_hooks, extent_t *extent); bool chunk_commit_wrapper(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, extent_t *extent, size_t offset, size_t length); + extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, + size_t length); bool chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, extent_t *extent, size_t offset, size_t length); + extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, + size_t length); bool chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, extent_t *extent, size_t offset, size_t length); + extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, + size_t length); extent_t *chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, extent_t *extent, size_t size_a, size_t usize_a, - size_t size_b, size_t usize_b); + extent_hooks_t *extent_hooks, extent_t *extent, size_t size_a, + size_t usize_a, size_t size_b, size_t usize_b); bool chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, extent_t *a, extent_t *b); + extent_hooks_t *extent_hooks, extent_t *a, extent_t *b); bool chunk_boot(void); void chunk_prefork(tsdn_t *tsdn); void chunk_postfork_parent(tsdn_t *tsdn); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index cab0fc54..b5fd4c0c 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -131,9 +131,6 @@ chunk_dss_postfork_parent chunk_dss_prec_get chunk_dss_prec_set chunk_dss_prefork -chunk_hooks_default -chunk_hooks_get -chunk_hooks_set chunk_in_dss chunk_lookup chunk_merge_wrapper @@ -185,6 +182,9 @@ extent_heap_insert extent_heap_new extent_heap_remove extent_heap_remove_first +extent_hooks_default +extent_hooks_get +extent_hooks_set extent_init extent_last_get extent_past_get diff --git a/include/jemalloc/jemalloc_typedefs.h.in b/include/jemalloc/jemalloc_typedefs.h.in index fa7b350a..2b07e362 100644 --- a/include/jemalloc/jemalloc_typedefs.h.in +++ b/include/jemalloc/jemalloc_typedefs.h.in @@ -54,4 +54,4 @@ typedef struct { chunk_purge_t *purge; chunk_split_t *split; chunk_merge_t *merge; -} chunk_hooks_t; +} extent_hooks_t; diff --git a/src/arena.c b/src/arena.c index 8194ced7..9a8c2e26 100644 --- a/src/arena.c +++ b/src/arena.c @@ -54,25 +54,25 @@ arena_chunk_dirty_npages(const extent_t *extent) static extent_t * arena_chunk_cache_alloc_locked(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *new_addr, size_t usize, size_t pad, + extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool slab) { malloc_mutex_assert_owner(tsdn, &arena->lock); - return (chunk_alloc_cache(tsdn, arena, chunk_hooks, new_addr, usize, + return (chunk_alloc_cache(tsdn, arena, extent_hooks, new_addr, usize, pad, alignment, zero, slab)); } extent_t * arena_chunk_cache_alloc(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *new_addr, size_t size, size_t alignment, + extent_hooks_t *extent_hooks, void *new_addr, size_t size, size_t alignment, bool *zero) { extent_t *extent; malloc_mutex_lock(tsdn, &arena->lock); - extent = arena_chunk_cache_alloc_locked(tsdn, arena, chunk_hooks, + extent = arena_chunk_cache_alloc_locked(tsdn, arena, extent_hooks, new_addr, size, 0, alignment, zero, false); malloc_mutex_unlock(tsdn, &arena->lock); @@ -81,22 +81,22 @@ arena_chunk_cache_alloc(tsdn_t *tsdn, arena_t *arena, static void arena_chunk_cache_dalloc_locked(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, extent_t *extent) + extent_hooks_t *extent_hooks, extent_t *extent) { malloc_mutex_assert_owner(tsdn, &arena->lock); - chunk_dalloc_cache(tsdn, arena, chunk_hooks, extent); + chunk_dalloc_cache(tsdn, arena, extent_hooks, extent); arena_maybe_purge(tsdn, arena); } void arena_chunk_cache_dalloc(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, extent_t *extent) + extent_hooks_t *extent_hooks, extent_t *extent) { malloc_mutex_lock(tsdn, &arena->lock); - arena_chunk_cache_dalloc_locked(tsdn, arena, chunk_hooks, extent); + arena_chunk_cache_dalloc_locked(tsdn, arena, extent_hooks, extent); malloc_mutex_unlock(tsdn, &arena->lock); } @@ -321,12 +321,12 @@ arena_large_ralloc_stats_update(arena_t *arena, size_t oldusize, size_t usize) static extent_t * arena_chunk_alloc_large_hard(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, size_t usize, size_t alignment, bool *zero) + extent_hooks_t *extent_hooks, size_t usize, size_t alignment, bool *zero) { extent_t *extent; bool commit = true; - extent = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, usize, + extent = chunk_alloc_wrapper(tsdn, arena, extent_hooks, NULL, usize, large_pad, alignment, zero, &commit, false); if (extent == NULL) { /* Revert optimistic stats updates. */ @@ -347,7 +347,7 @@ arena_chunk_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero) { extent_t *extent; - chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; + extent_hooks_t extent_hooks = CHUNK_HOOKS_INITIALIZER; malloc_mutex_lock(tsdn, &arena->lock); @@ -358,12 +358,12 @@ arena_chunk_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, } arena_nactive_add(arena, (usize + large_pad) >> LG_PAGE); - extent = arena_chunk_cache_alloc_locked(tsdn, arena, &chunk_hooks, NULL, - usize, large_pad, alignment, zero, false); + extent = arena_chunk_cache_alloc_locked(tsdn, arena, &extent_hooks, + NULL, usize, large_pad, alignment, zero, false); malloc_mutex_unlock(tsdn, &arena->lock); if (extent == NULL) { - extent = arena_chunk_alloc_large_hard(tsdn, arena, &chunk_hooks, - usize, alignment, zero); + extent = arena_chunk_alloc_large_hard(tsdn, arena, + &extent_hooks, usize, alignment, zero); } return (extent); @@ -373,7 +373,7 @@ void arena_chunk_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, bool locked) { - chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; + extent_hooks_t extent_hooks = CHUNK_HOOKS_INITIALIZER; if (!locked) malloc_mutex_lock(tsdn, &arena->lock); @@ -384,7 +384,7 @@ arena_chunk_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, } arena_nactive_sub(arena, extent_size_get(extent) >> LG_PAGE); - arena_chunk_cache_dalloc_locked(tsdn, arena, &chunk_hooks, extent); + arena_chunk_cache_dalloc_locked(tsdn, arena, &extent_hooks, extent); if (!locked) malloc_mutex_unlock(tsdn, &arena->lock); } @@ -735,7 +735,7 @@ arena_dirty_count(tsdn_t *tsdn, arena_t *arena) } static size_t -arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, +arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, size_t ndirty_limit, extent_t *purge_extents_sentinel) { extent_t *extent, *next; @@ -757,7 +757,7 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, /* Allocate. */ zero = false; textent = arena_chunk_cache_alloc_locked(tsdn, arena, - chunk_hooks, extent_base_get(extent), + extent_hooks, extent_base_get(extent), extent_size_get(extent), 0, CACHELINE, &zero, false); assert(textent == extent); assert(zero == extent_zeroed_get(extent)); @@ -774,7 +774,7 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } static size_t -arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, +arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_t *purge_extents_sentinel) { UNUSED size_t nmadvise; @@ -793,7 +793,7 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, next = qr_next(extent, qr_link); extent_ring_remove(extent); - chunk_dalloc_wrapper(tsdn, arena, chunk_hooks, extent); + chunk_dalloc_wrapper(tsdn, arena, extent_hooks, extent); } if (config_stats) { @@ -816,7 +816,7 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, static void arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) { - chunk_hooks_t chunk_hooks = chunk_hooks_get(tsdn, arena); + extent_hooks_t extent_hooks = extent_hooks_get(tsdn, arena); size_t npurge, npurged; extent_t purge_extents_sentinel; @@ -836,11 +836,11 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) extent_init(&purge_extents_sentinel, arena, NULL, 0, 0, false, false, false, false); - npurge = arena_stash_dirty(tsdn, arena, &chunk_hooks, ndirty_limit, + npurge = arena_stash_dirty(tsdn, arena, &extent_hooks, ndirty_limit, &purge_extents_sentinel); if (npurge == 0) goto label_return; - npurged = arena_purge_stashed(tsdn, arena, &chunk_hooks, + npurged = arena_purge_stashed(tsdn, arena, &extent_hooks, &purge_extents_sentinel); assert(npurged == npurge); @@ -866,10 +866,10 @@ arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) static void arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) { - chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; + extent_hooks_t extent_hooks = CHUNK_HOOKS_INITIALIZER; arena_nactive_sub(arena, extent_size_get(slab) >> LG_PAGE); - arena_chunk_cache_dalloc_locked(tsdn, arena, &chunk_hooks, slab); + arena_chunk_cache_dalloc_locked(tsdn, arena, &extent_hooks, slab); } void @@ -987,8 +987,8 @@ arena_bin_slabs_full_remove(extent_t *slab) } static extent_t * -arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - const arena_bin_info_t *bin_info) +arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, const arena_bin_info_t *bin_info) { extent_t *slab; bool zero, commit; @@ -996,7 +996,7 @@ arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, zero = false; commit = true; malloc_mutex_unlock(tsdn, &arena->lock); - slab = chunk_alloc_wrapper(tsdn, arena, chunk_hooks, NULL, + slab = chunk_alloc_wrapper(tsdn, arena, extent_hooks, NULL, bin_info->slab_size, 0, PAGE, &zero, &commit, true); malloc_mutex_lock(tsdn, &arena->lock); @@ -1009,14 +1009,14 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, { extent_t *slab; arena_slab_data_t *slab_data; - chunk_hooks_t chunk_hooks = CHUNK_HOOKS_INITIALIZER; + extent_hooks_t extent_hooks = CHUNK_HOOKS_INITIALIZER; bool zero; zero = false; - slab = arena_chunk_cache_alloc_locked(tsdn, arena, &chunk_hooks, NULL, + slab = arena_chunk_cache_alloc_locked(tsdn, arena, &extent_hooks, NULL, bin_info->slab_size, 0, PAGE, &zero, true); if (slab == NULL) { - slab = arena_slab_alloc_hard(tsdn, arena, &chunk_hooks, + slab = arena_slab_alloc_hard(tsdn, arena, &extent_hooks, bin_info); if (slab == NULL) return (NULL); @@ -1805,7 +1805,7 @@ arena_new(tsdn_t *tsdn, unsigned ind) WITNESS_RANK_ARENA_EXTENT_CACHE)) return (NULL); - arena->chunk_hooks = chunk_hooks_default; + arena->extent_hooks = extent_hooks_default; /* Initialize bins. */ for (i = 0; i < NBINS; i++) { diff --git a/src/chunk.c b/src/chunk.c index e2e9de03..6ca40572 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -33,7 +33,7 @@ static bool chunk_split_default(void *chunk, size_t size, size_t size_a, static bool chunk_merge_default(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b, bool committed, unsigned arena_ind); -const chunk_hooks_t chunk_hooks_default = { +const extent_hooks_t extent_hooks_default = { chunk_alloc_default, chunk_dalloc_default, chunk_commit_default, @@ -50,8 +50,8 @@ const chunk_hooks_t chunk_hooks_default = { */ static void chunk_record(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, extent_heap_t extent_heaps[NPSIZES], bool cache, - extent_t *extent); + extent_hooks_t *extent_hooks, extent_heap_t extent_heaps[NPSIZES], + bool cache, extent_t *extent); /******************************************************************************/ @@ -71,37 +71,38 @@ extent_heaps_remove(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) extent_heap_remove(&extent_heaps[pind], extent); } -static chunk_hooks_t -chunk_hooks_get_locked(arena_t *arena) +static extent_hooks_t +extent_hooks_get_locked(arena_t *arena) { - return (arena->chunk_hooks); + return (arena->extent_hooks); } -chunk_hooks_t -chunk_hooks_get(tsdn_t *tsdn, arena_t *arena) +extent_hooks_t +extent_hooks_get(tsdn_t *tsdn, arena_t *arena) { - chunk_hooks_t chunk_hooks; + extent_hooks_t extent_hooks; malloc_mutex_lock(tsdn, &arena->chunks_mtx); - chunk_hooks = chunk_hooks_get_locked(arena); + extent_hooks = extent_hooks_get_locked(arena); malloc_mutex_unlock(tsdn, &arena->chunks_mtx); - return (chunk_hooks); + return (extent_hooks); } -chunk_hooks_t -chunk_hooks_set(tsdn_t *tsdn, arena_t *arena, const chunk_hooks_t *chunk_hooks) +extent_hooks_t +extent_hooks_set(tsdn_t *tsdn, arena_t *arena, + const extent_hooks_t *extent_hooks) { - chunk_hooks_t old_chunk_hooks; + extent_hooks_t old_extent_hooks; malloc_mutex_lock(tsdn, &arena->chunks_mtx); - old_chunk_hooks = arena->chunk_hooks; + old_extent_hooks = arena->extent_hooks; /* * Copy each field atomically so that it is impossible for readers to * see partially updated pointers. There are places where readers only * need one hook function pointer (therefore no need to copy the - * entirety of arena->chunk_hooks), and stale reads do not affect + * entirety of arena->extent_hooks), and stale reads do not affect * correctness, so they perform unlocked reads. */ #define ATOMIC_COPY_HOOK(n) do { \ @@ -109,8 +110,8 @@ chunk_hooks_set(tsdn_t *tsdn, arena_t *arena, const chunk_hooks_t *chunk_hooks) chunk_##n##_t **n; \ void **v; \ } u; \ - u.n = &arena->chunk_hooks.n; \ - atomic_write_p(u.v, chunk_hooks->n); \ + u.n = &arena->extent_hooks.n; \ + atomic_write_p(u.v, extent_hooks->n); \ } while (0) ATOMIC_COPY_HOOK(alloc); ATOMIC_COPY_HOOK(dalloc); @@ -122,37 +123,37 @@ chunk_hooks_set(tsdn_t *tsdn, arena_t *arena, const chunk_hooks_t *chunk_hooks) #undef ATOMIC_COPY_HOOK malloc_mutex_unlock(tsdn, &arena->chunks_mtx); - return (old_chunk_hooks); + return (old_extent_hooks); } static void -chunk_hooks_assure_initialized_impl(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, bool locked) +extent_hooks_assure_initialized_impl(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, bool locked) { - static const chunk_hooks_t uninitialized_hooks = + static const extent_hooks_t uninitialized_hooks = CHUNK_HOOKS_INITIALIZER; - if (memcmp(chunk_hooks, &uninitialized_hooks, sizeof(chunk_hooks_t)) == - 0) { - *chunk_hooks = locked ? chunk_hooks_get_locked(arena) : - chunk_hooks_get(tsdn, arena); + if (memcmp(extent_hooks, &uninitialized_hooks, sizeof(extent_hooks_t)) + == 0) { + *extent_hooks = locked ? extent_hooks_get_locked(arena) : + extent_hooks_get(tsdn, arena); } } static void -chunk_hooks_assure_initialized_locked(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks) +extent_hooks_assure_initialized_locked(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks) { - chunk_hooks_assure_initialized_impl(tsdn, arena, chunk_hooks, true); + extent_hooks_assure_initialized_impl(tsdn, arena, extent_hooks, true); } static void -chunk_hooks_assure_initialized(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks) +extent_hooks_assure_initialized(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks) { - chunk_hooks_assure_initialized_impl(tsdn, arena, chunk_hooks, false); + extent_hooks_assure_initialized_impl(tsdn, arena, extent_hooks, false); } static bool @@ -297,8 +298,8 @@ chunk_first_best_fit(arena_t *arena, extent_heap_t extent_heaps[NPSIZES], } static void -chunk_leak(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, bool cache, - extent_t *extent) +chunk_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, + bool cache, extent_t *extent) { /* @@ -306,14 +307,14 @@ chunk_leak(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, bool cache, * that this is only a virtual memory leak. */ if (cache) { - chunk_purge_wrapper(tsdn, arena, chunk_hooks, extent, 0, + chunk_purge_wrapper(tsdn, arena, extent_hooks, extent, 0, extent_size_get(extent)); } extent_dalloc(tsdn, arena, extent); } static extent_t * -chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, +chunk_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_heap_t extent_heaps[NPSIZES], bool cache, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) @@ -330,7 +331,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, if (alloc_size < usize) return (NULL); malloc_mutex_lock(tsdn, &arena->chunks_mtx); - chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); + extent_hooks_assure_initialized_locked(tsdn, arena, extent_hooks); if (new_addr != NULL) { rtree_elm_t *elm; @@ -368,10 +369,10 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, /* Split the lead. */ if (leadsize != 0) { extent_t *lead = extent; - extent = chunk_split_wrapper(tsdn, arena, chunk_hooks, lead, + extent = chunk_split_wrapper(tsdn, arena, extent_hooks, lead, leadsize, leadsize, size + trailsize, usize + trailsize); if (extent == NULL) { - chunk_leak(tsdn, arena, chunk_hooks, cache, lead); + chunk_leak(tsdn, arena, extent_hooks, cache, lead); malloc_mutex_unlock(tsdn, &arena->chunks_mtx); return (NULL); } @@ -381,10 +382,10 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, /* Split the trail. */ if (trailsize != 0) { - extent_t *trail = chunk_split_wrapper(tsdn, arena, chunk_hooks, + extent_t *trail = chunk_split_wrapper(tsdn, arena, extent_hooks, extent, size, usize, trailsize, trailsize); if (trail == NULL) { - chunk_leak(tsdn, arena, chunk_hooks, cache, extent); + chunk_leak(tsdn, arena, extent_hooks, cache, extent); malloc_mutex_unlock(tsdn, &arena->chunks_mtx); return (NULL); } @@ -399,10 +400,10 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } if (!extent_committed_get(extent) && - chunk_hooks->commit(extent_base_get(extent), + extent_hooks->commit(extent_base_get(extent), extent_size_get(extent), 0, extent_size_get(extent), arena->ind)) { malloc_mutex_unlock(tsdn, &arena->chunks_mtx); - chunk_record(tsdn, arena, chunk_hooks, extent_heaps, cache, + chunk_record(tsdn, arena, extent_hooks, extent_heaps, cache, extent); return (NULL); } @@ -468,7 +469,7 @@ chunk_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, } extent_t * -chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, +chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool slab) { @@ -479,7 +480,7 @@ chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert(alignment != 0); commit = true; - extent = chunk_recycle(tsdn, arena, chunk_hooks, arena->chunks_cached, + extent = chunk_recycle(tsdn, arena, extent_hooks, arena->chunks_cached, true, new_addr, usize, pad, alignment, zero, &commit, slab); if (extent == NULL) return (NULL); @@ -520,7 +521,7 @@ chunk_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero, } static extent_t * -chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, +chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) { @@ -529,8 +530,9 @@ chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert(usize != 0); assert(alignment != 0); - extent = chunk_recycle(tsdn, arena, chunk_hooks, arena->chunks_retained, - false, new_addr, usize, pad, alignment, zero, commit, slab); + extent = chunk_recycle(tsdn, arena, extent_hooks, + arena->chunks_retained, false, new_addr, usize, pad, alignment, + zero, commit, slab); if (extent != NULL && config_stats) { size_t size = usize + pad; arena->stats.retained -= size; @@ -541,7 +543,7 @@ chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, static extent_t * chunk_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, - chunk_hooks_t *chunk_hooks, void *new_addr, size_t usize, size_t pad, + extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) { extent_t *extent; @@ -552,7 +554,7 @@ chunk_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, extent = extent_alloc(tsdn, arena); if (extent == NULL) return (NULL); - addr = chunk_hooks->alloc(new_addr, size, alignment, zero, commit, + addr = extent_hooks->alloc(new_addr, size, alignment, zero, commit, arena->ind); if (addr == NULL) { extent_dalloc(tsdn, arena, extent); @@ -562,7 +564,7 @@ chunk_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, if (pad != 0) extent_addr_randomize(tsdn, extent, alignment); if (chunk_register(tsdn, extent)) { - chunk_leak(tsdn, arena, chunk_hooks, false, extent); + chunk_leak(tsdn, arena, extent_hooks, false, extent); return (NULL); } @@ -570,18 +572,18 @@ chunk_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, } extent_t * -chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, +chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) { extent_t *extent; - chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); + extent_hooks_assure_initialized(tsdn, arena, extent_hooks); - extent = chunk_alloc_retained(tsdn, arena, chunk_hooks, new_addr, usize, - pad, alignment, zero, commit, slab); + extent = chunk_alloc_retained(tsdn, arena, extent_hooks, new_addr, + usize, pad, alignment, zero, commit, slab); if (extent == NULL) { - extent = chunk_alloc_wrapper_hard(tsdn, arena, chunk_hooks, + extent = chunk_alloc_wrapper_hard(tsdn, arena, extent_hooks, new_addr, usize, pad, alignment, zero, commit, slab); } @@ -605,7 +607,7 @@ chunk_can_coalesce(const extent_t *a, const extent_t *b) } static void -chunk_try_coalesce(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, +chunk_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_t *a, extent_t *b, extent_heap_t extent_heaps[NPSIZES], bool cache) { @@ -618,7 +620,7 @@ chunk_try_coalesce(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, arena_chunk_cache_maybe_remove(extent_arena_get(a), a, cache); arena_chunk_cache_maybe_remove(extent_arena_get(b), b, cache); - if (chunk_merge_wrapper(tsdn, arena, chunk_hooks, a, b)) { + if (chunk_merge_wrapper(tsdn, arena, extent_hooks, a, b)) { extent_heaps_insert(extent_heaps, a); extent_heaps_insert(extent_heaps, b); arena_chunk_cache_maybe_insert(extent_arena_get(a), a, cache); @@ -631,7 +633,7 @@ chunk_try_coalesce(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } static void -chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, +chunk_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_heap_t extent_heaps[NPSIZES], bool cache, extent_t *extent) { extent_t *prev, *next; @@ -639,7 +641,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert(!cache || !extent_zeroed_get(extent)); malloc_mutex_lock(tsdn, &arena->chunks_mtx); - chunk_hooks_assure_initialized_locked(tsdn, arena, chunk_hooks); + extent_hooks_assure_initialized_locked(tsdn, arena, extent_hooks); extent_usize_set(extent, 0); extent_active_set(extent, false); @@ -657,7 +659,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, next = rtree_read(tsdn, &chunks_rtree, (uintptr_t)extent_past_get(extent), false); if (next != NULL) { - chunk_try_coalesce(tsdn, arena, chunk_hooks, extent, next, + chunk_try_coalesce(tsdn, arena, extent_hooks, extent, next, extent_heaps, cache); } @@ -665,7 +667,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, prev = rtree_read(tsdn, &chunks_rtree, (uintptr_t)extent_before_get(extent), false); if (prev != NULL) { - chunk_try_coalesce(tsdn, arena, chunk_hooks, prev, extent, + chunk_try_coalesce(tsdn, arena, extent_hooks, prev, extent, extent_heaps, cache); } @@ -673,7 +675,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, } void -chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, +chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_t *extent) { @@ -683,7 +685,7 @@ chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_addr_set(extent, extent_base_get(extent)); extent_zeroed_set(extent, false); - chunk_record(tsdn, arena, chunk_hooks, arena->chunks_cached, true, + chunk_record(tsdn, arena, extent_hooks, arena->chunks_cached, true, extent); } @@ -698,7 +700,7 @@ chunk_dalloc_default(void *chunk, size_t size, bool committed, } void -chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, +chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_t *extent) { @@ -707,9 +709,9 @@ chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, extent_addr_set(extent, extent_base_get(extent)); - chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); + extent_hooks_assure_initialized(tsdn, arena, extent_hooks); /* Try to deallocate. */ - if (!chunk_hooks->dalloc(extent_base_get(extent), + if (!extent_hooks->dalloc(extent_base_get(extent), extent_size_get(extent), extent_committed_get(extent), arena->ind)) { chunk_deregister(tsdn, extent); @@ -719,18 +721,18 @@ chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, /* Try to decommit; purge if that fails. */ if (extent_committed_get(extent)) { extent_committed_set(extent, - chunk_hooks->decommit(extent_base_get(extent), + extent_hooks->decommit(extent_base_get(extent), extent_size_get(extent), 0, extent_size_get(extent), arena->ind)); } extent_zeroed_set(extent, !extent_committed_get(extent) || - !chunk_hooks->purge(extent_base_get(extent), + !extent_hooks->purge(extent_base_get(extent), extent_size_get(extent), 0, extent_size_get(extent), arena->ind)); if (config_stats) arena->stats.retained += extent_size_get(extent); - chunk_record(tsdn, arena, chunk_hooks, arena->chunks_retained, false, + chunk_record(tsdn, arena, extent_hooks, arena->chunks_retained, false, extent); } @@ -744,12 +746,12 @@ chunk_commit_default(void *chunk, size_t size, size_t offset, size_t length, } bool -chunk_commit_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, +chunk_commit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, size_t length) { - chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); - return (chunk_hooks->commit(extent_base_get(extent), + extent_hooks_assure_initialized(tsdn, arena, extent_hooks); + return (extent_hooks->commit(extent_base_get(extent), extent_size_get(extent), offset, length, arena->ind)); } @@ -763,12 +765,13 @@ chunk_decommit_default(void *chunk, size_t size, size_t offset, size_t length, } bool -chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, - extent_t *extent, size_t offset, size_t length) +chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, + size_t length) { - chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); - return (chunk_hooks->decommit(extent_base_get(extent), + extent_hooks_assure_initialized(tsdn, arena, extent_hooks); + return (extent_hooks->decommit(extent_base_get(extent), extent_size_get(extent), offset, length, arena->ind)); } @@ -787,12 +790,12 @@ chunk_purge_default(void *chunk, size_t size, size_t offset, size_t length, } bool -chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, +chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, size_t length) { - chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); - return (chunk_hooks->purge(extent_base_get(extent), + extent_hooks_assure_initialized(tsdn, arena, extent_hooks); + return (extent_hooks->purge(extent_base_get(extent), extent_size_get(extent), offset, length, arena->ind)); } @@ -807,7 +810,7 @@ chunk_split_default(void *chunk, size_t size, size_t size_a, size_t size_b, } extent_t * -chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, +chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_t *extent, size_t size_a, size_t usize_a, size_t size_b, size_t usize_b) { @@ -816,7 +819,7 @@ chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, assert(extent_size_get(extent) == size_a + size_b); - chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); + extent_hooks_assure_initialized(tsdn, arena, extent_hooks); trail = extent_alloc(tsdn, arena); if (trail == NULL) @@ -843,7 +846,7 @@ chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, &trail_elm_b)) goto label_error_c; - if (chunk_hooks->split(extent_base_get(extent), size_a + size_b, size_a, + if (extent_hooks->split(extent_base_get(extent), size_a + size_b, size_a, size_b, extent_committed_get(extent), arena->ind)) goto label_error_d; @@ -884,13 +887,13 @@ chunk_merge_default(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b, } bool -chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, chunk_hooks_t *chunk_hooks, +chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_t *a, extent_t *b) { rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; - chunk_hooks_assure_initialized(tsdn, arena, chunk_hooks); - if (chunk_hooks->merge(extent_base_get(a), extent_size_get(a), + extent_hooks_assure_initialized(tsdn, arena, extent_hooks); + if (extent_hooks->merge(extent_base_get(a), extent_size_get(a), extent_base_get(b), extent_size_get(b), extent_committed_get(a), arena->ind)) return (true); diff --git a/src/chunk_dss.c b/src/chunk_dss.c index f8c968b3..c5323dea 100644 --- a/src/chunk_dss.c +++ b/src/chunk_dss.c @@ -136,10 +136,10 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, dss_max = dss_next; malloc_mutex_unlock(tsdn, &dss_mtx); if (pad_size != 0) { - chunk_hooks_t chunk_hooks = + extent_hooks_t extent_hooks = CHUNK_HOOKS_INITIALIZER; chunk_dalloc_wrapper(tsdn, arena, - &chunk_hooks, pad); + &extent_hooks, pad); } else extent_dalloc(tsdn, arena, pad); if (*zero) diff --git a/src/ctl.c b/src/ctl.c index 85ca2e86..5ff2a42d 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -120,7 +120,7 @@ CTL_PROTO(arena_i_reset) CTL_PROTO(arena_i_dss) CTL_PROTO(arena_i_lg_dirty_mult) CTL_PROTO(arena_i_decay_time) -CTL_PROTO(arena_i_chunk_hooks) +CTL_PROTO(arena_i_extent_hooks) INDEX_PROTO(arena_i) CTL_PROTO(arenas_bin_i_size) CTL_PROTO(arenas_bin_i_nregs) @@ -287,7 +287,7 @@ static const ctl_named_node_t arena_i_node[] = { {NAME("dss"), CTL(arena_i_dss)}, {NAME("lg_dirty_mult"), CTL(arena_i_lg_dirty_mult)}, {NAME("decay_time"), CTL(arena_i_decay_time)}, - {NAME("chunk_hooks"), CTL(arena_i_chunk_hooks)} + {NAME("extent_hooks"), CTL(arena_i_extent_hooks)} }; static const ctl_named_node_t super_arena_i_node[] = { {NAME(""), CHILD(named, arena_i)} @@ -1647,7 +1647,7 @@ label_return: } static int -arena_i_chunk_hooks_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, +arena_i_extent_hooks_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; @@ -1658,15 +1658,15 @@ arena_i_chunk_hooks_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, if (arena_ind < narenas_total_get() && (arena = arena_get(tsd_tsdn(tsd), arena_ind, false)) != NULL) { if (newp != NULL) { - chunk_hooks_t old_chunk_hooks, new_chunk_hooks; - WRITE(new_chunk_hooks, chunk_hooks_t); - old_chunk_hooks = chunk_hooks_set(tsd_tsdn(tsd), arena, - &new_chunk_hooks); - READ(old_chunk_hooks, chunk_hooks_t); + extent_hooks_t old_extent_hooks, new_extent_hooks; + WRITE(new_extent_hooks, extent_hooks_t); + old_extent_hooks = extent_hooks_set(tsd_tsdn(tsd), + arena, &new_extent_hooks); + READ(old_extent_hooks, extent_hooks_t); } else { - chunk_hooks_t old_chunk_hooks = - chunk_hooks_get(tsd_tsdn(tsd), arena); - READ(old_chunk_hooks, chunk_hooks_t); + extent_hooks_t old_extent_hooks = + extent_hooks_get(tsd_tsdn(tsd), arena); + READ(old_extent_hooks, extent_hooks_t); } } else { ret = EFAULT; diff --git a/src/jemalloc.c b/src/jemalloc.c index 85a592e9..a9bba12b 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -207,14 +207,16 @@ static void WINAPI _init_init_lock(void) { - /* If another constructor in the same binary is using mallctl to - * e.g. setup chunk hooks, it may end up running before this one, - * and malloc_init_hard will crash trying to lock the uninitialized - * lock. So we force an initialization of the lock in - * malloc_init_hard as well. We don't try to care about atomicity - * of the accessed to the init_lock_initialized boolean, since it - * really only matters early in the process creation, before any - * separate thread normally starts doing anything. */ + /* + * If another constructor in the same binary is using mallctl to e.g. + * set up extent hooks, it may end up running before this one, and + * malloc_init_hard will crash trying to lock the uninitialized lock. So + * we force an initialization of the lock in malloc_init_hard as well. + * We don't try to care about atomicity of the accessed to the + * init_lock_initialized boolean, since it really only matters early in + * the process creation, before any separate thread normally starts + * doing anything. + */ if (!init_lock_initialized) malloc_mutex_init(&init_lock, "init", WITNESS_RANK_INIT); init_lock_initialized = true; diff --git a/src/large.c b/src/large.c index 43bfb284..ce8d32fb 100644 --- a/src/large.c +++ b/src/large.c @@ -96,15 +96,16 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { arena_t *arena = extent_arena_get(extent); size_t oldusize = extent_usize_get(extent); - chunk_hooks_t chunk_hooks = chunk_hooks_get(tsdn, arena); + extent_hooks_t extent_hooks = extent_hooks_get(tsdn, arena); size_t diff = extent_size_get(extent) - (usize + large_pad); assert(oldusize > usize); /* Split excess pages. */ if (diff != 0) { - extent_t *trail = chunk_split_wrapper(tsdn, arena, &chunk_hooks, - extent, usize + large_pad, usize, diff, diff); + extent_t *trail = chunk_split_wrapper(tsdn, arena, + &extent_hooks, extent, usize + large_pad, usize, diff, + diff); if (trail == NULL) return (true); @@ -113,7 +114,7 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) extent_usize_get(trail)); } - arena_chunk_cache_dalloc(tsdn, arena, &chunk_hooks, trail); + arena_chunk_cache_dalloc(tsdn, arena, &extent_hooks, trail); } arena_chunk_ralloc_large_shrink(tsdn, arena, extent, oldusize); @@ -128,22 +129,22 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, arena_t *arena = extent_arena_get(extent); size_t oldusize = extent_usize_get(extent); bool is_zeroed_trail = false; - chunk_hooks_t chunk_hooks = chunk_hooks_get(tsdn, arena); + extent_hooks_t extent_hooks = extent_hooks_get(tsdn, arena); size_t trailsize = usize - extent_usize_get(extent); extent_t *trail; - if ((trail = arena_chunk_cache_alloc(tsdn, arena, &chunk_hooks, + if ((trail = arena_chunk_cache_alloc(tsdn, arena, &extent_hooks, extent_past_get(extent), trailsize, CACHELINE, &is_zeroed_trail)) == NULL) { bool commit = true; - if ((trail = chunk_alloc_wrapper(tsdn, arena, &chunk_hooks, + if ((trail = chunk_alloc_wrapper(tsdn, arena, &extent_hooks, extent_past_get(extent), trailsize, 0, CACHELINE, &is_zeroed_trail, &commit, false)) == NULL) return (true); } - if (chunk_merge_wrapper(tsdn, arena, &chunk_hooks, extent, trail)) { - chunk_dalloc_wrapper(tsdn, arena, &chunk_hooks, trail); + if (chunk_merge_wrapper(tsdn, arena, &extent_hooks, extent, trail)) { + chunk_dalloc_wrapper(tsdn, arena, &extent_hooks, trail); return (true); } diff --git a/test/integration/chunk.c b/test/integration/chunk.c index ca87e80f..10c4ba77 100644 --- a/test/integration/chunk.c +++ b/test/integration/chunk.c @@ -4,8 +4,8 @@ const char *malloc_conf = "junk:false"; #endif -static chunk_hooks_t orig_hooks; -static chunk_hooks_t old_hooks; +static extent_hooks_t orig_hooks; +static extent_hooks_t old_hooks; static bool do_dalloc = true; static bool do_decommit; @@ -125,7 +125,7 @@ TEST_BEGIN(test_chunk) int flags; size_t hooks_mib[3], purge_mib[3]; size_t hooks_miblen, purge_miblen; - chunk_hooks_t new_hooks = { + extent_hooks_t new_hooks = { chunk_alloc, chunk_dalloc, chunk_commit, @@ -141,15 +141,15 @@ TEST_BEGIN(test_chunk) "Unexpected mallctl() failure"); flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; - /* Install custom chunk hooks. */ + /* Install custom extent hooks. */ hooks_miblen = sizeof(hooks_mib)/sizeof(size_t); - assert_d_eq(mallctlnametomib("arena.0.chunk_hooks", hooks_mib, + assert_d_eq(mallctlnametomib("arena.0.extent_hooks", hooks_mib, &hooks_miblen), 0, "Unexpected mallctlnametomib() failure"); hooks_mib[1] = (size_t)arena_ind; - old_size = sizeof(chunk_hooks_t); - new_size = sizeof(chunk_hooks_t); + old_size = sizeof(extent_hooks_t); + new_size = sizeof(extent_hooks_t); assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, &old_hooks, &old_size, - &new_hooks, new_size), 0, "Unexpected chunk_hooks error"); + &new_hooks, new_size), 0, "Unexpected extent_hooks error"); orig_hooks = old_hooks; assert_ptr_ne(old_hooks.alloc, chunk_alloc, "Unexpected alloc error"); assert_ptr_ne(old_hooks.dalloc, chunk_dalloc, @@ -223,11 +223,11 @@ TEST_BEGIN(test_chunk) assert_ptr_not_null(p, "Unexpected mallocx() error"); dallocx(p, flags); - /* Restore chunk hooks. */ + /* Restore extent hooks. */ assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, NULL, NULL, - &old_hooks, new_size), 0, "Unexpected chunk_hooks error"); + &old_hooks, new_size), 0, "Unexpected extent_hooks error"); assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, &old_hooks, &old_size, - NULL, 0), 0, "Unexpected chunk_hooks error"); + NULL, 0), 0, "Unexpected extent_hooks error"); assert_ptr_eq(old_hooks.alloc, orig_hooks.alloc, "Unexpected alloc error"); assert_ptr_eq(old_hooks.dalloc, orig_hooks.dalloc, -- GitLab From 127026ad989c06feda12371e584b4af4dffaf2db Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Jun 2016 11:23:50 -0700 Subject: [PATCH 047/544] Rename chunk_*_t hooks to extent_*_t. --- doc/jemalloc.xml.in | 154 ++++++++++++------------ include/jemalloc/jemalloc_typedefs.h.in | 43 +++---- src/chunk.c | 58 ++++----- 3 files changed, 129 insertions(+), 126 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 801fd497..ab90e30f 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -1554,45 +1554,45 @@ malloc_conf = "xmalloc:true";]]> (extent_hooks_t) rw - Get or set the chunk management hook functions for arena - <i>. The functions must be capable of operating on all extant - chunks associated with arena <i>, usually by passing unknown - chunks to the replaced functions. In practice, it is feasible to - control allocation for arenas created via Get or set the extent management hook functions for + arena <i>. The functions must be capable of operating on all + extant extents associated with arena <i>, usually by passing + unknown extents to the replaced functions. In practice, it is feasible + to control allocation for arenas created via arenas.extend such - that all chunks originate from an application-supplied chunk allocator + that all extents originate from an application-supplied extent allocator (by setting custom extent hook functions just after arena creation), but - the automatically created arenas may have already created chunks prior - to the application having an opportunity to take over chunk + the automatically created arenas may have already created extents prior + to the application having an opportunity to take over extent allocation. The extent_hooks_t structure comprises function pointers which are described individually below. jemalloc uses these - functions to manage chunk lifetime, which starts off with allocation of + functions to manage extent lifetime, which starts off with allocation of mapped committed memory, in the simplest case followed by deallocation. - However, there are performance and platform reasons to retain chunks for - later reuse. Cleanup attempts cascade from deallocation to decommit to - purging, which gives the chunk management functions opportunities to + However, there are performance and platform reasons to retain extents + for later reuse. Cleanup attempts cascade from deallocation to decommit + to purging, which gives the extent management functions opportunities to reject the most permanent cleanup operations in favor of less permanent - (and often less costly) operations. The chunk splitting and merging + (and often less costly) operations. The extent splitting and merging operations can also be opted out of, but this is mainly intended to support platforms on which virtual memory mappings provided by the operating system kernel do not automatically coalesce and split, e.g. Windows. - typedef void *(chunk_alloc_t) - void *chunk + typedef void *(extent_alloc_t) + void *new_addr size_t size size_t alignment bool *zero @@ -1600,62 +1600,62 @@ typedef struct { unsigned arena_ind - A chunk allocation function conforms to the - chunk_alloc_t type and upon success returns a pointer to + An extent allocation function conforms to the + extent_alloc_t type and upon success returns a pointer to size bytes of mapped memory on behalf of arena - arena_ind such that the chunk's base address is a - multiple of alignment, as well as setting - *zero to indicate whether the chunk is zeroed and - *commit to indicate whether the chunk is + arena_ind such that the extent's base address is + a multiple of alignment, as well as setting + *zero to indicate whether the extent is zeroed + and *commit to indicate whether the extent is committed. Upon error the function returns NULL and leaves *zero and *commit unmodified. The - size parameter is always a multiple of the chunk + size parameter is always a multiple of the page size. The alignment parameter is always a power - of two at least as large as the chunk size. Zeroing is mandatory if + of two at least as large as the page size. Zeroing is mandatory if *zero is true upon function entry. Committing is mandatory if *commit is true upon function entry. - If chunk is not NULL, the - returned pointer must be chunk on success or + If new_addr is not NULL, the + returned pointer must be new_addr on success or NULL on error. Committed memory may be committed in absolute terms as on a system that does not overcommit, or in implicit terms as on a system that overcommits and satisfies physical memory needs on demand via soft page faults. Note that replacing the - default chunk allocation function makes the arena's arena.<i>.dss setting irrelevant. - typedef bool (chunk_dalloc_t) - void *chunk + typedef bool (extent_dalloc_t) + void *addr size_t size bool committed unsigned arena_ind - A chunk deallocation function conforms to the - chunk_dalloc_t type and deallocates a - chunk of given size with + An extent deallocation function conforms to the + extent_dalloc_t type and deallocates an extent at given + addr and size with committed/decommited memory as indicated, on behalf of arena arena_ind, returning false upon success. If the function returns true, this indicates opt-out from - deallocation; the virtual memory mapping associated with the chunk + deallocation; the virtual memory mapping associated with the extent remains mapped, in the same commit state, and available for future use, in which case it will be automatically retained for later reuse. - typedef bool (chunk_commit_t) - void *chunk + typedef bool (extent_commit_t) + void *addr size_t size size_t offset size_t length unsigned arena_ind - A chunk commit function conforms to the - chunk_commit_t type and commits zeroed physical memory to - back pages within a chunk of given + An extent commit function conforms to the + extent_commit_t type and commits zeroed physical memory to + back pages within an extent at given addr and size at offset bytes, extending for length on behalf of arena arena_ind, returning false upon success. @@ -1666,46 +1666,48 @@ typedef struct { physical memory to satisfy the request. - typedef bool (chunk_decommit_t) - void *chunk + typedef bool (extent_decommit_t) + void *addr size_t size size_t offset size_t length unsigned arena_ind - A chunk decommit function conforms to the - chunk_decommit_t type and decommits any physical memory - that is backing pages within a chunk of given - size at offset bytes, - extending for length on behalf of arena + An extent decommit function conforms to the + extent_decommit_t type and decommits any physical memory + that is backing pages within an extent at given + addr and size at + offset bytes, extending for + length on behalf of arena arena_ind, returning false upon success, in which - case the pages will be committed via the chunk commit function before + case the pages will be committed via the extent commit function before being reused. If the function returns true, this indicates opt-out from decommit; the memory remains committed and available for future use, in which case it will be automatically retained for later reuse. - typedef bool (chunk_purge_t) - void *chunk + typedef bool (extent_purge_t) + void *addr size_tsize size_t offset size_t length unsigned arena_ind - A chunk purge function conforms to the chunk_purge_t - type and optionally discards physical pages within the virtual memory - mapping associated with chunk of given - size at offset bytes, - extending for length on behalf of arena + An extent purge function conforms to the + extent_purge_t type and optionally discards physical pages + within the virtual memory mapping associated with an extent at given + addr and size at + offset bytes, extending for + length on behalf of arena arena_ind, returning false if pages within the purged virtual memory range will be zero-filled the next time they are accessed. - typedef bool (chunk_split_t) - void *chunk + typedef bool (extent_split_t) + void *addr size_t size size_t size_a size_t size_b @@ -1713,35 +1715,35 @@ typedef struct { unsigned arena_ind - A chunk split function conforms to the chunk_split_t - type and optionally splits chunk of given - size into two adjacent chunks, the first of - size_a bytes, and the second of - size_b bytes, operating on + An extent split function conforms to the + extent_split_t type and optionally splits an extent at + given addr and size into + two adjacent extents, the first of size_a bytes, + and the second of size_b bytes, operating on committed/decommitted memory as indicated, on behalf of arena arena_ind, returning false upon - success. If the function returns true, this indicates that the chunk + success. If the function returns true, this indicates that the extent remains unsplit and therefore should continue to be operated on as a whole. - typedef bool (chunk_merge_t) - void *chunk_a + typedef bool (extent_merge_t) + void *addr_a size_t size_a - void *chunk_b + void *addr_b size_t size_b bool committed unsigned arena_ind - A chunk merge function conforms to the chunk_merge_t - type and optionally merges adjacent chunks, - chunk_a of given size_a - and chunk_b of given - size_b into one contiguous chunk, operating on + An extent merge function conforms to the + extent_merge_t type and optionally merges adjacent extents, + at given addr_a and size_a + with given addr_b and + size_b into one contiguous extent, operating on committed/decommitted memory as indicated, on behalf of arena arena_ind, returning false upon - success. If the function returns true, this indicates that the chunks + success. If the function returns true, this indicates that the extents remain distinct mappings and therefore should continue to be operated on independently. diff --git a/include/jemalloc/jemalloc_typedefs.h.in b/include/jemalloc/jemalloc_typedefs.h.in index 2b07e362..99f07ab2 100644 --- a/include/jemalloc/jemalloc_typedefs.h.in +++ b/include/jemalloc/jemalloc_typedefs.h.in @@ -1,57 +1,58 @@ /* * void * - * chunk_alloc(void *new_addr, size_t size, size_t alignment, bool *zero, + * extent_alloc(void *new_addr, size_t size, size_t alignment, bool *zero, * bool *commit, unsigned arena_ind); */ -typedef void *(chunk_alloc_t)(void *, size_t, size_t, bool *, bool *, unsigned); +typedef void *(extent_alloc_t)(void *, size_t, size_t, bool *, bool *, + unsigned); /* * bool - * chunk_dalloc(void *chunk, size_t size, bool committed, unsigned arena_ind); + * extent_dalloc(void *addr, size_t size, bool committed, unsigned arena_ind); */ -typedef bool (chunk_dalloc_t)(void *, size_t, bool, unsigned); +typedef bool (extent_dalloc_t)(void *, size_t, bool, unsigned); /* * bool - * chunk_commit(void *chunk, size_t size, size_t offset, size_t length, + * extent_commit(void *addr, size_t size, size_t offset, size_t length, * unsigned arena_ind); */ -typedef bool (chunk_commit_t)(void *, size_t, size_t, size_t, unsigned); +typedef bool (extent_commit_t)(void *, size_t, size_t, size_t, unsigned); /* * bool - * chunk_decommit(void *chunk, size_t size, size_t offset, size_t length, + * extent_decommit(void *addr, size_t size, size_t offset, size_t length, * unsigned arena_ind); */ -typedef bool (chunk_decommit_t)(void *, size_t, size_t, size_t, unsigned); +typedef bool (extent_decommit_t)(void *, size_t, size_t, size_t, unsigned); /* * bool - * chunk_purge(void *chunk, size_t size, size_t offset, size_t length, + * extent_purge(void *addr, size_t size, size_t offset, size_t length, * unsigned arena_ind); */ -typedef bool (chunk_purge_t)(void *, size_t, size_t, size_t, unsigned); +typedef bool (extent_purge_t)(void *, size_t, size_t, size_t, unsigned); /* * bool - * chunk_split(void *chunk, size_t size, size_t size_a, size_t size_b, + * extent_split(void *addr, size_t size, size_t size_a, size_t size_b, * bool committed, unsigned arena_ind); */ -typedef bool (chunk_split_t)(void *, size_t, size_t, size_t, bool, unsigned); +typedef bool (extent_split_t)(void *, size_t, size_t, size_t, bool, unsigned); /* * bool - * chunk_merge(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b, + * extent_merge(void *addr_a, size_t size_a, void *addr_b, size_t size_b, * bool committed, unsigned arena_ind); */ -typedef bool (chunk_merge_t)(void *, size_t, void *, size_t, bool, unsigned); +typedef bool (extent_merge_t)(void *, size_t, void *, size_t, bool, unsigned); typedef struct { - chunk_alloc_t *alloc; - chunk_dalloc_t *dalloc; - chunk_commit_t *commit; - chunk_decommit_t *decommit; - chunk_purge_t *purge; - chunk_split_t *split; - chunk_merge_t *merge; + extent_alloc_t *alloc; + extent_dalloc_t *dalloc; + extent_commit_t *commit; + extent_decommit_t *decommit; + extent_purge_t *purge; + extent_split_t *split; + extent_merge_t *merge; } extent_hooks_t; diff --git a/src/chunk.c b/src/chunk.c index 6ca40572..78f08d49 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -18,29 +18,29 @@ size_t chunksize; size_t chunksize_mask; /* (chunksize - 1). */ size_t chunk_npages; -static void *chunk_alloc_default(void *new_addr, size_t size, +static void *extent_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit, unsigned arena_ind); -static bool chunk_dalloc_default(void *chunk, size_t size, bool committed, +static bool extent_dalloc_default(void *addr, size_t size, bool committed, unsigned arena_ind); -static bool chunk_commit_default(void *chunk, size_t size, size_t offset, +static bool extent_commit_default(void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); -static bool chunk_decommit_default(void *chunk, size_t size, size_t offset, +static bool extent_decommit_default(void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); -static bool chunk_purge_default(void *chunk, size_t size, size_t offset, +static bool extent_purge_default(void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); -static bool chunk_split_default(void *chunk, size_t size, size_t size_a, +static bool extent_split_default(void *addr, size_t size, size_t size_a, size_t size_b, bool committed, unsigned arena_ind); -static bool chunk_merge_default(void *chunk_a, size_t size_a, void *chunk_b, +static bool extent_merge_default(void *addr_a, size_t size_a, void *addr_b, size_t size_b, bool committed, unsigned arena_ind); const extent_hooks_t extent_hooks_default = { - chunk_alloc_default, - chunk_dalloc_default, - chunk_commit_default, - chunk_decommit_default, - chunk_purge_default, - chunk_split_default, - chunk_merge_default + extent_alloc_default, + extent_dalloc_default, + extent_commit_default, + extent_decommit_default, + extent_purge_default, + extent_split_default, + extent_merge_default }; /******************************************************************************/ @@ -107,7 +107,7 @@ extent_hooks_set(tsdn_t *tsdn, arena_t *arena, */ #define ATOMIC_COPY_HOOK(n) do { \ union { \ - chunk_##n##_t **n; \ + extent_##n##_t **n; \ void **v; \ } u; \ u.n = &arena->extent_hooks.n; \ @@ -503,7 +503,7 @@ chunk_arena_get(tsdn_t *tsdn, unsigned arena_ind) } static void * -chunk_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero, +extent_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit, unsigned arena_ind) { void *ret; @@ -690,12 +690,12 @@ chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, } static bool -chunk_dalloc_default(void *chunk, size_t size, bool committed, +extent_dalloc_default(void *addr, size_t size, bool committed, unsigned arena_ind) { - if (!have_dss || !chunk_in_dss(tsdn_fetch(), chunk)) - return (chunk_dalloc_mmap(chunk, size)); + if (!have_dss || !chunk_in_dss(tsdn_fetch(), addr)) + return (chunk_dalloc_mmap(addr, size)); return (true); } @@ -737,11 +737,11 @@ chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, } static bool -chunk_commit_default(void *chunk, size_t size, size_t offset, size_t length, +extent_commit_default(void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { - return (pages_commit((void *)((uintptr_t)chunk + (uintptr_t)offset), + return (pages_commit((void *)((uintptr_t)addr + (uintptr_t)offset), length)); } @@ -756,11 +756,11 @@ chunk_commit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, } static bool -chunk_decommit_default(void *chunk, size_t size, size_t offset, size_t length, +extent_decommit_default(void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { - return (pages_decommit((void *)((uintptr_t)chunk + (uintptr_t)offset), + return (pages_decommit((void *)((uintptr_t)addr + (uintptr_t)offset), length)); } @@ -776,16 +776,16 @@ chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, } static bool -chunk_purge_default(void *chunk, size_t size, size_t offset, size_t length, +extent_purge_default(void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { - assert(chunk != NULL); + assert(addr != NULL); assert((offset & PAGE_MASK) == 0); assert(length != 0); assert((length & PAGE_MASK) == 0); - return (pages_purge((void *)((uintptr_t)chunk + (uintptr_t)offset), + return (pages_purge((void *)((uintptr_t)addr + (uintptr_t)offset), length)); } @@ -800,7 +800,7 @@ chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, } static bool -chunk_split_default(void *chunk, size_t size, size_t size_a, size_t size_b, +extent_split_default(void *addr, size_t size, size_t size_a, size_t size_b, bool committed, unsigned arena_ind) { @@ -871,7 +871,7 @@ label_error_a: } static bool -chunk_merge_default(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b, +extent_merge_default(void *addr_a, size_t size_a, void *addr_b, size_t size_b, bool committed, unsigned arena_ind) { @@ -879,7 +879,7 @@ chunk_merge_default(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b, return (true); if (have_dss) { tsdn_t *tsdn = tsdn_fetch(); - if (chunk_in_dss(tsdn, chunk_a) != chunk_in_dss(tsdn, chunk_b)) + if (chunk_in_dss(tsdn, addr_a) != chunk_in_dss(tsdn, addr_b)) return (true); } -- GitLab From c9a76481d8e411e52240a4e4313dbbfa99801073 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Jun 2016 11:35:30 -0700 Subject: [PATCH 048/544] Rename chunks_{cached,retained,mtx} to extents_{cached,retained,mtx}. --- include/jemalloc/internal/arena.h | 16 +++++++-------- include/jemalloc/internal/witness.h | 2 +- src/arena.c | 19 +++++++++-------- src/chunk.c | 32 ++++++++++++++--------------- 4 files changed, 35 insertions(+), 34 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index f60b9d60..0707b863 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -235,20 +235,20 @@ struct arena_s { malloc_mutex_t large_mtx; /* - * Heaps of chunks that were previously allocated. These are used when - * allocating chunks, in an attempt to re-use address space. + * Heaps of extents that were previously allocated. These are used when + * allocating extents, in an attempt to re-use address space. */ - extent_heap_t chunks_cached[NPSIZES]; - extent_heap_t chunks_retained[NPSIZES]; + extent_heap_t extents_cached[NPSIZES]; + extent_heap_t extents_retained[NPSIZES]; + /* User-configurable extent hook functions. */ + extent_hooks_t extent_hooks; + /* Protects extents_cached, extents_retained, and extent_hooks. */ + malloc_mutex_t extents_mtx; - malloc_mutex_t chunks_mtx; /* Cache of extent structures that were allocated via base_alloc(). */ ql_head(extent_t) extent_cache; malloc_mutex_t extent_cache_mtx; - /* User-configurable extent hook functions. */ - extent_hooks_t extent_hooks; - /* bins is used to store heaps of free regions. */ arena_bin_t bins[NBINS]; }; diff --git a/include/jemalloc/internal/witness.h b/include/jemalloc/internal/witness.h index 8c56c21a..e2f85634 100644 --- a/include/jemalloc/internal/witness.h +++ b/include/jemalloc/internal/witness.h @@ -24,7 +24,7 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *, #define WITNESS_RANK_PROF_GCTX 7U #define WITNESS_RANK_ARENA 8U -#define WITNESS_RANK_ARENA_CHUNKS 9U +#define WITNESS_RANK_ARENA_EXTENTS 9U #define WITNESS_RANK_ARENA_EXTENT_CACHE 10 #define WITNESS_RANK_RTREE_ELM 11U diff --git a/src/arena.c b/src/arena.c index 9a8c2e26..de6605a0 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1793,20 +1793,21 @@ arena_new(tsdn_t *tsdn, unsigned ind) return (NULL); for (i = 0; i < NPSIZES; i++) { - extent_heap_new(&arena->chunks_cached[i]); - extent_heap_new(&arena->chunks_retained[i]); + extent_heap_new(&arena->extents_cached[i]); + extent_heap_new(&arena->extents_retained[i]); } - if (malloc_mutex_init(&arena->chunks_mtx, "arena_chunks", - WITNESS_RANK_ARENA_CHUNKS)) + arena->extent_hooks = extent_hooks_default; + + if (malloc_mutex_init(&arena->extents_mtx, "arena_extents", + WITNESS_RANK_ARENA_EXTENTS)) return (NULL); + ql_new(&arena->extent_cache); if (malloc_mutex_init(&arena->extent_cache_mtx, "arena_extent_cache", WITNESS_RANK_ARENA_EXTENT_CACHE)) return (NULL); - arena->extent_hooks = extent_hooks_default; - /* Initialize bins. */ for (i = 0; i < NBINS; i++) { arena_bin_t *bin = &arena->bins[i]; @@ -1843,7 +1844,7 @@ void arena_prefork1(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_prefork(tsdn, &arena->chunks_mtx); + malloc_mutex_prefork(tsdn, &arena->extents_mtx); } void @@ -1872,7 +1873,7 @@ arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) for (i = 0; i < NBINS; i++) malloc_mutex_postfork_parent(tsdn, &arena->bins[i].lock); malloc_mutex_postfork_parent(tsdn, &arena->extent_cache_mtx); - malloc_mutex_postfork_parent(tsdn, &arena->chunks_mtx); + malloc_mutex_postfork_parent(tsdn, &arena->extents_mtx); malloc_mutex_postfork_parent(tsdn, &arena->lock); } @@ -1885,6 +1886,6 @@ arena_postfork_child(tsdn_t *tsdn, arena_t *arena) for (i = 0; i < NBINS; i++) malloc_mutex_postfork_child(tsdn, &arena->bins[i].lock); malloc_mutex_postfork_child(tsdn, &arena->extent_cache_mtx); - malloc_mutex_postfork_child(tsdn, &arena->chunks_mtx); + malloc_mutex_postfork_child(tsdn, &arena->extents_mtx); malloc_mutex_postfork_child(tsdn, &arena->lock); } diff --git a/src/chunk.c b/src/chunk.c index 78f08d49..2ac44b0a 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -83,9 +83,9 @@ extent_hooks_get(tsdn_t *tsdn, arena_t *arena) { extent_hooks_t extent_hooks; - malloc_mutex_lock(tsdn, &arena->chunks_mtx); + malloc_mutex_lock(tsdn, &arena->extents_mtx); extent_hooks = extent_hooks_get_locked(arena); - malloc_mutex_unlock(tsdn, &arena->chunks_mtx); + malloc_mutex_unlock(tsdn, &arena->extents_mtx); return (extent_hooks); } @@ -96,7 +96,7 @@ extent_hooks_set(tsdn_t *tsdn, arena_t *arena, { extent_hooks_t old_extent_hooks; - malloc_mutex_lock(tsdn, &arena->chunks_mtx); + malloc_mutex_lock(tsdn, &arena->extents_mtx); old_extent_hooks = arena->extent_hooks; /* * Copy each field atomically so that it is impossible for readers to @@ -121,7 +121,7 @@ extent_hooks_set(tsdn_t *tsdn, arena_t *arena, ATOMIC_COPY_HOOK(split); ATOMIC_COPY_HOOK(merge); #undef ATOMIC_COPY_HOOK - malloc_mutex_unlock(tsdn, &arena->chunks_mtx); + malloc_mutex_unlock(tsdn, &arena->extents_mtx); return (old_extent_hooks); } @@ -330,7 +330,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, /* Beware size_t wrap-around. */ if (alloc_size < usize) return (NULL); - malloc_mutex_lock(tsdn, &arena->chunks_mtx); + malloc_mutex_lock(tsdn, &arena->extents_mtx); extent_hooks_assure_initialized_locked(tsdn, arena, extent_hooks); if (new_addr != NULL) { rtree_elm_t *elm; @@ -350,7 +350,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent = chunk_first_best_fit(arena, extent_heaps, alloc_size); if (extent == NULL || (new_addr != NULL && extent_size_get(extent) < size)) { - malloc_mutex_unlock(tsdn, &arena->chunks_mtx); + malloc_mutex_unlock(tsdn, &arena->extents_mtx); return (NULL); } extent_heaps_remove(extent_heaps, extent); @@ -373,7 +373,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, leadsize, leadsize, size + trailsize, usize + trailsize); if (extent == NULL) { chunk_leak(tsdn, arena, extent_hooks, cache, lead); - malloc_mutex_unlock(tsdn, &arena->chunks_mtx); + malloc_mutex_unlock(tsdn, &arena->extents_mtx); return (NULL); } extent_heaps_insert(extent_heaps, lead); @@ -386,7 +386,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent, size, usize, trailsize, trailsize); if (trail == NULL) { chunk_leak(tsdn, arena, extent_hooks, cache, extent); - malloc_mutex_unlock(tsdn, &arena->chunks_mtx); + malloc_mutex_unlock(tsdn, &arena->extents_mtx); return (NULL); } extent_heaps_insert(extent_heaps, trail); @@ -402,7 +402,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, if (!extent_committed_get(extent) && extent_hooks->commit(extent_base_get(extent), extent_size_get(extent), 0, extent_size_get(extent), arena->ind)) { - malloc_mutex_unlock(tsdn, &arena->chunks_mtx); + malloc_mutex_unlock(tsdn, &arena->extents_mtx); chunk_record(tsdn, arena, extent_hooks, extent_heaps, cache, extent); return (NULL); @@ -416,7 +416,7 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, chunk_interior_register(tsdn, extent); } - malloc_mutex_unlock(tsdn, &arena->chunks_mtx); + malloc_mutex_unlock(tsdn, &arena->extents_mtx); if (*zero) { if (!extent_zeroed_get(extent)) { @@ -480,7 +480,7 @@ chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, assert(alignment != 0); commit = true; - extent = chunk_recycle(tsdn, arena, extent_hooks, arena->chunks_cached, + extent = chunk_recycle(tsdn, arena, extent_hooks, arena->extents_cached, true, new_addr, usize, pad, alignment, zero, &commit, slab); if (extent == NULL) return (NULL); @@ -531,7 +531,7 @@ chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, assert(alignment != 0); extent = chunk_recycle(tsdn, arena, extent_hooks, - arena->chunks_retained, false, new_addr, usize, pad, alignment, + arena->extents_retained, false, new_addr, usize, pad, alignment, zero, commit, slab); if (extent != NULL && config_stats) { size_t size = usize + pad; @@ -640,7 +640,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, assert(!cache || !extent_zeroed_get(extent)); - malloc_mutex_lock(tsdn, &arena->chunks_mtx); + malloc_mutex_lock(tsdn, &arena->extents_mtx); extent_hooks_assure_initialized_locked(tsdn, arena, extent_hooks); extent_usize_set(extent, 0); @@ -671,7 +671,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_heaps, cache); } - malloc_mutex_unlock(tsdn, &arena->chunks_mtx); + malloc_mutex_unlock(tsdn, &arena->extents_mtx); } void @@ -685,7 +685,7 @@ chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_addr_set(extent, extent_base_get(extent)); extent_zeroed_set(extent, false); - chunk_record(tsdn, arena, extent_hooks, arena->chunks_cached, true, + chunk_record(tsdn, arena, extent_hooks, arena->extents_cached, true, extent); } @@ -732,7 +732,7 @@ chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, if (config_stats) arena->stats.retained += extent_size_get(extent); - chunk_record(tsdn, arena, extent_hooks, arena->chunks_retained, false, + chunk_record(tsdn, arena, extent_hooks, arena->extents_retained, false, extent); } -- GitLab From 4a55daa363e9622a1c98a129bbda1b7086773fa6 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Jun 2016 11:56:45 -0700 Subject: [PATCH 049/544] s/CHUNK_HOOKS_INITIALIZER/EXTENT_HOOKS_INITIALIZER/g --- include/jemalloc/internal/chunk.h | 10 ---------- include/jemalloc/internal/extent.h | 10 ++++++++++ src/arena.c | 8 ++++---- src/chunk.c | 2 +- src/chunk_dss.c | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index 10f2ae72..a6f6f7c3 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -11,16 +11,6 @@ #define CHUNK_CEILING(s) \ (((s) + chunksize_mask) & ~chunksize_mask) -#define CHUNK_HOOKS_INITIALIZER { \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ - NULL \ -} - #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ #ifdef JEMALLOC_H_STRUCTS diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index cf717d9e..b590ae0f 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -3,6 +3,16 @@ typedef struct extent_s extent_t; +#define EXTENT_HOOKS_INITIALIZER { \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL \ +} + #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ #ifdef JEMALLOC_H_STRUCTS diff --git a/src/arena.c b/src/arena.c index de6605a0..075082b1 100644 --- a/src/arena.c +++ b/src/arena.c @@ -347,7 +347,7 @@ arena_chunk_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero) { extent_t *extent; - extent_hooks_t extent_hooks = CHUNK_HOOKS_INITIALIZER; + extent_hooks_t extent_hooks = EXTENT_HOOKS_INITIALIZER; malloc_mutex_lock(tsdn, &arena->lock); @@ -373,7 +373,7 @@ void arena_chunk_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, bool locked) { - extent_hooks_t extent_hooks = CHUNK_HOOKS_INITIALIZER; + extent_hooks_t extent_hooks = EXTENT_HOOKS_INITIALIZER; if (!locked) malloc_mutex_lock(tsdn, &arena->lock); @@ -866,7 +866,7 @@ arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) static void arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) { - extent_hooks_t extent_hooks = CHUNK_HOOKS_INITIALIZER; + extent_hooks_t extent_hooks = EXTENT_HOOKS_INITIALIZER; arena_nactive_sub(arena, extent_size_get(slab) >> LG_PAGE); arena_chunk_cache_dalloc_locked(tsdn, arena, &extent_hooks, slab); @@ -1009,7 +1009,7 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, { extent_t *slab; arena_slab_data_t *slab_data; - extent_hooks_t extent_hooks = CHUNK_HOOKS_INITIALIZER; + extent_hooks_t extent_hooks = EXTENT_HOOKS_INITIALIZER; bool zero; zero = false; diff --git a/src/chunk.c b/src/chunk.c index 2ac44b0a..7f80bb42 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -131,7 +131,7 @@ extent_hooks_assure_initialized_impl(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, bool locked) { static const extent_hooks_t uninitialized_hooks = - CHUNK_HOOKS_INITIALIZER; + EXTENT_HOOKS_INITIALIZER; if (memcmp(extent_hooks, &uninitialized_hooks, sizeof(extent_hooks_t)) == 0) { diff --git a/src/chunk_dss.c b/src/chunk_dss.c index c5323dea..9fa4ad81 100644 --- a/src/chunk_dss.c +++ b/src/chunk_dss.c @@ -137,7 +137,7 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, malloc_mutex_unlock(tsdn, &dss_mtx); if (pad_size != 0) { extent_hooks_t extent_hooks = - CHUNK_HOOKS_INITIALIZER; + EXTENT_HOOKS_INITIALIZER; chunk_dalloc_wrapper(tsdn, arena, &extent_hooks, pad); } else -- GitLab From 0c4932eb1e522211297ae40435ab6d3bd74242bc Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Jun 2016 12:10:39 -0700 Subject: [PATCH 050/544] s/chunk_lookup/extent_lookup/g, s/chunks_rtree/extents_rtree/g --- include/jemalloc/internal/chunk.h | 15 ------- include/jemalloc/internal/extent.h | 12 ++++++ .../jemalloc/internal/jemalloc_internal.h.in | 6 +-- include/jemalloc/internal/private_symbols.txt | 5 ++- src/chunk.c | 41 ++++++++----------- src/extent.c | 16 ++++++++ src/jemalloc.c | 2 + test/unit/arena_reset.c | 2 +- 8 files changed, 55 insertions(+), 44 deletions(-) diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index a6f6f7c3..ddfa0046 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -22,8 +22,6 @@ extern size_t opt_lg_chunk; extern const char *opt_dss; -extern rtree_t chunks_rtree; - extern size_t chunksize; extern size_t chunksize_mask; /* (chunksize - 1). */ extern size_t chunk_npages; @@ -67,19 +65,6 @@ void chunk_postfork_child(tsdn_t *tsdn); /******************************************************************************/ #ifdef JEMALLOC_H_INLINES -#ifndef JEMALLOC_ENABLE_INLINE -extent_t *chunk_lookup(tsdn_t *tsdn, const void *chunk, bool dependent); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_CHUNK_C_)) -JEMALLOC_INLINE extent_t * -chunk_lookup(tsdn_t *tsdn, const void *ptr, bool dependent) -{ - - return (rtree_read(tsdn, &chunks_rtree, (uintptr_t)ptr, dependent)); -} -#endif - #endif /* JEMALLOC_H_INLINES */ /******************************************************************************/ diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index b590ae0f..8552f701 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -87,6 +87,8 @@ typedef ph(extent_t) extent_heap_t; /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS +extern rtree_t extents_rtree; + extent_t *extent_alloc(tsdn_t *tsdn, arena_t *arena); void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent); @@ -101,11 +103,14 @@ size_t extent_size_quantize_ceil(size_t size); ph_proto(, extent_heap_, extent_heap_t, extent_t) +bool extent_boot(void); + #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE +extent_t *extent_lookup(tsdn_t *tsdn, const void *chunk, bool dependent); arena_t *extent_arena_get(const extent_t *extent); void *extent_base_get(const extent_t *extent); void *extent_addr_get(const extent_t *extent); @@ -140,6 +145,13 @@ void extent_ring_remove(extent_t *extent); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_)) +JEMALLOC_INLINE extent_t * +extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent) +{ + + return (rtree_read(tsdn, &extents_rtree, (uintptr_t)ptr, dependent)); +} + JEMALLOC_INLINE arena_t * extent_arena_get(const extent_t *extent) { diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 58a18ae5..fb3991bc 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -510,9 +510,9 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/witness.h" #include "jemalloc/internal/mutex.h" #include "jemalloc/internal/mb.h" +#include "jemalloc/internal/rtree.h" #include "jemalloc/internal/extent.h" #include "jemalloc/internal/base.h" -#include "jemalloc/internal/rtree.h" #include "jemalloc/internal/pages.h" #include "jemalloc/internal/chunk.h" #include "jemalloc/internal/large.h" @@ -929,7 +929,7 @@ JEMALLOC_ALWAYS_INLINE extent_t * iealloc(tsdn_t *tsdn, const void *ptr) { - return (chunk_lookup(tsdn, ptr, true)); + return (extent_lookup(tsdn, ptr, true)); } #endif @@ -1062,7 +1062,7 @@ ivsalloc(tsdn_t *tsdn, const void *ptr) extent_t *extent; /* Return 0 if ptr is not within a chunk managed by jemalloc. */ - extent = chunk_lookup(tsdn, ptr, false); + extent = extent_lookup(tsdn, ptr, false); if (extent == NULL) return (0); assert(extent_active_get(extent)); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index b5fd4c0c..92f91e44 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -132,7 +132,6 @@ chunk_dss_prec_get chunk_dss_prec_set chunk_dss_prefork chunk_in_dss -chunk_lookup chunk_merge_wrapper chunk_npages chunk_postfork_child @@ -140,7 +139,6 @@ chunk_postfork_parent chunk_prefork chunk_purge_wrapper chunk_split_wrapper -chunks_rtree chunksize chunksize_mask ckh_count @@ -173,6 +171,7 @@ extent_arena_get extent_arena_set extent_base_get extent_before_get +extent_boot extent_committed_get extent_committed_set extent_dalloc @@ -187,6 +186,7 @@ extent_hooks_get extent_hooks_set extent_init extent_last_get +extent_lookup extent_past_get extent_prof_tctx_get extent_prof_tctx_set @@ -205,6 +205,7 @@ extent_usize_get extent_usize_set extent_zeroed_get extent_zeroed_set +extents_rtree ffs_llu ffs_lu ffs_u diff --git a/src/chunk.c b/src/chunk.c index 7f80bb42..3ce6e015 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -11,8 +11,6 @@ size_t opt_lg_chunk = 0; static size_t curchunks; static size_t highchunks; -rtree_t chunks_rtree; - /* Various chunk-related settings. */ size_t chunksize; size_t chunksize_mask; /* (chunksize - 1). */ @@ -161,14 +159,14 @@ extent_rtree_acquire(tsdn_t *tsdn, const extent_t *extent, bool dependent, bool init_missing, rtree_elm_t **r_elm_a, rtree_elm_t **r_elm_b) { - *r_elm_a = rtree_elm_acquire(tsdn, &chunks_rtree, + *r_elm_a = rtree_elm_acquire(tsdn, &extents_rtree, (uintptr_t)extent_base_get(extent), dependent, init_missing); if (!dependent && *r_elm_a == NULL) return (true); assert(*r_elm_a != NULL); if (extent_size_get(extent) > PAGE) { - *r_elm_b = rtree_elm_acquire(tsdn, &chunks_rtree, + *r_elm_b = rtree_elm_acquire(tsdn, &extents_rtree, (uintptr_t)extent_last_get(extent), dependent, init_missing); if (!dependent && *r_elm_b == NULL) @@ -185,18 +183,18 @@ extent_rtree_write_acquired(tsdn_t *tsdn, rtree_elm_t *elm_a, rtree_elm_t *elm_b, const extent_t *extent) { - rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_a, extent); + rtree_elm_write_acquired(tsdn, &extents_rtree, elm_a, extent); if (elm_b != NULL) - rtree_elm_write_acquired(tsdn, &chunks_rtree, elm_b, extent); + rtree_elm_write_acquired(tsdn, &extents_rtree, elm_b, extent); } static void extent_rtree_release(tsdn_t *tsdn, rtree_elm_t *elm_a, rtree_elm_t *elm_b) { - rtree_elm_release(tsdn, &chunks_rtree, elm_a); + rtree_elm_release(tsdn, &extents_rtree, elm_a); if (elm_b != NULL) - rtree_elm_release(tsdn, &chunks_rtree, elm_b); + rtree_elm_release(tsdn, &extents_rtree, elm_b); } static void @@ -207,7 +205,7 @@ chunk_interior_register(tsdn_t *tsdn, const extent_t *extent) assert(extent_slab_get(extent)); for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) { - rtree_write(tsdn, &chunks_rtree, + rtree_write(tsdn, &extents_rtree, (uintptr_t)extent_base_get(extent) + (uintptr_t)(i << LG_PAGE), extent); } @@ -252,7 +250,7 @@ chunk_interior_deregister(tsdn_t *tsdn, const extent_t *extent) assert(extent_slab_get(extent)); for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) { - rtree_clear(tsdn, &chunks_rtree, + rtree_clear(tsdn, &extents_rtree, (uintptr_t)extent_base_get(extent) + (uintptr_t)(i << LG_PAGE)); } @@ -335,15 +333,15 @@ chunk_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, if (new_addr != NULL) { rtree_elm_t *elm; - elm = rtree_elm_acquire(tsdn, &chunks_rtree, + elm = rtree_elm_acquire(tsdn, &extents_rtree, (uintptr_t)new_addr, false, false); if (elm != NULL) { - extent = rtree_elm_read_acquired(tsdn, &chunks_rtree, + extent = rtree_elm_read_acquired(tsdn, &extents_rtree, elm); if (extent != NULL && (extent_active_get(extent) || extent_retained_get(extent) == cache)) extent = NULL; - rtree_elm_release(tsdn, &chunks_rtree, elm); + rtree_elm_release(tsdn, &extents_rtree, elm); } else extent = NULL; } else @@ -651,12 +649,12 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_slab_set(extent, false); } - assert(chunk_lookup(tsdn, extent_base_get(extent), true) == extent); + assert(extent_lookup(tsdn, extent_base_get(extent), true) == extent); extent_heaps_insert(extent_heaps, extent); arena_chunk_cache_maybe_insert(arena, extent, cache); /* Try to coalesce forward. */ - next = rtree_read(tsdn, &chunks_rtree, + next = rtree_read(tsdn, &extents_rtree, (uintptr_t)extent_past_get(extent), false); if (next != NULL) { chunk_try_coalesce(tsdn, arena, extent_hooks, extent, next, @@ -664,7 +662,7 @@ chunk_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, } /* Try to coalesce backward. */ - prev = rtree_read(tsdn, &chunks_rtree, + prev = rtree_read(tsdn, &extents_rtree, (uintptr_t)extent_before_get(extent), false); if (prev != NULL) { chunk_try_coalesce(tsdn, arena, extent_hooks, prev, extent, @@ -907,12 +905,12 @@ chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_rtree_acquire(tsdn, b, true, false, &b_elm_a, &b_elm_b); if (a_elm_b != NULL) { - rtree_elm_write_acquired(tsdn, &chunks_rtree, a_elm_b, NULL); - rtree_elm_release(tsdn, &chunks_rtree, a_elm_b); + rtree_elm_write_acquired(tsdn, &extents_rtree, a_elm_b, NULL); + rtree_elm_release(tsdn, &extents_rtree, a_elm_b); } if (b_elm_b != NULL) { - rtree_elm_write_acquired(tsdn, &chunks_rtree, b_elm_a, NULL); - rtree_elm_release(tsdn, &chunks_rtree, b_elm_a); + rtree_elm_write_acquired(tsdn, &extents_rtree, b_elm_a, NULL); + rtree_elm_release(tsdn, &extents_rtree, b_elm_a); } else b_elm_b = b_elm_a; @@ -963,9 +961,6 @@ chunk_boot(void) if (have_dss && chunk_dss_boot()) return (true); - if (rtree_new(&chunks_rtree, (unsigned)((ZU(1) << (LG_SIZEOF_PTR+3)) - - LG_PAGE))) - return (true); return (false); } diff --git a/src/extent.c b/src/extent.c index 2f929a83..3e62e3bc 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1,6 +1,11 @@ #define JEMALLOC_EXTENT_C_ #include "jemalloc/internal/jemalloc_internal.h" +/******************************************************************************/ +/* Data. */ + +rtree_t extents_rtree; + /******************************************************************************/ extent_t * @@ -112,3 +117,14 @@ extent_ad_comp(const extent_t *a, const extent_t *b) /* Generate pairing heap functions. */ ph_gen(, extent_heap_, extent_heap_t, extent_t, ph_link, extent_ad_comp) + +bool +extent_boot(void) +{ + + if (rtree_new(&extents_rtree, (unsigned)((ZU(1) << (LG_SIZEOF_PTR+3)) - + LG_PAGE))) + return (true); + + return (false); +} diff --git a/src/jemalloc.c b/src/jemalloc.c index a9bba12b..03e61df6 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1232,6 +1232,8 @@ malloc_init_hard_a0_locked() return (true); if (chunk_boot()) return (true); + if (extent_boot()) + return (true); if (ctl_boot()) return (true); if (config_prof) diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index a9476b89..61caf3c5 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -70,7 +70,7 @@ vsalloc(tsdn_t *tsdn, const void *ptr) { extent_t *extent; - extent = chunk_lookup(tsdn, ptr, false); + extent = extent_lookup(tsdn, ptr, false); if (extent == NULL) return (0); if (!extent_active_get(extent)) -- GitLab From 22588dda6e09f63246064e2e692dc0dded2e8e35 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Jun 2016 12:59:02 -0700 Subject: [PATCH 051/544] Rename most remaining *chunk* APIs to *extent*. --- Makefile.in | 10 +- include/jemalloc/internal/arena.h | 18 +- include/jemalloc/internal/chunk.h | 36 - include/jemalloc/internal/extent.h | 41 +- .../internal/{chunk_dss.h => extent_dss.h} | 16 +- .../internal/{chunk_mmap.h => extent_mmap.h} | 4 +- include/jemalloc/internal/private_symbols.txt | 60 +- .../projects/vc2015/jemalloc/jemalloc.vcxproj | 8 +- .../vc2015/jemalloc/jemalloc.vcxproj.filters | 20 +- src/arena.c | 58 +- src/base.c | 8 +- src/chunk.c | 936 ------------------ src/ctl.c | 4 +- src/extent.c | 929 +++++++++++++++++ src/{chunk_dss.c => extent_dss.c} | 32 +- src/{chunk_mmap.c => extent_mmap.c} | 12 +- src/jemalloc.c | 8 +- src/large.c | 28 +- test/integration/{chunk.c => extent.c} | 82 +- 19 files changed, 1151 insertions(+), 1159 deletions(-) rename include/jemalloc/internal/{chunk_dss.h => extent_dss.h} (71%) rename include/jemalloc/internal/{chunk_mmap.h => extent_mmap.h} (84%) rename src/{chunk_dss.c => extent_dss.c} (86%) rename src/{chunk_mmap.c => extent_mmap.c} (83%) rename test/integration/{chunk.c => extent.c} (72%) diff --git a/Makefile.in b/Makefile.in index f90e2a4f..a24fde95 100644 --- a/Makefile.in +++ b/Makefile.in @@ -82,11 +82,11 @@ C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/base.c \ $(srcroot)src/bitmap.c \ $(srcroot)src/chunk.c \ - $(srcroot)src/chunk_dss.c \ - $(srcroot)src/chunk_mmap.c \ $(srcroot)src/ckh.c \ $(srcroot)src/ctl.c \ $(srcroot)src/extent.c \ + $(srcroot)src/extent_dss.c \ + $(srcroot)src/extent_mmap.c \ $(srcroot)src/hash.c \ $(srcroot)src/large.c \ $(srcroot)src/mb.c \ @@ -171,16 +171,16 @@ TESTS_UNIT := \ $(srcroot)test/unit/zero.c TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \ $(srcroot)test/integration/allocated.c \ - $(srcroot)test/integration/sdallocx.c \ + $(srcroot)test/integration/extent.c \ $(srcroot)test/integration/mallocx.c \ $(srcroot)test/integration/MALLOCX_ARENA.c \ $(srcroot)test/integration/overflow.c \ $(srcroot)test/integration/posix_memalign.c \ $(srcroot)test/integration/rallocx.c \ + $(srcroot)test/integration/sdallocx.c \ $(srcroot)test/integration/thread_arena.c \ $(srcroot)test/integration/thread_tcache_enabled.c \ - $(srcroot)test/integration/xallocx.c \ - $(srcroot)test/integration/chunk.c + $(srcroot)test/integration/xallocx.c TESTS_STRESS := $(srcroot)test/stress/microbench.c TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_STRESS) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 0707b863..bc169756 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -278,22 +278,22 @@ extern ssize_t opt_decay_time; extern const arena_bin_info_t arena_bin_info[NBINS]; -extent_t *arena_chunk_cache_alloc(tsdn_t *tsdn, arena_t *arena, +extent_t *arena_extent_cache_alloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, void *new_addr, size_t size, size_t alignment, bool *zero); -void arena_chunk_cache_dalloc(tsdn_t *tsdn, arena_t *arena, +void arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_t *extent); -void arena_chunk_cache_maybe_insert(arena_t *arena, extent_t *extent, +void arena_extent_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache); -void arena_chunk_cache_maybe_remove(arena_t *arena, extent_t *extent, +void arena_extent_cache_maybe_remove(arena_t *arena, extent_t *extent, bool cache); -extent_t *arena_chunk_alloc_large(tsdn_t *tsdn, arena_t *arena, +extent_t *arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero); -void arena_chunk_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - bool locked); -void arena_chunk_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, +void arena_extent_dalloc_large(tsdn_t *tsdn, arena_t *arena, + extent_t *extent, bool locked); +void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); -void arena_chunk_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, +void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); ssize_t arena_lg_dirty_mult_get(tsdn_t *tsdn, arena_t *arena); bool arena_lg_dirty_mult_set(tsdn_t *tsdn, arena_t *arena, diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h index ddfa0046..7a5ebbca 100644 --- a/include/jemalloc/internal/chunk.h +++ b/include/jemalloc/internal/chunk.h @@ -26,40 +26,7 @@ extern size_t chunksize; extern size_t chunksize_mask; /* (chunksize - 1). */ extern size_t chunk_npages; -extern const extent_hooks_t extent_hooks_default; - -extent_hooks_t extent_hooks_get(tsdn_t *tsdn, arena_t *arena); -extent_hooks_t extent_hooks_set(tsdn_t *tsdn, arena_t *arena, - const extent_hooks_t *extent_hooks); - -extent_t *chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool slab); -extent_t *chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab); -void chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent); -void chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent); -bool chunk_commit_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, - size_t length); -bool chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, - size_t length); -bool chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, - size_t length); -extent_t *chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent, size_t size_a, - size_t usize_a, size_t size_b, size_t usize_b); -bool chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *a, extent_t *b); bool chunk_boot(void); -void chunk_prefork(tsdn_t *tsdn); -void chunk_postfork_parent(tsdn_t *tsdn); -void chunk_postfork_child(tsdn_t *tsdn); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ @@ -67,6 +34,3 @@ void chunk_postfork_child(tsdn_t *tsdn); #endif /* JEMALLOC_H_INLINES */ /******************************************************************************/ - -#include "jemalloc/internal/chunk_dss.h" -#include "jemalloc/internal/chunk_mmap.h" diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 8552f701..a41a15ff 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -38,7 +38,7 @@ struct extent_s { bool e_active; /* - * The zeroed flag is used by chunk recycling code to track whether + * The zeroed flag is used by extent recycling code to track whether * memory is zero-filled. */ bool e_zeroed; @@ -87,11 +87,16 @@ typedef ph(extent_t) extent_heap_t; /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS -extern rtree_t extents_rtree; +extern rtree_t extents_rtree; +extern const extent_hooks_t extent_hooks_default; extent_t *extent_alloc(tsdn_t *tsdn, arena_t *arena); void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent); +extent_hooks_t extent_hooks_get(tsdn_t *tsdn, arena_t *arena); +extent_hooks_t extent_hooks_set(tsdn_t *tsdn, arena_t *arena, + const extent_hooks_t *extent_hooks); + #ifdef JEMALLOC_JET typedef size_t (extent_size_quantize_t)(size_t); extern extent_size_quantize_t *extent_size_quantize_floor; @@ -103,6 +108,34 @@ size_t extent_size_quantize_ceil(size_t size); ph_proto(, extent_heap_, extent_heap_t, extent_t) +extent_t *extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool slab); +extent_t *extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool *commit, bool slab); +void extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, extent_t *extent); +void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, extent_t *extent); +bool extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, + size_t length); +bool extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, + size_t length); +bool extent_purge_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, + size_t length); +extent_t *extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, extent_t *extent, size_t size_a, + size_t usize_a, size_t size_b, size_t usize_b); +bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, extent_t *a, extent_t *b); +void extent_prefork(tsdn_t *tsdn); +void extent_postfork_parent(tsdn_t *tsdn); +void extent_postfork_child(tsdn_t *tsdn); + bool extent_boot(void); #endif /* JEMALLOC_H_EXTERNS */ @@ -110,7 +143,7 @@ bool extent_boot(void); #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE -extent_t *extent_lookup(tsdn_t *tsdn, const void *chunk, bool dependent); +extent_t *extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent); arena_t *extent_arena_get(const extent_t *extent); void *extent_base_get(const extent_t *extent); void *extent_addr_get(const extent_t *extent); @@ -395,3 +428,5 @@ extent_ring_remove(extent_t *extent) #endif /* JEMALLOC_H_INLINES */ /******************************************************************************/ +#include "jemalloc/internal/extent_dss.h" +#include "jemalloc/internal/extent_mmap.h" diff --git a/include/jemalloc/internal/chunk_dss.h b/include/jemalloc/internal/extent_dss.h similarity index 71% rename from include/jemalloc/internal/chunk_dss.h rename to include/jemalloc/internal/extent_dss.h index 724fa579..43573775 100644 --- a/include/jemalloc/internal/chunk_dss.h +++ b/include/jemalloc/internal/extent_dss.h @@ -21,15 +21,15 @@ extern const char *dss_prec_names[]; /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS -dss_prec_t chunk_dss_prec_get(tsdn_t *tsdn); -bool chunk_dss_prec_set(tsdn_t *tsdn, dss_prec_t dss_prec); -void *chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, +dss_prec_t extent_dss_prec_get(tsdn_t *tsdn); +bool extent_dss_prec_set(tsdn_t *tsdn, dss_prec_t dss_prec); +void *extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit); -bool chunk_in_dss(tsdn_t *tsdn, void *chunk); -bool chunk_dss_boot(void); -void chunk_dss_prefork(tsdn_t *tsdn); -void chunk_dss_postfork_parent(tsdn_t *tsdn); -void chunk_dss_postfork_child(tsdn_t *tsdn); +bool extent_in_dss(tsdn_t *tsdn, void *addr); +bool extent_dss_boot(void); +void extent_dss_prefork(tsdn_t *tsdn); +void extent_dss_postfork_parent(tsdn_t *tsdn); +void extent_dss_postfork_child(tsdn_t *tsdn); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ diff --git a/include/jemalloc/internal/chunk_mmap.h b/include/jemalloc/internal/extent_mmap.h similarity index 84% rename from include/jemalloc/internal/chunk_mmap.h rename to include/jemalloc/internal/extent_mmap.h index 6f2d0ac2..3c1a7884 100644 --- a/include/jemalloc/internal/chunk_mmap.h +++ b/include/jemalloc/internal/extent_mmap.h @@ -9,9 +9,9 @@ /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS -void *chunk_alloc_mmap(void *new_addr, size_t size, size_t alignment, +void *extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit); -bool chunk_dalloc_mmap(void *chunk, size_t size); +bool extent_dalloc_mmap(void *addr, size_t size); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 92f91e44..a2f093ee 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -9,14 +9,6 @@ arena_boot arena_choose arena_choose_hard arena_choose_impl -arena_chunk_alloc_large -arena_chunk_cache_alloc -arena_chunk_cache_dalloc -arena_chunk_cache_maybe_insert -arena_chunk_cache_maybe_remove -arena_chunk_dalloc_large -arena_chunk_ralloc_large_expand -arena_chunk_ralloc_large_shrink arena_cleanup arena_dalloc arena_dalloc_bin_junked_locked @@ -31,6 +23,14 @@ arena_decay_time_get arena_decay_time_set arena_dss_prec_get arena_dss_prec_set +arena_extent_alloc_large +arena_extent_cache_alloc +arena_extent_cache_dalloc +arena_extent_cache_maybe_insert +arena_extent_cache_maybe_remove +arena_extent_dalloc_large +arena_extent_ralloc_large_expand +arena_extent_ralloc_large_shrink arena_get arena_ichoose arena_init @@ -115,30 +115,8 @@ bootstrap_free bootstrap_malloc bt_init buferror -chunk_alloc_cache -chunk_alloc_dss -chunk_alloc_mmap -chunk_alloc_wrapper chunk_boot -chunk_commit_wrapper -chunk_dalloc_cache -chunk_dalloc_mmap -chunk_dalloc_wrapper -chunk_decommit_wrapper -chunk_dss_boot -chunk_dss_postfork_child -chunk_dss_postfork_parent -chunk_dss_prec_get -chunk_dss_prec_set -chunk_dss_prefork -chunk_in_dss -chunk_merge_wrapper chunk_npages -chunk_postfork_child -chunk_postfork_parent -chunk_prefork -chunk_purge_wrapper -chunk_split_wrapper chunksize chunksize_mask ckh_count @@ -167,14 +145,29 @@ extent_addr_get extent_addr_randomize extent_addr_set extent_alloc +extent_alloc_cache +extent_alloc_dss +extent_alloc_mmap +extent_alloc_wrapper extent_arena_get extent_arena_set extent_base_get extent_before_get extent_boot +extent_commit_wrapper extent_committed_get extent_committed_set extent_dalloc +extent_dalloc_cache +extent_dalloc_mmap +extent_dalloc_wrapper +extent_decommit_wrapper +extent_dss_boot +extent_dss_postfork_child +extent_dss_postfork_parent +extent_dss_prec_get +extent_dss_prec_set +extent_dss_prefork extent_heap_empty extent_heap_first extent_heap_insert @@ -184,12 +177,18 @@ extent_heap_remove_first extent_hooks_default extent_hooks_get extent_hooks_set +extent_in_dss extent_init extent_last_get extent_lookup +extent_merge_wrapper extent_past_get +extent_postfork_child +extent_postfork_parent +extent_prefork extent_prof_tctx_get extent_prof_tctx_set +extent_purge_wrapper extent_retained_get extent_ring_insert extent_ring_remove @@ -201,6 +200,7 @@ extent_slab_data_get extent_slab_data_get_const extent_slab_get extent_slab_set +extent_split_wrapper extent_usize_get extent_usize_set extent_zeroed_get diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj index 91c949aa..59f52f96 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj @@ -41,11 +41,11 @@ - - + + @@ -92,11 +92,11 @@ - - + + diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters index 09d4cb20..159b2e72 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters @@ -62,19 +62,19 @@ Header Files\internal - + Header Files\internal - + Header Files\internal - + Header Files\internal - + Header Files\internal - + Header Files\internal @@ -187,19 +187,19 @@ Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files diff --git a/src/arena.c b/src/arena.c index 075082b1..990e0e89 100644 --- a/src/arena.c +++ b/src/arena.c @@ -46,33 +46,33 @@ static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, /******************************************************************************/ static size_t -arena_chunk_dirty_npages(const extent_t *extent) +arena_extent_dirty_npages(const extent_t *extent) { return (extent_size_get(extent) >> LG_PAGE); } static extent_t * -arena_chunk_cache_alloc_locked(tsdn_t *tsdn, arena_t *arena, +arena_extent_cache_alloc_locked(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool slab) { malloc_mutex_assert_owner(tsdn, &arena->lock); - return (chunk_alloc_cache(tsdn, arena, extent_hooks, new_addr, usize, + return (extent_alloc_cache(tsdn, arena, extent_hooks, new_addr, usize, pad, alignment, zero, slab)); } extent_t * -arena_chunk_cache_alloc(tsdn_t *tsdn, arena_t *arena, +arena_extent_cache_alloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, void *new_addr, size_t size, size_t alignment, bool *zero) { extent_t *extent; malloc_mutex_lock(tsdn, &arena->lock); - extent = arena_chunk_cache_alloc_locked(tsdn, arena, extent_hooks, + extent = arena_extent_cache_alloc_locked(tsdn, arena, extent_hooks, new_addr, size, 0, alignment, zero, false); malloc_mutex_unlock(tsdn, &arena->lock); @@ -80,44 +80,44 @@ arena_chunk_cache_alloc(tsdn_t *tsdn, arena_t *arena, } static void -arena_chunk_cache_dalloc_locked(tsdn_t *tsdn, arena_t *arena, +arena_extent_cache_dalloc_locked(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_t *extent) { malloc_mutex_assert_owner(tsdn, &arena->lock); - chunk_dalloc_cache(tsdn, arena, extent_hooks, extent); + extent_dalloc_cache(tsdn, arena, extent_hooks, extent); arena_maybe_purge(tsdn, arena); } void -arena_chunk_cache_dalloc(tsdn_t *tsdn, arena_t *arena, +arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_t *extent) { malloc_mutex_lock(tsdn, &arena->lock); - arena_chunk_cache_dalloc_locked(tsdn, arena, extent_hooks, extent); + arena_extent_cache_dalloc_locked(tsdn, arena, extent_hooks, extent); malloc_mutex_unlock(tsdn, &arena->lock); } void -arena_chunk_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache) +arena_extent_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache) { if (cache) { extent_ring_insert(&arena->extents_dirty, extent); - arena->ndirty += arena_chunk_dirty_npages(extent); + arena->ndirty += arena_extent_dirty_npages(extent); } } void -arena_chunk_cache_maybe_remove(arena_t *arena, extent_t *extent, bool dirty) +arena_extent_cache_maybe_remove(arena_t *arena, extent_t *extent, bool dirty) { if (dirty) { extent_ring_remove(extent); - assert(arena->ndirty >= arena_chunk_dirty_npages(extent)); - arena->ndirty -= arena_chunk_dirty_npages(extent); + assert(arena->ndirty >= arena_extent_dirty_npages(extent)); + arena->ndirty -= arena_extent_dirty_npages(extent); } } @@ -320,13 +320,13 @@ arena_large_ralloc_stats_update(arena_t *arena, size_t oldusize, size_t usize) } static extent_t * -arena_chunk_alloc_large_hard(tsdn_t *tsdn, arena_t *arena, +arena_extent_alloc_large_hard(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, size_t usize, size_t alignment, bool *zero) { extent_t *extent; bool commit = true; - extent = chunk_alloc_wrapper(tsdn, arena, extent_hooks, NULL, usize, + extent = extent_alloc_wrapper(tsdn, arena, extent_hooks, NULL, usize, large_pad, alignment, zero, &commit, false); if (extent == NULL) { /* Revert optimistic stats updates. */ @@ -343,7 +343,7 @@ arena_chunk_alloc_large_hard(tsdn_t *tsdn, arena_t *arena, } extent_t * -arena_chunk_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, +arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero) { extent_t *extent; @@ -358,11 +358,11 @@ arena_chunk_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, } arena_nactive_add(arena, (usize + large_pad) >> LG_PAGE); - extent = arena_chunk_cache_alloc_locked(tsdn, arena, &extent_hooks, + extent = arena_extent_cache_alloc_locked(tsdn, arena, &extent_hooks, NULL, usize, large_pad, alignment, zero, false); malloc_mutex_unlock(tsdn, &arena->lock); if (extent == NULL) { - extent = arena_chunk_alloc_large_hard(tsdn, arena, + extent = arena_extent_alloc_large_hard(tsdn, arena, &extent_hooks, usize, alignment, zero); } @@ -370,7 +370,7 @@ arena_chunk_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, } void -arena_chunk_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, +arena_extent_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, bool locked) { extent_hooks_t extent_hooks = EXTENT_HOOKS_INITIALIZER; @@ -384,13 +384,13 @@ arena_chunk_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, } arena_nactive_sub(arena, extent_size_get(extent) >> LG_PAGE); - arena_chunk_cache_dalloc_locked(tsdn, arena, &extent_hooks, extent); + arena_extent_cache_dalloc_locked(tsdn, arena, &extent_hooks, extent); if (!locked) malloc_mutex_unlock(tsdn, &arena->lock); } void -arena_chunk_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, +arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldusize) { size_t usize = extent_usize_get(extent); @@ -406,7 +406,7 @@ arena_chunk_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, } void -arena_chunk_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, +arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldusize) { size_t usize = extent_usize_get(extent); @@ -756,7 +756,7 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, next = qr_next(extent, qr_link); /* Allocate. */ zero = false; - textent = arena_chunk_cache_alloc_locked(tsdn, arena, + textent = arena_extent_cache_alloc_locked(tsdn, arena, extent_hooks, extent_base_get(extent), extent_size_get(extent), 0, CACHELINE, &zero, false); assert(textent == extent); @@ -793,7 +793,7 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, next = qr_next(extent, qr_link); extent_ring_remove(extent); - chunk_dalloc_wrapper(tsdn, arena, extent_hooks, extent); + extent_dalloc_wrapper(tsdn, arena, extent_hooks, extent); } if (config_stats) { @@ -869,7 +869,7 @@ arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) extent_hooks_t extent_hooks = EXTENT_HOOKS_INITIALIZER; arena_nactive_sub(arena, extent_size_get(slab) >> LG_PAGE); - arena_chunk_cache_dalloc_locked(tsdn, arena, &extent_hooks, slab); + arena_extent_cache_dalloc_locked(tsdn, arena, &extent_hooks, slab); } void @@ -996,7 +996,7 @@ arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, zero = false; commit = true; malloc_mutex_unlock(tsdn, &arena->lock); - slab = chunk_alloc_wrapper(tsdn, arena, extent_hooks, NULL, + slab = extent_alloc_wrapper(tsdn, arena, extent_hooks, NULL, bin_info->slab_size, 0, PAGE, &zero, &commit, true); malloc_mutex_lock(tsdn, &arena->lock); @@ -1013,7 +1013,7 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero; zero = false; - slab = arena_chunk_cache_alloc_locked(tsdn, arena, &extent_hooks, NULL, + slab = arena_extent_cache_alloc_locked(tsdn, arena, &extent_hooks, NULL, bin_info->slab_size, 0, PAGE, &zero, true); if (slab == NULL) { slab = arena_slab_alloc_hard(tsdn, arena, &extent_hooks, @@ -1774,7 +1774,7 @@ arena_new(tsdn_t *tsdn, unsigned ind) (uint64_t)(uintptr_t)arena; } - arena->dss_prec = chunk_dss_prec_get(tsdn); + arena->dss_prec = extent_dss_prec_get(tsdn); arena->lg_dirty_mult = arena_lg_dirty_mult_default_get(); arena->purging = false; diff --git a/src/base.c b/src/base.c index 3807422c..667786e1 100644 --- a/src/base.c +++ b/src/base.c @@ -38,7 +38,7 @@ base_extent_dalloc(tsdn_t *tsdn, extent_t *extent) } static extent_t * -base_chunk_alloc(tsdn_t *tsdn, size_t minsize) +base_extent_alloc(tsdn_t *tsdn, size_t minsize) { extent_t *extent; size_t csize, nsize; @@ -51,13 +51,13 @@ base_chunk_alloc(tsdn_t *tsdn, size_t minsize) nsize = (extent == NULL) ? CACHELINE_CEILING(sizeof(extent_t)) : 0; csize = CHUNK_CEILING(minsize + nsize); /* - * Directly call chunk_alloc_mmap() because it's critical to allocate + * Directly call extent_alloc_mmap() because it's critical to allocate * untouched demand-zeroed virtual memory. */ { bool zero = true; bool commit = true; - addr = chunk_alloc_mmap(NULL, csize, PAGE, &zero, &commit); + addr = extent_alloc_mmap(NULL, csize, PAGE, &zero, &commit); } if (addr == NULL) { if (extent != NULL) @@ -108,7 +108,7 @@ base_alloc(tsdn_t *tsdn, size_t size) } if (extent == NULL) { /* Try to allocate more space. */ - extent = base_chunk_alloc(tsdn, csize); + extent = base_extent_alloc(tsdn, csize); } if (extent == NULL) { ret = NULL; diff --git a/src/chunk.c b/src/chunk.c index 3ce6e015..d750f715 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -7,925 +7,13 @@ const char *opt_dss = DSS_DEFAULT; size_t opt_lg_chunk = 0; -/* Used exclusively for gdump triggering. */ -static size_t curchunks; -static size_t highchunks; - /* Various chunk-related settings. */ size_t chunksize; size_t chunksize_mask; /* (chunksize - 1). */ size_t chunk_npages; -static void *extent_alloc_default(void *new_addr, size_t size, - size_t alignment, bool *zero, bool *commit, unsigned arena_ind); -static bool extent_dalloc_default(void *addr, size_t size, bool committed, - unsigned arena_ind); -static bool extent_commit_default(void *addr, size_t size, size_t offset, - size_t length, unsigned arena_ind); -static bool extent_decommit_default(void *addr, size_t size, size_t offset, - size_t length, unsigned arena_ind); -static bool extent_purge_default(void *addr, size_t size, size_t offset, - size_t length, unsigned arena_ind); -static bool extent_split_default(void *addr, size_t size, size_t size_a, - size_t size_b, bool committed, unsigned arena_ind); -static bool extent_merge_default(void *addr_a, size_t size_a, void *addr_b, - size_t size_b, bool committed, unsigned arena_ind); - -const extent_hooks_t extent_hooks_default = { - extent_alloc_default, - extent_dalloc_default, - extent_commit_default, - extent_decommit_default, - extent_purge_default, - extent_split_default, - extent_merge_default -}; - -/******************************************************************************/ -/* - * Function prototypes for static functions that are referenced prior to - * definition. - */ - -static void chunk_record(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_heap_t extent_heaps[NPSIZES], - bool cache, extent_t *extent); - /******************************************************************************/ -static void -extent_heaps_insert(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) -{ - size_t psz = extent_size_quantize_floor(extent_size_get(extent)); - pszind_t pind = psz2ind(psz); - extent_heap_insert(&extent_heaps[pind], extent); -} - -static void -extent_heaps_remove(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) -{ - size_t psz = extent_size_quantize_floor(extent_size_get(extent)); - pszind_t pind = psz2ind(psz); - extent_heap_remove(&extent_heaps[pind], extent); -} - -static extent_hooks_t -extent_hooks_get_locked(arena_t *arena) -{ - - return (arena->extent_hooks); -} - -extent_hooks_t -extent_hooks_get(tsdn_t *tsdn, arena_t *arena) -{ - extent_hooks_t extent_hooks; - - malloc_mutex_lock(tsdn, &arena->extents_mtx); - extent_hooks = extent_hooks_get_locked(arena); - malloc_mutex_unlock(tsdn, &arena->extents_mtx); - - return (extent_hooks); -} - -extent_hooks_t -extent_hooks_set(tsdn_t *tsdn, arena_t *arena, - const extent_hooks_t *extent_hooks) -{ - extent_hooks_t old_extent_hooks; - - malloc_mutex_lock(tsdn, &arena->extents_mtx); - old_extent_hooks = arena->extent_hooks; - /* - * Copy each field atomically so that it is impossible for readers to - * see partially updated pointers. There are places where readers only - * need one hook function pointer (therefore no need to copy the - * entirety of arena->extent_hooks), and stale reads do not affect - * correctness, so they perform unlocked reads. - */ -#define ATOMIC_COPY_HOOK(n) do { \ - union { \ - extent_##n##_t **n; \ - void **v; \ - } u; \ - u.n = &arena->extent_hooks.n; \ - atomic_write_p(u.v, extent_hooks->n); \ -} while (0) - ATOMIC_COPY_HOOK(alloc); - ATOMIC_COPY_HOOK(dalloc); - ATOMIC_COPY_HOOK(commit); - ATOMIC_COPY_HOOK(decommit); - ATOMIC_COPY_HOOK(purge); - ATOMIC_COPY_HOOK(split); - ATOMIC_COPY_HOOK(merge); -#undef ATOMIC_COPY_HOOK - malloc_mutex_unlock(tsdn, &arena->extents_mtx); - - return (old_extent_hooks); -} - -static void -extent_hooks_assure_initialized_impl(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, bool locked) -{ - static const extent_hooks_t uninitialized_hooks = - EXTENT_HOOKS_INITIALIZER; - - if (memcmp(extent_hooks, &uninitialized_hooks, sizeof(extent_hooks_t)) - == 0) { - *extent_hooks = locked ? extent_hooks_get_locked(arena) : - extent_hooks_get(tsdn, arena); - } -} - -static void -extent_hooks_assure_initialized_locked(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks) -{ - - extent_hooks_assure_initialized_impl(tsdn, arena, extent_hooks, true); -} - -static void -extent_hooks_assure_initialized(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks) -{ - - extent_hooks_assure_initialized_impl(tsdn, arena, extent_hooks, false); -} - -static bool -extent_rtree_acquire(tsdn_t *tsdn, const extent_t *extent, bool dependent, - bool init_missing, rtree_elm_t **r_elm_a, rtree_elm_t **r_elm_b) -{ - - *r_elm_a = rtree_elm_acquire(tsdn, &extents_rtree, - (uintptr_t)extent_base_get(extent), dependent, init_missing); - if (!dependent && *r_elm_a == NULL) - return (true); - assert(*r_elm_a != NULL); - - if (extent_size_get(extent) > PAGE) { - *r_elm_b = rtree_elm_acquire(tsdn, &extents_rtree, - (uintptr_t)extent_last_get(extent), dependent, - init_missing); - if (!dependent && *r_elm_b == NULL) - return (true); - assert(*r_elm_b != NULL); - } else - *r_elm_b = NULL; - - return (false); -} - -static void -extent_rtree_write_acquired(tsdn_t *tsdn, rtree_elm_t *elm_a, - rtree_elm_t *elm_b, const extent_t *extent) -{ - - rtree_elm_write_acquired(tsdn, &extents_rtree, elm_a, extent); - if (elm_b != NULL) - rtree_elm_write_acquired(tsdn, &extents_rtree, elm_b, extent); -} - -static void -extent_rtree_release(tsdn_t *tsdn, rtree_elm_t *elm_a, rtree_elm_t *elm_b) -{ - - rtree_elm_release(tsdn, &extents_rtree, elm_a); - if (elm_b != NULL) - rtree_elm_release(tsdn, &extents_rtree, elm_b); -} - -static void -chunk_interior_register(tsdn_t *tsdn, const extent_t *extent) -{ - size_t i; - - assert(extent_slab_get(extent)); - - for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) { - rtree_write(tsdn, &extents_rtree, - (uintptr_t)extent_base_get(extent) + (uintptr_t)(i << - LG_PAGE), extent); - } -} - -static bool -chunk_register(tsdn_t *tsdn, const extent_t *extent) -{ - rtree_elm_t *elm_a, *elm_b; - - if (extent_rtree_acquire(tsdn, extent, false, true, &elm_a, &elm_b)) - return (true); - extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent); - if (extent_slab_get(extent)) - chunk_interior_register(tsdn, extent); - extent_rtree_release(tsdn, elm_a, elm_b); - - if (config_prof && opt_prof && extent_active_get(extent)) { - size_t nadd = (extent_size_get(extent) == 0) ? 1 : - extent_size_get(extent) / chunksize; - size_t cur = atomic_add_z(&curchunks, nadd); - size_t high = atomic_read_z(&highchunks); - while (cur > high && atomic_cas_z(&highchunks, high, cur)) { - /* - * Don't refresh cur, because it may have decreased - * since this thread lost the highchunks update race. - */ - high = atomic_read_z(&highchunks); - } - if (cur > high && prof_gdump_get_unlocked()) - prof_gdump(tsdn); - } - - return (false); -} - -static void -chunk_interior_deregister(tsdn_t *tsdn, const extent_t *extent) -{ - size_t i; - - assert(extent_slab_get(extent)); - - for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) { - rtree_clear(tsdn, &extents_rtree, - (uintptr_t)extent_base_get(extent) + (uintptr_t)(i << - LG_PAGE)); - } -} - -static void -chunk_deregister(tsdn_t *tsdn, const extent_t *extent) -{ - rtree_elm_t *elm_a, *elm_b; - - extent_rtree_acquire(tsdn, extent, true, false, &elm_a, &elm_b); - extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL); - if (extent_slab_get(extent)) - chunk_interior_deregister(tsdn, extent); - extent_rtree_release(tsdn, elm_a, elm_b); - - if (config_prof && opt_prof && extent_active_get(extent)) { - size_t nsub = (extent_size_get(extent) == 0) ? 1 : - extent_size_get(extent) / chunksize; - assert(atomic_read_z(&curchunks) >= nsub); - atomic_sub_z(&curchunks, nsub); - } -} - -/* - * Do first-best-fit chunk selection, i.e. select the lowest chunk that best - * fits. - */ -static extent_t * -chunk_first_best_fit(arena_t *arena, extent_heap_t extent_heaps[NPSIZES], - size_t size) -{ - pszind_t pind, i; - - pind = psz2ind(extent_size_quantize_ceil(size)); - for (i = pind; i < NPSIZES; i++) { - extent_t *extent = extent_heap_first(&extent_heaps[i]); - if (extent != NULL) - return (extent); - } - - return (NULL); -} - -static void -chunk_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - bool cache, extent_t *extent) -{ - - /* - * Leak chunk after making sure its pages have already been purged, so - * that this is only a virtual memory leak. - */ - if (cache) { - chunk_purge_wrapper(tsdn, arena, extent_hooks, extent, 0, - extent_size_get(extent)); - } - extent_dalloc(tsdn, arena, extent); -} - -static extent_t * -chunk_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_heap_t extent_heaps[NPSIZES], bool cache, void *new_addr, - size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, - bool slab) -{ - extent_t *extent; - size_t size, alloc_size, leadsize, trailsize; - - assert(new_addr == NULL || !slab); - assert(pad == 0 || !slab); - - size = usize + pad; - alloc_size = s2u(size + PAGE_CEILING(alignment) - PAGE); - /* Beware size_t wrap-around. */ - if (alloc_size < usize) - return (NULL); - malloc_mutex_lock(tsdn, &arena->extents_mtx); - extent_hooks_assure_initialized_locked(tsdn, arena, extent_hooks); - if (new_addr != NULL) { - rtree_elm_t *elm; - - elm = rtree_elm_acquire(tsdn, &extents_rtree, - (uintptr_t)new_addr, false, false); - if (elm != NULL) { - extent = rtree_elm_read_acquired(tsdn, &extents_rtree, - elm); - if (extent != NULL && (extent_active_get(extent) || - extent_retained_get(extent) == cache)) - extent = NULL; - rtree_elm_release(tsdn, &extents_rtree, elm); - } else - extent = NULL; - } else - extent = chunk_first_best_fit(arena, extent_heaps, alloc_size); - if (extent == NULL || (new_addr != NULL && extent_size_get(extent) < - size)) { - malloc_mutex_unlock(tsdn, &arena->extents_mtx); - return (NULL); - } - extent_heaps_remove(extent_heaps, extent); - arena_chunk_cache_maybe_remove(arena, extent, cache); - - leadsize = ALIGNMENT_CEILING((uintptr_t)extent_base_get(extent), - PAGE_CEILING(alignment)) - (uintptr_t)extent_base_get(extent); - assert(new_addr == NULL || leadsize == 0); - assert(extent_size_get(extent) >= leadsize + size); - trailsize = extent_size_get(extent) - leadsize - size; - if (extent_zeroed_get(extent)) - *zero = true; - if (extent_committed_get(extent)) - *commit = true; - - /* Split the lead. */ - if (leadsize != 0) { - extent_t *lead = extent; - extent = chunk_split_wrapper(tsdn, arena, extent_hooks, lead, - leadsize, leadsize, size + trailsize, usize + trailsize); - if (extent == NULL) { - chunk_leak(tsdn, arena, extent_hooks, cache, lead); - malloc_mutex_unlock(tsdn, &arena->extents_mtx); - return (NULL); - } - extent_heaps_insert(extent_heaps, lead); - arena_chunk_cache_maybe_insert(arena, lead, cache); - } - - /* Split the trail. */ - if (trailsize != 0) { - extent_t *trail = chunk_split_wrapper(tsdn, arena, extent_hooks, - extent, size, usize, trailsize, trailsize); - if (trail == NULL) { - chunk_leak(tsdn, arena, extent_hooks, cache, extent); - malloc_mutex_unlock(tsdn, &arena->extents_mtx); - return (NULL); - } - extent_heaps_insert(extent_heaps, trail); - arena_chunk_cache_maybe_insert(arena, trail, cache); - } else if (leadsize == 0) { - /* - * Splitting causes usize to be set as a side effect, but no - * splitting occurred. - */ - extent_usize_set(extent, usize); - } - - if (!extent_committed_get(extent) && - extent_hooks->commit(extent_base_get(extent), - extent_size_get(extent), 0, extent_size_get(extent), arena->ind)) { - malloc_mutex_unlock(tsdn, &arena->extents_mtx); - chunk_record(tsdn, arena, extent_hooks, extent_heaps, cache, - extent); - return (NULL); - } - - if (pad != 0) - extent_addr_randomize(tsdn, extent, alignment); - extent_active_set(extent, true); - if (slab) { - extent_slab_set(extent, slab); - chunk_interior_register(tsdn, extent); - } - - malloc_mutex_unlock(tsdn, &arena->extents_mtx); - - if (*zero) { - if (!extent_zeroed_get(extent)) { - memset(extent_addr_get(extent), 0, - extent_usize_get(extent)); - } else if (config_debug) { - size_t i; - size_t *p = (size_t *)(uintptr_t) - extent_addr_get(extent); - - for (i = 0; i < usize / sizeof(size_t); i++) - assert(p[i] == 0); - } - } - return (extent); -} - -/* - * If the caller specifies (!*zero), it is still possible to receive zeroed - * memory, in which case *zero is toggled to true. arena_chunk_alloc() takes - * advantage of this to avoid demanding zeroed chunks, but taking advantage of - * them if they are returned. - */ -static void * -chunk_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, - size_t alignment, bool *zero, bool *commit, dss_prec_t dss_prec) -{ - void *ret; - - assert(size != 0); - assert(alignment != 0); - - /* "primary" dss. */ - if (have_dss && dss_prec == dss_prec_primary && (ret = - chunk_alloc_dss(tsdn, arena, new_addr, size, alignment, zero, - commit)) != NULL) - return (ret); - /* mmap. */ - if ((ret = chunk_alloc_mmap(new_addr, size, alignment, zero, commit)) != - NULL) - return (ret); - /* "secondary" dss. */ - if (have_dss && dss_prec == dss_prec_secondary && (ret = - chunk_alloc_dss(tsdn, arena, new_addr, size, alignment, zero, - commit)) != NULL) - return (ret); - - /* All strategies for allocation failed. */ - return (NULL); -} - -extent_t * -chunk_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, - bool slab) -{ - extent_t *extent; - bool commit; - - assert(usize + pad != 0); - assert(alignment != 0); - - commit = true; - extent = chunk_recycle(tsdn, arena, extent_hooks, arena->extents_cached, - true, new_addr, usize, pad, alignment, zero, &commit, slab); - if (extent == NULL) - return (NULL); - assert(commit); - return (extent); -} - -static arena_t * -chunk_arena_get(tsdn_t *tsdn, unsigned arena_ind) -{ - arena_t *arena; - - arena = arena_get(tsdn, arena_ind, false); - /* - * The arena we're allocating on behalf of must have been initialized - * already. - */ - assert(arena != NULL); - return (arena); -} - -static void * -extent_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero, - bool *commit, unsigned arena_ind) -{ - void *ret; - tsdn_t *tsdn; - arena_t *arena; - - tsdn = tsdn_fetch(); - arena = chunk_arena_get(tsdn, arena_ind); - ret = chunk_alloc_core(tsdn, arena, new_addr, size, alignment, zero, - commit, arena->dss_prec); - if (ret == NULL) - return (NULL); - - return (ret); -} - -static extent_t * -chunk_alloc_retained(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, - bool *commit, bool slab) -{ - extent_t *extent; - - assert(usize != 0); - assert(alignment != 0); - - extent = chunk_recycle(tsdn, arena, extent_hooks, - arena->extents_retained, false, new_addr, usize, pad, alignment, - zero, commit, slab); - if (extent != NULL && config_stats) { - size_t size = usize + pad; - arena->stats.retained -= size; - } - - return (extent); -} - -static extent_t * -chunk_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) -{ - extent_t *extent; - size_t size; - void *addr; - - size = usize + pad; - extent = extent_alloc(tsdn, arena); - if (extent == NULL) - return (NULL); - addr = extent_hooks->alloc(new_addr, size, alignment, zero, commit, - arena->ind); - if (addr == NULL) { - extent_dalloc(tsdn, arena, extent); - return (NULL); - } - extent_init(extent, arena, addr, size, usize, true, zero, commit, slab); - if (pad != 0) - extent_addr_randomize(tsdn, extent, alignment); - if (chunk_register(tsdn, extent)) { - chunk_leak(tsdn, arena, extent_hooks, false, extent); - return (NULL); - } - - return (extent); -} - -extent_t * -chunk_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, - bool *commit, bool slab) -{ - extent_t *extent; - - extent_hooks_assure_initialized(tsdn, arena, extent_hooks); - - extent = chunk_alloc_retained(tsdn, arena, extent_hooks, new_addr, - usize, pad, alignment, zero, commit, slab); - if (extent == NULL) { - extent = chunk_alloc_wrapper_hard(tsdn, arena, extent_hooks, - new_addr, usize, pad, alignment, zero, commit, slab); - } - - return (extent); -} - -static bool -chunk_can_coalesce(const extent_t *a, const extent_t *b) -{ - - if (extent_arena_get(a) != extent_arena_get(b)) - return (false); - if (extent_active_get(a) != extent_active_get(b)) - return (false); - if (extent_committed_get(a) != extent_committed_get(b)) - return (false); - if (extent_retained_get(a) != extent_retained_get(b)) - return (false); - - return (true); -} - -static void -chunk_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_t *a, extent_t *b, extent_heap_t extent_heaps[NPSIZES], bool cache) -{ - - if (!chunk_can_coalesce(a, b)) - return; - - extent_heaps_remove(extent_heaps, a); - extent_heaps_remove(extent_heaps, b); - - arena_chunk_cache_maybe_remove(extent_arena_get(a), a, cache); - arena_chunk_cache_maybe_remove(extent_arena_get(b), b, cache); - - if (chunk_merge_wrapper(tsdn, arena, extent_hooks, a, b)) { - extent_heaps_insert(extent_heaps, a); - extent_heaps_insert(extent_heaps, b); - arena_chunk_cache_maybe_insert(extent_arena_get(a), a, cache); - arena_chunk_cache_maybe_insert(extent_arena_get(b), b, cache); - return; - } - - extent_heaps_insert(extent_heaps, a); - arena_chunk_cache_maybe_insert(extent_arena_get(a), a, cache); -} - -static void -chunk_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_heap_t extent_heaps[NPSIZES], bool cache, extent_t *extent) -{ - extent_t *prev, *next; - - assert(!cache || !extent_zeroed_get(extent)); - - malloc_mutex_lock(tsdn, &arena->extents_mtx); - extent_hooks_assure_initialized_locked(tsdn, arena, extent_hooks); - - extent_usize_set(extent, 0); - extent_active_set(extent, false); - extent_zeroed_set(extent, !cache && extent_zeroed_get(extent)); - if (extent_slab_get(extent)) { - chunk_interior_deregister(tsdn, extent); - extent_slab_set(extent, false); - } - - assert(extent_lookup(tsdn, extent_base_get(extent), true) == extent); - extent_heaps_insert(extent_heaps, extent); - arena_chunk_cache_maybe_insert(arena, extent, cache); - - /* Try to coalesce forward. */ - next = rtree_read(tsdn, &extents_rtree, - (uintptr_t)extent_past_get(extent), false); - if (next != NULL) { - chunk_try_coalesce(tsdn, arena, extent_hooks, extent, next, - extent_heaps, cache); - } - - /* Try to coalesce backward. */ - prev = rtree_read(tsdn, &extents_rtree, - (uintptr_t)extent_before_get(extent), false); - if (prev != NULL) { - chunk_try_coalesce(tsdn, arena, extent_hooks, prev, extent, - extent_heaps, cache); - } - - malloc_mutex_unlock(tsdn, &arena->extents_mtx); -} - -void -chunk_dalloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_t *extent) -{ - - assert(extent_base_get(extent) != NULL); - assert(extent_size_get(extent) != 0); - - extent_addr_set(extent, extent_base_get(extent)); - extent_zeroed_set(extent, false); - - chunk_record(tsdn, arena, extent_hooks, arena->extents_cached, true, - extent); -} - -static bool -extent_dalloc_default(void *addr, size_t size, bool committed, - unsigned arena_ind) -{ - - if (!have_dss || !chunk_in_dss(tsdn_fetch(), addr)) - return (chunk_dalloc_mmap(addr, size)); - return (true); -} - -void -chunk_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_t *extent) -{ - - assert(extent_base_get(extent) != NULL); - assert(extent_size_get(extent) != 0); - - extent_addr_set(extent, extent_base_get(extent)); - - extent_hooks_assure_initialized(tsdn, arena, extent_hooks); - /* Try to deallocate. */ - if (!extent_hooks->dalloc(extent_base_get(extent), - extent_size_get(extent), extent_committed_get(extent), - arena->ind)) { - chunk_deregister(tsdn, extent); - extent_dalloc(tsdn, arena, extent); - return; - } - /* Try to decommit; purge if that fails. */ - if (extent_committed_get(extent)) { - extent_committed_set(extent, - extent_hooks->decommit(extent_base_get(extent), - extent_size_get(extent), 0, extent_size_get(extent), - arena->ind)); - } - extent_zeroed_set(extent, !extent_committed_get(extent) || - !extent_hooks->purge(extent_base_get(extent), - extent_size_get(extent), 0, extent_size_get(extent), arena->ind)); - - if (config_stats) - arena->stats.retained += extent_size_get(extent); - - chunk_record(tsdn, arena, extent_hooks, arena->extents_retained, false, - extent); -} - -static bool -extent_commit_default(void *addr, size_t size, size_t offset, size_t length, - unsigned arena_ind) -{ - - return (pages_commit((void *)((uintptr_t)addr + (uintptr_t)offset), - length)); -} - -bool -chunk_commit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_t *extent, size_t offset, size_t length) -{ - - extent_hooks_assure_initialized(tsdn, arena, extent_hooks); - return (extent_hooks->commit(extent_base_get(extent), - extent_size_get(extent), offset, length, arena->ind)); -} - -static bool -extent_decommit_default(void *addr, size_t size, size_t offset, size_t length, - unsigned arena_ind) -{ - - return (pages_decommit((void *)((uintptr_t)addr + (uintptr_t)offset), - length)); -} - -bool -chunk_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, - size_t length) -{ - - extent_hooks_assure_initialized(tsdn, arena, extent_hooks); - return (extent_hooks->decommit(extent_base_get(extent), - extent_size_get(extent), offset, length, arena->ind)); -} - -static bool -extent_purge_default(void *addr, size_t size, size_t offset, size_t length, - unsigned arena_ind) -{ - - assert(addr != NULL); - assert((offset & PAGE_MASK) == 0); - assert(length != 0); - assert((length & PAGE_MASK) == 0); - - return (pages_purge((void *)((uintptr_t)addr + (uintptr_t)offset), - length)); -} - -bool -chunk_purge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_t *extent, size_t offset, size_t length) -{ - - extent_hooks_assure_initialized(tsdn, arena, extent_hooks); - return (extent_hooks->purge(extent_base_get(extent), - extent_size_get(extent), offset, length, arena->ind)); -} - -static bool -extent_split_default(void *addr, size_t size, size_t size_a, size_t size_b, - bool committed, unsigned arena_ind) -{ - - if (!maps_coalesce) - return (true); - return (false); -} - -extent_t * -chunk_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_t *extent, size_t size_a, size_t usize_a, size_t size_b, - size_t usize_b) -{ - extent_t *trail; - rtree_elm_t *lead_elm_a, *lead_elm_b, *trail_elm_a, *trail_elm_b; - - assert(extent_size_get(extent) == size_a + size_b); - - extent_hooks_assure_initialized(tsdn, arena, extent_hooks); - - trail = extent_alloc(tsdn, arena); - if (trail == NULL) - goto label_error_a; - - { - extent_t lead; - - extent_init(&lead, arena, extent_addr_get(extent), size_a, - usize_a, extent_active_get(extent), - extent_zeroed_get(extent), extent_committed_get(extent), - extent_slab_get(extent)); - - if (extent_rtree_acquire(tsdn, &lead, false, true, &lead_elm_a, - &lead_elm_b)) - goto label_error_b; - } - - extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) + - size_a), size_b, usize_b, extent_active_get(extent), - extent_zeroed_get(extent), extent_committed_get(extent), - extent_slab_get(extent)); - if (extent_rtree_acquire(tsdn, trail, false, true, &trail_elm_a, - &trail_elm_b)) - goto label_error_c; - - if (extent_hooks->split(extent_base_get(extent), size_a + size_b, size_a, - size_b, extent_committed_get(extent), arena->ind)) - goto label_error_d; - - extent_size_set(extent, size_a); - extent_usize_set(extent, usize_a); - - extent_rtree_write_acquired(tsdn, lead_elm_a, lead_elm_b, extent); - extent_rtree_write_acquired(tsdn, trail_elm_a, trail_elm_b, trail); - - extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); - extent_rtree_release(tsdn, trail_elm_a, trail_elm_b); - - return (trail); -label_error_d: - extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); -label_error_c: - extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); -label_error_b: - extent_dalloc(tsdn, arena, trail); -label_error_a: - return (NULL); -} - -static bool -extent_merge_default(void *addr_a, size_t size_a, void *addr_b, size_t size_b, - bool committed, unsigned arena_ind) -{ - - if (!maps_coalesce) - return (true); - if (have_dss) { - tsdn_t *tsdn = tsdn_fetch(); - if (chunk_in_dss(tsdn, addr_a) != chunk_in_dss(tsdn, addr_b)) - return (true); - } - - return (false); -} - -bool -chunk_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_t *a, extent_t *b) -{ - rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; - - extent_hooks_assure_initialized(tsdn, arena, extent_hooks); - if (extent_hooks->merge(extent_base_get(a), extent_size_get(a), - extent_base_get(b), extent_size_get(b), extent_committed_get(a), - arena->ind)) - return (true); - - /* - * The rtree writes must happen while all the relevant elements are - * owned, so the following code uses decomposed helper functions rather - * than chunk_{,de}register() to do things in the right order. - */ - extent_rtree_acquire(tsdn, a, true, false, &a_elm_a, &a_elm_b); - extent_rtree_acquire(tsdn, b, true, false, &b_elm_a, &b_elm_b); - - if (a_elm_b != NULL) { - rtree_elm_write_acquired(tsdn, &extents_rtree, a_elm_b, NULL); - rtree_elm_release(tsdn, &extents_rtree, a_elm_b); - } - if (b_elm_b != NULL) { - rtree_elm_write_acquired(tsdn, &extents_rtree, b_elm_a, NULL); - rtree_elm_release(tsdn, &extents_rtree, b_elm_a); - } else - b_elm_b = b_elm_a; - - extent_size_set(a, extent_size_get(a) + extent_size_get(b)); - extent_usize_set(a, extent_usize_get(a) + extent_usize_get(b)); - extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b)); - - extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a); - extent_rtree_release(tsdn, a_elm_a, b_elm_b); - - extent_dalloc(tsdn, extent_arena_get(b), b); - - return (false); -} - bool chunk_boot(void) { @@ -959,29 +47,5 @@ chunk_boot(void) chunksize_mask = chunksize - 1; chunk_npages = (chunksize >> LG_PAGE); - if (have_dss && chunk_dss_boot()) - return (true); - return (false); } - -void -chunk_prefork(tsdn_t *tsdn) -{ - - chunk_dss_prefork(tsdn); -} - -void -chunk_postfork_parent(tsdn_t *tsdn) -{ - - chunk_dss_postfork_parent(tsdn); -} - -void -chunk_postfork_child(tsdn_t *tsdn) -{ - - chunk_dss_postfork_child(tsdn); -} diff --git a/src/ctl.c b/src/ctl.c index 5ff2a42d..61f3aa1c 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1560,11 +1560,11 @@ arena_i_dss_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, dss_prec_old = arena_dss_prec_get(tsd_tsdn(tsd), arena); } else { if (dss_prec != dss_prec_limit && - chunk_dss_prec_set(tsd_tsdn(tsd), dss_prec)) { + extent_dss_prec_set(tsd_tsdn(tsd), dss_prec)) { ret = EFAULT; goto label_return; } - dss_prec_old = chunk_dss_prec_get(tsd_tsdn(tsd)); + dss_prec_old = extent_dss_prec_get(tsd_tsdn(tsd)); } dss = dss_prec_names[dss_prec_old]; diff --git a/src/extent.c b/src/extent.c index 3e62e3bc..9f3ddd95 100644 --- a/src/extent.c +++ b/src/extent.c @@ -6,6 +6,45 @@ rtree_t extents_rtree; +static void *extent_alloc_default(void *new_addr, size_t size, + size_t alignment, bool *zero, bool *commit, unsigned arena_ind); +static bool extent_dalloc_default(void *addr, size_t size, bool committed, + unsigned arena_ind); +static bool extent_commit_default(void *addr, size_t size, size_t offset, + size_t length, unsigned arena_ind); +static bool extent_decommit_default(void *addr, size_t size, size_t offset, + size_t length, unsigned arena_ind); +static bool extent_purge_default(void *addr, size_t size, size_t offset, + size_t length, unsigned arena_ind); +static bool extent_split_default(void *addr, size_t size, size_t size_a, + size_t size_b, bool committed, unsigned arena_ind); +static bool extent_merge_default(void *addr_a, size_t size_a, void *addr_b, + size_t size_b, bool committed, unsigned arena_ind); + +const extent_hooks_t extent_hooks_default = { + extent_alloc_default, + extent_dalloc_default, + extent_commit_default, + extent_decommit_default, + extent_purge_default, + extent_split_default, + extent_merge_default +}; + +/* Used exclusively for gdump triggering. */ +static size_t curchunks; +static size_t highchunks; + +/******************************************************************************/ +/* + * Function prototypes for static functions that are referenced prior to + * definition. + */ + +static void extent_record(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, extent_heap_t extent_heaps[NPSIZES], + bool cache, extent_t *extent); + /******************************************************************************/ extent_t * @@ -34,6 +73,91 @@ extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); } +static extent_hooks_t +extent_hooks_get_locked(arena_t *arena) +{ + + return (arena->extent_hooks); +} + +extent_hooks_t +extent_hooks_get(tsdn_t *tsdn, arena_t *arena) +{ + extent_hooks_t extent_hooks; + + malloc_mutex_lock(tsdn, &arena->extents_mtx); + extent_hooks = extent_hooks_get_locked(arena); + malloc_mutex_unlock(tsdn, &arena->extents_mtx); + + return (extent_hooks); +} + +extent_hooks_t +extent_hooks_set(tsdn_t *tsdn, arena_t *arena, + const extent_hooks_t *extent_hooks) +{ + extent_hooks_t old_extent_hooks; + + malloc_mutex_lock(tsdn, &arena->extents_mtx); + old_extent_hooks = arena->extent_hooks; + /* + * Copy each field atomically so that it is impossible for readers to + * see partially updated pointers. There are places where readers only + * need one hook function pointer (therefore no need to copy the + * entirety of arena->extent_hooks), and stale reads do not affect + * correctness, so they perform unlocked reads. + */ +#define ATOMIC_COPY_HOOK(n) do { \ + union { \ + extent_##n##_t **n; \ + void **v; \ + } u; \ + u.n = &arena->extent_hooks.n; \ + atomic_write_p(u.v, extent_hooks->n); \ +} while (0) + ATOMIC_COPY_HOOK(alloc); + ATOMIC_COPY_HOOK(dalloc); + ATOMIC_COPY_HOOK(commit); + ATOMIC_COPY_HOOK(decommit); + ATOMIC_COPY_HOOK(purge); + ATOMIC_COPY_HOOK(split); + ATOMIC_COPY_HOOK(merge); +#undef ATOMIC_COPY_HOOK + malloc_mutex_unlock(tsdn, &arena->extents_mtx); + + return (old_extent_hooks); +} + +static void +extent_hooks_assure_initialized_impl(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, bool locked) +{ + static const extent_hooks_t uninitialized_hooks = + EXTENT_HOOKS_INITIALIZER; + + if (memcmp(extent_hooks, &uninitialized_hooks, sizeof(extent_hooks_t)) + == 0) { + *extent_hooks = locked ? extent_hooks_get_locked(arena) : + extent_hooks_get(tsdn, arena); + } +} + +static void +extent_hooks_assure_initialized_locked(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks) +{ + + extent_hooks_assure_initialized_impl(tsdn, arena, extent_hooks, true); +} + +static void +extent_hooks_assure_initialized(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks) +{ + + extent_hooks_assure_initialized_impl(tsdn, arena, extent_hooks, false); +} + #ifdef JEMALLOC_JET #undef extent_size_quantize_floor #define extent_size_quantize_floor JEMALLOC_N(n_extent_size_quantize_floor) @@ -118,6 +242,787 @@ extent_ad_comp(const extent_t *a, const extent_t *b) /* Generate pairing heap functions. */ ph_gen(, extent_heap_, extent_heap_t, extent_t, ph_link, extent_ad_comp) +static void +extent_heaps_insert(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) +{ + size_t psz = extent_size_quantize_floor(extent_size_get(extent)); + pszind_t pind = psz2ind(psz); + extent_heap_insert(&extent_heaps[pind], extent); +} + +static void +extent_heaps_remove(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) +{ + size_t psz = extent_size_quantize_floor(extent_size_get(extent)); + pszind_t pind = psz2ind(psz); + extent_heap_remove(&extent_heaps[pind], extent); +} + +static bool +extent_rtree_acquire(tsdn_t *tsdn, const extent_t *extent, bool dependent, + bool init_missing, rtree_elm_t **r_elm_a, rtree_elm_t **r_elm_b) +{ + + *r_elm_a = rtree_elm_acquire(tsdn, &extents_rtree, + (uintptr_t)extent_base_get(extent), dependent, init_missing); + if (!dependent && *r_elm_a == NULL) + return (true); + assert(*r_elm_a != NULL); + + if (extent_size_get(extent) > PAGE) { + *r_elm_b = rtree_elm_acquire(tsdn, &extents_rtree, + (uintptr_t)extent_last_get(extent), dependent, + init_missing); + if (!dependent && *r_elm_b == NULL) + return (true); + assert(*r_elm_b != NULL); + } else + *r_elm_b = NULL; + + return (false); +} + +static void +extent_rtree_write_acquired(tsdn_t *tsdn, rtree_elm_t *elm_a, + rtree_elm_t *elm_b, const extent_t *extent) +{ + + rtree_elm_write_acquired(tsdn, &extents_rtree, elm_a, extent); + if (elm_b != NULL) + rtree_elm_write_acquired(tsdn, &extents_rtree, elm_b, extent); +} + +static void +extent_rtree_release(tsdn_t *tsdn, rtree_elm_t *elm_a, rtree_elm_t *elm_b) +{ + + rtree_elm_release(tsdn, &extents_rtree, elm_a); + if (elm_b != NULL) + rtree_elm_release(tsdn, &extents_rtree, elm_b); +} + +static void +extent_interior_register(tsdn_t *tsdn, const extent_t *extent) +{ + size_t i; + + assert(extent_slab_get(extent)); + + for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) { + rtree_write(tsdn, &extents_rtree, + (uintptr_t)extent_base_get(extent) + (uintptr_t)(i << + LG_PAGE), extent); + } +} + +static bool +extent_register(tsdn_t *tsdn, const extent_t *extent) +{ + rtree_elm_t *elm_a, *elm_b; + + if (extent_rtree_acquire(tsdn, extent, false, true, &elm_a, &elm_b)) + return (true); + extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent); + if (extent_slab_get(extent)) + extent_interior_register(tsdn, extent); + extent_rtree_release(tsdn, elm_a, elm_b); + + if (config_prof && opt_prof && extent_active_get(extent)) { + size_t nadd = (extent_size_get(extent) == 0) ? 1 : + extent_size_get(extent) / chunksize; + size_t cur = atomic_add_z(&curchunks, nadd); + size_t high = atomic_read_z(&highchunks); + while (cur > high && atomic_cas_z(&highchunks, high, cur)) { + /* + * Don't refresh cur, because it may have decreased + * since this thread lost the highchunks update race. + */ + high = atomic_read_z(&highchunks); + } + if (cur > high && prof_gdump_get_unlocked()) + prof_gdump(tsdn); + } + + return (false); +} + +static void +extent_interior_deregister(tsdn_t *tsdn, const extent_t *extent) +{ + size_t i; + + assert(extent_slab_get(extent)); + + for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) { + rtree_clear(tsdn, &extents_rtree, + (uintptr_t)extent_base_get(extent) + (uintptr_t)(i << + LG_PAGE)); + } +} + +static void +extent_deregister(tsdn_t *tsdn, const extent_t *extent) +{ + rtree_elm_t *elm_a, *elm_b; + + extent_rtree_acquire(tsdn, extent, true, false, &elm_a, &elm_b); + extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL); + if (extent_slab_get(extent)) + extent_interior_deregister(tsdn, extent); + extent_rtree_release(tsdn, elm_a, elm_b); + + if (config_prof && opt_prof && extent_active_get(extent)) { + size_t nsub = (extent_size_get(extent) == 0) ? 1 : + extent_size_get(extent) / chunksize; + assert(atomic_read_z(&curchunks) >= nsub); + atomic_sub_z(&curchunks, nsub); + } +} + +/* + * Do first-best-fit extent selection, i.e. select the lowest extent that best + * fits. + */ +static extent_t * +extent_first_best_fit(arena_t *arena, extent_heap_t extent_heaps[NPSIZES], + size_t size) +{ + pszind_t pind, i; + + pind = psz2ind(extent_size_quantize_ceil(size)); + for (i = pind; i < NPSIZES; i++) { + extent_t *extent = extent_heap_first(&extent_heaps[i]); + if (extent != NULL) + return (extent); + } + + return (NULL); +} + +static void +extent_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, + bool cache, extent_t *extent) +{ + + /* + * Leak extent after making sure its pages have already been purged, so + * that this is only a virtual memory leak. + */ + if (cache) { + extent_purge_wrapper(tsdn, arena, extent_hooks, extent, 0, + extent_size_get(extent)); + } + extent_dalloc(tsdn, arena, extent); +} + +static extent_t * +extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, + extent_heap_t extent_heaps[NPSIZES], bool cache, void *new_addr, + size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, + bool slab) +{ + extent_t *extent; + size_t size, alloc_size, leadsize, trailsize; + + assert(new_addr == NULL || !slab); + assert(pad == 0 || !slab); + + size = usize + pad; + alloc_size = s2u(size + PAGE_CEILING(alignment) - PAGE); + /* Beware size_t wrap-around. */ + if (alloc_size < usize) + return (NULL); + malloc_mutex_lock(tsdn, &arena->extents_mtx); + extent_hooks_assure_initialized_locked(tsdn, arena, extent_hooks); + if (new_addr != NULL) { + rtree_elm_t *elm; + + elm = rtree_elm_acquire(tsdn, &extents_rtree, + (uintptr_t)new_addr, false, false); + if (elm != NULL) { + extent = rtree_elm_read_acquired(tsdn, &extents_rtree, + elm); + if (extent != NULL && (extent_active_get(extent) || + extent_retained_get(extent) == cache)) + extent = NULL; + rtree_elm_release(tsdn, &extents_rtree, elm); + } else + extent = NULL; + } else + extent = extent_first_best_fit(arena, extent_heaps, alloc_size); + if (extent == NULL || (new_addr != NULL && extent_size_get(extent) < + size)) { + malloc_mutex_unlock(tsdn, &arena->extents_mtx); + return (NULL); + } + extent_heaps_remove(extent_heaps, extent); + arena_extent_cache_maybe_remove(arena, extent, cache); + + leadsize = ALIGNMENT_CEILING((uintptr_t)extent_base_get(extent), + PAGE_CEILING(alignment)) - (uintptr_t)extent_base_get(extent); + assert(new_addr == NULL || leadsize == 0); + assert(extent_size_get(extent) >= leadsize + size); + trailsize = extent_size_get(extent) - leadsize - size; + if (extent_zeroed_get(extent)) + *zero = true; + if (extent_committed_get(extent)) + *commit = true; + + /* Split the lead. */ + if (leadsize != 0) { + extent_t *lead = extent; + extent = extent_split_wrapper(tsdn, arena, extent_hooks, lead, + leadsize, leadsize, size + trailsize, usize + trailsize); + if (extent == NULL) { + extent_leak(tsdn, arena, extent_hooks, cache, lead); + malloc_mutex_unlock(tsdn, &arena->extents_mtx); + return (NULL); + } + extent_heaps_insert(extent_heaps, lead); + arena_extent_cache_maybe_insert(arena, lead, cache); + } + + /* Split the trail. */ + if (trailsize != 0) { + extent_t *trail = extent_split_wrapper(tsdn, arena, + extent_hooks, extent, size, usize, trailsize, trailsize); + if (trail == NULL) { + extent_leak(tsdn, arena, extent_hooks, cache, extent); + malloc_mutex_unlock(tsdn, &arena->extents_mtx); + return (NULL); + } + extent_heaps_insert(extent_heaps, trail); + arena_extent_cache_maybe_insert(arena, trail, cache); + } else if (leadsize == 0) { + /* + * Splitting causes usize to be set as a side effect, but no + * splitting occurred. + */ + extent_usize_set(extent, usize); + } + + if (!extent_committed_get(extent) && + extent_hooks->commit(extent_base_get(extent), + extent_size_get(extent), 0, extent_size_get(extent), arena->ind)) { + malloc_mutex_unlock(tsdn, &arena->extents_mtx); + extent_record(tsdn, arena, extent_hooks, extent_heaps, cache, + extent); + return (NULL); + } + + if (pad != 0) + extent_addr_randomize(tsdn, extent, alignment); + extent_active_set(extent, true); + if (slab) { + extent_slab_set(extent, slab); + extent_interior_register(tsdn, extent); + } + + malloc_mutex_unlock(tsdn, &arena->extents_mtx); + + if (*zero) { + if (!extent_zeroed_get(extent)) { + memset(extent_addr_get(extent), 0, + extent_usize_get(extent)); + } else if (config_debug) { + size_t i; + size_t *p = (size_t *)(uintptr_t) + extent_addr_get(extent); + + for (i = 0; i < usize / sizeof(size_t); i++) + assert(p[i] == 0); + } + } + return (extent); +} + +/* + * If the caller specifies (!*zero), it is still possible to receive zeroed + * memory, in which case *zero is toggled to true. arena_extent_alloc() takes + * advantage of this to avoid demanding zeroed extents, but taking advantage of + * them if they are returned. + */ +static void * +extent_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, + size_t alignment, bool *zero, bool *commit, dss_prec_t dss_prec) +{ + void *ret; + + assert(size != 0); + assert(alignment != 0); + + /* "primary" dss. */ + if (have_dss && dss_prec == dss_prec_primary && (ret = + extent_alloc_dss(tsdn, arena, new_addr, size, alignment, zero, + commit)) != NULL) + return (ret); + /* mmap. */ + if ((ret = extent_alloc_mmap(new_addr, size, alignment, zero, commit)) + != NULL) + return (ret); + /* "secondary" dss. */ + if (have_dss && dss_prec == dss_prec_secondary && (ret = + extent_alloc_dss(tsdn, arena, new_addr, size, alignment, zero, + commit)) != NULL) + return (ret); + + /* All strategies for allocation failed. */ + return (NULL); +} + +extent_t * +extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, + void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, + bool slab) +{ + extent_t *extent; + bool commit; + + assert(usize + pad != 0); + assert(alignment != 0); + + commit = true; + extent = extent_recycle(tsdn, arena, extent_hooks, + arena->extents_cached, true, new_addr, usize, pad, alignment, zero, + &commit, slab); + if (extent == NULL) + return (NULL); + assert(commit); + return (extent); +} + +static void * +extent_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero, + bool *commit, unsigned arena_ind) +{ + void *ret; + tsdn_t *tsdn; + arena_t *arena; + + tsdn = tsdn_fetch(); + arena = arena_get(tsdn, arena_ind, false); + /* + * The arena we're allocating on behalf of must have been initialized + * already. + */ + assert(arena != NULL); + ret = extent_alloc_core(tsdn, arena, new_addr, size, alignment, zero, + commit, arena->dss_prec); + if (ret == NULL) + return (NULL); + + return (ret); +} + +static extent_t * +extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool *commit, bool slab) +{ + extent_t *extent; + + assert(usize != 0); + assert(alignment != 0); + + extent = extent_recycle(tsdn, arena, extent_hooks, + arena->extents_retained, false, new_addr, usize, pad, alignment, + zero, commit, slab); + if (extent != NULL && config_stats) { + size_t size = usize + pad; + arena->stats.retained -= size; + } + + return (extent); +} + +static extent_t * +extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool *commit, bool slab) +{ + extent_t *extent; + size_t size; + void *addr; + + size = usize + pad; + extent = extent_alloc(tsdn, arena); + if (extent == NULL) + return (NULL); + addr = extent_hooks->alloc(new_addr, size, alignment, zero, commit, + arena->ind); + if (addr == NULL) { + extent_dalloc(tsdn, arena, extent); + return (NULL); + } + extent_init(extent, arena, addr, size, usize, true, zero, commit, slab); + if (pad != 0) + extent_addr_randomize(tsdn, extent, alignment); + if (extent_register(tsdn, extent)) { + extent_leak(tsdn, arena, extent_hooks, false, extent); + return (NULL); + } + + return (extent); +} + +extent_t * +extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, + void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, + bool *commit, bool slab) +{ + extent_t *extent; + + extent_hooks_assure_initialized(tsdn, arena, extent_hooks); + + extent = extent_alloc_retained(tsdn, arena, extent_hooks, new_addr, + usize, pad, alignment, zero, commit, slab); + if (extent == NULL) { + extent = extent_alloc_wrapper_hard(tsdn, arena, extent_hooks, + new_addr, usize, pad, alignment, zero, commit, slab); + } + + return (extent); +} + +static bool +extent_can_coalesce(const extent_t *a, const extent_t *b) +{ + + if (extent_arena_get(a) != extent_arena_get(b)) + return (false); + if (extent_active_get(a) != extent_active_get(b)) + return (false); + if (extent_committed_get(a) != extent_committed_get(b)) + return (false); + if (extent_retained_get(a) != extent_retained_get(b)) + return (false); + + return (true); +} + +static void +extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, + extent_t *a, extent_t *b, extent_heap_t extent_heaps[NPSIZES], bool cache) +{ + + if (!extent_can_coalesce(a, b)) + return; + + extent_heaps_remove(extent_heaps, a); + extent_heaps_remove(extent_heaps, b); + + arena_extent_cache_maybe_remove(extent_arena_get(a), a, cache); + arena_extent_cache_maybe_remove(extent_arena_get(b), b, cache); + + if (extent_merge_wrapper(tsdn, arena, extent_hooks, a, b)) { + extent_heaps_insert(extent_heaps, a); + extent_heaps_insert(extent_heaps, b); + arena_extent_cache_maybe_insert(extent_arena_get(a), a, cache); + arena_extent_cache_maybe_insert(extent_arena_get(b), b, cache); + return; + } + + extent_heaps_insert(extent_heaps, a); + arena_extent_cache_maybe_insert(extent_arena_get(a), a, cache); +} + +static void +extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, + extent_heap_t extent_heaps[NPSIZES], bool cache, extent_t *extent) +{ + extent_t *prev, *next; + + assert(!cache || !extent_zeroed_get(extent)); + + malloc_mutex_lock(tsdn, &arena->extents_mtx); + extent_hooks_assure_initialized_locked(tsdn, arena, extent_hooks); + + extent_usize_set(extent, 0); + extent_active_set(extent, false); + extent_zeroed_set(extent, !cache && extent_zeroed_get(extent)); + if (extent_slab_get(extent)) { + extent_interior_deregister(tsdn, extent); + extent_slab_set(extent, false); + } + + assert(extent_lookup(tsdn, extent_base_get(extent), true) == extent); + extent_heaps_insert(extent_heaps, extent); + arena_extent_cache_maybe_insert(arena, extent, cache); + + /* Try to coalesce forward. */ + next = rtree_read(tsdn, &extents_rtree, + (uintptr_t)extent_past_get(extent), false); + if (next != NULL) { + extent_try_coalesce(tsdn, arena, extent_hooks, extent, next, + extent_heaps, cache); + } + + /* Try to coalesce backward. */ + prev = rtree_read(tsdn, &extents_rtree, + (uintptr_t)extent_before_get(extent), false); + if (prev != NULL) { + extent_try_coalesce(tsdn, arena, extent_hooks, prev, extent, + extent_heaps, cache); + } + + malloc_mutex_unlock(tsdn, &arena->extents_mtx); +} + +void +extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, + extent_t *extent) +{ + + assert(extent_base_get(extent) != NULL); + assert(extent_size_get(extent) != 0); + + extent_addr_set(extent, extent_base_get(extent)); + extent_zeroed_set(extent, false); + + extent_record(tsdn, arena, extent_hooks, arena->extents_cached, true, + extent); +} + +static bool +extent_dalloc_default(void *addr, size_t size, bool committed, + unsigned arena_ind) +{ + + if (!have_dss || !extent_in_dss(tsdn_fetch(), addr)) + return (extent_dalloc_mmap(addr, size)); + return (true); +} + +void +extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, extent_t *extent) +{ + + assert(extent_base_get(extent) != NULL); + assert(extent_size_get(extent) != 0); + + extent_addr_set(extent, extent_base_get(extent)); + + extent_hooks_assure_initialized(tsdn, arena, extent_hooks); + /* Try to deallocate. */ + if (!extent_hooks->dalloc(extent_base_get(extent), + extent_size_get(extent), extent_committed_get(extent), + arena->ind)) { + extent_deregister(tsdn, extent); + extent_dalloc(tsdn, arena, extent); + return; + } + /* Try to decommit; purge if that fails. */ + if (extent_committed_get(extent)) { + extent_committed_set(extent, + extent_hooks->decommit(extent_base_get(extent), + extent_size_get(extent), 0, extent_size_get(extent), + arena->ind)); + } + extent_zeroed_set(extent, !extent_committed_get(extent) || + !extent_hooks->purge(extent_base_get(extent), + extent_size_get(extent), 0, extent_size_get(extent), arena->ind)); + + if (config_stats) + arena->stats.retained += extent_size_get(extent); + + extent_record(tsdn, arena, extent_hooks, arena->extents_retained, false, + extent); +} + +static bool +extent_commit_default(void *addr, size_t size, size_t offset, size_t length, + unsigned arena_ind) +{ + + return (pages_commit((void *)((uintptr_t)addr + (uintptr_t)offset), + length)); +} + +bool +extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, + size_t length) +{ + + extent_hooks_assure_initialized(tsdn, arena, extent_hooks); + return (extent_hooks->commit(extent_base_get(extent), + extent_size_get(extent), offset, length, arena->ind)); +} + +static bool +extent_decommit_default(void *addr, size_t size, size_t offset, size_t length, + unsigned arena_ind) +{ + + return (pages_decommit((void *)((uintptr_t)addr + (uintptr_t)offset), + length)); +} + +bool +extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, + size_t length) +{ + + extent_hooks_assure_initialized(tsdn, arena, extent_hooks); + return (extent_hooks->decommit(extent_base_get(extent), + extent_size_get(extent), offset, length, arena->ind)); +} + +static bool +extent_purge_default(void *addr, size_t size, size_t offset, size_t length, + unsigned arena_ind) +{ + + assert(addr != NULL); + assert((offset & PAGE_MASK) == 0); + assert(length != 0); + assert((length & PAGE_MASK) == 0); + + return (pages_purge((void *)((uintptr_t)addr + (uintptr_t)offset), + length)); +} + +bool +extent_purge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, + extent_t *extent, size_t offset, size_t length) +{ + + extent_hooks_assure_initialized(tsdn, arena, extent_hooks); + return (extent_hooks->purge(extent_base_get(extent), + extent_size_get(extent), offset, length, arena->ind)); +} + +static bool +extent_split_default(void *addr, size_t size, size_t size_a, size_t size_b, + bool committed, unsigned arena_ind) +{ + + if (!maps_coalesce) + return (true); + return (false); +} + +extent_t * +extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, + extent_t *extent, size_t size_a, size_t usize_a, size_t size_b, + size_t usize_b) +{ + extent_t *trail; + rtree_elm_t *lead_elm_a, *lead_elm_b, *trail_elm_a, *trail_elm_b; + + assert(extent_size_get(extent) == size_a + size_b); + + extent_hooks_assure_initialized(tsdn, arena, extent_hooks); + + trail = extent_alloc(tsdn, arena); + if (trail == NULL) + goto label_error_a; + + { + extent_t lead; + + extent_init(&lead, arena, extent_addr_get(extent), size_a, + usize_a, extent_active_get(extent), + extent_zeroed_get(extent), extent_committed_get(extent), + extent_slab_get(extent)); + + if (extent_rtree_acquire(tsdn, &lead, false, true, &lead_elm_a, + &lead_elm_b)) + goto label_error_b; + } + + extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) + + size_a), size_b, usize_b, extent_active_get(extent), + extent_zeroed_get(extent), extent_committed_get(extent), + extent_slab_get(extent)); + if (extent_rtree_acquire(tsdn, trail, false, true, &trail_elm_a, + &trail_elm_b)) + goto label_error_c; + + if (extent_hooks->split(extent_base_get(extent), size_a + size_b, + size_a, size_b, extent_committed_get(extent), arena->ind)) + goto label_error_d; + + extent_size_set(extent, size_a); + extent_usize_set(extent, usize_a); + + extent_rtree_write_acquired(tsdn, lead_elm_a, lead_elm_b, extent); + extent_rtree_write_acquired(tsdn, trail_elm_a, trail_elm_b, trail); + + extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); + extent_rtree_release(tsdn, trail_elm_a, trail_elm_b); + + return (trail); +label_error_d: + extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); +label_error_c: + extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); +label_error_b: + extent_dalloc(tsdn, arena, trail); +label_error_a: + return (NULL); +} + +static bool +extent_merge_default(void *addr_a, size_t size_a, void *addr_b, size_t size_b, + bool committed, unsigned arena_ind) +{ + + if (!maps_coalesce) + return (true); + if (have_dss) { + tsdn_t *tsdn = tsdn_fetch(); + if (extent_in_dss(tsdn, addr_a) != extent_in_dss(tsdn, addr_b)) + return (true); + } + + return (false); +} + +bool +extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, + extent_t *a, extent_t *b) +{ + rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; + + extent_hooks_assure_initialized(tsdn, arena, extent_hooks); + if (extent_hooks->merge(extent_base_get(a), extent_size_get(a), + extent_base_get(b), extent_size_get(b), extent_committed_get(a), + arena->ind)) + return (true); + + /* + * The rtree writes must happen while all the relevant elements are + * owned, so the following code uses decomposed helper functions rather + * than extent_{,de}register() to do things in the right order. + */ + extent_rtree_acquire(tsdn, a, true, false, &a_elm_a, &a_elm_b); + extent_rtree_acquire(tsdn, b, true, false, &b_elm_a, &b_elm_b); + + if (a_elm_b != NULL) { + rtree_elm_write_acquired(tsdn, &extents_rtree, a_elm_b, NULL); + rtree_elm_release(tsdn, &extents_rtree, a_elm_b); + } + if (b_elm_b != NULL) { + rtree_elm_write_acquired(tsdn, &extents_rtree, b_elm_a, NULL); + rtree_elm_release(tsdn, &extents_rtree, b_elm_a); + } else + b_elm_b = b_elm_a; + + extent_size_set(a, extent_size_get(a) + extent_size_get(b)); + extent_usize_set(a, extent_usize_get(a) + extent_usize_get(b)); + extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b)); + + extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a); + extent_rtree_release(tsdn, a_elm_a, b_elm_b); + + extent_dalloc(tsdn, extent_arena_get(b), b); + + return (false); +} + bool extent_boot(void) { @@ -126,5 +1031,29 @@ extent_boot(void) LG_PAGE))) return (true); + if (have_dss && extent_dss_boot()) + return (true); + return (false); } + +void +extent_prefork(tsdn_t *tsdn) +{ + + extent_dss_prefork(tsdn); +} + +void +extent_postfork_parent(tsdn_t *tsdn) +{ + + extent_dss_postfork_parent(tsdn); +} + +void +extent_postfork_child(tsdn_t *tsdn) +{ + + extent_dss_postfork_child(tsdn); +} diff --git a/src/chunk_dss.c b/src/extent_dss.c similarity index 86% rename from src/chunk_dss.c rename to src/extent_dss.c index 9fa4ad81..0e34a440 100644 --- a/src/chunk_dss.c +++ b/src/extent_dss.c @@ -1,4 +1,4 @@ -#define JEMALLOC_CHUNK_DSS_C_ +#define JEMALLOC_EXTENT_DSS_C_ #include "jemalloc/internal/jemalloc_internal.h" /******************************************************************************/ /* Data. */ @@ -29,7 +29,7 @@ static void *dss_max; /******************************************************************************/ static void * -chunk_dss_sbrk(intptr_t increment) +extent_dss_sbrk(intptr_t increment) { #ifdef JEMALLOC_DSS @@ -41,7 +41,7 @@ chunk_dss_sbrk(intptr_t increment) } dss_prec_t -chunk_dss_prec_get(tsdn_t *tsdn) +extent_dss_prec_get(tsdn_t *tsdn) { dss_prec_t ret; @@ -54,7 +54,7 @@ chunk_dss_prec_get(tsdn_t *tsdn) } bool -chunk_dss_prec_set(tsdn_t *tsdn, dss_prec_t dss_prec) +extent_dss_prec_set(tsdn_t *tsdn, dss_prec_t dss_prec) { if (!have_dss) @@ -66,7 +66,7 @@ chunk_dss_prec_set(tsdn_t *tsdn, dss_prec_t dss_prec) } void * -chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, +extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit) { void *ret; @@ -104,7 +104,7 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, break; /* Get the current end of the DSS. */ - dss_max = chunk_dss_sbrk(0); + dss_max = extent_dss_sbrk(0); /* Make sure the earlier condition still holds. */ if (new_addr != NULL && dss_max != new_addr) @@ -128,7 +128,7 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, (uintptr_t)dss_next < (uintptr_t)dss_max) break; /* Wrap-around. */ incr = pad_size + size; - dss_prev = chunk_dss_sbrk(incr); + dss_prev = extent_dss_sbrk(incr); if (dss_prev == (void *)-1) break; if (dss_prev == dss_max) { @@ -138,7 +138,7 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, if (pad_size != 0) { extent_hooks_t extent_hooks = EXTENT_HOOKS_INITIALIZER; - chunk_dalloc_wrapper(tsdn, arena, + extent_dalloc_wrapper(tsdn, arena, &extent_hooks, pad); } else extent_dalloc(tsdn, arena, pad); @@ -157,15 +157,15 @@ chunk_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, } bool -chunk_in_dss(tsdn_t *tsdn, void *chunk) +extent_in_dss(tsdn_t *tsdn, void *addr) { bool ret; cassert(have_dss); malloc_mutex_lock(tsdn, &dss_mtx); - if ((uintptr_t)chunk >= (uintptr_t)dss_base - && (uintptr_t)chunk < (uintptr_t)dss_max) + if ((uintptr_t)addr >= (uintptr_t)dss_base + && (uintptr_t)addr < (uintptr_t)dss_max) ret = true; else ret = false; @@ -175,14 +175,14 @@ chunk_in_dss(tsdn_t *tsdn, void *chunk) } bool -chunk_dss_boot(void) +extent_dss_boot(void) { cassert(have_dss); if (malloc_mutex_init(&dss_mtx, "dss", WITNESS_RANK_DSS)) return (true); - dss_base = chunk_dss_sbrk(0); + dss_base = extent_dss_sbrk(0); dss_prev = dss_base; dss_max = dss_base; @@ -190,7 +190,7 @@ chunk_dss_boot(void) } void -chunk_dss_prefork(tsdn_t *tsdn) +extent_dss_prefork(tsdn_t *tsdn) { if (have_dss) @@ -198,7 +198,7 @@ chunk_dss_prefork(tsdn_t *tsdn) } void -chunk_dss_postfork_parent(tsdn_t *tsdn) +extent_dss_postfork_parent(tsdn_t *tsdn) { if (have_dss) @@ -206,7 +206,7 @@ chunk_dss_postfork_parent(tsdn_t *tsdn) } void -chunk_dss_postfork_child(tsdn_t *tsdn) +extent_dss_postfork_child(tsdn_t *tsdn) { if (have_dss) diff --git a/src/chunk_mmap.c b/src/extent_mmap.c similarity index 83% rename from src/chunk_mmap.c rename to src/extent_mmap.c index e1ee26f4..0dd3247e 100644 --- a/src/chunk_mmap.c +++ b/src/extent_mmap.c @@ -1,10 +1,10 @@ -#define JEMALLOC_CHUNK_MMAP_C_ +#define JEMALLOC_EXTENT_MMAP_C_ #include "jemalloc/internal/jemalloc_internal.h" /******************************************************************************/ static void * -chunk_alloc_mmap_slow(size_t size, size_t alignment, bool *zero, bool *commit) +extent_alloc_mmap_slow(size_t size, size_t alignment, bool *zero, bool *commit) { void *ret; size_t alloc_size; @@ -30,7 +30,7 @@ chunk_alloc_mmap_slow(size_t size, size_t alignment, bool *zero, bool *commit) } void * -chunk_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, +extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit) { void *ret; @@ -58,7 +58,7 @@ chunk_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, offset = ALIGNMENT_ADDR2OFFSET(ret, alignment); if (offset != 0) { pages_unmap(ret, size); - return (chunk_alloc_mmap_slow(size, alignment, zero, commit)); + return (extent_alloc_mmap_slow(size, alignment, zero, commit)); } assert(ret != NULL); @@ -67,10 +67,10 @@ chunk_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, } bool -chunk_dalloc_mmap(void *chunk, size_t size) +extent_dalloc_mmap(void *addr, size_t size) { if (config_munmap) - pages_unmap(chunk, size); + pages_unmap(addr, size); return (!config_munmap); } diff --git a/src/jemalloc.c b/src/jemalloc.c index 03e61df6..82d2e6b3 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1067,7 +1067,7 @@ malloc_conf_init(void) for (i = 0; i < dss_prec_limit; i++) { if (strncmp(dss_prec_names[i], v, vlen) == 0) { - if (chunk_dss_prec_set(NULL, + if (extent_dss_prec_set(NULL, i)) { malloc_conf_error( "Error setting dss", @@ -2686,7 +2686,7 @@ _malloc_prefork(void) } } base_prefork(tsd_tsdn(tsd)); - chunk_prefork(tsd_tsdn(tsd)); + extent_prefork(tsd_tsdn(tsd)); for (i = 0; i < narenas; i++) { if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) arena_prefork3(tsd_tsdn(tsd), arena); @@ -2715,7 +2715,7 @@ _malloc_postfork(void) witness_postfork_parent(tsd); /* Release all mutexes, now that fork() has completed. */ - chunk_postfork_parent(tsd_tsdn(tsd)); + extent_postfork_parent(tsd_tsdn(tsd)); base_postfork_parent(tsd_tsdn(tsd)); for (i = 0, narenas = narenas_total_get(); i < narenas; i++) { arena_t *arena; @@ -2740,7 +2740,7 @@ jemalloc_postfork_child(void) witness_postfork_child(tsd); /* Release all mutexes, now that fork() has completed. */ - chunk_postfork_child(tsd_tsdn(tsd)); + extent_postfork_child(tsd_tsdn(tsd)); base_postfork_child(tsd_tsdn(tsd)); for (i = 0, narenas = narenas_total_get(); i < narenas; i++) { arena_t *arena; diff --git a/src/large.c b/src/large.c index ce8d32fb..60a0745e 100644 --- a/src/large.c +++ b/src/large.c @@ -28,13 +28,13 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, return (NULL); /* - * Copy zero into is_zeroed and pass the copy to chunk_alloc(), so that + * Copy zero into is_zeroed and pass the copy to extent_alloc(), so that * it is possible to make correct junk/zero fill decisions below. */ is_zeroed = zero; if (likely(!tsdn_null(tsdn))) arena = arena_choose(tsdn_tsd(tsdn), arena); - if (unlikely(arena == NULL) || (extent = arena_chunk_alloc_large(tsdn, + if (unlikely(arena == NULL) || (extent = arena_extent_alloc_large(tsdn, arena, usize, alignment, &is_zeroed)) == NULL) return (NULL); @@ -82,10 +82,10 @@ large_dalloc_maybe_junk(tsdn_t *tsdn, void *ptr, size_t usize) if (config_fill && have_dss && unlikely(opt_junk_free)) { /* - * Only bother junk filling if the chunk isn't about to be + * Only bother junk filling if the extent isn't about to be * unmapped. */ - if (!config_munmap || (have_dss && chunk_in_dss(tsdn, ptr))) + if (!config_munmap || (have_dss && extent_in_dss(tsdn, ptr))) large_dalloc_junk(ptr, usize); memset(ptr, JEMALLOC_FREE_JUNK, usize); } @@ -103,7 +103,7 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) /* Split excess pages. */ if (diff != 0) { - extent_t *trail = chunk_split_wrapper(tsdn, arena, + extent_t *trail = extent_split_wrapper(tsdn, arena, &extent_hooks, extent, usize + large_pad, usize, diff, diff); if (trail == NULL) @@ -114,10 +114,10 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) extent_usize_get(trail)); } - arena_chunk_cache_dalloc(tsdn, arena, &extent_hooks, trail); + arena_extent_cache_dalloc(tsdn, arena, &extent_hooks, trail); } - arena_chunk_ralloc_large_shrink(tsdn, arena, extent, oldusize); + arena_extent_ralloc_large_shrink(tsdn, arena, extent, oldusize); return (false); } @@ -133,18 +133,18 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, size_t trailsize = usize - extent_usize_get(extent); extent_t *trail; - if ((trail = arena_chunk_cache_alloc(tsdn, arena, &extent_hooks, + if ((trail = arena_extent_cache_alloc(tsdn, arena, &extent_hooks, extent_past_get(extent), trailsize, CACHELINE, &is_zeroed_trail)) == NULL) { bool commit = true; - if ((trail = chunk_alloc_wrapper(tsdn, arena, &extent_hooks, + if ((trail = extent_alloc_wrapper(tsdn, arena, &extent_hooks, extent_past_get(extent), trailsize, 0, CACHELINE, &is_zeroed_trail, &commit, false)) == NULL) return (true); } - if (chunk_merge_wrapper(tsdn, arena, &extent_hooks, extent, trail)) { - chunk_dalloc_wrapper(tsdn, arena, &extent_hooks, trail); + if (extent_merge_wrapper(tsdn, arena, &extent_hooks, extent, trail)) { + extent_dalloc_wrapper(tsdn, arena, &extent_hooks, trail); return (true); } @@ -174,7 +174,7 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, JEMALLOC_ALLOC_JUNK, usize - oldusize); } - arena_chunk_ralloc_large_expand(tsdn, arena, extent, oldusize); + arena_extent_ralloc_large_expand(tsdn, arena, extent, oldusize); return (false); } @@ -209,7 +209,7 @@ large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, } /* - * Avoid moving the allocation if the existing chunk size accommodates + * Avoid moving the allocation if the existing extent size accommodates * the new size. */ if (extent_usize_get(extent) >= usize_min && extent_usize_get(extent) <= @@ -287,7 +287,7 @@ large_dalloc_impl(tsdn_t *tsdn, extent_t *extent, bool junked_locked) large_dalloc_maybe_junk(tsdn, extent_addr_get(extent), extent_usize_get(extent)); } - arena_chunk_dalloc_large(tsdn, arena, extent, junked_locked); + arena_extent_dalloc_large(tsdn, arena, extent, junked_locked); if (!junked_locked) arena_decay_tick(tsdn, arena); diff --git a/test/integration/chunk.c b/test/integration/extent.c similarity index 72% rename from test/integration/chunk.c rename to test/integration/extent.c index 10c4ba77..15b96a00 100644 --- a/test/integration/chunk.c +++ b/test/integration/extent.c @@ -25,7 +25,7 @@ static bool did_merge; #endif void * -chunk_alloc(void *new_addr, size_t size, size_t alignment, bool *zero, +extent_alloc(void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit, unsigned arena_ind) { @@ -38,86 +38,86 @@ chunk_alloc(void *new_addr, size_t size, size_t alignment, bool *zero, } bool -chunk_dalloc(void *chunk, size_t size, bool committed, unsigned arena_ind) +extent_dalloc(void *addr, size_t size, bool committed, unsigned arena_ind) { - TRACE_HOOK("%s(chunk=%p, size=%zu, committed=%s, arena_ind=%u)\n", - __func__, chunk, size, committed ? "true" : "false", arena_ind); + TRACE_HOOK("%s(addr=%p, size=%zu, committed=%s, arena_ind=%u)\n", + __func__, addr, size, committed ? "true" : "false", arena_ind); did_dalloc = true; if (!do_dalloc) return (true); - return (old_hooks.dalloc(chunk, size, committed, arena_ind)); + return (old_hooks.dalloc(addr, size, committed, arena_ind)); } bool -chunk_commit(void *chunk, size_t size, size_t offset, size_t length, +extent_commit(void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { bool err; - TRACE_HOOK("%s(chunk=%p, size=%zu, offset=%zu, length=%zu, " - "arena_ind=%u)\n", __func__, chunk, size, offset, length, + TRACE_HOOK("%s(addr=%p, size=%zu, offset=%zu, length=%zu, " + "arena_ind=%u)\n", __func__, addr, size, offset, length, arena_ind); - err = old_hooks.commit(chunk, size, offset, length, arena_ind); + err = old_hooks.commit(addr, size, offset, length, arena_ind); did_commit = !err; return (err); } bool -chunk_decommit(void *chunk, size_t size, size_t offset, size_t length, +extent_decommit(void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { bool err; - TRACE_HOOK("%s(chunk=%p, size=%zu, offset=%zu, length=%zu, " - "arena_ind=%u)\n", __func__, chunk, size, offset, length, + TRACE_HOOK("%s(addr=%p, size=%zu, offset=%zu, length=%zu, " + "arena_ind=%u)\n", __func__, addr, size, offset, length, arena_ind); if (!do_decommit) return (true); - err = old_hooks.decommit(chunk, size, offset, length, arena_ind); + err = old_hooks.decommit(addr, size, offset, length, arena_ind); did_decommit = !err; return (err); } bool -chunk_purge(void *chunk, size_t size, size_t offset, size_t length, +extent_purge(void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { - TRACE_HOOK("%s(chunk=%p, size=%zu, offset=%zu, length=%zu " - "arena_ind=%u)\n", __func__, chunk, size, offset, length, + TRACE_HOOK("%s(addr=%p, size=%zu, offset=%zu, length=%zu " + "arena_ind=%u)\n", __func__, addr, size, offset, length, arena_ind); did_purge = true; - return (old_hooks.purge(chunk, size, offset, length, arena_ind)); + return (old_hooks.purge(addr, size, offset, length, arena_ind)); } bool -chunk_split(void *chunk, size_t size, size_t size_a, size_t size_b, +extent_split(void *addr, size_t size, size_t size_a, size_t size_b, bool committed, unsigned arena_ind) { - TRACE_HOOK("%s(chunk=%p, size=%zu, size_a=%zu, size_b=%zu, " - "committed=%s, arena_ind=%u)\n", __func__, chunk, size, size_a, + TRACE_HOOK("%s(addr=%p, size=%zu, size_a=%zu, size_b=%zu, " + "committed=%s, arena_ind=%u)\n", __func__, addr, size, size_a, size_b, committed ? "true" : "false", arena_ind); did_split = true; - return (old_hooks.split(chunk, size, size_a, size_b, committed, + return (old_hooks.split(addr, size, size_a, size_b, committed, arena_ind)); } bool -chunk_merge(void *chunk_a, size_t size_a, void *chunk_b, size_t size_b, +extent_merge(void *addr_a, size_t size_a, void *addr_b, size_t size_b, bool committed, unsigned arena_ind) { - TRACE_HOOK("%s(chunk_a=%p, size_a=%zu, chunk_b=%p size_b=%zu, " - "committed=%s, arena_ind=%u)\n", __func__, chunk_a, size_a, chunk_b, + TRACE_HOOK("%s(addr_a=%p, size_a=%zu, addr_b=%p size_b=%zu, " + "committed=%s, arena_ind=%u)\n", __func__, addr_a, size_a, addr_b, size_b, committed ? "true" : "false", arena_ind); did_merge = true; - return (old_hooks.merge(chunk_a, size_a, chunk_b, size_b, + return (old_hooks.merge(addr_a, size_a, addr_b, size_b, committed, arena_ind)); } -TEST_BEGIN(test_chunk) +TEST_BEGIN(test_extent) { void *p; size_t old_size, new_size, large0, large1, large2, sz; @@ -126,13 +126,13 @@ TEST_BEGIN(test_chunk) size_t hooks_mib[3], purge_mib[3]; size_t hooks_miblen, purge_miblen; extent_hooks_t new_hooks = { - chunk_alloc, - chunk_dalloc, - chunk_commit, - chunk_decommit, - chunk_purge, - chunk_split, - chunk_merge + extent_alloc, + extent_dalloc, + extent_commit, + extent_decommit, + extent_purge, + extent_split, + extent_merge }; bool xallocx_success_a, xallocx_success_b, xallocx_success_c; @@ -151,16 +151,16 @@ TEST_BEGIN(test_chunk) assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, &old_hooks, &old_size, &new_hooks, new_size), 0, "Unexpected extent_hooks error"); orig_hooks = old_hooks; - assert_ptr_ne(old_hooks.alloc, chunk_alloc, "Unexpected alloc error"); - assert_ptr_ne(old_hooks.dalloc, chunk_dalloc, + assert_ptr_ne(old_hooks.alloc, extent_alloc, "Unexpected alloc error"); + assert_ptr_ne(old_hooks.dalloc, extent_dalloc, "Unexpected dalloc error"); - assert_ptr_ne(old_hooks.commit, chunk_commit, + assert_ptr_ne(old_hooks.commit, extent_commit, "Unexpected commit error"); - assert_ptr_ne(old_hooks.decommit, chunk_decommit, + assert_ptr_ne(old_hooks.decommit, extent_decommit, "Unexpected decommit error"); - assert_ptr_ne(old_hooks.purge, chunk_purge, "Unexpected purge error"); - assert_ptr_ne(old_hooks.split, chunk_split, "Unexpected split error"); - assert_ptr_ne(old_hooks.merge, chunk_merge, "Unexpected merge error"); + assert_ptr_ne(old_hooks.purge, extent_purge, "Unexpected purge error"); + assert_ptr_ne(old_hooks.split, extent_split, "Unexpected split error"); + assert_ptr_ne(old_hooks.merge, extent_merge, "Unexpected merge error"); /* Get large size classes. */ sz = sizeof(size_t); @@ -249,5 +249,5 @@ int main(void) { - return (test(test_chunk)); + return (test(test_extent)); } -- GitLab From 03eea4fb8b464ff399ef3118207feb6b376ceded Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Jun 2016 13:14:18 -0700 Subject: [PATCH 052/544] Better document --enable-ivsalloc. --- INSTALL | 7 ++++--- include/jemalloc/internal/jemalloc_internal.h.in | 11 +++++++++-- include/jemalloc/internal/jemalloc_internal_defs.h.in | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/INSTALL b/INSTALL index e4f7bbd5..00c428b1 100644 --- a/INSTALL +++ b/INSTALL @@ -124,9 +124,10 @@ any of the following arguments (not a definitive list) to 'configure': option documentation for usage details. --enable-ivsalloc - Enable validation code, which verifies that pointers reside within - jemalloc-owned chunks before dereferencing them. This incurs a minor - performance hit. + Enable validation code for malloc_usable_size() and sallocx(), which + verifies that pointers reside within jemalloc-owned extents before + dereferencing metadata. This incurs a minor performance hit, and causes + the functions to return 0 for failed lookups. --enable-prof Enable heap profiling and leak detection functionality. See the "opt.prof" diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index fb3991bc..243aae6c 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -1061,12 +1061,19 @@ ivsalloc(tsdn_t *tsdn, const void *ptr) { extent_t *extent; - /* Return 0 if ptr is not within a chunk managed by jemalloc. */ + /* + * Return 0 if ptr is not within an extent managed by jemalloc. This + * function has two extra costs relative to isalloc(): + * - The extent_lookup() call cannot claim to be a dependent lookup, + * which induces rtree lookup load dependencies. + * - The lookup may fail, so there is an extra branch to check for + * failure. + * */ extent = extent_lookup(tsdn, ptr, false); if (extent == NULL) return (0); assert(extent_active_get(extent)); - /* Only arena chunks should be looked up via interior pointers. */ + /* Only slab members should be looked up via interior pointers. */ assert(extent_addr_get(extent) == ptr || extent_slab_get(extent)); return (isalloc(tsdn, extent, ptr)); diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 7a38c91d..6721bc85 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -195,7 +195,7 @@ /* * JEMALLOC_IVSALLOC enables ivsalloc(), which verifies that pointers reside - * within jemalloc-owned chunks before dereferencing them. + * within jemalloc-owned extents before dereferencing them. */ #undef JEMALLOC_IVSALLOC -- GitLab From 751f2c332d91209c5ae3234fa444a20850067960 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Jun 2016 13:40:48 -0700 Subject: [PATCH 053/544] Remove obsolete stats.arenas..metadata.mapped mallctl. Rename stats.arenas..metadata.allocated mallctl to stats.arenas..metadata . --- doc/jemalloc.xml.in | 25 ++++-------------- include/jemalloc/internal/arena.h | 18 ++++++------- .../jemalloc/internal/jemalloc_internal.h.in | 8 +++--- include/jemalloc/internal/private_symbols.txt | 6 ++--- include/jemalloc/internal/stats.h | 8 ++---- src/arena.c | 3 +-- src/ctl.c | 26 +++++-------------- src/stats.c | 13 +++------- 8 files changed, 34 insertions(+), 73 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index ab90e30f..185f955a 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -2059,10 +2059,8 @@ typedef struct { Total number of bytes dedicated to metadata, which comprise base allocations used for bootstrap-sensitive internal - allocator data structures, arena chunk headers (see stats.arenas.<i>.metadata.mapped), - and internal allocations (see stats.arenas.<i>.metadata.allocated). + allocator data structures and internal allocations (see stats.arenas.<i>.metadata). @@ -2210,20 +2208,9 @@ typedef struct { details. - + - stats.arenas.<i>.metadata.mapped - (size_t) - r- - [] - - Number of mapped bytes in arena chunk headers, which - track the states of the non-metadata pages. - - - - - stats.arenas.<i>.metadata.allocated + stats.arenas.<i>.metadata (size_t) r- [] @@ -2232,9 +2219,7 @@ typedef struct { Internal allocations differ from application-originated allocations in that they are for internal use, and that they are omitted from heap profiles. This statistic is reported separately from stats.metadata and - stats.arenas.<i>.metadata.mapped + linkend="stats.metadata">stats.metadata because it overlaps with e.g. the stats.allocated and stats.active diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index bc169756..fc0a755f 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -359,9 +359,9 @@ void arena_postfork_child(tsdn_t *tsdn, arena_t *arena); #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE -void arena_metadata_allocated_add(arena_t *arena, size_t size); -void arena_metadata_allocated_sub(arena_t *arena, size_t size); -size_t arena_metadata_allocated_get(arena_t *arena); +void arena_metadata_add(arena_t *arena, size_t size); +void arena_metadata_sub(arena_t *arena, size_t size); +size_t arena_metadata_get(arena_t *arena); bool arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes); bool arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes); bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes); @@ -387,24 +387,24 @@ void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) # ifdef JEMALLOC_ARENA_INLINE_A JEMALLOC_INLINE void -arena_metadata_allocated_add(arena_t *arena, size_t size) +arena_metadata_add(arena_t *arena, size_t size) { - atomic_add_z(&arena->stats.metadata_allocated, size); + atomic_add_z(&arena->stats.metadata, size); } JEMALLOC_INLINE void -arena_metadata_allocated_sub(arena_t *arena, size_t size) +arena_metadata_sub(arena_t *arena, size_t size) { - atomic_sub_z(&arena->stats.metadata_allocated, size); + atomic_sub_z(&arena->stats.metadata, size); } JEMALLOC_INLINE size_t -arena_metadata_allocated_get(arena_t *arena) +arena_metadata_get(arena_t *arena) { - return (atomic_read_z(&arena->stats.metadata_allocated)); + return (atomic_read_z(&arena->stats.metadata)); } JEMALLOC_INLINE bool diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 243aae6c..176487ef 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -1006,7 +1006,7 @@ iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, ret = arena_malloc(tsdn, arena, size, ind, zero, tcache, slow_path); if (config_stats && is_metadata && likely(ret != NULL)) { - arena_metadata_allocated_add(iaalloc(tsdn, ret), isalloc(tsdn, + arena_metadata_add(iaalloc(tsdn, ret), isalloc(tsdn, iealloc(tsdn, ret), ret)); } return (ret); @@ -1034,7 +1034,7 @@ ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, ret = arena_palloc(tsdn, arena, usize, alignment, zero, tcache); assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret); if (config_stats && is_metadata && likely(ret != NULL)) { - arena_metadata_allocated_add(iaalloc(tsdn, ret), isalloc(tsdn, + arena_metadata_add(iaalloc(tsdn, ret), isalloc(tsdn, iealloc(tsdn, ret), ret)); } return (ret); @@ -1088,8 +1088,8 @@ idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, assert(!is_metadata || tcache == NULL); assert(!is_metadata || iaalloc(tsdn, ptr)->ind < narenas_auto); if (config_stats && is_metadata) { - arena_metadata_allocated_sub(iaalloc(tsdn, ptr), isalloc(tsdn, - extent, ptr)); + arena_metadata_sub(iaalloc(tsdn, ptr), isalloc(tsdn, extent, + ptr)); } arena_dalloc(tsdn, extent, ptr, tcache, slow_path); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index a2f093ee..be81d746 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -41,9 +41,9 @@ arena_lg_dirty_mult_set arena_malloc arena_malloc_hard arena_maybe_purge -arena_metadata_allocated_add -arena_metadata_allocated_get -arena_metadata_allocated_sub +arena_metadata_add +arena_metadata_get +arena_metadata_sub arena_migrate arena_new arena_nthreads_dec diff --git a/include/jemalloc/internal/stats.h b/include/jemalloc/internal/stats.h index 7bba57a7..d5eea8e7 100644 --- a/include/jemalloc/internal/stats.h +++ b/include/jemalloc/internal/stats.h @@ -101,12 +101,8 @@ struct arena_stats_s { uint64_t nmadvise; uint64_t purged; - /* - * Number of bytes currently mapped purely for metadata purposes, and - * number of bytes currently allocated for internal metadata. - */ - size_t metadata_mapped; - size_t metadata_allocated; /* Protected via atomic_*_z(). */ + /* Number of bytes currently allocated for internal metadata. */ + size_t metadata; /* Protected via atomic_*_z(). */ size_t allocated_large; uint64_t nmalloc_large; diff --git a/src/arena.c b/src/arena.c index 990e0e89..c77db5d0 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1686,8 +1686,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, astats->npurge += arena->stats.npurge; astats->nmadvise += arena->stats.nmadvise; astats->purged += arena->stats.purged; - astats->metadata_mapped += arena->stats.metadata_mapped; - astats->metadata_allocated += arena_metadata_allocated_get(arena); + astats->metadata += arena_metadata_get(arena); astats->allocated_large += arena->stats.allocated_large; astats->nmalloc_large += arena->stats.nmalloc_large; astats->ndalloc_large += arena->stats.ndalloc_large; diff --git a/src/ctl.c b/src/ctl.c index 61f3aa1c..b91ea135 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -180,8 +180,7 @@ CTL_PROTO(stats_arenas_i_retained) CTL_PROTO(stats_arenas_i_npurge) CTL_PROTO(stats_arenas_i_nmadvise) CTL_PROTO(stats_arenas_i_purged) -CTL_PROTO(stats_arenas_i_metadata_mapped) -CTL_PROTO(stats_arenas_i_metadata_allocated) +CTL_PROTO(stats_arenas_i_metadata) INDEX_PROTO(stats_arenas_i) CTL_PROTO(stats_cactive) CTL_PROTO(stats_allocated) @@ -347,11 +346,6 @@ static const ctl_named_node_t prof_node[] = { {NAME("lg_sample"), CTL(lg_prof_sample)} }; -static const ctl_named_node_t stats_arenas_i_metadata_node[] = { - {NAME("mapped"), CTL(stats_arenas_i_metadata_mapped)}, - {NAME("allocated"), CTL(stats_arenas_i_metadata_allocated)} -}; - static const ctl_named_node_t stats_arenas_i_small_node[] = { {NAME("allocated"), CTL(stats_arenas_i_small_allocated)}, {NAME("nmalloc"), CTL(stats_arenas_i_small_nmalloc)}, @@ -411,7 +405,7 @@ static const ctl_named_node_t stats_arenas_i_node[] = { {NAME("npurge"), CTL(stats_arenas_i_npurge)}, {NAME("nmadvise"), CTL(stats_arenas_i_nmadvise)}, {NAME("purged"), CTL(stats_arenas_i_purged)}, - {NAME("metadata"), CHILD(named, stats_arenas_i_metadata)}, + {NAME("metadata"), CTL(stats_arenas_i_metadata)}, {NAME("small"), CHILD(named, stats_arenas_i_small)}, {NAME("large"), CHILD(named, stats_arenas_i_large)}, {NAME("bins"), CHILD(indexed, stats_arenas_i_bins)}, @@ -522,10 +516,7 @@ ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats) sstats->astats.nmadvise += astats->astats.nmadvise; sstats->astats.purged += astats->astats.purged; - sstats->astats.metadata_mapped += - astats->astats.metadata_mapped; - sstats->astats.metadata_allocated += - astats->astats.metadata_allocated; + sstats->astats.metadata += astats->astats.metadata; sstats->allocated_small += astats->allocated_small; sstats->nmalloc_small += astats->nmalloc_small; @@ -649,11 +640,8 @@ ctl_refresh(tsdn_t *tsdn) ctl_stats.active = (ctl_stats.arenas[ctl_stats.narenas].pactive << LG_PAGE); ctl_stats.metadata = base_allocated + - ctl_stats.arenas[ctl_stats.narenas].astats.metadata_mapped + - ctl_stats.arenas[ctl_stats.narenas].astats - .metadata_allocated; + ctl_stats.arenas[ctl_stats.narenas].astats.metadata; ctl_stats.resident = base_resident + - ctl_stats.arenas[ctl_stats.narenas].astats.metadata_mapped + ((ctl_stats.arenas[ctl_stats.narenas].pactive + ctl_stats.arenas[ctl_stats.narenas].pdirty) << LG_PAGE); ctl_stats.mapped = base_mapped + @@ -2001,10 +1989,8 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise, ctl_stats.arenas[mib[2]].astats.nmadvise, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_purged, ctl_stats.arenas[mib[2]].astats.purged, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_metadata_mapped, - ctl_stats.arenas[mib[2]].astats.metadata_mapped, size_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_metadata_allocated, - ctl_stats.arenas[mib[2]].astats.metadata_allocated, size_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_metadata, + ctl_stats.arenas[mib[2]].astats.metadata, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated, ctl_stats.arenas[mib[2]].allocated_small, size_t) diff --git a/src/stats.c b/src/stats.c index 493e409a..d8815855 100644 --- a/src/stats.c +++ b/src/stats.c @@ -211,8 +211,7 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, unsigned nthreads; const char *dss; ssize_t lg_dirty_mult, decay_time; - size_t page, pactive, pdirty, mapped, retained; - size_t metadata_mapped, metadata_allocated; + size_t page, pactive, pdirty, mapped, retained, metadata; uint64_t npurge, nmadvise, purged; size_t small_allocated; uint64_t small_nmalloc, small_ndalloc, small_nrequests; @@ -291,13 +290,9 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, CTL_M2_GET("stats.arenas.0.retained", i, &retained, size_t); malloc_cprintf(write_cb, cbopaque, "retained: %12zu\n", retained); - CTL_M2_GET("stats.arenas.0.metadata.mapped", i, &metadata_mapped, - size_t); - CTL_M2_GET("stats.arenas.0.metadata.allocated", i, &metadata_allocated, - size_t); - malloc_cprintf(write_cb, cbopaque, - "metadata: mapped: %zu, allocated: %zu\n", - metadata_mapped, metadata_allocated); + CTL_M2_GET("stats.arenas.0.metadata", i, &metadata, size_t); + malloc_cprintf(write_cb, cbopaque, "metadata: %12zu\n", + metadata); if (bins) stats_arena_bins_print(write_cb, cbopaque, i); -- GitLab From a83a31c1c5976d960bf9ef98ed7d9066d3d5b0f2 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Jun 2016 13:52:30 -0700 Subject: [PATCH 054/544] Relax opt_lg_chunk clamping constraints. --- src/jemalloc.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index 82d2e6b3..c5fd4419 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1051,16 +1051,8 @@ malloc_conf_init(void) } CONF_HANDLE_BOOL(opt_abort, "abort", true) - /* - * Chunks always require at least one header page and as - * many as 2^(LG_SIZE_CLASS_GROUP+1) data pages. In - * order to simplify options processing, use a - * conservative bound that accommodates all these - * constraints. - */ - CONF_HANDLE_SIZE_T(opt_lg_chunk, "lg_chunk", LG_PAGE + - LG_SIZE_CLASS_GROUP + 1, (sizeof(size_t) << 3) - 1, - true) + CONF_HANDLE_SIZE_T(opt_lg_chunk, "lg_chunk", LG_PAGE, + (sizeof(size_t) << 3) - 1, true) if (strncmp("dss", k, klen) == 0) { int i; bool match = false; -- GitLab From a43db1c6088914d1a488abb93315e858c018419b Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Jun 2016 13:53:05 -0700 Subject: [PATCH 055/544] Relax NBINS constraint (max 255 --> max 256). --- include/jemalloc/internal/size_classes.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/jemalloc/internal/size_classes.sh b/include/jemalloc/internal/size_classes.sh index 38fe4902..5a57f87d 100755 --- a/include/jemalloc/internal/size_classes.sh +++ b/include/jemalloc/internal/size_classes.sh @@ -331,11 +331,9 @@ cat < 255) +#if (NBINS > 256) # error "Too many small size classes" #endif -- GitLab From c8c3cbdf47f97c2661395efc572b12ff2a7de05f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Jun 2016 13:53:56 -0700 Subject: [PATCH 056/544] Miscellaneous s/chunk/extent/ updates. --- doc/jemalloc.xml.in | 17 +++++++++-------- .../internal/jemalloc_internal_defs.h.in | 4 ++-- include/jemalloc/internal/rtree.h | 2 +- include/jemalloc/internal/stats.h | 3 +-- src/zone.c | 2 +- test/integration/aligned_alloc.c | 1 - test/integration/posix_memalign.c | 1 - test/unit/mallctl.c | 6 +++--- 8 files changed, 17 insertions(+), 19 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 185f955a..74daf6a8 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -2087,12 +2087,12 @@ typedef struct { r- [] - Total number of bytes in active chunks mapped by the - allocator. This is a multiple of the chunk size, and is larger than - stats.active. - This does not include inactive chunks, even those that contain unused - dirty pages, which means that there is no strict ordering between this - and Total number of bytes in active extents mapped by the + allocator. This is larger than stats.active. This + does not include inactive extents, even those that contain unused dirty + pages, which means that there is no strict ordering between this and + stats.resident. @@ -2737,9 +2737,10 @@ MAPPED_LIBRARIES: To dump core whenever a problem occurs: ln -s 'abort:true' /etc/malloc.conf - To specify in the source a chunk size that is 16 MiB: + To specify in the source that only one arena should be automatically + created: +malloc_conf = "narenas:1";]]> SEE ALSO diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 6721bc85..49e2cf06 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -137,7 +137,7 @@ #undef JEMALLOC_TCACHE /* - * JEMALLOC_DSS enables use of sbrk(2) to allocate chunks from the data storage + * JEMALLOC_DSS enables use of sbrk(2) to allocate extents from the data storage * segment (DSS). */ #undef JEMALLOC_DSS @@ -176,7 +176,7 @@ #undef JEMALLOC_MAPS_COALESCE /* - * If defined, use munmap() to unmap freed chunks, rather than storing them for + * If defined, use munmap() to unmap freed extents, rather than storing them for * later reuse. This is disabled by default on Linux because common sequences * of mmap()/munmap() calls will cause virtual memory map holes. */ diff --git a/include/jemalloc/internal/rtree.h b/include/jemalloc/internal/rtree.h index e62ab6b9..af52f9ff 100644 --- a/include/jemalloc/internal/rtree.h +++ b/include/jemalloc/internal/rtree.h @@ -1,6 +1,6 @@ /* * This radix tree implementation is tailored to the singular purpose of - * associating metadata with chunks that are currently owned by jemalloc. + * associating metadata with extents that are currently owned by jemalloc. * ******************************************************************************* */ diff --git a/include/jemalloc/internal/stats.h b/include/jemalloc/internal/stats.h index d5eea8e7..da019605 100644 --- a/include/jemalloc/internal/stats.h +++ b/include/jemalloc/internal/stats.h @@ -5,7 +5,6 @@ typedef struct tcache_bin_stats_s tcache_bin_stats_t; typedef struct malloc_bin_stats_s malloc_bin_stats_t; typedef struct malloc_large_stats_s malloc_large_stats_t; typedef struct arena_stats_s arena_stats_t; -typedef struct chunk_stats_s chunk_stats_t; #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ @@ -76,7 +75,7 @@ struct malloc_large_stats_s { */ uint64_t nrequests; - /* Current number of (multi-)chunk allocations of this size class. */ + /* Current number of allocations of this size class. */ size_t curlextents; }; diff --git a/src/zone.c b/src/zone.c index 4609503a..ca235da4 100644 --- a/src/zone.c +++ b/src/zone.c @@ -54,7 +54,7 @@ zone_size(malloc_zone_t *zone, void *ptr) * our zone into two parts, and use one as the default allocator and * the other as the default deallocator/reallocator. Since that will * not work in practice, we must check all pointers to assure that they - * reside within a mapped chunk before determining size. + * reside within a mapped extent before determining size. */ return (ivsalloc(tsdn_fetch(), ptr)); } diff --git a/test/integration/aligned_alloc.c b/test/integration/aligned_alloc.c index 60900148..ec2f5a7b 100644 --- a/test/integration/aligned_alloc.c +++ b/test/integration/aligned_alloc.c @@ -1,6 +1,5 @@ #include "test/jemalloc_test.h" -#define CHUNK 0x400000 /* #define MAXALIGN ((size_t)UINT64_C(0x80000000000)) */ #define MAXALIGN ((size_t)0x2000000LU) #define NITER 4 diff --git a/test/integration/posix_memalign.c b/test/integration/posix_memalign.c index 19741c6c..d5e39b63 100644 --- a/test/integration/posix_memalign.c +++ b/test/integration/posix_memalign.c @@ -1,6 +1,5 @@ #include "test/jemalloc_test.h" -#define CHUNK 0x400000 /* #define MAXALIGN ((size_t)UINT64_C(0x80000000000)) */ #define MAXALIGN ((size_t)0x2000000LU) #define NITER 4 diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 8eb5a60c..1954bfc5 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -625,7 +625,7 @@ TEST_END TEST_BEGIN(test_arenas_lextent_constants) { -#define TEST_ARENAS_HCHUNK_CONSTANT(t, name, expected) do { \ +#define TEST_ARENAS_LEXTENT_CONSTANT(t, name, expected) do { \ t name; \ size_t sz = sizeof(t); \ assert_d_eq(mallctl("arenas.lextent.0."#name, &name, &sz, NULL, \ @@ -633,9 +633,9 @@ TEST_BEGIN(test_arenas_lextent_constants) assert_zu_eq(name, expected, "Incorrect "#name" size"); \ } while (0) - TEST_ARENAS_HCHUNK_CONSTANT(size_t, size, LARGE_MINCLASS); + TEST_ARENAS_LEXTENT_CONSTANT(size_t, size, LARGE_MINCLASS); -#undef TEST_ARENAS_HCHUNK_CONSTANT +#undef TEST_ARENAS_LEXTENT_CONSTANT } TEST_END -- GitLab From b14fdaaca0f3a8affac1bef468c3e446c56abbe2 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Jun 2016 16:17:31 -0700 Subject: [PATCH 057/544] Add a missing prof_alloc_rollback() call. In the case where prof_alloc_prep() is called with an over-estimate of allocation size, and sampling doesn't end up being triggered, the tctx must be discarded. --- include/jemalloc/internal/prof.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/jemalloc/internal/prof.h b/include/jemalloc/internal/prof.h index 8fdc27f6..0fdee08c 100644 --- a/include/jemalloc/internal/prof.h +++ b/include/jemalloc/internal/prof.h @@ -520,6 +520,7 @@ prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, * though its actual usize was insufficient to cross the * sample threshold. */ + prof_alloc_rollback(tsd, tctx, true); tctx = (prof_tctx_t *)(uintptr_t)1U; } } -- GitLab From 819417580e60f063d2a0dc83044a1b4d8994e50a Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Jun 2016 16:19:22 -0700 Subject: [PATCH 058/544] Fix rallocx() sampling code to not eagerly commit sampler update. rallocx() for an alignment-constrained request may end up with a smaller-than-worst-case size if in-place reallocation succeeds due to serendipitous alignment. In such cases, sampling may not happen. --- src/jemalloc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index c5fd4419..2d33464c 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -2155,7 +2155,7 @@ irallocx_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, prof_active = prof_active_get_unlocked(); old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_extent, old_ptr); - tctx = prof_alloc_prep(tsd, *usize, prof_active, true); + tctx = prof_alloc_prep(tsd, *usize, prof_active, false); if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { p = irallocx_prof_sample(tsd_tsdn(tsd), old_extent, old_ptr, old_usize, *usize, alignment, zero, tcache, arena, tctx); @@ -2164,7 +2164,7 @@ irallocx_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, size, alignment, zero, tcache, arena); } if (unlikely(p == NULL)) { - prof_alloc_rollback(tsd, tctx, true); + prof_alloc_rollback(tsd, tctx, false); return (NULL); } @@ -2181,7 +2181,7 @@ irallocx_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, *usize = isalloc(tsd_tsdn(tsd), extent, p); } else extent = iealloc(tsd_tsdn(tsd), p); - prof_realloc(tsd, extent, p, *usize, tctx, prof_active, true, + prof_realloc(tsd, extent, p, *usize, tctx, prof_active, false, old_extent, old_ptr, old_usize, old_tctx); return (p); -- GitLab From 37f0e346064a201f9938650ecf7e359cb260d079 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Jun 2016 16:23:31 -0700 Subject: [PATCH 059/544] Reduce NSZS, since NSIZES (was nsizes) can not be so large. --- test/integration/rallocx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/rallocx.c b/test/integration/rallocx.c index 6278a490..030fb479 100644 --- a/test/integration/rallocx.c +++ b/test/integration/rallocx.c @@ -52,7 +52,7 @@ TEST_BEGIN(test_grow_and_shrink) size_t tsz; #define NCYCLES 3 unsigned i, j; -#define NSZS 2500 +#define NSZS 1024 size_t szs[NSZS]; #define MAXSZ ZU(12 * 1024 * 1024) -- GitLab From e28b43a739b841c0ca7b0c0e3faf46e40bfc4616 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Jun 2016 16:24:49 -0700 Subject: [PATCH 060/544] Remove some unnecessary locking. --- src/large.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/large.c b/src/large.c index 60a0745e..952d4644 100644 --- a/src/large.c +++ b/src/large.c @@ -310,40 +310,22 @@ large_dalloc(tsdn_t *tsdn, extent_t *extent) size_t large_salloc(tsdn_t *tsdn, const extent_t *extent) { - size_t usize; - arena_t *arena; - arena = extent_arena_get(extent); - malloc_mutex_lock(tsdn, &arena->large_mtx); - usize = extent_usize_get(extent); - malloc_mutex_unlock(tsdn, &arena->large_mtx); - - return (usize); + return (extent_usize_get(extent)); } prof_tctx_t * large_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent) { - prof_tctx_t *tctx; - arena_t *arena; - - arena = extent_arena_get(extent); - malloc_mutex_lock(tsdn, &arena->large_mtx); - tctx = extent_prof_tctx_get(extent); - malloc_mutex_unlock(tsdn, &arena->large_mtx); - return (tctx); + return (extent_prof_tctx_get(extent)); } void large_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx) { - arena_t *arena; - arena = extent_arena_get(extent); - malloc_mutex_lock(tsdn, &arena->large_mtx); extent_prof_tctx_set(extent, tctx); - malloc_mutex_unlock(tsdn, &arena->large_mtx); } void -- GitLab From 7be2ebc23f0f145e095e7230d7d8a202b8dcc55e Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 2 Jun 2016 11:11:35 -0700 Subject: [PATCH 061/544] Make tsd cleanup functions optional, remove noop cleanup functions. --- .../jemalloc/internal/jemalloc_internal.h.in | 4 --- include/jemalloc/internal/private_symbols.txt | 7 ---- include/jemalloc/internal/rtree.h | 1 - include/jemalloc/internal/tcache.h | 1 - include/jemalloc/internal/tsd.h | 34 +++++++++---------- include/jemalloc/internal/witness.h | 1 - src/jemalloc.c | 28 --------------- src/rtree.c | 7 ---- src/tcache.c | 7 ---- src/tsd.c | 7 +++- src/witness.c | 7 ---- 11 files changed, 23 insertions(+), 81 deletions(-) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 176487ef..5b809bfa 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -455,13 +455,9 @@ arena_t *arena_init(tsdn_t *tsdn, unsigned ind); arena_tdata_t *arena_tdata_get_hard(tsd_t *tsd, unsigned ind); arena_t *arena_choose_hard(tsd_t *tsd, bool internal); void arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind); -void thread_allocated_cleanup(tsd_t *tsd); -void thread_deallocated_cleanup(tsd_t *tsd); void iarena_cleanup(tsd_t *tsd); void arena_cleanup(tsd_t *tsd); void arenas_tdata_cleanup(tsd_t *tsd); -void narenas_tdata_cleanup(tsd_t *tsd); -void arenas_tdata_bypass_cleanup(tsd_t *tsd); void jemalloc_prefork(void); void jemalloc_postfork_parent(void); void jemalloc_postfork_child(void); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index be81d746..d4e5525f 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -74,7 +74,6 @@ arena_tcache_fill_small arena_tdata_get arena_tdata_get_hard arenas -arenas_tdata_bypass_cleanup arenas_tdata_cleanup atomic_add_p atomic_add_u @@ -285,7 +284,6 @@ malloc_vsnprintf malloc_write mb_write narenas_auto -narenas_tdata_cleanup narenas_total_get ncpus nhbins @@ -410,7 +408,6 @@ rtree_elm_release rtree_elm_witness_access rtree_elm_witness_acquire rtree_elm_witness_release -rtree_elm_witnesses_cleanup rtree_elm_write rtree_elm_write_acquired rtree_new @@ -451,7 +448,6 @@ tcache_cleanup tcache_create tcache_dalloc_large tcache_dalloc_small -tcache_enabled_cleanup tcache_enabled_get tcache_enabled_set tcache_event @@ -467,8 +463,6 @@ tcaches_create tcaches_destroy tcaches_flush tcaches_get -thread_allocated_cleanup -thread_deallocated_cleanup ticker_copy ticker_init ticker_read @@ -539,7 +533,6 @@ tsdn_tsd witness_assert_lockless witness_assert_not_owner witness_assert_owner -witness_fork_cleanup witness_init witness_lock witness_lock_error diff --git a/include/jemalloc/internal/rtree.h b/include/jemalloc/internal/rtree.h index af52f9ff..a47a79ea 100644 --- a/include/jemalloc/internal/rtree.h +++ b/include/jemalloc/internal/rtree.h @@ -137,7 +137,6 @@ void rtree_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, const rtree_elm_t *elm); void rtree_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, const rtree_elm_t *elm); -void rtree_elm_witnesses_cleanup(tsd_t *tsd); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ diff --git a/include/jemalloc/internal/tcache.h b/include/jemalloc/internal/tcache.h index e7606d6e..933255ce 100644 --- a/include/jemalloc/internal/tcache.h +++ b/include/jemalloc/internal/tcache.h @@ -143,7 +143,6 @@ void tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, tcache_t *tcache_get_hard(tsd_t *tsd); tcache_t *tcache_create(tsdn_t *tsdn, arena_t *arena); void tcache_cleanup(tsd_t *tsd); -void tcache_enabled_cleanup(tsd_t *tsd); void tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); bool tcaches_create(tsdn_t *tsdn, unsigned *r_ind); void tcaches_flush(tsd_t *tsd, unsigned ind); diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h index ca8915ea..988edf56 100644 --- a/include/jemalloc/internal/tsd.h +++ b/include/jemalloc/internal/tsd.h @@ -561,20 +561,20 @@ struct tsd_init_head_s { #endif #define MALLOC_TSD \ -/* O(name, type) */ \ - O(tcache, tcache_t *) \ - O(thread_allocated, uint64_t) \ - O(thread_deallocated, uint64_t) \ - O(prof_tdata, prof_tdata_t *) \ - O(iarena, arena_t *) \ - O(arena, arena_t *) \ - O(arenas_tdata, arena_tdata_t *) \ - O(narenas_tdata, unsigned) \ - O(arenas_tdata_bypass, bool) \ - O(tcache_enabled, tcache_enabled_t) \ - O(witnesses, witness_list_t) \ - O(rtree_elm_witnesses, rtree_elm_witness_tsd_t) \ - O(witness_fork, bool) \ +/* O(name, type, cleanup) */ \ + O(tcache, tcache_t *, yes) \ + O(thread_allocated, uint64_t, no) \ + O(thread_deallocated, uint64_t, no) \ + O(prof_tdata, prof_tdata_t *, yes) \ + O(iarena, arena_t *, yes) \ + O(arena, arena_t *, yes) \ + O(arenas_tdata, arena_tdata_t *, yes) \ + O(narenas_tdata, unsigned, no) \ + O(arenas_tdata_bypass, bool, no) \ + O(tcache_enabled, tcache_enabled_t, no) \ + O(witnesses, witness_list_t, yes) \ + O(rtree_elm_witnesses, rtree_elm_witness_tsd_t,no) \ + O(witness_fork, bool, no) \ #define TSD_INITIALIZER { \ tsd_state_uninitialized, \ @@ -595,7 +595,7 @@ struct tsd_init_head_s { struct tsd_s { tsd_state_t state; -#define O(n, t) \ +#define O(n, t, c) \ t n; MALLOC_TSD #undef O @@ -642,7 +642,7 @@ malloc_tsd_protos(JEMALLOC_ATTR(unused), , tsd_t) tsd_t *tsd_fetch(void); tsdn_t *tsd_tsdn(tsd_t *tsd); bool tsd_nominal(tsd_t *tsd); -#define O(n, t) \ +#define O(n, t, c) \ t *tsd_##n##p_get(tsd_t *tsd); \ t tsd_##n##_get(tsd_t *tsd); \ void tsd_##n##_set(tsd_t *tsd, t n); @@ -691,7 +691,7 @@ tsd_nominal(tsd_t *tsd) return (tsd->state == tsd_state_nominal); } -#define O(n, t) \ +#define O(n, t, c) \ JEMALLOC_ALWAYS_INLINE t * \ tsd_##n##p_get(tsd_t *tsd) \ { \ diff --git a/include/jemalloc/internal/witness.h b/include/jemalloc/internal/witness.h index e2f85634..9a2a6760 100644 --- a/include/jemalloc/internal/witness.h +++ b/include/jemalloc/internal/witness.h @@ -103,7 +103,6 @@ void witness_lockless_error(const witness_list_t *witnesses); #endif void witnesses_cleanup(tsd_t *tsd); -void witness_fork_cleanup(tsd_t *tsd); void witness_prefork(tsd_t *tsd); void witness_postfork_parent(tsd_t *tsd); void witness_postfork_child(tsd_t *tsd); diff --git a/src/jemalloc.c b/src/jemalloc.c index 2d33464c..10074013 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -644,20 +644,6 @@ arena_choose_hard(tsd_t *tsd, bool internal) return (ret); } -void -thread_allocated_cleanup(tsd_t *tsd) -{ - - /* Do nothing. */ -} - -void -thread_deallocated_cleanup(tsd_t *tsd) -{ - - /* Do nothing. */ -} - void iarena_cleanup(tsd_t *tsd) { @@ -693,20 +679,6 @@ arenas_tdata_cleanup(tsd_t *tsd) } } -void -narenas_tdata_cleanup(tsd_t *tsd) -{ - - /* Do nothing. */ -} - -void -arenas_tdata_bypass_cleanup(tsd_t *tsd) -{ - - /* Do nothing. */ -} - static void stats_print_atexit(void) { diff --git a/src/rtree.c b/src/rtree.c index 504f9f2e..b6027303 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -285,10 +285,3 @@ rtree_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, witness_unlock(tsdn, witness); rtree_elm_witness_dalloc(tsdn_tsd(tsdn), witness, elm); } - -void -rtree_elm_witnesses_cleanup(tsd_t *tsd) -{ - - /* Do nothing. */ -} diff --git a/src/tcache.c b/src/tcache.c index 69444fac..96e54e1a 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -404,13 +404,6 @@ tcache_cleanup(tsd_t *tsd) } } -void -tcache_enabled_cleanup(tsd_t *tsd) -{ - - /* Do nothing. */ -} - void tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { diff --git a/src/tsd.c b/src/tsd.c index ec69a51c..5d9fc9f9 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -77,9 +77,14 @@ tsd_cleanup(void *arg) /* Do nothing. */ break; case tsd_state_nominal: -#define O(n, t) \ +#define MALLOC_TSD_cleanup_yes(n, t) \ n##_cleanup(tsd); +#define MALLOC_TSD_cleanup_no(n, t) +#define O(n, t, c) \ + MALLOC_TSD_cleanup_##c(n, t) MALLOC_TSD +#undef MALLOC_TSD_cleanup_yes +#undef MALLOC_TSD_cleanup_no #undef O tsd->state = tsd_state_purgatory; tsd_set(tsd); diff --git a/src/witness.c b/src/witness.c index 8efff56d..0f5c0d73 100644 --- a/src/witness.c +++ b/src/witness.c @@ -103,13 +103,6 @@ witnesses_cleanup(tsd_t *tsd) /* Do nothing. */ } -void -witness_fork_cleanup(tsd_t *tsd) -{ - - /* Do nothing. */ -} - void witness_prefork(tsd_t *tsd) { -- GitLab From 6f29a8392403f70bfa1080964a65540b6f3699fe Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 2 Jun 2016 18:43:10 -0700 Subject: [PATCH 062/544] Add rtree lookup path caching. rtree-based extent lookups remain more expensive than chunk-based run lookups, but with this optimization the fast path slowdown is ~3 CPU cycles per metadata lookup (on Intel Core i7-4980HQ), versus ~11 cycles prior. The path caching speedup tends to degrade gracefully unless allocated memory is spread far apart (as is the case when using a mixture of sbrk() and mmap()). --- include/jemalloc/internal/extent.h | 5 +- include/jemalloc/internal/private_symbols.txt | 5 + include/jemalloc/internal/rtree.h | 183 ++++++++++++++---- include/jemalloc/internal/tsd.h | 19 ++ src/extent.c | 65 ++++--- src/rtree.c | 3 +- test/unit/rtree.c | 83 ++++---- 7 files changed, 268 insertions(+), 95 deletions(-) diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index a41a15ff..8b8dbe80 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -181,8 +181,11 @@ void extent_ring_remove(extent_t *extent); JEMALLOC_INLINE extent_t * extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent) { + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - return (rtree_read(tsdn, &extents_rtree, (uintptr_t)ptr, dependent)); + return (rtree_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, + dependent)); } JEMALLOC_INLINE arena_t * diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index d4e5525f..07e7f287 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -399,6 +399,7 @@ rtree_child_read rtree_child_read_hard rtree_child_tryread rtree_clear +rtree_ctx_start_level rtree_delete rtree_elm_acquire rtree_elm_lookup @@ -502,6 +503,9 @@ tsd_nominal tsd_prof_tdata_get tsd_prof_tdata_set tsd_prof_tdatap_get +tsd_rtree_ctx_get +tsd_rtree_ctx_set +tsd_rtree_ctxp_get tsd_rtree_elm_witnesses_get tsd_rtree_elm_witnesses_set tsd_rtree_elm_witnessesp_get @@ -529,6 +533,7 @@ tsd_witnesses_set tsd_witnessesp_get tsdn_fetch tsdn_null +tsdn_rtree_ctx tsdn_tsd witness_assert_lockless witness_assert_not_owner diff --git a/include/jemalloc/internal/rtree.h b/include/jemalloc/internal/rtree.h index a47a79ea..fc88dfec 100644 --- a/include/jemalloc/internal/rtree.h +++ b/include/jemalloc/internal/rtree.h @@ -10,6 +10,7 @@ typedef struct rtree_elm_s rtree_elm_t; typedef struct rtree_elm_witness_s rtree_elm_witness_t; typedef struct rtree_elm_witness_tsd_s rtree_elm_witness_tsd_t; typedef struct rtree_level_s rtree_level_t; +typedef struct rtree_ctx_s rtree_ctx_t; typedef struct rtree_s rtree_t; /* @@ -25,6 +26,13 @@ typedef struct rtree_s rtree_t; /* Used for two-stage lock-free node initialization. */ #define RTREE_NODE_INITIALIZING ((rtree_elm_t *)0x1) +#define RTREE_CTX_INITIALIZER { \ + false, \ + 0, \ + 0, \ + {NULL /* C initializes all trailing elements to NULL. */} \ +} + /* * Maximum number of concurrently acquired elements per thread. This controls * how many witness_t structures are embedded in tsd. Ideally rtree_elm_t would @@ -78,9 +86,9 @@ struct rtree_level_s { * * Suppose keys comprise 48 bits, and LG_RTREE_BITS_PER_LEVEL is 4. * This results in a 3-level tree, and the leftmost leaf can be directly - * accessed via subtrees[2], the subtree prefixed by 0x0000 (excluding - * 0x00000000) can be accessed via subtrees[1], and the remainder of the - * tree can be accessed via subtrees[0]. + * accessed via levels[2], the subtree prefixed by 0x0000 (excluding + * 0x00000000) can be accessed via levels[1], and the remainder of the + * tree can be accessed via levels[0]. * * levels[0] : [ | 0x0001******** | 0x0002******** | ...] * @@ -90,7 +98,7 @@ struct rtree_level_s { * * This has practical implications on x64, which currently uses only the * lower 47 bits of virtual address space in userland, thus leaving - * subtrees[0] unused and avoiding a level of tree traversal. + * levels[0] unused and avoiding a level of tree traversal. */ union { void *subtree_pun; @@ -105,13 +113,31 @@ struct rtree_level_s { unsigned cumbits; }; +struct rtree_ctx_s { + /* If false, key/elms have not yet been initialized by a lookup. */ + bool valid; + /* Key that corresponds to the tree path recorded in elms. */ + uintptr_t key; + /* Memoized rtree_start_level(key). */ + unsigned start_level; + /* + * A path through rtree, driven by key. Only elements that could + * actually be used for subsequent lookups are initialized, i.e. if + * start_level = rtree_start_level(key) is non-zero, the first + * start_level elements are uninitialized. The last element contains a + * pointer to the leaf node element that corresponds to key, so that + * exact matches require no tree node offset computation. + */ + rtree_elm_t *elms[RTREE_HEIGHT_MAX + 1]; +}; + struct rtree_s { unsigned height; /* * Precomputed table used to convert from the number of leading 0 key * bits to which subtree level to start at. */ - unsigned start_level[RTREE_HEIGHT_MAX]; + unsigned start_level[RTREE_HEIGHT_MAX + 1]; rtree_level_t levels[RTREE_HEIGHT_MAX]; }; @@ -143,7 +169,9 @@ void rtree_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE -unsigned rtree_start_level(rtree_t *rtree, uintptr_t key); +unsigned rtree_start_level(const rtree_t *rtree, uintptr_t key); +unsigned rtree_ctx_start_level(const rtree_t *rtree, + const rtree_ctx_t *rtree_ctx, uintptr_t key); uintptr_t rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level); bool rtree_node_valid(rtree_elm_t *node); @@ -156,33 +184,55 @@ rtree_elm_t *rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent); rtree_elm_t *rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, unsigned level, bool dependent); -rtree_elm_t *rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, - bool dependent, bool init_missing); - -bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, - const extent_t *extent); -extent_t *rtree_read(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, - bool dependent); -rtree_elm_t *rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, - bool dependent, bool init_missing); +rtree_elm_t *rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, + rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); + +bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, + uintptr_t key, const extent_t *extent); +extent_t *rtree_read(tsdn_t *tsdn, rtree_t *rtree, + rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent); +rtree_elm_t *rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, + rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); extent_t *rtree_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm); void rtree_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm, const extent_t *extent); void rtree_elm_release(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm); -void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key); +void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, + uintptr_t key); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_RTREE_C_)) JEMALLOC_ALWAYS_INLINE unsigned -rtree_start_level(rtree_t *rtree, uintptr_t key) +rtree_start_level(const rtree_t *rtree, uintptr_t key) { unsigned start_level; if (unlikely(key == 0)) return (rtree->height - 1); - start_level = rtree->start_level[lg_floor(key) >> + start_level = rtree->start_level[(lg_floor(key) + 1) >> + LG_RTREE_BITS_PER_LEVEL]; + assert(start_level < rtree->height); + return (start_level); +} + +JEMALLOC_ALWAYS_INLINE unsigned +rtree_ctx_start_level(const rtree_t *rtree, const rtree_ctx_t *rtree_ctx, + uintptr_t key) +{ + unsigned start_level; + uintptr_t key_diff; + + /* Compute the difference between old and new lookup keys. */ + key_diff = key ^ rtree_ctx->key; + assert(key_diff != 0); /* Handled in rtree_elm_lookup(). */ + + /* + * Compute the last traversal path element at which the keys' paths + * are the same. + */ + start_level = rtree->start_level[(lg_floor(key_diff) + 1) >> LG_RTREE_BITS_PER_LEVEL]; assert(start_level < rtree->height); return (start_level); @@ -291,8 +341,8 @@ rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, unsigned level, bool dependent) } JEMALLOC_ALWAYS_INLINE rtree_elm_t * -rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, bool dependent, - bool init_missing) +rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, + uintptr_t key, bool dependent, bool init_missing) { uintptr_t subkey; unsigned start_level; @@ -300,35 +350,95 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, bool dependent, assert(!dependent || !init_missing); - start_level = rtree_start_level(rtree, key); + if (dependent || init_missing) { + if (likely(rtree_ctx->valid)) { + if (key == rtree_ctx->key) + return (rtree_ctx->elms[rtree->height]); + else { + unsigned no_ctx_start_level = + rtree_start_level(rtree, key); + unsigned ctx_start_level; + + if (likely(no_ctx_start_level <= + rtree_ctx->start_level && (ctx_start_level = + rtree_ctx_start_level(rtree, rtree_ctx, + key)) >= rtree_ctx->start_level)) { + start_level = ctx_start_level; + node = rtree_ctx->elms[ctx_start_level]; + } else { + start_level = no_ctx_start_level; + node = init_missing ? + rtree_subtree_read(tsdn, rtree, + no_ctx_start_level, dependent) : + rtree_subtree_tryread(rtree, + no_ctx_start_level, dependent); + rtree_ctx->start_level = + no_ctx_start_level; + rtree_ctx->elms[no_ctx_start_level] = + node; + } + } + } else { + unsigned no_ctx_start_level = rtree_start_level(rtree, + key); + + start_level = no_ctx_start_level; + node = init_missing ? rtree_subtree_read(tsdn, rtree, + no_ctx_start_level, dependent) : + rtree_subtree_tryread(rtree, no_ctx_start_level, + dependent); + rtree_ctx->valid = true; + rtree_ctx->start_level = no_ctx_start_level; + rtree_ctx->elms[no_ctx_start_level] = node; + } + rtree_ctx->key = key; + } else { + start_level = rtree_start_level(rtree, key); + node = init_missing ? rtree_subtree_read(tsdn, rtree, + start_level, dependent) : rtree_subtree_tryread(rtree, + start_level, dependent); + } - node = init_missing ? rtree_subtree_read(tsdn, rtree, start_level, - dependent) : rtree_subtree_tryread(rtree, start_level, dependent); #define RTREE_GET_BIAS (RTREE_HEIGHT_MAX - rtree->height) switch (start_level + RTREE_GET_BIAS) { #define RTREE_GET_SUBTREE(level) \ case level: \ assert(level < (RTREE_HEIGHT_MAX-1)); \ - if (!dependent && unlikely(!rtree_node_valid(node))) \ + if (!dependent && unlikely(!rtree_node_valid(node))) { \ + if (init_missing) \ + rtree_ctx->valid = false; \ return (NULL); \ + } \ subkey = rtree_subkey(rtree, key, level - \ RTREE_GET_BIAS); \ node = init_missing ? rtree_child_read(tsdn, rtree, \ &node[subkey], level - RTREE_GET_BIAS, dependent) : \ rtree_child_tryread(&node[subkey], dependent); \ + if (dependent || init_missing) { \ + rtree_ctx->elms[level - RTREE_GET_BIAS + 1] = \ + node; \ + } \ /* Fall through. */ #define RTREE_GET_LEAF(level) \ case level: \ assert(level == (RTREE_HEIGHT_MAX-1)); \ - if (!dependent && unlikely(!rtree_node_valid(node))) \ + if (!dependent && unlikely(!rtree_node_valid(node))) { \ + if (init_missing) \ + rtree_ctx->valid = false; \ return (NULL); \ + } \ subkey = rtree_subkey(rtree, key, level - \ RTREE_GET_BIAS); \ /* \ * node is a leaf, so it contains values rather than \ * child pointers. \ */ \ - return (&node[subkey]); + node = &node[subkey]; \ + if (dependent || init_missing) { \ + rtree_ctx->elms[level - RTREE_GET_BIAS + 1] = \ + node; \ + } \ + return (node); #if RTREE_HEIGHT_MAX > 1 RTREE_GET_SUBTREE(0) #endif @@ -387,14 +497,15 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, bool dependent, } JEMALLOC_INLINE bool -rtree_write(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, const extent_t *extent) +rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, + const extent_t *extent) { rtree_elm_t *elm; assert(extent != NULL); /* Use rtree_clear() for this case. */ assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); - elm = rtree_elm_lookup(tsdn, rtree, key, false, true); + elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, false, true); if (elm == NULL) return (true); assert(rtree_elm_read(elm, false) == NULL); @@ -404,11 +515,12 @@ rtree_write(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, const extent_t *extent) } JEMALLOC_ALWAYS_INLINE extent_t * -rtree_read(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, bool dependent) +rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, + bool dependent) { rtree_elm_t *elm; - elm = rtree_elm_lookup(tsdn, rtree, key, dependent, false); + elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, dependent, false); if (elm == NULL) return (NULL); @@ -416,12 +528,13 @@ rtree_read(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, bool dependent) } JEMALLOC_INLINE rtree_elm_t * -rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key, bool dependent, - bool init_missing) +rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, + uintptr_t key, bool dependent, bool init_missing) { rtree_elm_t *elm; - elm = rtree_elm_lookup(tsdn, rtree, key, dependent, init_missing); + elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, dependent, + init_missing); if (!dependent && elm == NULL) return (NULL); { @@ -481,11 +594,11 @@ rtree_elm_release(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm) } JEMALLOC_INLINE void -rtree_clear(tsdn_t *tsdn, rtree_t *rtree, uintptr_t key) +rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key) { rtree_elm_t *elm; - elm = rtree_elm_acquire(tsdn, rtree, key, true, false); + elm = rtree_elm_acquire(tsdn, rtree, rtree_ctx, key, true, false); rtree_elm_write_acquired(tsdn, rtree, elm, NULL); rtree_elm_release(tsdn, rtree, elm); } diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h index 988edf56..2355f9c6 100644 --- a/include/jemalloc/internal/tsd.h +++ b/include/jemalloc/internal/tsd.h @@ -572,6 +572,7 @@ struct tsd_init_head_s { O(narenas_tdata, unsigned, no) \ O(arenas_tdata_bypass, bool, no) \ O(tcache_enabled, tcache_enabled_t, no) \ + O(rtree_ctx, rtree_ctx_t, no) \ O(witnesses, witness_list_t, yes) \ O(rtree_elm_witnesses, rtree_elm_witness_tsd_t,no) \ O(witness_fork, bool, no) \ @@ -588,6 +589,7 @@ struct tsd_init_head_s { 0, \ false, \ tcache_enabled_default, \ + RTREE_CTX_INITIALIZER, \ ql_head_initializer(witnesses), \ RTREE_ELM_WITNESS_TSD_INITIALIZER, \ false \ @@ -651,6 +653,7 @@ MALLOC_TSD tsdn_t *tsdn_fetch(void); bool tsdn_null(const tsdn_t *tsdn); tsd_t *tsdn_tsd(tsdn_t *tsdn); +rtree_ctx_t *tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TSD_C_)) @@ -741,6 +744,22 @@ tsdn_tsd(tsdn_t *tsdn) return (&tsdn->tsd); } + +JEMALLOC_ALWAYS_INLINE rtree_ctx_t * +tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback) +{ + + /* + * If tsd cannot be accessed, initialize the fallback rtree_ctx and + * return a pointer to it. + */ + if (unlikely(tsdn_null(tsdn))) { + static const rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; + memcpy(fallback, &rtree_ctx, sizeof(rtree_ctx_t)); + return (fallback); + } + return (tsd_rtree_ctxp_get(tsdn_tsd(tsdn))); +} #endif #endif /* JEMALLOC_H_INLINES */ diff --git a/src/extent.c b/src/extent.c index 9f3ddd95..0c41c066 100644 --- a/src/extent.c +++ b/src/extent.c @@ -259,18 +259,19 @@ extent_heaps_remove(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) } static bool -extent_rtree_acquire(tsdn_t *tsdn, const extent_t *extent, bool dependent, - bool init_missing, rtree_elm_t **r_elm_a, rtree_elm_t **r_elm_b) +extent_rtree_acquire(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, + const extent_t *extent, bool dependent, bool init_missing, + rtree_elm_t **r_elm_a, rtree_elm_t **r_elm_b) { - *r_elm_a = rtree_elm_acquire(tsdn, &extents_rtree, + *r_elm_a = rtree_elm_acquire(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_base_get(extent), dependent, init_missing); if (!dependent && *r_elm_a == NULL) return (true); assert(*r_elm_a != NULL); if (extent_size_get(extent) > PAGE) { - *r_elm_b = rtree_elm_acquire(tsdn, &extents_rtree, + *r_elm_b = rtree_elm_acquire(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_last_get(extent), dependent, init_missing); if (!dependent && *r_elm_b == NULL) @@ -302,14 +303,15 @@ extent_rtree_release(tsdn_t *tsdn, rtree_elm_t *elm_a, rtree_elm_t *elm_b) } static void -extent_interior_register(tsdn_t *tsdn, const extent_t *extent) +extent_interior_register(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, + const extent_t *extent) { size_t i; assert(extent_slab_get(extent)); for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) { - rtree_write(tsdn, &extents_rtree, + rtree_write(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_base_get(extent) + (uintptr_t)(i << LG_PAGE), extent); } @@ -318,13 +320,16 @@ extent_interior_register(tsdn_t *tsdn, const extent_t *extent) static bool extent_register(tsdn_t *tsdn, const extent_t *extent) { + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_elm_t *elm_a, *elm_b; - if (extent_rtree_acquire(tsdn, extent, false, true, &elm_a, &elm_b)) + if (extent_rtree_acquire(tsdn, rtree_ctx, extent, false, true, &elm_a, + &elm_b)) return (true); extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent); if (extent_slab_get(extent)) - extent_interior_register(tsdn, extent); + extent_interior_register(tsdn, rtree_ctx, extent); extent_rtree_release(tsdn, elm_a, elm_b); if (config_prof && opt_prof && extent_active_get(extent)) { @@ -347,14 +352,15 @@ extent_register(tsdn_t *tsdn, const extent_t *extent) } static void -extent_interior_deregister(tsdn_t *tsdn, const extent_t *extent) +extent_interior_deregister(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, + const extent_t *extent) { size_t i; assert(extent_slab_get(extent)); for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) { - rtree_clear(tsdn, &extents_rtree, + rtree_clear(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_base_get(extent) + (uintptr_t)(i << LG_PAGE)); } @@ -363,12 +369,15 @@ extent_interior_deregister(tsdn_t *tsdn, const extent_t *extent) static void extent_deregister(tsdn_t *tsdn, const extent_t *extent) { + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_elm_t *elm_a, *elm_b; - extent_rtree_acquire(tsdn, extent, true, false, &elm_a, &elm_b); + extent_rtree_acquire(tsdn, rtree_ctx, extent, true, false, &elm_a, + &elm_b); extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL); if (extent_slab_get(extent)) - extent_interior_deregister(tsdn, extent); + extent_interior_deregister(tsdn, rtree_ctx, extent); extent_rtree_release(tsdn, elm_a, elm_b); if (config_prof && opt_prof && extent_active_get(extent)) { @@ -422,6 +431,8 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, bool slab) { extent_t *extent; + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); size_t size, alloc_size, leadsize, trailsize; assert(new_addr == NULL || !slab); @@ -437,7 +448,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, if (new_addr != NULL) { rtree_elm_t *elm; - elm = rtree_elm_acquire(tsdn, &extents_rtree, + elm = rtree_elm_acquire(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)new_addr, false, false); if (elm != NULL) { extent = rtree_elm_read_acquired(tsdn, &extents_rtree, @@ -515,7 +526,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_active_set(extent, true); if (slab) { extent_slab_set(extent, slab); - extent_interior_register(tsdn, extent); + extent_interior_register(tsdn, rtree_ctx, extent); } malloc_mutex_unlock(tsdn, &arena->extents_mtx); @@ -731,6 +742,8 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_heap_t extent_heaps[NPSIZES], bool cache, extent_t *extent) { extent_t *prev, *next; + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); assert(!cache || !extent_zeroed_get(extent)); @@ -741,7 +754,7 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_active_set(extent, false); extent_zeroed_set(extent, !cache && extent_zeroed_get(extent)); if (extent_slab_get(extent)) { - extent_interior_deregister(tsdn, extent); + extent_interior_deregister(tsdn, rtree_ctx, extent); extent_slab_set(extent, false); } @@ -750,7 +763,7 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, arena_extent_cache_maybe_insert(arena, extent, cache); /* Try to coalesce forward. */ - next = rtree_read(tsdn, &extents_rtree, + next = rtree_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_past_get(extent), false); if (next != NULL) { extent_try_coalesce(tsdn, arena, extent_hooks, extent, next, @@ -758,7 +771,7 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, } /* Try to coalesce backward. */ - prev = rtree_read(tsdn, &extents_rtree, + prev = rtree_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_before_get(extent), false); if (prev != NULL) { extent_try_coalesce(tsdn, arena, extent_hooks, prev, extent, @@ -910,6 +923,8 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, size_t usize_b) { extent_t *trail; + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_elm_t *lead_elm_a, *lead_elm_b, *trail_elm_a, *trail_elm_b; assert(extent_size_get(extent) == size_a + size_b); @@ -928,8 +943,8 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_zeroed_get(extent), extent_committed_get(extent), extent_slab_get(extent)); - if (extent_rtree_acquire(tsdn, &lead, false, true, &lead_elm_a, - &lead_elm_b)) + if (extent_rtree_acquire(tsdn, rtree_ctx, &lead, false, true, + &lead_elm_a, &lead_elm_b)) goto label_error_b; } @@ -937,8 +952,8 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, size_a), size_b, usize_b, extent_active_get(extent), extent_zeroed_get(extent), extent_committed_get(extent), extent_slab_get(extent)); - if (extent_rtree_acquire(tsdn, trail, false, true, &trail_elm_a, - &trail_elm_b)) + if (extent_rtree_acquire(tsdn, rtree_ctx, trail, false, true, + &trail_elm_a, &trail_elm_b)) goto label_error_c; if (extent_hooks->split(extent_base_get(extent), size_a + size_b, @@ -985,6 +1000,8 @@ bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_t *a, extent_t *b) { + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; extent_hooks_assure_initialized(tsdn, arena, extent_hooks); @@ -998,8 +1015,10 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, * owned, so the following code uses decomposed helper functions rather * than extent_{,de}register() to do things in the right order. */ - extent_rtree_acquire(tsdn, a, true, false, &a_elm_a, &a_elm_b); - extent_rtree_acquire(tsdn, b, true, false, &b_elm_a, &b_elm_b); + extent_rtree_acquire(tsdn, rtree_ctx, a, true, false, &a_elm_a, + &a_elm_b); + extent_rtree_acquire(tsdn, rtree_ctx, b, true, false, &b_elm_a, + &b_elm_b); if (a_elm_b != NULL) { rtree_elm_write_acquired(tsdn, &extents_rtree, a_elm_b, NULL); diff --git a/src/rtree.c b/src/rtree.c index b6027303..421de3e8 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -52,11 +52,12 @@ rtree_new(rtree_t *rtree, unsigned bits) rtree->levels[height-1].cumbits = bits; } - /* Compute lookup table to be used by rtree_start_level(). */ + /* Compute lookup table to be used by rtree_[ctx_]start_level(). */ for (i = 0; i < RTREE_HEIGHT_MAX; i++) { rtree->start_level[i] = hmin(RTREE_HEIGHT_MAX - 1 - i, height - 1); } + rtree->start_level[RTREE_HEIGHT_MAX] = 0; return (false); } diff --git a/test/unit/rtree.c b/test/unit/rtree.c index 786cc351..a05834fa 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -40,10 +40,11 @@ TEST_BEGIN(test_rtree_read_empty) for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) { rtree_t rtree; + rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; test_rtree = &rtree; assert_false(rtree_new(&rtree, i), "Unexpected rtree_new() failure"); - assert_ptr_null(rtree_read(tsdn, &rtree, 0, false), + assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, 0, false), "rtree_read() should return NULL for empty tree"); rtree_delete(tsdn, &rtree); test_rtree = NULL; @@ -66,7 +67,8 @@ static void * thd_start(void *varg) { thd_start_arg_t *arg = (thd_start_arg_t *)varg; - sfmt_t *sfmt; + rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; + sfmt_t *sfmt; extent_t *extent; tsdn_t *tsdn; unsigned i; @@ -81,21 +83,22 @@ thd_start(void *varg) if (i % 2 == 0) { rtree_elm_t *elm; - elm = rtree_elm_acquire(tsdn, &arg->rtree, key, false, - true); + elm = rtree_elm_acquire(tsdn, &arg->rtree, &rtree_ctx, + key, false, true); assert_ptr_not_null(elm, "Unexpected rtree_elm_acquire() failure"); - rtree_elm_write_acquired(tsdn, &arg->rtree, elm, extent); + rtree_elm_write_acquired(tsdn, &arg->rtree, elm, + extent); rtree_elm_release(tsdn, &arg->rtree, elm); - elm = rtree_elm_acquire(tsdn, &arg->rtree, key, true, - false); + elm = rtree_elm_acquire(tsdn, &arg->rtree, &rtree_ctx, + key, true, false); assert_ptr_not_null(elm, "Unexpected rtree_elm_acquire() failure"); rtree_elm_read_acquired(tsdn, &arg->rtree, elm); rtree_elm_release(tsdn, &arg->rtree, elm); } else - rtree_read(tsdn, &arg->rtree, key, false); + rtree_read(tsdn, &arg->rtree, &rtree_ctx, key, false); } free(extent); @@ -145,19 +148,22 @@ TEST_BEGIN(test_rtree_extrema) for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) { rtree_t rtree; + rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; test_rtree = &rtree; assert_false(rtree_new(&rtree, i), "Unexpected rtree_new() failure"); - assert_false(rtree_write(tsdn, &rtree, 0, &extent_a), - "Unexpected rtree_write() failure, i=%u", i); - assert_ptr_eq(rtree_read(tsdn, &rtree, 0, true), &extent_a, + assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, 0, + &extent_a), "Unexpected rtree_write() failure, i=%u", i); + assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, 0, true), + &extent_a, "rtree_read() should return previously set value, i=%u", i); - assert_false(rtree_write(tsdn, &rtree, ~((uintptr_t)0), - &extent_b), "Unexpected rtree_write() failure, i=%u", i); - assert_ptr_eq(rtree_read(tsdn, &rtree, ~((uintptr_t)0), true), - &extent_b, + assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, + ~((uintptr_t)0), &extent_b), + "Unexpected rtree_write() failure, i=%u", i); + assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, + ~((uintptr_t)0), true), &extent_b, "rtree_read() should return previously set value, i=%u", i); rtree_delete(tsdn, &rtree); @@ -178,27 +184,30 @@ TEST_BEGIN(test_rtree_bits) (((uintptr_t)1) << (sizeof(uintptr_t)*8-i)) - 1}; extent_t extent; rtree_t rtree; + rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; test_rtree = &rtree; assert_false(rtree_new(&rtree, i), "Unexpected rtree_new() failure"); for (j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) { - assert_false(rtree_write(tsdn, &rtree, keys[j], - &extent), "Unexpected rtree_write() failure"); + assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, + keys[j], &extent), + "Unexpected rtree_write() failure"); for (k = 0; k < sizeof(keys)/sizeof(uintptr_t); k++) { - assert_ptr_eq(rtree_read(tsdn, &rtree, keys[k], - true), &extent, "rtree_read() should " - "return previously set value and ignore " - "insignificant key bits; i=%u, j=%u, k=%u, " - "set key=%#"FMTxPTR", get key=%#"FMTxPTR, i, - j, k, keys[j], keys[k]); + assert_ptr_eq(rtree_read(tsdn, &rtree, + &rtree_ctx, keys[k], true), &extent, + "rtree_read() should return previously set " + "value and ignore insignificant key bits; " + "i=%u, j=%u, k=%u, set key=%#"FMTxPTR", " + "get key=%#"FMTxPTR, i, j, k, keys[j], + keys[k]); } - assert_ptr_null(rtree_read(tsdn, &rtree, + assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, (((uintptr_t)1) << (sizeof(uintptr_t)*8-i)), false), "Only leftmost rtree leaf should be set; " "i=%u, j=%u", i, j); - rtree_clear(tsdn, &rtree, keys[j]); + rtree_clear(tsdn, &rtree, &rtree_ctx, keys[j]); } rtree_delete(tsdn, &rtree); @@ -222,6 +231,7 @@ TEST_BEGIN(test_rtree_random) extent_t extent; unsigned j; rtree_t rtree; + rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; rtree_elm_t *elm; test_rtree = &rtree; @@ -230,29 +240,32 @@ TEST_BEGIN(test_rtree_random) for (j = 0; j < NSET; j++) { keys[j] = (uintptr_t)gen_rand64(sfmt); - elm = rtree_elm_acquire(tsdn, &rtree, keys[j], false, - true); + elm = rtree_elm_acquire(tsdn, &rtree, &rtree_ctx, + keys[j], false, true); assert_ptr_not_null(elm, "Unexpected rtree_elm_acquire() failure"); rtree_elm_write_acquired(tsdn, &rtree, elm, &extent); rtree_elm_release(tsdn, &rtree, elm); - assert_ptr_eq(rtree_read(tsdn, &rtree, keys[j], true), - &extent, + assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, + keys[j], true), &extent, "rtree_read() should return previously set value"); } for (j = 0; j < NSET; j++) { - assert_ptr_eq(rtree_read(tsdn, &rtree, keys[j], true), - &extent, "rtree_read() should return previously " - "set value, j=%u", j); + assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, + keys[j], true), &extent, + "rtree_read() should return previously set value, " + "j=%u", j); } for (j = 0; j < NSET; j++) { - rtree_clear(tsdn, &rtree, keys[j]); - assert_ptr_null(rtree_read(tsdn, &rtree, keys[j], true), + rtree_clear(tsdn, &rtree, &rtree_ctx, keys[j]); + assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, + keys[j], true), "rtree_read() should return previously set value"); } for (j = 0; j < NSET; j++) { - assert_ptr_null(rtree_read(tsdn, &rtree, keys[j], true), + assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, + keys[j], true), "rtree_read() should return previously set value"); } -- GitLab From f8f0542194e2a7fb0eff8a20143a26fe4a6ea6a5 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 3 Jun 2016 12:05:53 -0700 Subject: [PATCH 063/544] Modify extent hook functions to take an (extent_t *) argument. This facilitates the application accessing its own extent allocator metadata during hook invocations. This resolves #259. --- doc/jemalloc.xml.in | 14 +- include/jemalloc/internal/arena.h | 16 +- include/jemalloc/internal/extent.h | 33 +-- include/jemalloc/jemalloc_typedefs.h.in | 28 ++- src/arena.c | 48 ++-- src/ctl.c | 16 +- src/extent.c | 307 +++++++++++------------- src/extent_dss.c | 2 +- src/large.c | 4 +- test/integration/extent.c | 151 ++++++------ 10 files changed, 308 insertions(+), 311 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 74daf6a8..bfc0073b 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -1551,7 +1551,7 @@ malloc_conf = "xmalloc:true";]]> arena.<i>.extent_hooks - (extent_hooks_t) + (extent_hooks_t *) rw Get or set the extent management hook functions for @@ -1567,7 +1567,8 @@ malloc_conf = "xmalloc:true";]]> allocation. +};]]> The extent_hooks_t structure comprises function pointers which are described individually below. jemalloc uses these functions to manage extent lifetime, which starts off with allocation of @@ -1592,6 +1593,7 @@ typedef struct { typedef void *(extent_alloc_t) + extent_hooks_t *extent_hooks void *new_addr size_t size size_t alignment @@ -1627,6 +1629,7 @@ typedef struct { typedef bool (extent_dalloc_t) + extent_hooks_t *extent_hooks void *addr size_t size bool committed @@ -1646,6 +1649,7 @@ typedef struct { typedef bool (extent_commit_t) + extent_hooks_t *extent_hooks void *addr size_t size size_t offset @@ -1667,6 +1671,7 @@ typedef struct { typedef bool (extent_decommit_t) + extent_hooks_t *extent_hooks void *addr size_t size size_t offset @@ -1688,6 +1693,7 @@ typedef struct { typedef bool (extent_purge_t) + extent_hooks_t *extent_hooks void *addr size_tsize size_t offset @@ -1707,6 +1713,7 @@ typedef struct { typedef bool (extent_split_t) + extent_hooks_t *extent_hooks void *addr size_t size size_t size_a @@ -1728,6 +1735,7 @@ typedef struct { typedef bool (extent_merge_t) + extent_hooks_t *extent_hooks void *addr_a size_t size_a void *addr_b diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index fc0a755f..3c931c34 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -240,11 +240,15 @@ struct arena_s { */ extent_heap_t extents_cached[NPSIZES]; extent_heap_t extents_retained[NPSIZES]; - /* User-configurable extent hook functions. */ - extent_hooks_t extent_hooks; - /* Protects extents_cached, extents_retained, and extent_hooks. */ + /* Protects extents_cached and extents_retained. */ malloc_mutex_t extents_mtx; + /* User-configurable extent hook functions. */ + union { + extent_hooks_t *extent_hooks; + void *extent_hooks_pun; + }; + /* Cache of extent structures that were allocated via base_alloc(). */ ql_head(extent_t) extent_cache; malloc_mutex_t extent_cache_mtx; @@ -279,10 +283,10 @@ extern ssize_t opt_decay_time; extern const arena_bin_info_t arena_bin_info[NBINS]; extent_t *arena_extent_cache_alloc(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, void *new_addr, size_t size, size_t alignment, - bool *zero); + extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, + size_t alignment, bool *zero); void arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent); + extent_hooks_t **r_extent_hooks, extent_t *extent); void arena_extent_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache); void arena_extent_cache_maybe_remove(arena_t *arena, extent_t *extent, diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 8b8dbe80..6e155206 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -3,15 +3,7 @@ typedef struct extent_s extent_t; -#define EXTENT_HOOKS_INITIALIZER { \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ - NULL \ -} +#define EXTENT_HOOKS_INITIALIZER NULL #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ @@ -93,9 +85,8 @@ extern const extent_hooks_t extent_hooks_default; extent_t *extent_alloc(tsdn_t *tsdn, arena_t *arena); void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent); -extent_hooks_t extent_hooks_get(tsdn_t *tsdn, arena_t *arena); -extent_hooks_t extent_hooks_set(tsdn_t *tsdn, arena_t *arena, - const extent_hooks_t *extent_hooks); +extent_hooks_t *extent_hooks_get(arena_t *arena); +extent_hooks_t *extent_hooks_set(arena_t *arena, extent_hooks_t *extent_hooks); #ifdef JEMALLOC_JET typedef size_t (extent_size_quantize_t)(size_t); @@ -109,29 +100,29 @@ size_t extent_size_quantize_ceil(size_t size); ph_proto(, extent_heap_, extent_heap_t, extent_t) extent_t *extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool slab); extent_t *extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab); void extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent); + extent_hooks_t **r_extent_hooks, extent_t *extent); void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent); + extent_hooks_t **r_extent_hooks, extent_t *extent); bool extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length); bool extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length); bool extent_purge_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length); extent_t *extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent, size_t size_a, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a, size_t usize_a, size_t size_b, size_t usize_b); bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *a, extent_t *b); + extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b); void extent_prefork(tsdn_t *tsdn); void extent_postfork_parent(tsdn_t *tsdn); void extent_postfork_child(tsdn_t *tsdn); diff --git a/include/jemalloc/jemalloc_typedefs.h.in b/include/jemalloc/jemalloc_typedefs.h.in index 99f07ab2..e5ba7166 100644 --- a/include/jemalloc/jemalloc_typedefs.h.in +++ b/include/jemalloc/jemalloc_typedefs.h.in @@ -1,53 +1,61 @@ +typedef struct extent_hooks_s extent_hooks_t; + /* * void * * extent_alloc(void *new_addr, size_t size, size_t alignment, bool *zero, * bool *commit, unsigned arena_ind); */ -typedef void *(extent_alloc_t)(void *, size_t, size_t, bool *, bool *, - unsigned); +typedef void *(extent_alloc_t)(extent_hooks_t *, void *, size_t, size_t, bool *, + bool *, unsigned); /* * bool * extent_dalloc(void *addr, size_t size, bool committed, unsigned arena_ind); */ -typedef bool (extent_dalloc_t)(void *, size_t, bool, unsigned); +typedef bool (extent_dalloc_t)(extent_hooks_t *, void *, size_t, bool, + unsigned); /* * bool * extent_commit(void *addr, size_t size, size_t offset, size_t length, * unsigned arena_ind); */ -typedef bool (extent_commit_t)(void *, size_t, size_t, size_t, unsigned); +typedef bool (extent_commit_t)(extent_hooks_t *, void *, size_t, size_t, size_t, + unsigned); /* * bool * extent_decommit(void *addr, size_t size, size_t offset, size_t length, * unsigned arena_ind); */ -typedef bool (extent_decommit_t)(void *, size_t, size_t, size_t, unsigned); +typedef bool (extent_decommit_t)(extent_hooks_t *, void *, size_t, size_t, + size_t, unsigned); /* * bool * extent_purge(void *addr, size_t size, size_t offset, size_t length, * unsigned arena_ind); */ -typedef bool (extent_purge_t)(void *, size_t, size_t, size_t, unsigned); +typedef bool (extent_purge_t)(extent_hooks_t *, void *, size_t, size_t, size_t, + unsigned); /* * bool * extent_split(void *addr, size_t size, size_t size_a, size_t size_b, * bool committed, unsigned arena_ind); */ -typedef bool (extent_split_t)(void *, size_t, size_t, size_t, bool, unsigned); +typedef bool (extent_split_t)(extent_hooks_t *, void *, size_t, size_t, size_t, + bool, unsigned); /* * bool * extent_merge(void *addr_a, size_t size_a, void *addr_b, size_t size_b, * bool committed, unsigned arena_ind); */ -typedef bool (extent_merge_t)(void *, size_t, void *, size_t, bool, unsigned); +typedef bool (extent_merge_t)(extent_hooks_t *, void *, size_t, void *, size_t, + bool, unsigned); -typedef struct { +struct extent_hooks_s { extent_alloc_t *alloc; extent_dalloc_t *dalloc; extent_commit_t *commit; @@ -55,4 +63,4 @@ typedef struct { extent_purge_t *purge; extent_split_t *split; extent_merge_t *merge; -} extent_hooks_t; +}; diff --git a/src/arena.c b/src/arena.c index c77db5d0..32e1915c 100644 --- a/src/arena.c +++ b/src/arena.c @@ -54,25 +54,25 @@ arena_extent_dirty_npages(const extent_t *extent) static extent_t * arena_extent_cache_alloc_locked(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool slab) { malloc_mutex_assert_owner(tsdn, &arena->lock); - return (extent_alloc_cache(tsdn, arena, extent_hooks, new_addr, usize, + return (extent_alloc_cache(tsdn, arena, r_extent_hooks, new_addr, usize, pad, alignment, zero, slab)); } extent_t * arena_extent_cache_alloc(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, void *new_addr, size_t size, size_t alignment, - bool *zero) + extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, + size_t alignment, bool *zero) { extent_t *extent; malloc_mutex_lock(tsdn, &arena->lock); - extent = arena_extent_cache_alloc_locked(tsdn, arena, extent_hooks, + extent = arena_extent_cache_alloc_locked(tsdn, arena, r_extent_hooks, new_addr, size, 0, alignment, zero, false); malloc_mutex_unlock(tsdn, &arena->lock); @@ -81,22 +81,22 @@ arena_extent_cache_alloc(tsdn_t *tsdn, arena_t *arena, static void arena_extent_cache_dalloc_locked(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent) + extent_hooks_t **r_extent_hooks, extent_t *extent) { malloc_mutex_assert_owner(tsdn, &arena->lock); - extent_dalloc_cache(tsdn, arena, extent_hooks, extent); + extent_dalloc_cache(tsdn, arena, r_extent_hooks, extent); arena_maybe_purge(tsdn, arena); } void arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent) + extent_hooks_t **r_extent_hooks, extent_t *extent) { malloc_mutex_lock(tsdn, &arena->lock); - arena_extent_cache_dalloc_locked(tsdn, arena, extent_hooks, extent); + arena_extent_cache_dalloc_locked(tsdn, arena, r_extent_hooks, extent); malloc_mutex_unlock(tsdn, &arena->lock); } @@ -321,12 +321,12 @@ arena_large_ralloc_stats_update(arena_t *arena, size_t oldusize, size_t usize) static extent_t * arena_extent_alloc_large_hard(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, size_t usize, size_t alignment, bool *zero) + extent_hooks_t **r_extent_hooks, size_t usize, size_t alignment, bool *zero) { extent_t *extent; bool commit = true; - extent = extent_alloc_wrapper(tsdn, arena, extent_hooks, NULL, usize, + extent = extent_alloc_wrapper(tsdn, arena, r_extent_hooks, NULL, usize, large_pad, alignment, zero, &commit, false); if (extent == NULL) { /* Revert optimistic stats updates. */ @@ -347,7 +347,7 @@ arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero) { extent_t *extent; - extent_hooks_t extent_hooks = EXTENT_HOOKS_INITIALIZER; + extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; malloc_mutex_lock(tsdn, &arena->lock); @@ -373,7 +373,7 @@ void arena_extent_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, bool locked) { - extent_hooks_t extent_hooks = EXTENT_HOOKS_INITIALIZER; + extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; if (!locked) malloc_mutex_lock(tsdn, &arena->lock); @@ -735,7 +735,7 @@ arena_dirty_count(tsdn_t *tsdn, arena_t *arena) } static size_t -arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, +arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, size_t ndirty_limit, extent_t *purge_extents_sentinel) { extent_t *extent, *next; @@ -757,7 +757,7 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, /* Allocate. */ zero = false; textent = arena_extent_cache_alloc_locked(tsdn, arena, - extent_hooks, extent_base_get(extent), + r_extent_hooks, extent_base_get(extent), extent_size_get(extent), 0, CACHELINE, &zero, false); assert(textent == extent); assert(zero == extent_zeroed_get(extent)); @@ -774,8 +774,8 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, } static size_t -arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_t *purge_extents_sentinel) +arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *purge_extents_sentinel) { UNUSED size_t nmadvise; size_t npurged; @@ -793,7 +793,7 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, next = qr_next(extent, qr_link); extent_ring_remove(extent); - extent_dalloc_wrapper(tsdn, arena, extent_hooks, extent); + extent_dalloc_wrapper(tsdn, arena, r_extent_hooks, extent); } if (config_stats) { @@ -816,7 +816,7 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, static void arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) { - extent_hooks_t extent_hooks = extent_hooks_get(tsdn, arena); + extent_hooks_t *extent_hooks = extent_hooks_get(arena); size_t npurge, npurged; extent_t purge_extents_sentinel; @@ -866,7 +866,7 @@ arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) static void arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) { - extent_hooks_t extent_hooks = EXTENT_HOOKS_INITIALIZER; + extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; arena_nactive_sub(arena, extent_size_get(slab) >> LG_PAGE); arena_extent_cache_dalloc_locked(tsdn, arena, &extent_hooks, slab); @@ -988,7 +988,7 @@ arena_bin_slabs_full_remove(extent_t *slab) static extent_t * arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, const arena_bin_info_t *bin_info) + extent_hooks_t **r_extent_hooks, const arena_bin_info_t *bin_info) { extent_t *slab; bool zero, commit; @@ -996,7 +996,7 @@ arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, zero = false; commit = true; malloc_mutex_unlock(tsdn, &arena->lock); - slab = extent_alloc_wrapper(tsdn, arena, extent_hooks, NULL, + slab = extent_alloc_wrapper(tsdn, arena, r_extent_hooks, NULL, bin_info->slab_size, 0, PAGE, &zero, &commit, true); malloc_mutex_lock(tsdn, &arena->lock); @@ -1009,7 +1009,7 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, { extent_t *slab; arena_slab_data_t *slab_data; - extent_hooks_t extent_hooks = EXTENT_HOOKS_INITIALIZER; + extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; bool zero; zero = false; @@ -1796,7 +1796,7 @@ arena_new(tsdn_t *tsdn, unsigned ind) extent_heap_new(&arena->extents_retained[i]); } - arena->extent_hooks = extent_hooks_default; + arena->extent_hooks = (extent_hooks_t *)&extent_hooks_default; if (malloc_mutex_init(&arena->extents_mtx, "arena_extents", WITNESS_RANK_ARENA_EXTENTS)) diff --git a/src/ctl.c b/src/ctl.c index b91ea135..813d5fab 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1646,15 +1646,15 @@ arena_i_extent_hooks_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, if (arena_ind < narenas_total_get() && (arena = arena_get(tsd_tsdn(tsd), arena_ind, false)) != NULL) { if (newp != NULL) { - extent_hooks_t old_extent_hooks, new_extent_hooks; - WRITE(new_extent_hooks, extent_hooks_t); - old_extent_hooks = extent_hooks_set(tsd_tsdn(tsd), - arena, &new_extent_hooks); - READ(old_extent_hooks, extent_hooks_t); + extent_hooks_t *old_extent_hooks, *new_extent_hooks; + WRITE(new_extent_hooks, extent_hooks_t *); + old_extent_hooks = extent_hooks_set(arena, + new_extent_hooks); + READ(old_extent_hooks, extent_hooks_t *); } else { - extent_hooks_t old_extent_hooks = - extent_hooks_get(tsd_tsdn(tsd), arena); - READ(old_extent_hooks, extent_hooks_t); + extent_hooks_t *old_extent_hooks = + extent_hooks_get(arena); + READ(old_extent_hooks, extent_hooks_t *); } } else { ret = EFAULT; diff --git a/src/extent.c b/src/extent.c index 0c41c066..0c66e31a 100644 --- a/src/extent.c +++ b/src/extent.c @@ -6,20 +6,23 @@ rtree_t extents_rtree; -static void *extent_alloc_default(void *new_addr, size_t size, - size_t alignment, bool *zero, bool *commit, unsigned arena_ind); -static bool extent_dalloc_default(void *addr, size_t size, bool committed, +static void *extent_alloc_default(extent_hooks_t *extent_hooks, + void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit, + unsigned arena_ind); +static bool extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, + size_t size, bool committed, unsigned arena_ind); +static bool extent_commit_default(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t offset, size_t length, unsigned arena_ind); +static bool extent_decommit_default(extent_hooks_t *extent_hooks, + void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); +static bool extent_purge_default(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t offset, size_t length, unsigned arena_ind); +static bool extent_split_default(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t size_a, size_t size_b, bool committed, + unsigned arena_ind); +static bool extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, + size_t size_a, void *addr_b, size_t size_b, bool committed, unsigned arena_ind); -static bool extent_commit_default(void *addr, size_t size, size_t offset, - size_t length, unsigned arena_ind); -static bool extent_decommit_default(void *addr, size_t size, size_t offset, - size_t length, unsigned arena_ind); -static bool extent_purge_default(void *addr, size_t size, size_t offset, - size_t length, unsigned arena_ind); -static bool extent_split_default(void *addr, size_t size, size_t size_a, - size_t size_b, bool committed, unsigned arena_ind); -static bool extent_merge_default(void *addr_a, size_t size_a, void *addr_b, - size_t size_b, bool committed, unsigned arena_ind); const extent_hooks_t extent_hooks_default = { extent_alloc_default, @@ -42,7 +45,7 @@ static size_t highchunks; */ static void extent_record(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_heap_t extent_heaps[NPSIZES], + extent_hooks_t **r_extent_hooks, extent_heap_t extent_heaps[NPSIZES], bool cache, extent_t *extent); /******************************************************************************/ @@ -73,89 +76,34 @@ extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); } -static extent_hooks_t -extent_hooks_get_locked(arena_t *arena) -{ - - return (arena->extent_hooks); -} - -extent_hooks_t -extent_hooks_get(tsdn_t *tsdn, arena_t *arena) +extent_hooks_t * +extent_hooks_get(arena_t *arena) { - extent_hooks_t extent_hooks; - malloc_mutex_lock(tsdn, &arena->extents_mtx); - extent_hooks = extent_hooks_get_locked(arena); - malloc_mutex_unlock(tsdn, &arena->extents_mtx); - - return (extent_hooks); + return ((extent_hooks_t *)atomic_read_p(&arena->extent_hooks_pun)); } -extent_hooks_t -extent_hooks_set(tsdn_t *tsdn, arena_t *arena, - const extent_hooks_t *extent_hooks) +extent_hooks_t * +extent_hooks_set(arena_t *arena, extent_hooks_t *extent_hooks) { - extent_hooks_t old_extent_hooks; + extent_hooks_t *old_extent_hooks = extent_hooks_get(arena); + union { + extent_hooks_t **h; + void **v; + } u; - malloc_mutex_lock(tsdn, &arena->extents_mtx); - old_extent_hooks = arena->extent_hooks; - /* - * Copy each field atomically so that it is impossible for readers to - * see partially updated pointers. There are places where readers only - * need one hook function pointer (therefore no need to copy the - * entirety of arena->extent_hooks), and stale reads do not affect - * correctness, so they perform unlocked reads. - */ -#define ATOMIC_COPY_HOOK(n) do { \ - union { \ - extent_##n##_t **n; \ - void **v; \ - } u; \ - u.n = &arena->extent_hooks.n; \ - atomic_write_p(u.v, extent_hooks->n); \ -} while (0) - ATOMIC_COPY_HOOK(alloc); - ATOMIC_COPY_HOOK(dalloc); - ATOMIC_COPY_HOOK(commit); - ATOMIC_COPY_HOOK(decommit); - ATOMIC_COPY_HOOK(purge); - ATOMIC_COPY_HOOK(split); - ATOMIC_COPY_HOOK(merge); -#undef ATOMIC_COPY_HOOK - malloc_mutex_unlock(tsdn, &arena->extents_mtx); + u.h = &arena->extent_hooks; + atomic_write_p(u.v, extent_hooks); return (old_extent_hooks); } static void -extent_hooks_assure_initialized_impl(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, bool locked) -{ - static const extent_hooks_t uninitialized_hooks = - EXTENT_HOOKS_INITIALIZER; - - if (memcmp(extent_hooks, &uninitialized_hooks, sizeof(extent_hooks_t)) - == 0) { - *extent_hooks = locked ? extent_hooks_get_locked(arena) : - extent_hooks_get(tsdn, arena); - } -} - -static void -extent_hooks_assure_initialized_locked(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks) +extent_hooks_assure_initialized(arena_t *arena, extent_hooks_t **r_extent_hooks) { - extent_hooks_assure_initialized_impl(tsdn, arena, extent_hooks, true); -} - -static void -extent_hooks_assure_initialized(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks) -{ - - extent_hooks_assure_initialized_impl(tsdn, arena, extent_hooks, false); + if (*r_extent_hooks == EXTENT_HOOKS_INITIALIZER) + *r_extent_hooks = extent_hooks_get(arena); } #ifdef JEMALLOC_JET @@ -409,7 +357,7 @@ extent_first_best_fit(arena_t *arena, extent_heap_t extent_heaps[NPSIZES], } static void -extent_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, +extent_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, bool cache, extent_t *extent) { @@ -418,14 +366,14 @@ extent_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, * that this is only a virtual memory leak. */ if (cache) { - extent_purge_wrapper(tsdn, arena, extent_hooks, extent, 0, + extent_purge_wrapper(tsdn, arena, r_extent_hooks, extent, 0, extent_size_get(extent)); } extent_dalloc(tsdn, arena, extent); } static extent_t * -extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, +extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_heap_t extent_heaps[NPSIZES], bool cache, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) @@ -444,7 +392,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, if (alloc_size < usize) return (NULL); malloc_mutex_lock(tsdn, &arena->extents_mtx); - extent_hooks_assure_initialized_locked(tsdn, arena, extent_hooks); + extent_hooks_assure_initialized(arena, r_extent_hooks); if (new_addr != NULL) { rtree_elm_t *elm; @@ -482,10 +430,11 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, /* Split the lead. */ if (leadsize != 0) { extent_t *lead = extent; - extent = extent_split_wrapper(tsdn, arena, extent_hooks, lead, - leadsize, leadsize, size + trailsize, usize + trailsize); + extent = extent_split_wrapper(tsdn, arena, r_extent_hooks, + lead, leadsize, leadsize, size + trailsize, usize + + trailsize); if (extent == NULL) { - extent_leak(tsdn, arena, extent_hooks, cache, lead); + extent_leak(tsdn, arena, r_extent_hooks, cache, lead); malloc_mutex_unlock(tsdn, &arena->extents_mtx); return (NULL); } @@ -496,9 +445,10 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, /* Split the trail. */ if (trailsize != 0) { extent_t *trail = extent_split_wrapper(tsdn, arena, - extent_hooks, extent, size, usize, trailsize, trailsize); + r_extent_hooks, extent, size, usize, trailsize, trailsize); if (trail == NULL) { - extent_leak(tsdn, arena, extent_hooks, cache, extent); + extent_leak(tsdn, arena, r_extent_hooks, cache, + extent); malloc_mutex_unlock(tsdn, &arena->extents_mtx); return (NULL); } @@ -513,10 +463,10 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, } if (!extent_committed_get(extent) && - extent_hooks->commit(extent_base_get(extent), + (*r_extent_hooks)->commit(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), 0, extent_size_get(extent), arena->ind)) { malloc_mutex_unlock(tsdn, &arena->extents_mtx); - extent_record(tsdn, arena, extent_hooks, extent_heaps, cache, + extent_record(tsdn, arena, r_extent_hooks, extent_heaps, cache, extent); return (NULL); } @@ -582,9 +532,9 @@ extent_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, } extent_t * -extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, - bool slab) +extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool slab) { extent_t *extent; bool commit; @@ -593,7 +543,7 @@ extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, assert(alignment != 0); commit = true; - extent = extent_recycle(tsdn, arena, extent_hooks, + extent = extent_recycle(tsdn, arena, r_extent_hooks, arena->extents_cached, true, new_addr, usize, pad, alignment, zero, &commit, slab); if (extent == NULL) @@ -603,13 +553,15 @@ extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, } static void * -extent_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero, - bool *commit, unsigned arena_ind) +extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, size_t size, + size_t alignment, bool *zero, bool *commit, unsigned arena_ind) { void *ret; tsdn_t *tsdn; arena_t *arena; + assert(extent_hooks == &extent_hooks_default); + tsdn = tsdn_fetch(); arena = arena_get(tsdn, arena_ind, false); /* @@ -627,7 +579,7 @@ extent_alloc_default(void *new_addr, size_t size, size_t alignment, bool *zero, static extent_t * extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) { extent_t *extent; @@ -635,7 +587,7 @@ extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, assert(usize != 0); assert(alignment != 0); - extent = extent_recycle(tsdn, arena, extent_hooks, + extent = extent_recycle(tsdn, arena, r_extent_hooks, arena->extents_retained, false, new_addr, usize, pad, alignment, zero, commit, slab); if (extent != NULL && config_stats) { @@ -648,7 +600,7 @@ extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, static extent_t * extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, void *new_addr, size_t usize, size_t pad, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) { extent_t *extent; @@ -659,8 +611,8 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, extent = extent_alloc(tsdn, arena); if (extent == NULL) return (NULL); - addr = extent_hooks->alloc(new_addr, size, alignment, zero, commit, - arena->ind); + addr = (*r_extent_hooks)->alloc(*r_extent_hooks, new_addr, size, + alignment, zero, commit, arena->ind); if (addr == NULL) { extent_dalloc(tsdn, arena, extent); return (NULL); @@ -669,7 +621,7 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, if (pad != 0) extent_addr_randomize(tsdn, extent, alignment); if (extent_register(tsdn, extent)) { - extent_leak(tsdn, arena, extent_hooks, false, extent); + extent_leak(tsdn, arena, r_extent_hooks, false, extent); return (NULL); } @@ -677,18 +629,18 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, } extent_t * -extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, - bool *commit, bool slab) +extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool *commit, bool slab) { extent_t *extent; - extent_hooks_assure_initialized(tsdn, arena, extent_hooks); + extent_hooks_assure_initialized(arena, r_extent_hooks); - extent = extent_alloc_retained(tsdn, arena, extent_hooks, new_addr, + extent = extent_alloc_retained(tsdn, arena, r_extent_hooks, new_addr, usize, pad, alignment, zero, commit, slab); if (extent == NULL) { - extent = extent_alloc_wrapper_hard(tsdn, arena, extent_hooks, + extent = extent_alloc_wrapper_hard(tsdn, arena, r_extent_hooks, new_addr, usize, pad, alignment, zero, commit, slab); } @@ -712,8 +664,9 @@ extent_can_coalesce(const extent_t *a, const extent_t *b) } static void -extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_t *a, extent_t *b, extent_heap_t extent_heaps[NPSIZES], bool cache) +extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b, + extent_heap_t extent_heaps[NPSIZES], bool cache) { if (!extent_can_coalesce(a, b)) @@ -725,7 +678,7 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, arena_extent_cache_maybe_remove(extent_arena_get(a), a, cache); arena_extent_cache_maybe_remove(extent_arena_get(b), b, cache); - if (extent_merge_wrapper(tsdn, arena, extent_hooks, a, b)) { + if (extent_merge_wrapper(tsdn, arena, r_extent_hooks, a, b)) { extent_heaps_insert(extent_heaps, a); extent_heaps_insert(extent_heaps, b); arena_extent_cache_maybe_insert(extent_arena_get(a), a, cache); @@ -738,7 +691,7 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, } static void -extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, +extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_heap_t extent_heaps[NPSIZES], bool cache, extent_t *extent) { extent_t *prev, *next; @@ -748,7 +701,7 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, assert(!cache || !extent_zeroed_get(extent)); malloc_mutex_lock(tsdn, &arena->extents_mtx); - extent_hooks_assure_initialized_locked(tsdn, arena, extent_hooks); + extent_hooks_assure_initialized(arena, r_extent_hooks); extent_usize_set(extent, 0); extent_active_set(extent, false); @@ -766,7 +719,7 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, next = rtree_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_past_get(extent), false); if (next != NULL) { - extent_try_coalesce(tsdn, arena, extent_hooks, extent, next, + extent_try_coalesce(tsdn, arena, r_extent_hooks, extent, next, extent_heaps, cache); } @@ -774,7 +727,7 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, prev = rtree_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_before_get(extent), false); if (prev != NULL) { - extent_try_coalesce(tsdn, arena, extent_hooks, prev, extent, + extent_try_coalesce(tsdn, arena, r_extent_hooks, prev, extent, extent_heaps, cache); } @@ -782,8 +735,8 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, } void -extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_t *extent) +extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent) { assert(extent_base_get(extent) != NULL); @@ -792,15 +745,17 @@ extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, extent_addr_set(extent, extent_base_get(extent)); extent_zeroed_set(extent, false); - extent_record(tsdn, arena, extent_hooks, arena->extents_cached, true, + extent_record(tsdn, arena, r_extent_hooks, arena->extents_cached, true, extent); } static bool -extent_dalloc_default(void *addr, size_t size, bool committed, - unsigned arena_ind) +extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, size_t size, + bool committed, unsigned arena_ind) { + assert(extent_hooks == &extent_hooks_default); + if (!have_dss || !extent_in_dss(tsdn_fetch(), addr)) return (extent_dalloc_mmap(addr, size)); return (true); @@ -808,7 +763,7 @@ extent_dalloc_default(void *addr, size_t size, bool committed, void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent) + extent_hooks_t **r_extent_hooks, extent_t *extent) { assert(extent_base_get(extent) != NULL); @@ -816,9 +771,9 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_addr_set(extent, extent_base_get(extent)); - extent_hooks_assure_initialized(tsdn, arena, extent_hooks); + extent_hooks_assure_initialized(arena, r_extent_hooks); /* Try to deallocate. */ - if (!extent_hooks->dalloc(extent_base_get(extent), + if (!(*r_extent_hooks)->dalloc(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), extent_committed_get(extent), arena->ind)) { extent_deregister(tsdn, extent); @@ -828,66 +783,73 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, /* Try to decommit; purge if that fails. */ if (extent_committed_get(extent)) { extent_committed_set(extent, - extent_hooks->decommit(extent_base_get(extent), - extent_size_get(extent), 0, extent_size_get(extent), - arena->ind)); + (*r_extent_hooks)->decommit(*r_extent_hooks, + extent_base_get(extent), extent_size_get(extent), 0, + extent_size_get(extent), arena->ind)); } extent_zeroed_set(extent, !extent_committed_get(extent) || - !extent_hooks->purge(extent_base_get(extent), + !(*r_extent_hooks)->purge(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), 0, extent_size_get(extent), arena->ind)); if (config_stats) arena->stats.retained += extent_size_get(extent); - extent_record(tsdn, arena, extent_hooks, arena->extents_retained, false, - extent); + extent_record(tsdn, arena, r_extent_hooks, arena->extents_retained, + false, extent); } static bool -extent_commit_default(void *addr, size_t size, size_t offset, size_t length, - unsigned arena_ind) +extent_commit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t offset, size_t length, unsigned arena_ind) { + assert(extent_hooks == &extent_hooks_default); + return (pages_commit((void *)((uintptr_t)addr + (uintptr_t)offset), length)); } bool extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { - extent_hooks_assure_initialized(tsdn, arena, extent_hooks); - return (extent_hooks->commit(extent_base_get(extent), - extent_size_get(extent), offset, length, arena->ind)); + extent_hooks_assure_initialized(arena, r_extent_hooks); + return ((*r_extent_hooks)->commit(*r_extent_hooks, + extent_base_get(extent), extent_size_get(extent), offset, length, + arena->ind)); } static bool -extent_decommit_default(void *addr, size_t size, size_t offset, size_t length, - unsigned arena_ind) +extent_decommit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t offset, size_t length, unsigned arena_ind) { + assert(extent_hooks == &extent_hooks_default); + return (pages_decommit((void *)((uintptr_t)addr + (uintptr_t)offset), length)); } bool extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t *extent_hooks, extent_t *extent, size_t offset, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { - extent_hooks_assure_initialized(tsdn, arena, extent_hooks); - return (extent_hooks->decommit(extent_base_get(extent), - extent_size_get(extent), offset, length, arena->ind)); + extent_hooks_assure_initialized(arena, r_extent_hooks); + return ((*r_extent_hooks)->decommit(*r_extent_hooks, + extent_base_get(extent), extent_size_get(extent), offset, length, + arena->ind)); } static bool -extent_purge_default(void *addr, size_t size, size_t offset, size_t length, - unsigned arena_ind) +extent_purge_default(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t offset, size_t length, unsigned arena_ind) { + assert(extent_hooks == &extent_hooks_default); assert(addr != NULL); assert((offset & PAGE_MASK) == 0); assert(length != 0); @@ -898,29 +860,33 @@ extent_purge_default(void *addr, size_t size, size_t offset, size_t length, } bool -extent_purge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_t *extent, size_t offset, size_t length) +extent_purge_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, + size_t length) { - extent_hooks_assure_initialized(tsdn, arena, extent_hooks); - return (extent_hooks->purge(extent_base_get(extent), - extent_size_get(extent), offset, length, arena->ind)); + extent_hooks_assure_initialized(arena, r_extent_hooks); + return ((*r_extent_hooks)->purge(*r_extent_hooks, + extent_base_get(extent), extent_size_get(extent), offset, length, + arena->ind)); } static bool -extent_split_default(void *addr, size_t size, size_t size_a, size_t size_b, - bool committed, unsigned arena_ind) +extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t size_a, size_t size_b, bool committed, unsigned arena_ind) { + assert(extent_hooks == &extent_hooks_default); + if (!maps_coalesce) return (true); return (false); } extent_t * -extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_t *extent, size_t size_a, size_t usize_a, size_t size_b, - size_t usize_b) +extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a, + size_t usize_a, size_t size_b, size_t usize_b) { extent_t *trail; rtree_ctx_t rtree_ctx_fallback; @@ -929,7 +895,7 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, assert(extent_size_get(extent) == size_a + size_b); - extent_hooks_assure_initialized(tsdn, arena, extent_hooks); + extent_hooks_assure_initialized(arena, r_extent_hooks); trail = extent_alloc(tsdn, arena); if (trail == NULL) @@ -956,8 +922,9 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, &trail_elm_a, &trail_elm_b)) goto label_error_c; - if (extent_hooks->split(extent_base_get(extent), size_a + size_b, - size_a, size_b, extent_committed_get(extent), arena->ind)) + if ((*r_extent_hooks)->split(*r_extent_hooks, extent_base_get(extent), + size_a + size_b, size_a, size_b, extent_committed_get(extent), + arena->ind)) goto label_error_d; extent_size_set(extent, size_a); @@ -981,10 +948,12 @@ label_error_a: } static bool -extent_merge_default(void *addr_a, size_t size_a, void *addr_b, size_t size_b, - bool committed, unsigned arena_ind) +extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, + void *addr_b, size_t size_b, bool committed, unsigned arena_ind) { + assert(extent_hooks == &extent_hooks_default); + if (!maps_coalesce) return (true); if (have_dss) { @@ -997,17 +966,17 @@ extent_merge_default(void *addr_a, size_t size_a, void *addr_b, size_t size_b, } bool -extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t *extent_hooks, - extent_t *a, extent_t *b) +extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b) { rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; - extent_hooks_assure_initialized(tsdn, arena, extent_hooks); - if (extent_hooks->merge(extent_base_get(a), extent_size_get(a), - extent_base_get(b), extent_size_get(b), extent_committed_get(a), - arena->ind)) + extent_hooks_assure_initialized(arena, r_extent_hooks); + if ((*r_extent_hooks)->merge(*r_extent_hooks, extent_base_get(a), + extent_size_get(a), extent_base_get(b), extent_size_get(b), + extent_committed_get(a), arena->ind)) return (true); /* diff --git a/src/extent_dss.c b/src/extent_dss.c index 0e34a440..9cc1d8f7 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -136,7 +136,7 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, dss_max = dss_next; malloc_mutex_unlock(tsdn, &dss_mtx); if (pad_size != 0) { - extent_hooks_t extent_hooks = + extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; extent_dalloc_wrapper(tsdn, arena, &extent_hooks, pad); diff --git a/src/large.c b/src/large.c index 952d4644..5c7b4453 100644 --- a/src/large.c +++ b/src/large.c @@ -96,7 +96,7 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { arena_t *arena = extent_arena_get(extent); size_t oldusize = extent_usize_get(extent); - extent_hooks_t extent_hooks = extent_hooks_get(tsdn, arena); + extent_hooks_t *extent_hooks = extent_hooks_get(arena); size_t diff = extent_size_get(extent) - (usize + large_pad); assert(oldusize > usize); @@ -129,7 +129,7 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, arena_t *arena = extent_arena_get(extent); size_t oldusize = extent_usize_get(extent); bool is_zeroed_trail = false; - extent_hooks_t extent_hooks = extent_hooks_get(tsdn, arena); + extent_hooks_t *extent_hooks = extent_hooks_get(arena); size_t trailsize = usize - extent_usize_get(extent); extent_t *trail; diff --git a/test/integration/extent.c b/test/integration/extent.c index 15b96a00..78176711 100644 --- a/test/integration/extent.c +++ b/test/integration/extent.c @@ -4,8 +4,8 @@ const char *malloc_conf = "junk:false"; #endif -static extent_hooks_t orig_hooks; -static extent_hooks_t old_hooks; +static extent_hooks_t *orig_hooks; +static extent_hooks_t *old_hooks; static bool do_dalloc = true; static bool do_decommit; @@ -24,96 +24,111 @@ static bool did_merge; # define TRACE_HOOK(fmt, ...) #endif -void * -extent_alloc(void *new_addr, size_t size, size_t alignment, bool *zero, - bool *commit, unsigned arena_ind) +static void * +extent_alloc(extent_hooks_t *extent_hooks, void *new_addr, size_t size, + size_t alignment, bool *zero, bool *commit, unsigned arena_ind) { - TRACE_HOOK("%s(new_addr=%p, size=%zu, alignment=%zu, *zero=%s, " - "*commit=%s, arena_ind=%u)\n", __func__, new_addr, size, alignment, - *zero ? "true" : "false", *commit ? "true" : "false", arena_ind); + TRACE_HOOK("%s(extent_hooks=%p, new_addr=%p, size=%zu, alignment=%zu, " + "*zero=%s, *commit=%s, arena_ind=%u)\n", __func__, extent_hooks, + new_addr, size, alignment, *zero ? "true" : "false", *commit ? + "true" : "false", arena_ind); + assert(extent_hooks->alloc == extent_alloc); did_alloc = true; - return (old_hooks.alloc(new_addr, size, alignment, zero, commit, - arena_ind)); + return (old_hooks->alloc(old_hooks, new_addr, size, alignment, zero, + commit, arena_ind)); } -bool -extent_dalloc(void *addr, size_t size, bool committed, unsigned arena_ind) +static bool +extent_dalloc(extent_hooks_t *extent_hooks, void *addr, size_t size, + bool committed, unsigned arena_ind) { - TRACE_HOOK("%s(addr=%p, size=%zu, committed=%s, arena_ind=%u)\n", - __func__, addr, size, committed ? "true" : "false", arena_ind); + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, " + "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ? + "true" : "false", arena_ind); + assert(extent_hooks->dalloc == extent_dalloc); did_dalloc = true; if (!do_dalloc) return (true); - return (old_hooks.dalloc(addr, size, committed, arena_ind)); + return (old_hooks->dalloc(old_hooks, addr, size, committed, arena_ind)); } -bool -extent_commit(void *addr, size_t size, size_t offset, size_t length, - unsigned arena_ind) +static bool +extent_commit(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t offset, size_t length, unsigned arena_ind) { bool err; - TRACE_HOOK("%s(addr=%p, size=%zu, offset=%zu, length=%zu, " - "arena_ind=%u)\n", __func__, addr, size, offset, length, + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " + "length=%zu, arena_ind=%u)\n", __func__, extent_hooks, addr, size, + offset, length, arena_ind); + assert(extent_hooks->commit == extent_commit); + err = old_hooks->commit(old_hooks, addr, size, offset, length, arena_ind); - err = old_hooks.commit(addr, size, offset, length, arena_ind); did_commit = !err; return (err); } -bool -extent_decommit(void *addr, size_t size, size_t offset, size_t length, - unsigned arena_ind) +static bool +extent_decommit(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t offset, size_t length, unsigned arena_ind) { bool err; - TRACE_HOOK("%s(addr=%p, size=%zu, offset=%zu, length=%zu, " - "arena_ind=%u)\n", __func__, addr, size, offset, length, - arena_ind); + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " + "length=%zu, arena_ind=%u)\n", __func__, extent_hooks, addr, size, + offset, length, arena_ind); + assert(extent_hooks->decommit == extent_decommit); if (!do_decommit) return (true); - err = old_hooks.decommit(addr, size, offset, length, arena_ind); + err = old_hooks->decommit(old_hooks, addr, size, offset, length, + arena_ind); did_decommit = !err; return (err); } -bool -extent_purge(void *addr, size_t size, size_t offset, size_t length, - unsigned arena_ind) +static bool +extent_purge(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t offset, size_t length, unsigned arena_ind) { - TRACE_HOOK("%s(addr=%p, size=%zu, offset=%zu, length=%zu " - "arena_ind=%u)\n", __func__, addr, size, offset, length, - arena_ind); + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " + "length=%zu arena_ind=%u)\n", __func__, extent_hooks, addr, size, + offset, length, arena_ind); + assert(extent_hooks->purge == extent_purge); did_purge = true; - return (old_hooks.purge(addr, size, offset, length, arena_ind)); + return (old_hooks->purge(old_hooks, addr, size, offset, length, + arena_ind)); } -bool -extent_split(void *addr, size_t size, size_t size_a, size_t size_b, - bool committed, unsigned arena_ind) +static bool +extent_split(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t size_a, size_t size_b, bool committed, unsigned arena_ind) { - TRACE_HOOK("%s(addr=%p, size=%zu, size_a=%zu, size_b=%zu, " - "committed=%s, arena_ind=%u)\n", __func__, addr, size, size_a, - size_b, committed ? "true" : "false", arena_ind); + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, size_a=%zu, " + "size_b=%zu, committed=%s, arena_ind=%u)\n", __func__, extent_hooks, + addr, size, size_a, size_b, committed ? "true" : "false", + arena_ind); + assert(extent_hooks->split == extent_split); did_split = true; - return (old_hooks.split(addr, size, size_a, size_b, committed, - arena_ind)); + return (old_hooks->split(old_hooks, addr, size, size_a, size_b, + committed, arena_ind)); } -bool -extent_merge(void *addr_a, size_t size_a, void *addr_b, size_t size_b, - bool committed, unsigned arena_ind) +static bool +extent_merge(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, + void *addr_b, size_t size_b, bool committed, unsigned arena_ind) { - TRACE_HOOK("%s(addr_a=%p, size_a=%zu, addr_b=%p size_b=%zu, " - "committed=%s, arena_ind=%u)\n", __func__, addr_a, size_a, addr_b, - size_b, committed ? "true" : "false", arena_ind); + TRACE_HOOK("%s(extent_hooks=%p, addr_a=%p, size_a=%zu, addr_b=%p " + "size_b=%zu, committed=%s, arena_ind=%u)\n", __func__, extent_hooks, + addr_a, size_a, addr_b, size_b, committed ? "true" : "false", + arena_ind); + assert(extent_hooks->merge == extent_merge); did_merge = true; - return (old_hooks.merge(addr_a, size_a, addr_b, size_b, + return (old_hooks->merge(old_hooks, addr_a, size_a, addr_b, size_b, committed, arena_ind)); } @@ -125,7 +140,7 @@ TEST_BEGIN(test_extent) int flags; size_t hooks_mib[3], purge_mib[3]; size_t hooks_miblen, purge_miblen; - extent_hooks_t new_hooks = { + extent_hooks_t hooks = { extent_alloc, extent_dalloc, extent_commit, @@ -134,6 +149,7 @@ TEST_BEGIN(test_extent) extent_split, extent_merge }; + extent_hooks_t *new_hooks = &hooks; bool xallocx_success_a, xallocx_success_b, xallocx_success_c; sz = sizeof(unsigned); @@ -146,21 +162,21 @@ TEST_BEGIN(test_extent) assert_d_eq(mallctlnametomib("arena.0.extent_hooks", hooks_mib, &hooks_miblen), 0, "Unexpected mallctlnametomib() failure"); hooks_mib[1] = (size_t)arena_ind; - old_size = sizeof(extent_hooks_t); - new_size = sizeof(extent_hooks_t); + old_size = sizeof(extent_hooks_t *); + new_size = sizeof(extent_hooks_t *); assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, &old_hooks, &old_size, &new_hooks, new_size), 0, "Unexpected extent_hooks error"); orig_hooks = old_hooks; - assert_ptr_ne(old_hooks.alloc, extent_alloc, "Unexpected alloc error"); - assert_ptr_ne(old_hooks.dalloc, extent_dalloc, + assert_ptr_ne(old_hooks->alloc, extent_alloc, "Unexpected alloc error"); + assert_ptr_ne(old_hooks->dalloc, extent_dalloc, "Unexpected dalloc error"); - assert_ptr_ne(old_hooks.commit, extent_commit, + assert_ptr_ne(old_hooks->commit, extent_commit, "Unexpected commit error"); - assert_ptr_ne(old_hooks.decommit, extent_decommit, + assert_ptr_ne(old_hooks->decommit, extent_decommit, "Unexpected decommit error"); - assert_ptr_ne(old_hooks.purge, extent_purge, "Unexpected purge error"); - assert_ptr_ne(old_hooks.split, extent_split, "Unexpected split error"); - assert_ptr_ne(old_hooks.merge, extent_merge, "Unexpected merge error"); + assert_ptr_ne(old_hooks->purge, extent_purge, "Unexpected purge error"); + assert_ptr_ne(old_hooks->split, extent_split, "Unexpected split error"); + assert_ptr_ne(old_hooks->merge, extent_merge, "Unexpected merge error"); /* Get large size classes. */ sz = sizeof(size_t); @@ -228,19 +244,20 @@ TEST_BEGIN(test_extent) &old_hooks, new_size), 0, "Unexpected extent_hooks error"); assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, &old_hooks, &old_size, NULL, 0), 0, "Unexpected extent_hooks error"); - assert_ptr_eq(old_hooks.alloc, orig_hooks.alloc, + assert_ptr_eq(old_hooks, orig_hooks, "Unexpected hooks error"); + assert_ptr_eq(old_hooks->alloc, orig_hooks->alloc, "Unexpected alloc error"); - assert_ptr_eq(old_hooks.dalloc, orig_hooks.dalloc, + assert_ptr_eq(old_hooks->dalloc, orig_hooks->dalloc, "Unexpected dalloc error"); - assert_ptr_eq(old_hooks.commit, orig_hooks.commit, + assert_ptr_eq(old_hooks->commit, orig_hooks->commit, "Unexpected commit error"); - assert_ptr_eq(old_hooks.decommit, orig_hooks.decommit, + assert_ptr_eq(old_hooks->decommit, orig_hooks->decommit, "Unexpected decommit error"); - assert_ptr_eq(old_hooks.purge, orig_hooks.purge, + assert_ptr_eq(old_hooks->purge, orig_hooks->purge, "Unexpected purge error"); - assert_ptr_eq(old_hooks.split, orig_hooks.split, + assert_ptr_eq(old_hooks->split, orig_hooks->split, "Unexpected split error"); - assert_ptr_eq(old_hooks.merge, orig_hooks.merge, + assert_ptr_eq(old_hooks->merge, orig_hooks->merge, "Unexpected merge error"); } TEST_END -- GitLab From 8835cf3bed1888fc0110b0c59dbf2ce1288a7a8c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 3 Jun 2016 19:25:13 -0700 Subject: [PATCH 064/544] Fix locking order reversal in arena_reset(). --- src/arena.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/arena.c b/src/arena.c index 32e1915c..7dcf12d5 100644 --- a/src/arena.c +++ b/src/arena.c @@ -917,20 +917,28 @@ arena_reset(tsd_t *tsd, arena_t *arena) /* Bins. */ for (i = 0; i < NBINS; i++) { - extent_t *slab, *next; + extent_t *slab; arena_bin_t *bin = &arena->bins[i]; malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); if (bin->slabcur != NULL) { - arena_slab_dalloc(tsd_tsdn(tsd), arena, bin->slabcur); + slab = bin->slabcur; bin->slabcur = NULL; + malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); + arena_slab_dalloc(tsd_tsdn(tsd), arena, slab); + malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); } while ((slab = extent_heap_remove_first(&bin->slabs_nonfull)) != - NULL) + NULL) { + malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); arena_slab_dalloc(tsd_tsdn(tsd), arena, slab); + malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); + } for (slab = qr_next(&bin->slabs_full, qr_link); slab != - &bin->slabs_full; slab = next) { - next = qr_next(slab, qr_link); + &bin->slabs_full; slab = qr_next(&bin->slabs_full, + qr_link)) { + malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); arena_slab_dalloc(tsd_tsdn(tsd), arena, slab); + malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); } if (config_stats) { bin->stats.curregs = 0; -- GitLab From f02fec8839856fad3106f429f9316e844557e99f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 3 Jun 2016 19:39:14 -0700 Subject: [PATCH 065/544] Silence a bogus compiler warning. --- src/ctl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ctl.c b/src/ctl.c index 813d5fab..535f1eab 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1646,7 +1646,9 @@ arena_i_extent_hooks_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, if (arena_ind < narenas_total_get() && (arena = arena_get(tsd_tsdn(tsd), arena_ind, false)) != NULL) { if (newp != NULL) { - extent_hooks_t *old_extent_hooks, *new_extent_hooks; + extent_hooks_t *old_extent_hooks; + extent_hooks_t *new_extent_hooks + JEMALLOC_CC_SILENCE_INIT(NULL); WRITE(new_extent_hooks, extent_hooks_t *); old_extent_hooks = extent_hooks_set(arena, new_extent_hooks); -- GitLab From 04942c3d9068647b2d4600b72ab6aaeb4ebf920c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 3 Jun 2016 20:04:30 -0700 Subject: [PATCH 066/544] Remove a stray memset(), and fix a junk filling test regression. --- include/jemalloc/internal/large.h | 3 +++ include/jemalloc/internal/private_symbols.txt | 1 + src/large.c | 13 ++++++++-- test/unit/junk.c | 24 +++++++++++++++---- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/include/jemalloc/internal/large.h b/include/jemalloc/internal/large.h index afaa6c3c..8345f89e 100644 --- a/include/jemalloc/internal/large.h +++ b/include/jemalloc/internal/large.h @@ -19,8 +19,11 @@ void *large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, #ifdef JEMALLOC_JET typedef void (large_dalloc_junk_t)(void *, size_t); extern large_dalloc_junk_t *large_dalloc_junk; +typedef void (large_dalloc_maybe_junk_t)(tsdn_t *, void *, size_t); +extern large_dalloc_maybe_junk_t *large_dalloc_maybe_junk; #else void large_dalloc_junk(void *ptr, size_t usize); +void large_dalloc_maybe_junk(tsdn_t *tsdn, void *ptr, size_t usize); #endif void large_dalloc_junked_locked(tsdn_t *tsdn, extent_t *extent); void large_dalloc(tsdn_t *tsdn, extent_t *extent); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 07e7f287..d2c882d3 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -250,6 +250,7 @@ jemalloc_prefork large_dalloc large_dalloc_junk large_dalloc_junked_locked +large_dalloc_maybe_junk large_malloc large_palloc large_prof_tctx_get diff --git a/src/large.c b/src/large.c index 5c7b4453..325b5f10 100644 --- a/src/large.c +++ b/src/large.c @@ -76,7 +76,11 @@ large_dalloc_junk(void *ptr, size_t usize) large_dalloc_junk_t *large_dalloc_junk = JEMALLOC_N(n_large_dalloc_junk); #endif -static void +#ifdef JEMALLOC_JET +#undef large_dalloc_maybe_junk +#define large_dalloc_maybe_junk JEMALLOC_N(n_large_dalloc_maybe_junk) +#endif +void large_dalloc_maybe_junk(tsdn_t *tsdn, void *ptr, size_t usize) { @@ -87,9 +91,14 @@ large_dalloc_maybe_junk(tsdn_t *tsdn, void *ptr, size_t usize) */ if (!config_munmap || (have_dss && extent_in_dss(tsdn, ptr))) large_dalloc_junk(ptr, usize); - memset(ptr, JEMALLOC_FREE_JUNK, usize); } } +#ifdef JEMALLOC_JET +#undef large_dalloc_maybe_junk +#define large_dalloc_maybe_junk JEMALLOC_N(large_dalloc_maybe_junk) +large_dalloc_maybe_junk_t *large_dalloc_maybe_junk = + JEMALLOC_N(n_large_dalloc_maybe_junk); +#endif static bool large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) diff --git a/test/unit/junk.c b/test/unit/junk.c index 7a923509..dea0f615 100644 --- a/test/unit/junk.c +++ b/test/unit/junk.c @@ -10,6 +10,7 @@ const char *malloc_conf = static arena_dalloc_junk_small_t *arena_dalloc_junk_small_orig; static large_dalloc_junk_t *large_dalloc_junk_orig; +static large_dalloc_maybe_junk_t *large_dalloc_maybe_junk_orig; static void *watch_for_junking; static bool saw_junking; @@ -39,13 +40,23 @@ arena_dalloc_junk_small_intercept(void *ptr, const arena_bin_info_t *bin_info) static void large_dalloc_junk_intercept(void *ptr, size_t usize) { + size_t i; large_dalloc_junk_orig(ptr, usize); - /* - * The conditions under which junk filling actually occurs are nuanced - * enough that it doesn't make sense to duplicate the decision logic in - * test code, so don't actually check that the region is junk-filled. - */ + for (i = 0; i < usize; i++) { + assert_u_eq(((uint8_t *)ptr)[i], JEMALLOC_FREE_JUNK, + "Missing junk fill for byte %zu/%zu of deallocated region", + i, usize); + } + if (ptr == watch_for_junking) + saw_junking = true; +} + +static void +large_dalloc_maybe_junk_intercept(tsdn_t *tsdn, void *ptr, size_t usize) +{ + + large_dalloc_maybe_junk_orig(tsdn, ptr, usize); if (ptr == watch_for_junking) saw_junking = true; } @@ -61,6 +72,8 @@ test_junk(size_t sz_min, size_t sz_max) arena_dalloc_junk_small = arena_dalloc_junk_small_intercept; large_dalloc_junk_orig = large_dalloc_junk; large_dalloc_junk = large_dalloc_junk_intercept; + large_dalloc_maybe_junk_orig = large_dalloc_maybe_junk; + large_dalloc_maybe_junk = large_dalloc_maybe_junk_intercept; } sz_prev = 0; @@ -111,6 +124,7 @@ test_junk(size_t sz_min, size_t sz_max) if (opt_junk_free) { arena_dalloc_junk_small = arena_dalloc_junk_small_orig; large_dalloc_junk = large_dalloc_junk_orig; + large_dalloc_maybe_junk = large_dalloc_maybe_junk_orig; } } -- GitLab From 42faa9e3e0b4a9347c46153356163bd921c6e90c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 5 Jun 2016 14:01:32 -0700 Subject: [PATCH 067/544] Work around legitimate xallocx() failures during testing. With the removal of subchunk size class infrastructure, there are no large size classes that are guaranteed to be re-expandable in place unless munmap() is disabled. Work around these legitimate failures with rallocx() fallback calls. If there were no test configuration for which the xallocx() calls succeeded, it would be important to override the extent hooks for testing purposes, but by default these tests don't use the rallocx() fallbacks on Linux, so test coverage is still sufficient. --- test/integration/xallocx.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/test/integration/xallocx.c b/test/integration/xallocx.c index 4ff099f8..72db818a 100644 --- a/test/integration/xallocx.c +++ b/test/integration/xallocx.c @@ -249,8 +249,10 @@ TEST_BEGIN(test_extra_large) assert_zu_ge(xallocx(p, smallmax, 0, flags), large1, "Unexpected xallocx() behavior"); - assert_zu_eq(xallocx(p, large3, 0, flags), large3, - "Unexpected xallocx() behavior"); + if (xallocx(p, large3, 0, flags) != large3) { + p = rallocx(p, large3, flags); + assert_ptr_not_null(p, "Unexpected rallocx() failure"); + } /* Test size decrease with non-zero extra. */ assert_zu_eq(xallocx(p, large1, large3 - large1, flags), large3, "Unexpected xallocx() behavior"); @@ -281,8 +283,10 @@ TEST_BEGIN(test_extra_large) assert_zu_le(xallocx(p, large1, large3 - large1, flags), large3, "Unexpected xallocx() behavior"); - assert_zu_eq(xallocx(p, large3, 0, flags), large3, - "Unexpected xallocx() behavior"); + if (xallocx(p, large3, 0, flags) != large3) { + p = rallocx(p, large3, flags); + assert_ptr_not_null(p, "Unexpected rallocx() failure"); + } /* Test size+extra overflow. */ assert_zu_le(xallocx(p, large3, largemax - large3 + 1, flags), largemax, "Unexpected xallocx() behavior"); @@ -360,8 +364,10 @@ test_zero(size_t szmin, size_t szmax) for (sz = szmin; sz < szmax; sz = nsz) { nsz = nallocx(sz+1, flags); - assert_zu_eq(xallocx(p, sz+1, 0, flags), nsz, - "Unexpected xallocx() failure"); + if (xallocx(p, sz+1, 0, flags) != nsz) { + p = rallocx(p, sz+1, flags); + assert_ptr_not_null(p, "Unexpected rallocx() failure"); + } assert_false(validate_fill(p, FILL_BYTE, 0, sz), "Memory not filled: sz=%zu", sz); assert_false(validate_fill(p, 0x00, sz, nsz-sz), -- GitLab From c4bb17f891768cb57d4559d9ffb53c304448dcdc Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 5 Jun 2016 14:43:20 -0700 Subject: [PATCH 068/544] Fix gdump triggering regression. Now that extents are not multiples of chunksize, it's necessary to track pages rather than chunks. --- src/extent.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/extent.c b/src/extent.c index 0c66e31a..0ea10fb9 100644 --- a/src/extent.c +++ b/src/extent.c @@ -35,8 +35,8 @@ const extent_hooks_t extent_hooks_default = { }; /* Used exclusively for gdump triggering. */ -static size_t curchunks; -static size_t highchunks; +static size_t curpages; +static size_t highpages; /******************************************************************************/ /* @@ -281,16 +281,15 @@ extent_register(tsdn_t *tsdn, const extent_t *extent) extent_rtree_release(tsdn, elm_a, elm_b); if (config_prof && opt_prof && extent_active_get(extent)) { - size_t nadd = (extent_size_get(extent) == 0) ? 1 : - extent_size_get(extent) / chunksize; - size_t cur = atomic_add_z(&curchunks, nadd); - size_t high = atomic_read_z(&highchunks); - while (cur > high && atomic_cas_z(&highchunks, high, cur)) { + size_t nadd = extent_size_get(extent) >> LG_PAGE; + size_t cur = atomic_add_z(&curpages, nadd); + size_t high = atomic_read_z(&highpages); + while (cur > high && atomic_cas_z(&highpages, high, cur)) { /* * Don't refresh cur, because it may have decreased - * since this thread lost the highchunks update race. + * since this thread lost the highpages update race. */ - high = atomic_read_z(&highchunks); + high = atomic_read_z(&highpages); } if (cur > high && prof_gdump_get_unlocked()) prof_gdump(tsdn); @@ -329,10 +328,9 @@ extent_deregister(tsdn_t *tsdn, const extent_t *extent) extent_rtree_release(tsdn, elm_a, elm_b); if (config_prof && opt_prof && extent_active_get(extent)) { - size_t nsub = (extent_size_get(extent) == 0) ? 1 : - extent_size_get(extent) / chunksize; - assert(atomic_read_z(&curchunks) >= nsub); - atomic_sub_z(&curchunks, nsub); + size_t nsub = extent_size_get(extent) >> LG_PAGE; + assert(atomic_read_z(&curpages) >= nsub); + atomic_sub_z(&curpages, nsub); } } -- GitLab From 4e910fc958a9df0b05ff91666c6a8cf6c76b0e76 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 5 Jun 2016 15:27:20 -0700 Subject: [PATCH 069/544] Fix extent_alloc_dss() regressions. Page-align the gap, if any, and add/use extent_dalloc_gap(), which registers the gap extent before deallocation. --- include/jemalloc/internal/extent.h | 1 + include/jemalloc/internal/private_symbols.txt | 1 + src/extent.c | 12 ++++++ src/extent_dss.c | 41 +++++++++---------- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 6e155206..d7944c1c 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -105,6 +105,7 @@ extent_t *extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_t *extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab); +void extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent); void extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent); void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index d2c882d3..a489e14a 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -158,6 +158,7 @@ extent_committed_get extent_committed_set extent_dalloc extent_dalloc_cache +extent_dalloc_gap extent_dalloc_mmap extent_dalloc_wrapper extent_decommit_wrapper diff --git a/src/extent.c b/src/extent.c index 0ea10fb9..838cb73b 100644 --- a/src/extent.c +++ b/src/extent.c @@ -732,6 +732,18 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, malloc_mutex_unlock(tsdn, &arena->extents_mtx); } +void +extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent) +{ + extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; + + if (extent_register(tsdn, extent)) { + extent_leak(tsdn, arena, &extent_hooks, false, extent); + return; + } + extent_dalloc_wrapper(tsdn, arena, &extent_hooks, extent); +} + void extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) diff --git a/src/extent_dss.c b/src/extent_dss.c index 9cc1d8f7..9c5cd25a 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -70,7 +70,7 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit) { void *ret; - extent_t *pad; + extent_t *gap; cassert(have_dss); assert(size > 0); @@ -83,8 +83,8 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, if ((intptr_t)size < 0) return (NULL); - pad = extent_alloc(tsdn, arena); - if (pad == NULL) + gap = extent_alloc(tsdn, arena); + if (gap == NULL) return (NULL); malloc_mutex_lock(tsdn, &dss_mtx); @@ -95,8 +95,8 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, * malloc. */ while (true) { - void *pad_addr, *dss_next; - size_t pad_size; + void *gap_addr, *dss_next; + size_t gap_size; intptr_t incr; /* Avoid an unnecessary system call. */ @@ -111,23 +111,23 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, break; /* - * Compute how much pad space (if any) is necessary to + * Compute how much gap space (if any) is necessary to * satisfy alignment. This space can be recycled for * later use. */ - pad_addr = (void *)((uintptr_t)dss_max); - ret = (void *)ALIGNMENT_CEILING((uintptr_t)dss_max, - alignment); - pad_size = (uintptr_t)ret - (uintptr_t)pad_addr; - if (pad_size != 0) { - extent_init(pad, arena, pad_addr, pad_size, - pad_size, false, false, true, false); + gap_addr = (void *)(PAGE_CEILING((uintptr_t)dss_max)); + ret = (void *)ALIGNMENT_CEILING((uintptr_t)gap_addr, + PAGE_CEILING(alignment)); + gap_size = (uintptr_t)ret - (uintptr_t)gap_addr; + if (gap_size != 0) { + extent_init(gap, arena, gap_addr, gap_size, + gap_size, false, false, true, false); } dss_next = (void *)((uintptr_t)ret + size); if ((uintptr_t)ret < (uintptr_t)dss_max || (uintptr_t)dss_next < (uintptr_t)dss_max) break; /* Wrap-around. */ - incr = pad_size + size; + incr = gap_size + size; dss_prev = extent_dss_sbrk(incr); if (dss_prev == (void *)-1) break; @@ -135,13 +135,10 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, /* Success. */ dss_max = dss_next; malloc_mutex_unlock(tsdn, &dss_mtx); - if (pad_size != 0) { - extent_hooks_t *extent_hooks = - EXTENT_HOOKS_INITIALIZER; - extent_dalloc_wrapper(tsdn, arena, - &extent_hooks, pad); - } else - extent_dalloc(tsdn, arena, pad); + if (gap_size != 0) + extent_dalloc_gap(tsdn, arena, gap); + else + extent_dalloc(tsdn, arena, gap); if (*zero) memset(ret, 0, size); if (!*commit) @@ -152,7 +149,7 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, } /* OOM. */ malloc_mutex_unlock(tsdn, &dss_mtx); - extent_dalloc(tsdn, arena, pad); + extent_dalloc(tsdn, arena, gap); return (NULL); } -- GitLab From 9a645c612f1d80e234915de4211816504f4d0869 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 5 Jun 2016 20:39:25 -0700 Subject: [PATCH 070/544] Fix an extent [de]allocation/[de]registration race. Deregister extents before deallocation, so that subsequent reallocation/registration doesn't race with deregistration. --- src/extent.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/extent.c b/src/extent.c index 838cb73b..824b08d4 100644 --- a/src/extent.c +++ b/src/extent.c @@ -298,6 +298,13 @@ extent_register(tsdn_t *tsdn, const extent_t *extent) return (false); } +static void +extent_reregister(tsdn_t *tsdn, const extent_t *extent) +{ + bool err = extent_register(tsdn, extent); + assert(!err); +} + static void extent_interior_deregister(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, const extent_t *extent) @@ -314,7 +321,7 @@ extent_interior_deregister(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, } static void -extent_deregister(tsdn_t *tsdn, const extent_t *extent) +extent_deregister(tsdn_t *tsdn, extent_t *extent) { rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); @@ -323,8 +330,10 @@ extent_deregister(tsdn_t *tsdn, const extent_t *extent) extent_rtree_acquire(tsdn, rtree_ctx, extent, true, false, &elm_a, &elm_b); extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL); - if (extent_slab_get(extent)) + if (extent_slab_get(extent)) { extent_interior_deregister(tsdn, rtree_ctx, extent); + extent_slab_set(extent, false); + } extent_rtree_release(tsdn, elm_a, elm_b); if (config_prof && opt_prof && extent_active_get(extent)) { @@ -782,14 +791,18 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_addr_set(extent, extent_base_get(extent)); extent_hooks_assure_initialized(arena, r_extent_hooks); - /* Try to deallocate. */ + /* + * Try to deallocate. Deregister first to avoid a race with other + * allocating threads, and reregister if deallocation fails. + */ + extent_deregister(tsdn, extent); if (!(*r_extent_hooks)->dalloc(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), extent_committed_get(extent), arena->ind)) { - extent_deregister(tsdn, extent); extent_dalloc(tsdn, arena, extent); return; } + extent_reregister(tsdn, extent); /* Try to decommit; purge if that fails. */ if (extent_committed_get(extent)) { extent_committed_set(extent, -- GitLab From 487093d999c7d45bee8047604fda1b5ba0f3f382 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 5 Jun 2016 22:08:20 -0700 Subject: [PATCH 071/544] Fix regressions related extent splitting failures. Fix a fundamental extent_split_wrapper() bug in an error path. Fix extent_recycle() to deregister unsplittable extents before leaking them. Relax xallocx() test assertions so that unsplittable extents don't cause test failures. --- src/extent.c | 4 +++- test/integration/xallocx.c | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/extent.c b/src/extent.c index 824b08d4..841afa42 100644 --- a/src/extent.c +++ b/src/extent.c @@ -441,6 +441,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, lead, leadsize, leadsize, size + trailsize, usize + trailsize); if (extent == NULL) { + extent_deregister(tsdn, lead); extent_leak(tsdn, arena, r_extent_hooks, cache, lead); malloc_mutex_unlock(tsdn, &arena->extents_mtx); return (NULL); @@ -454,6 +455,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *trail = extent_split_wrapper(tsdn, arena, r_extent_hooks, extent, size, usize, trailsize, trailsize); if (trail == NULL) { + extent_deregister(tsdn, extent); extent_leak(tsdn, arena, r_extent_hooks, cache, extent); malloc_mutex_unlock(tsdn, &arena->extents_mtx); @@ -961,7 +963,7 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, return (trail); label_error_d: - extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); + extent_rtree_release(tsdn, trail_elm_a, trail_elm_b); label_error_c: extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); label_error_b: diff --git a/test/integration/xallocx.c b/test/integration/xallocx.c index 72db818a..4dcf08da 100644 --- a/test/integration/xallocx.c +++ b/test/integration/xallocx.c @@ -258,7 +258,7 @@ TEST_BEGIN(test_extra_large) "Unexpected xallocx() behavior"); assert_zu_eq(xallocx(p, large2, large3 - large2, flags), large3, "Unexpected xallocx() behavior"); - assert_zu_eq(xallocx(p, large1, large2 - large1, flags), large2, + assert_zu_ge(xallocx(p, large1, large2 - large1, flags), large2, "Unexpected xallocx() behavior"); assert_zu_ge(xallocx(p, smallmax, large1 - smallmax, flags), large1, "Unexpected xallocx() behavior"); @@ -357,8 +357,10 @@ test_zero(size_t szmin, size_t szmax) /* Shrink in place so that we can expect growing in place to succeed. */ sz = szmin; - assert_zu_eq(xallocx(p, sz, 0, flags), sz, - "Unexpected xallocx() error"); + if (xallocx(p, sz, 0, flags) != sz) { + p = rallocx(p, sz, flags); + assert_ptr_not_null(p, "Unexpected rallocx() failure"); + } assert_false(validate_fill(p, FILL_BYTE, 0, sz), "Memory not filled: sz=%zu", sz); -- GitLab From 0c5cec833fb2b075222ee19a41c03f32178d3be1 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 5 Jun 2016 22:30:31 -0700 Subject: [PATCH 072/544] Relax extent hook tests to work with unsplittable extents. --- test/integration/extent.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/test/integration/extent.c b/test/integration/extent.c index 78176711..10de8bbf 100644 --- a/test/integration/extent.c +++ b/test/integration/extent.c @@ -15,6 +15,7 @@ static bool did_dalloc; static bool did_commit; static bool did_decommit; static bool did_purge; +static bool tried_split; static bool did_split; static bool did_merge; @@ -106,30 +107,35 @@ static bool extent_split(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t size_a, size_t size_b, bool committed, unsigned arena_ind) { + bool err; TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, size_a=%zu, " "size_b=%zu, committed=%s, arena_ind=%u)\n", __func__, extent_hooks, addr, size, size_a, size_b, committed ? "true" : "false", arena_ind); assert(extent_hooks->split == extent_split); - did_split = true; - return (old_hooks->split(old_hooks, addr, size, size_a, size_b, - committed, arena_ind)); + tried_split = true; + err = old_hooks->split(old_hooks, addr, size, size_a, size_b, committed, + arena_ind); + did_split = !err; + return (err); } static bool extent_merge(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, void *addr_b, size_t size_b, bool committed, unsigned arena_ind) { + bool err; TRACE_HOOK("%s(extent_hooks=%p, addr_a=%p, size_a=%zu, addr_b=%p " "size_b=%zu, committed=%s, arena_ind=%u)\n", __func__, extent_hooks, addr_a, size_a, addr_b, size_b, committed ? "true" : "false", arena_ind); assert(extent_hooks->merge == extent_merge); - did_merge = true; - return (old_hooks->merge(old_hooks, addr_a, size_a, addr_b, size_b, - committed, arena_ind)); + err = old_hooks->merge(old_hooks, addr_a, size_a, addr_b, size_b, + committed, arena_ind); + did_merge = !err; + return (err); } TEST_BEGIN(test_extent) @@ -199,6 +205,7 @@ TEST_BEGIN(test_extent) did_dalloc = false; did_decommit = false; did_purge = false; + tried_split = false; did_split = false; xallocx_success_a = (xallocx(p, large0, 0, flags) == large0); assert_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0), @@ -208,7 +215,7 @@ TEST_BEGIN(test_extent) assert_false(did_decommit, "Unexpected decommit"); assert_true(did_purge, "Expected purge"); } - assert_true(did_split, "Expected split"); + assert_true(tried_split, "Expected split"); dallocx(p, flags); do_dalloc = true; @@ -219,6 +226,7 @@ TEST_BEGIN(test_extent) assert_ptr_not_null(p, "Unexpected mallocx() error"); did_decommit = false; did_commit = false; + tried_split = false; did_split = false; did_merge = false; xallocx_success_b = (xallocx(p, large0, 0, flags) == large0); @@ -227,7 +235,10 @@ TEST_BEGIN(test_extent) if (xallocx_success_b) assert_true(did_split, "Expected split"); xallocx_success_c = (xallocx(p, large0 * 2, 0, flags) == large0 * 2); - assert_b_eq(did_decommit, did_commit, "Expected decommit/commit match"); + if (did_split) { + assert_b_eq(did_decommit, did_commit, + "Expected decommit/commit match"); + } if (xallocx_success_b && xallocx_success_c) assert_true(did_merge, "Expected merge"); dallocx(p, flags); -- GitLab From 10b9087b14d96e6d7f2d14788668bdc346c383ad Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 5 Jun 2016 23:24:52 -0700 Subject: [PATCH 073/544] Set 'committed' in extent_[de]commit_wrapper(). --- src/extent.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/extent.c b/src/extent.c index 841afa42..51a47644 100644 --- a/src/extent.c +++ b/src/extent.c @@ -807,10 +807,8 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_reregister(tsdn, extent); /* Try to decommit; purge if that fails. */ if (extent_committed_get(extent)) { - extent_committed_set(extent, - (*r_extent_hooks)->decommit(*r_extent_hooks, - extent_base_get(extent), extent_size_get(extent), 0, - extent_size_get(extent), arena->ind)); + extent_decommit_wrapper(tsdn, arena, r_extent_hooks, extent, + 0, extent_size_get(extent)); } extent_zeroed_set(extent, !extent_committed_get(extent) || !(*r_extent_hooks)->purge(*r_extent_hooks, extent_base_get(extent), @@ -839,11 +837,14 @@ extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { + bool err; extent_hooks_assure_initialized(arena, r_extent_hooks); - return ((*r_extent_hooks)->commit(*r_extent_hooks, + err = (*r_extent_hooks)->commit(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), offset, length, - arena->ind)); + arena->ind); + extent_committed_set(extent, extent_committed_get(extent) || !err); + return (err); } static bool @@ -862,11 +863,15 @@ extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { + bool err; extent_hooks_assure_initialized(arena, r_extent_hooks); - return ((*r_extent_hooks)->decommit(*r_extent_hooks, + + err = (*r_extent_hooks)->decommit(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), offset, length, - arena->ind)); + arena->ind); + extent_committed_set(extent, extent_committed_get(extent) && err); + return (err); } static bool -- GitLab From 02a475d89aad1a7f94b3a102923a6527e05ca055 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 6 Jun 2016 15:32:01 -0700 Subject: [PATCH 074/544] Use extent_commit_wrapper() rather than directly calling commit hook. As a side effect this causes the extent's 'committed' flag to be updated. --- src/extent.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/extent.c b/src/extent.c index 51a47644..32f34887 100644 --- a/src/extent.c +++ b/src/extent.c @@ -471,9 +471,8 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_usize_set(extent, usize); } - if (!extent_committed_get(extent) && - (*r_extent_hooks)->commit(*r_extent_hooks, extent_base_get(extent), - extent_size_get(extent), 0, extent_size_get(extent), arena->ind)) { + if (!extent_committed_get(extent) && extent_commit_wrapper(tsdn, arena, + r_extent_hooks, extent, 0, extent_size_get(extent))) { malloc_mutex_unlock(tsdn, &arena->extents_mtx); extent_record(tsdn, arena, r_extent_hooks, extent_heaps, cache, extent); -- GitLab From cc289f40b6e7b119566abf8a1c09c97e08597a3d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 7 Jun 2016 13:37:22 -0700 Subject: [PATCH 075/544] Propagate tsdn to default extent hooks. This avoids bootstrapping issues for configurations that require allocation during tsd initialization. This resolves #390. --- src/extent.c | 103 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 78 insertions(+), 25 deletions(-) diff --git a/src/extent.c b/src/extent.c index 32f34887..cb67a27c 100644 --- a/src/extent.c +++ b/src/extent.c @@ -560,11 +560,24 @@ extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, return (extent); } +static void * +extent_alloc_default_impl(tsdn_t *tsdn, arena_t *arena, void *new_addr, + size_t size, size_t alignment, bool *zero, bool *commit) +{ + void *ret; + + ret = extent_alloc_core(tsdn, arena, new_addr, size, alignment, zero, + commit, arena->dss_prec); + if (ret == NULL) + return (NULL); + + return (ret); +} + static void * extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit, unsigned arena_ind) { - void *ret; tsdn_t *tsdn; arena_t *arena; @@ -577,12 +590,9 @@ extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, size_t size, * already. */ assert(arena != NULL); - ret = extent_alloc_core(tsdn, arena, new_addr, size, alignment, zero, - commit, arena->dss_prec); - if (ret == NULL) - return (NULL); - return (ret); + return (extent_alloc_default_impl(tsdn, arena, new_addr, size, + alignment, zero, commit)); } static extent_t * @@ -619,8 +629,14 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, extent = extent_alloc(tsdn, arena); if (extent == NULL) return (NULL); - addr = (*r_extent_hooks)->alloc(*r_extent_hooks, new_addr, size, - alignment, zero, commit, arena->ind); + if (*r_extent_hooks == &extent_hooks_default) { + /* Call directly to propagate tsdn. */ + addr = extent_alloc_default_impl(tsdn, arena, new_addr, size, + alignment, zero, commit); + } else { + addr = (*r_extent_hooks)->alloc(*r_extent_hooks, new_addr, size, + alignment, zero, commit, arena->ind); + } if (addr == NULL) { extent_dalloc(tsdn, arena, extent); return (NULL); @@ -769,22 +785,34 @@ extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, extent); } +static bool +extent_dalloc_default_impl(tsdn_t *tsdn, void *addr, size_t size) +{ + + if (!have_dss || !extent_in_dss(tsdn, addr)) + return (extent_dalloc_mmap(addr, size)); + return (true); +} + + static bool extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, size_t size, bool committed, unsigned arena_ind) { + tsdn_t *tsdn; assert(extent_hooks == &extent_hooks_default); - if (!have_dss || !extent_in_dss(tsdn_fetch(), addr)) - return (extent_dalloc_mmap(addr, size)); - return (true); + tsdn = tsdn_fetch(); + + return (extent_dalloc_default_impl(tsdn, addr, size)); } void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { + bool err; assert(extent_base_get(extent) != NULL); assert(extent_size_get(extent) != 0); @@ -797,9 +825,17 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, * allocating threads, and reregister if deallocation fails. */ extent_deregister(tsdn, extent); - if (!(*r_extent_hooks)->dalloc(*r_extent_hooks, extent_base_get(extent), - extent_size_get(extent), extent_committed_get(extent), - arena->ind)) { + if (*r_extent_hooks == &extent_hooks_default) { + /* Call directly to propagate tsdn. */ + err = extent_dalloc_default_impl(tsdn, extent_base_get(extent), + extent_size_get(extent)); + } else { + err = (*r_extent_hooks)->dalloc(*r_extent_hooks, + extent_base_get(extent), extent_size_get(extent), + extent_committed_get(extent), arena->ind); + } + + if (!err) { extent_dalloc(tsdn, arena, extent); return; } @@ -977,35 +1013,52 @@ label_error_a: } static bool -extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, - void *addr_b, size_t size_b, bool committed, unsigned arena_ind) +extent_merge_default_impl(tsdn_t *tsdn, void *addr_a, void *addr_b) { - assert(extent_hooks == &extent_hooks_default); - if (!maps_coalesce) return (true); - if (have_dss) { - tsdn_t *tsdn = tsdn_fetch(); - if (extent_in_dss(tsdn, addr_a) != extent_in_dss(tsdn, addr_b)) + if (have_dss && extent_in_dss(tsdn, addr_a) != extent_in_dss(tsdn, + addr_b)) return (true); - } return (false); } +static bool +extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, + void *addr_b, size_t size_b, bool committed, unsigned arena_ind) +{ + tsdn_t *tsdn; + + assert(extent_hooks == &extent_hooks_default); + + tsdn = tsdn_fetch(); + + return (extent_merge_default_impl(tsdn, addr_a, addr_b)); +} + bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b) { + bool err; rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; extent_hooks_assure_initialized(arena, r_extent_hooks); - if ((*r_extent_hooks)->merge(*r_extent_hooks, extent_base_get(a), - extent_size_get(a), extent_base_get(b), extent_size_get(b), - extent_committed_get(a), arena->ind)) + if (*r_extent_hooks == &extent_hooks_default) { + /* Call directly to propagate tsdn. */ + err = extent_merge_default_impl(tsdn, extent_base_get(a), + extent_base_get(b)); + } else { + err = (*r_extent_hooks)->merge(*r_extent_hooks, + extent_base_get(a), extent_size_get(a), extent_base_get(b), + extent_size_get(b), extent_committed_get(a), arena->ind); + } + + if (err) return (true); /* -- GitLab From de23f6fce7fa49b3ac9c1a6e36131464ecce2f01 Mon Sep 17 00:00:00 2001 From: Elliot Ronaghan Date: Fri, 27 May 2016 16:20:23 -0700 Subject: [PATCH 076/544] Fix mixed decl in nstime.c Fix mixed decl in the gettimeofday() branch of nstime_update() --- src/nstime.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/nstime.c b/src/nstime.c index 26e49dc5..aad2c260 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -128,9 +128,11 @@ nstime_update(nstime_t *time) time->ns = ts.tv_sec * BILLION + ts.tv_nsec; } #else - struct timeval tv; - gettimeofday(&tv, NULL); - time->ns = tv.tv_sec * BILLION + tv.tv_usec * 1000; + { + struct timeval tv; + gettimeofday(&tv, NULL); + time->ns = tv.tv_sec * BILLION + tv.tv_usec * 1000; + } #endif /* Handle non-monotonic clocks. */ -- GitLab From dd752c1ffd92b9d7573aa5ce49bcc5e74588c3dc Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 7 Jun 2016 14:15:49 -0700 Subject: [PATCH 077/544] Fix potential VM map fragmentation regression. Revert 245ae6036c09cc11a72fab4335495d95cddd5beb (Support --with-lg-page values larger than actual page size.), because it could cause VM map fragmentation if the kernel grows mmap()ed memory downward. This resolves #391. --- include/jemalloc/internal/jemalloc_internal.h.in | 2 +- src/extent_mmap.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 5b809bfa..8ba4a19a 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -813,7 +813,7 @@ sa2u(size_t size, size_t alignment) * Calculate the multi-page mapping that large_palloc() would need in * order to guarantee the alignment. */ - if (usize + large_pad + PAGE_CEILING(alignment) < usize) { + if (usize + large_pad + PAGE_CEILING(alignment) - PAGE < usize) { /* size_t overflow. */ return (0); } diff --git a/src/extent_mmap.c b/src/extent_mmap.c index 0dd3247e..23dd4f88 100644 --- a/src/extent_mmap.c +++ b/src/extent_mmap.c @@ -9,7 +9,7 @@ extent_alloc_mmap_slow(size_t size, size_t alignment, bool *zero, bool *commit) void *ret; size_t alloc_size; - alloc_size = size + alignment; + alloc_size = size + alignment - PAGE; /* Beware size_t wrap-around. */ if (alloc_size < size) return (NULL); -- GitLab From b9b35562893afd258d0dc94787acfe53153e5c65 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 7 Jun 2016 14:40:43 -0700 Subject: [PATCH 078/544] Update ChangeLog for 4.2.1. --- ChangeLog | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ChangeLog b/ChangeLog index c9ce7c4d..532255d1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,17 @@ brevity. Much more detail can be found in the git revision history: https://github.com/jemalloc/jemalloc +* 4.2.1 (June 8, 2016) + + Bug fixes: + - Fix bootstrapping issues for configurations that require allocation during + tsd initialization (e.g. --disable-tls). (@cferris1000, @jasone) + - Fix gettimeofday() version of nstime_update(). (@ronawho) + - Fix Valgrind regressions in calloc() and chunk_alloc_wrapper(). (@ronawho) + - Fix potential VM map fragmentation regression. (@jasone) + - Fix opt_zero-triggered in-place huge reallocation zeroing. (@jasone) + - Fix heap profiling context leaks in reallocation edge cases. (@jasone) + * 4.2.0 (May 12, 2016) New features: -- GitLab From fbd7956d45eda7e2717e263b983b6fd9d51b83a6 Mon Sep 17 00:00:00 2001 From: Elliot Ronaghan Date: Wed, 8 Jun 2016 14:20:32 -0700 Subject: [PATCH 079/544] Work around a weird pgi bug in test/unit/math.c pgi fails to compile math.c, reporting that `-INFINITY` in `pt_norm_expected[]` is a "Non-constant" expression. A simplified version of this failure is: ```c #include static double inf1, inf2 = INFINITY; // no complaints static double inf3 = INFINITY; // suddenly INFINITY is "Non-constant" int main() { } ``` ```sh PGC-S-0074-Non-constant expression in initializer (t.c: 4) ``` pgi errors on the declaration of inf3, and will compile fine if that line is removed. I've reported this bug to pgi, but in the meantime I just switched to using (DBL_MAX + DBL_MAX) to work around this bug. --- test/unit/math.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/unit/math.c b/test/unit/math.c index ebec77a6..adb72bed 100644 --- a/test/unit/math.c +++ b/test/unit/math.c @@ -5,6 +5,10 @@ #include +#ifdef __PGI +#undef INFINITY +#endif + #ifndef INFINITY #define INFINITY (DBL_MAX + DBL_MAX) #endif -- GitLab From 8a1a794b0c79268ed9570719579b18b55e0bfd2d Mon Sep 17 00:00:00 2001 From: Elliot Ronaghan Date: Wed, 8 Jun 2016 14:48:55 -0700 Subject: [PATCH 080/544] Don't use compact red-black trees with the pgi compiler Some bug (either in the red-black tree code, or in the pgi compiler) seems to cause red-black trees to become unbalanced. This issue seems to go away if we don't use compact red-black trees. Since red-black trees don't seem to be used much anymore, I opted for what seems to be an easy fix here instead of digging in and trying to find the root cause of the bug. Some context in case it's helpful: I experienced a ton of segfaults while using pgi as Chapel's target compiler with jemalloc 4.0.4. The little bit of debugging I did pointed me somewhere deep in red-black tree manipulation, but I didn't get a chance to investigate further. It looks like 4.2.0 replaced most uses of red-black trees with pairing-heaps, which seems to avoid whatever bug I was hitting. However, `make check_unit` was still failing on the rb test, so I figured the core issue was just being masked. Here's the `make check_unit` failure: ```sh === test/unit/rb === test_rb_empty: pass tree_recurse:test/unit/rb.c:90: Failed assertion: (((_Bool) (((uintptr_t) (left_node)->link.rbn_right_red) & ((size_t)1)))) == (false) --> true != false: Node should be black test_rb_random:test/unit/rb.c:274: Failed assertion: (imbalances) == (0) --> 1 != 0: Tree is unbalanced tree_recurse:test/unit/rb.c:90: Failed assertion: (((_Bool) (((uintptr_t) (left_node)->link.rbn_right_red) & ((size_t)1)))) == (false) --> true != false: Node should be black test_rb_random:test/unit/rb.c:274: Failed assertion: (imbalances) == (0) --> 1 != 0: Tree is unbalanced node_remove:test/unit/rb.c:190: Failed assertion: (imbalances) == (0) --> 2 != 0: Tree is unbalanced : test/unit/rb.c:43: Failed assertion: "pathp[-1].cmp < 0" test/test.sh: line 22: 12926 Aborted Test harness error ``` While starting to debug I saw the RB_COMPACT option and decided to check if turning that off resolved the bug. It seems to have fixed it (`make check_unit` passes and the segfaults under Chapel are gone) so it seems like on okay work-around. I'd imagine this has performance implications for red-black trees under pgi, but if they're not going to be used much anymore it's probably not a big deal. --- include/jemalloc/internal/jemalloc_internal.h.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 8ba4a19a..c35280fa 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -155,7 +155,9 @@ static const bool config_cache_oblivious = #endif #include "jemalloc/internal/ph.h" +#ifndef __PGI #define RB_COMPACT +#endif #include "jemalloc/internal/rb.h" #include "jemalloc/internal/qr.h" #include "jemalloc/internal/ql.h" -- GitLab From 91278fbddfb5a0adf265b1b9907a1509b4e1e18c Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 9 Jun 2016 17:10:16 +0900 Subject: [PATCH 081/544] Add an AppVeyor config This builds jemalloc and runs all checks with: - MSVC 2015 64-bits - MSVC 2015 32-bits - MINGW64 (from msys2) - MINGW32 (from msys2) Normally, AppVeyor configs are named appveyor.yml, but it is possible to configure the .yml file name in the AppVeyor project settings such that the file stays "hidden", like typical travis configs. --- .appveyor.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .appveyor.yml diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 00000000..ddd5c571 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,28 @@ +version: '{build}' + +environment: + matrix: + - MSYSTEM: MINGW64 + CPU: x86_64 + MSVC: amd64 + - MSYSTEM: MINGW32 + CPU: i686 + MSVC: x86 + - MSYSTEM: MINGW64 + CPU: x86_64 + - MSYSTEM: MINGW32 + CPU: i686 + +install: + - set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH% + - if defined MSVC call "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %MSVC% + - if defined MSVC pacman --noconfirm -Rsc mingw-w64-%CPU%-gcc gcc + - pacman --noconfirm -Suy mingw-w64-%CPU%-make + +build_script: + - bash -c "autoconf" + - bash -c "./configure" + - mingw32-make -j3 + - file lib/jemalloc.dll + - mingw32-make -j3 tests + - mingw32-make -k check -- GitLab From 0dad5b77196903ba2d6bc64a0d9fdda8e2e9ad78 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 9 Jun 2016 22:00:18 +0900 Subject: [PATCH 082/544] Fix extent_*_get to build with MSVC --- include/jemalloc/internal/extent.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index d7944c1c..dbdc8051 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -224,22 +224,22 @@ JEMALLOC_INLINE void * extent_before_get(const extent_t *extent) { - return ((void *)(uintptr_t)extent->e_addr - PAGE); + return ((void *)((uintptr_t)extent->e_addr - PAGE)); } JEMALLOC_INLINE void * extent_last_get(const extent_t *extent) { - return ((void *)(uintptr_t)extent->e_addr + extent_size_get(extent) - - PAGE); + return ((void *)((uintptr_t)extent->e_addr + extent_size_get(extent) - + PAGE)); } JEMALLOC_INLINE void * extent_past_get(const extent_t *extent) { - return ((void *)(uintptr_t)extent->e_addr + extent_size_get(extent)); + return ((void *)((uintptr_t)extent->e_addr + extent_size_get(extent))); } JEMALLOC_INLINE bool -- GitLab From c2942e2c0e097e7c75a3addd0b9c87758f91692e Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Thu, 9 Jun 2016 23:17:39 +0900 Subject: [PATCH 083/544] Define 64-bits atomics unconditionally They are used on all platforms in prng.h. --- include/jemalloc/internal/atomic.h | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/include/jemalloc/internal/atomic.h b/include/jemalloc/internal/atomic.h index 3f15ea14..3936f68b 100644 --- a/include/jemalloc/internal/atomic.h +++ b/include/jemalloc/internal/atomic.h @@ -66,8 +66,7 @@ void atomic_write_u(unsigned *p, unsigned x); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ATOMIC_C_)) /******************************************************************************/ /* 64-bit operations. */ -#if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) -# if (defined(__amd64__) || defined(__x86_64__)) +#if (defined(__amd64__) || defined(__x86_64__)) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) { @@ -125,7 +124,7 @@ atomic_write_uint64(uint64_t *p, uint64_t x) : "memory" /* Clobbers. */ ); } -# elif (defined(JEMALLOC_C11ATOMICS)) +#elif (defined(JEMALLOC_C11ATOMICS)) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) { @@ -153,7 +152,7 @@ atomic_write_uint64(uint64_t *p, uint64_t x) volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; atomic_store(a, x); } -# elif (defined(JEMALLOC_ATOMIC9)) +#elif (defined(JEMALLOC_ATOMIC9)) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) { @@ -193,7 +192,7 @@ atomic_write_uint64(uint64_t *p, uint64_t x) atomic_store_rel_long(p, x); } -# elif (defined(JEMALLOC_OSATOMIC)) +#elif (defined(JEMALLOC_OSATOMIC)) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) { @@ -225,7 +224,7 @@ atomic_write_uint64(uint64_t *p, uint64_t x) o = atomic_read_uint64(p); } while (atomic_cas_uint64(p, o, x)); } -# elif (defined(_MSC_VER)) +#elif (defined(_MSC_VER)) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) { @@ -255,7 +254,7 @@ atomic_write_uint64(uint64_t *p, uint64_t x) InterlockedExchange64(p, x); } -# elif (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || \ +#elif (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || \ defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8)) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) @@ -284,9 +283,8 @@ atomic_write_uint64(uint64_t *p, uint64_t x) __sync_lock_test_and_set(p, x); } -# else -# error "Missing implementation for 64-bit atomic operations" -# endif +#else +# error "Missing implementation for 64-bit atomic operations" #endif /******************************************************************************/ -- GitLab From 2ea7742e6ffa7fb20538c0e2dba6ceec80cbe8d9 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 10 Jun 2016 00:17:19 +0900 Subject: [PATCH 084/544] Add Travis-CI configuration --- .travis.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..1fed4f8e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,29 @@ +language: c + +matrix: + include: + - os: linux + compiler: gcc + - os: linux + compiler: gcc + env: + - EXTRA_FLAGS=-m32 + addons: + apt: + packages: + - gcc-multilib + - os: osx + compiler: clang + - os: osx + compiler: clang + env: + - EXTRA_FLAGS=-m32 + +before_script: + - autoconf + - ./configure${EXTRA_FLAGS:+ CC="$CC $EXTRA_FLAGS"} + - make -j3 + - make -j3 tests + +script: + - make check -- GitLab From ccd64160736c6e94f84a8bf045ecbbc6a4228604 Mon Sep 17 00:00:00 2001 From: Elliot Ronaghan Date: Tue, 14 Jun 2016 13:18:08 -0700 Subject: [PATCH 085/544] Add -dynamic for integration and stress tests with Cray compiler wrappers Cray systems come with compiler wrappers to simplify building parallel applications. CC is the C++ wrapper, and cc is the C wrapper. The wrappers call the base {Cray, Intel, PGI, or GNU} compiler with vendor specific flags. The "Programming Environment" (prgenv) that's currently loaded determines the base compiler. e.g. compiling with gnu looks something like: module load PrgEnv-gnu cc hello.c On most systems the wrappers defaults to `-static` mode, which causes them to only look for static libraries, and not for any dynamic ones (even if the dynamic version was explicitly listed.) The integration and stress tests expect to be using the .so, so we have to run the with -dynamic so that wrapper will find/use the .so. --- Makefile.in | 5 +++-- configure.ac | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Makefile.in b/Makefile.in index a24fde95..4347706c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -56,6 +56,7 @@ SOREV = @SOREV@ PIC_CFLAGS = @PIC_CFLAGS@ CTARGET = @CTARGET@ LDTARGET = @LDTARGET@ +TEST_LD_MODE = @TEST_LD_MODE@ MKLIB = @MKLIB@ AR = @AR@ ARFLAGS = @ARFLAGS@ @@ -293,11 +294,11 @@ $(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(TESTS_UNIT_LINK_OBJS) $(objroot)test/integration/%$(EXE): $(objroot)test/integration/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) @mkdir -p $(@D) - $(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(filter -lpthread,$(LIBS))) -lm $(EXTRA_LDFLAGS) + $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(filter -lpthread,$(LIBS))) -lm $(EXTRA_LDFLAGS) $(objroot)test/stress/%$(EXE): $(objroot)test/stress/%.$(O) $(C_JET_OBJS) $(C_TESTLIB_STRESS_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) @mkdir -p $(@D) - $(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(LIBS)) -lm $(EXTRA_LDFLAGS) + $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(LIBS)) -lm $(EXTRA_LDFLAGS) build_lib_shared: $(DSOS) build_lib_static: $(STATIC_LIBS) diff --git a/configure.ac b/configure.ac index 538e53f4..ede0993e 100644 --- a/configure.ac +++ b/configure.ac @@ -131,6 +131,18 @@ if test "x$GCC" != "xyes" ; then [je_cv_msvc=no])]) fi +dnl check if a cray prgenv wrapper compiler is being used +je_cv_cray_prgenv_wrapper="" +if test "x${PE_ENV}" != "x" ; then + case "${CC}" in + CC|cc) + je_cv_cray_prgenv_wrapper="yes" + ;; + *) + ;; + esac +fi + if test "x$CFLAGS" = "x" ; then no_CFLAGS="yes" if test "x$GCC" = "xyes" ; then @@ -269,11 +281,16 @@ SOREV="${so}.${rev}" PIC_CFLAGS='-fPIC -DPIC' CTARGET='-o $@' LDTARGET='-o $@' +TEST_LD_MODE= EXTRA_LDFLAGS= ARFLAGS='crus' AROUT=' $@' CC_MM=1 +if test "x$je_cv_cray_prgenv_wrapper" = "xyes" ; then + TEST_LD_MODE='-dynamic' +fi + AN_MAKEVAR([AR], [AC_PROG_AR]) AN_PROGRAM([ar], [AC_PROG_AR]) AC_DEFUN([AC_PROG_AR], [AC_CHECK_TOOL(AR, ar, :)]) @@ -432,6 +449,7 @@ AC_SUBST([SOREV]) AC_SUBST([PIC_CFLAGS]) AC_SUBST([CTARGET]) AC_SUBST([LDTARGET]) +AC_SUBST([TEST_LD_MODE]) AC_SUBST([MKLIB]) AC_SUBST([ARFLAGS]) AC_SUBST([AROUT]) -- GitLab From ae3314785bf9726e5a97e5c98f70dcb12e6a7a90 Mon Sep 17 00:00:00 2001 From: Elliot Ronaghan Date: Tue, 14 Jun 2016 14:20:28 -0700 Subject: [PATCH 086/544] Fix librt detection when using a Cray compiler wrapper The Cray compiler wrappers will often add `-lrt` to the base compiler with `-static` linking (the default at most sites.) However, `-lrt` isn't automatically added with `-dynamic`. This means that if jemalloc was built with `-static`, but then used in a program with `-dynamic` jemalloc won't have detected that librt is a dependency. The integration and stress tests use -dynamic, which is causing undefined references to clock_gettime(). This just adds an extra check for librt (ignoring the autoconf cache) with `-dynamic` thrown. It also stops filtering librt from the integration tests. With this `make check` passes for: - PrgEnv-gnu - PrgEnv-intel - PrgEnv-pgi PrgEnv-cray still needs more work (will be in a separate patch.) --- Makefile.in | 2 +- configure.ac | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 4347706c..b78e1500 100644 --- a/Makefile.in +++ b/Makefile.in @@ -294,7 +294,7 @@ $(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(TESTS_UNIT_LINK_OBJS) $(objroot)test/integration/%$(EXE): $(objroot)test/integration/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) @mkdir -p $(@D) - $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(filter -lpthread,$(LIBS))) -lm $(EXTRA_LDFLAGS) + $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -lpthread,$(LIBS))) -lm $(EXTRA_LDFLAGS) $(objroot)test/stress/%$(EXE): $(objroot)test/stress/%.$(O) $(C_JET_OBJS) $(C_TESTLIB_STRESS_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) @mkdir -p $(@D) diff --git a/configure.ac b/configure.ac index ede0993e..e5164ba8 100644 --- a/configure.ac +++ b/configure.ac @@ -1232,6 +1232,20 @@ CPPFLAGS="$CPPFLAGS -D_REENTRANT" dnl Check whether clock_gettime(2) is in libc or librt. AC_SEARCH_LIBS([clock_gettime], [rt]) +dnl Cray wrapper compiler often adds `-lrt` when using `-static`. Check with +dnl `-dynamic` as well in case a user tries to dynamically link in jemalloc +if test "x$je_cv_cray_prgenv_wrapper" = "xyes" ; then + if test "$ac_cv_search_clock_gettime" != "-lrt"; then + SAVED_CFLAGS="${CFLAGS}" + + unset ac_cv_search_clock_gettime + JE_CFLAGS_APPEND([-dynamic]) + AC_SEARCH_LIBS([clock_gettime], [rt]) + + CFLAGS="${SAVED_CFLAGS}" + fi +fi + dnl Check if the GNU-specific secure_getenv function exists. AC_CHECK_FUNC([secure_getenv], [have_secure_getenv="1"], -- GitLab From 1167e9eff342d3c0f39bb7e8aabc40a34ac0b2fe Mon Sep 17 00:00:00 2001 From: Elliot Ronaghan Date: Fri, 17 Jun 2016 13:28:39 -0700 Subject: [PATCH 087/544] Check for __builtin_unreachable at configure time Add a configure check for __builtin_unreachable instead of basing its availability on the __GNUC__ version. On OS X using gcc (a real gcc, not the bundled version that's just a gcc front-end) leads to a linker assertion: https://github.com/jemalloc/jemalloc/issues/266 It turns out that this is caused by a gcc bug resulting from the use of __builtin_unreachable(): https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57438 To work around this bug, check that __builtin_unreachable() actually works at configure time, and if it doesn't use abort() instead. The check is based on https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57438#c21. With this `make check` passes with a homebrew installed gcc-5 and gcc-6. --- configure.ac | 17 ++++++++++++++ .../internal/jemalloc_internal_defs.h.in | 6 +++++ include/jemalloc/internal/util.h | 22 +++++-------------- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/configure.ac b/configure.ac index e5164ba8..ad7ace52 100644 --- a/configure.ac +++ b/configure.ac @@ -1038,6 +1038,23 @@ if test "x$enable_cache_oblivious" = "x1" ; then fi AC_SUBST([enable_cache_oblivious]) + + +JE_COMPILABLE([a program using __builtin_unreachable], [ +void foo (void) { + __builtin_unreachable(); +} +], [ + { + foo(); + } +], [je_cv_gcc_builtin_unreachable]) +if test "x${je_cv_gcc_builtin_ffsl}" = "xyes" ; then + AC_DEFINE([JEMALLOC_INTERNAL_UNREACHABLE], [__builtin_unreachable]) +else + AC_DEFINE([JEMALLOC_INTERNAL_UNREACHABLE], [abort]) +fi + dnl ============================================================================ dnl Check for __builtin_ffsl(), then ffsl(3), and fail if neither are found. dnl One of those two functions should (theoretically) exist on all platforms diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 49e2cf06..cebd6a53 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -185,6 +185,12 @@ /* TLS is used to map arenas and magazine caches to threads. */ #undef JEMALLOC_TLS +/* + * Used to mark unreachable code to quiet "end of non-void" compiler warnings. + * Don't use this directly; instead use unreachable() from util.h + */ +#undef JEMALLOC_INTERNAL_UNREACHABLE + /* * ffs*() functions to use for bitmapping. Don't use these directly; instead, * use ffs_*() from util.h. diff --git a/include/jemalloc/internal/util.h b/include/jemalloc/internal/util.h index a0c2203d..aee00d6d 100644 --- a/include/jemalloc/internal/util.h +++ b/include/jemalloc/internal/util.h @@ -61,30 +61,20 @@ # define JEMALLOC_CC_SILENCE_INIT(v) #endif -#define JEMALLOC_GNUC_PREREQ(major, minor) \ - (!defined(__clang__) && \ - (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))) -#ifndef __has_builtin -# define __has_builtin(builtin) (0) -#endif -#define JEMALLOC_CLANG_HAS_BUILTIN(builtin) \ - (defined(__clang__) && __has_builtin(builtin)) - #ifdef __GNUC__ # define likely(x) __builtin_expect(!!(x), 1) # define unlikely(x) __builtin_expect(!!(x), 0) -# if JEMALLOC_GNUC_PREREQ(4, 6) || \ - JEMALLOC_CLANG_HAS_BUILTIN(__builtin_unreachable) -# define unreachable() __builtin_unreachable() -# else -# define unreachable() abort() -# endif #else # define likely(x) !!(x) # define unlikely(x) !!(x) -# define unreachable() abort() #endif +#if !defined(JEMALLOC_INTERNAL_UNREACHABLE) +# error JEMALLOC_INTERNAL_UNREACHABLE should have been defined by configure +#endif + +#define unreachable() JEMALLOC_INTERNAL_UNREACHABLE() + #include "jemalloc/internal/assert.h" /* Use to assert a particular configuration, e.g., cassert(config_debug). */ -- GitLab From e37720cb4a4661fd3b8ece01b1b1d83020ced99f Mon Sep 17 00:00:00 2001 From: rustyx Date: Wed, 22 Jun 2016 22:28:20 +0200 Subject: [PATCH 088/544] Fix MSVC project --- msvc/projects/vc2015/jemalloc/jemalloc.vcxproj | 5 ++++- .../projects/vc2015/jemalloc/jemalloc.vcxproj.filters | 11 ++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj index 59f52f96..da75a968 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj @@ -68,11 +68,13 @@ + + @@ -112,6 +114,7 @@ + {8D6BB292-9E1C-413D-9F98-4864BDC1514A} @@ -392,4 +395,4 @@ - + \ No newline at end of file diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters index 159b2e72..57395e70 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters @@ -170,6 +170,12 @@ Header Files\msvc_compat\C99 + + Header Files\internal + + + Header Files\internal + @@ -247,5 +253,8 @@ Source Files + + Source Files + - + \ No newline at end of file -- GitLab From aec07531bcfbdceaad020aee0048581d72a8c26f Mon Sep 17 00:00:00 2001 From: Elliot Ronaghan Date: Tue, 14 Jun 2016 15:26:07 -0700 Subject: [PATCH 089/544] Add initial support for building with the cray compiler Get jemalloc building and passing `make check_unit` with cray 8.4. An inlining bug in 8.4 results in internal errors while trying to build jemalloc. This has already been reported and fixed for the 8.5 release. In order to work around the inlining bug, disable gnu compatibility and limit ipa optimizations. I copied the msvc compiler check for cray, but note that we perform the test even if we think we're using gcc because cray pretends to be gcc if `-hgnu` (which is enabled by default) is used. I couldn't come up with a principled way to check for the inlining bug, so instead I just checked compiler versions. The build had lots of warnings I need to address and cray doesn't support -MM or -MT for dependency tracking, so I had to do `make CC_MM=`. --- configure.ac | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/configure.ac b/configure.ac index ad7ace52..1f0cc1f3 100644 --- a/configure.ac +++ b/configure.ac @@ -118,6 +118,7 @@ dnl If CFLAGS isn't defined, set CFLAGS to something reasonable. Otherwise, dnl just prevent autoconf from molesting CFLAGS. CFLAGS=$CFLAGS AC_PROG_CC + if test "x$GCC" != "xyes" ; then AC_CACHE_CHECK([whether compiler is MSVC], [je_cv_msvc], @@ -143,6 +144,30 @@ if test "x${PE_ENV}" != "x" ; then esac fi +AC_CACHE_CHECK([whether compiler is cray], + [je_cv_cray], + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], + [ +#ifndef _CRAYC + int fail[-1]; +#endif +])], + [je_cv_cray=yes], + [je_cv_cray=no])]) + +if test "x${je_cv_cray}" = "xyes" ; then + AC_CACHE_CHECK([whether cray compiler version is 8.4], + [je_cv_cray_84], + [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], + [ +#if !(_RELEASE_MAJOR == 8 && _RELEASE_MINOR == 4) + int fail[-1]; +#endif +])], + [je_cv_cray_84=yes], + [je_cv_cray_84=no])]) +fi + if test "x$CFLAGS" = "x" ; then no_CFLAGS="yes" if test "x$GCC" = "xyes" ; then @@ -164,6 +189,13 @@ if test "x$CFLAGS" = "x" ; then JE_CFLAGS_APPEND([-FS]) CPPFLAGS="$CPPFLAGS -I${srcdir}/include/msvc_compat" fi + if test "x$je_cv_cray" = "xyes" ; then + dnl cray compiler 8.4 has an inlining bug + if test "x$je_cv_cray_84" = "xyes" ; then + JE_CFLAGS_APPEND([-hipa2]) + JE_CFLAGS_APPEND([-hnognu]) + fi + fi fi dnl Append EXTRA_CFLAGS to CFLAGS, if defined. if test "x$EXTRA_CFLAGS" != "x" ; then -- GitLab From 3ef67930e025cbc68735d0ebd2de7690c816658c Mon Sep 17 00:00:00 2001 From: Elliot Ronaghan Date: Tue, 14 Jun 2016 15:26:29 -0700 Subject: [PATCH 090/544] Disable automatic dependency generation for the Cray compiler Cray only supports `-M` for generating dependency files. It does not support `-MM` or `-MT`, so don't try to use them. I just reused the existing mechanism for turning auto-dependency generation off (`CC_MM=`), but it might be more principled to add a configure test to check if the compiler supports `-MM` and `-MT`, instead of manually tracking which compilers don't support those flags. --- configure.ac | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure.ac b/configure.ac index 1f0cc1f3..db616e0e 100644 --- a/configure.ac +++ b/configure.ac @@ -323,6 +323,10 @@ if test "x$je_cv_cray_prgenv_wrapper" = "xyes" ; then TEST_LD_MODE='-dynamic' fi +if test "x${je_cv_cray}" = "xyes" ; then + CC_MM= +fi + AN_MAKEVAR([AR], [AC_PROG_AR]) AN_PROGRAM([ar], [AC_PROG_AR]) AC_DEFUN([AC_PROG_AR], [AC_CHECK_TOOL(AR, ar, :)]) -- GitLab From 3dee73faf2c9c1008a4e3281cd7dd0123d16a8d3 Mon Sep 17 00:00:00 2001 From: Elliot Ronaghan Date: Tue, 14 Jun 2016 15:26:53 -0700 Subject: [PATCH 091/544] Add Cray compiler's equivalent of -Werror before __attribute__ checks Cray uses -herror_on_warning instead of -Werror. Use it everywhere -Werror is currently used for __attribute__ checks so configure actually detects they're not supported. --- configure.ac | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure.ac b/configure.ac index db616e0e..13ce6860 100644 --- a/configure.ac +++ b/configure.ac @@ -504,6 +504,7 @@ fi dnl Check for tls_model attribute support (clang 3.0 still lacks support). SAVED_CFLAGS="${CFLAGS}" JE_CFLAGS_APPEND([-Werror]) +JE_CFLAGS_APPEND([-herror_on_warning]) JE_COMPILABLE([tls_model attribute], [], [static __thread int __attribute__((tls_model("initial-exec"), unused)) foo; @@ -519,6 +520,7 @@ fi dnl Check for alloc_size attribute support. SAVED_CFLAGS="${CFLAGS}" JE_CFLAGS_APPEND([-Werror]) +JE_CFLAGS_APPEND([-herror_on_warning]) JE_COMPILABLE([alloc_size attribute], [#include ], [void *foo(size_t size) __attribute__((alloc_size(1)));], [je_cv_alloc_size]) @@ -529,6 +531,7 @@ fi dnl Check for format(gnu_printf, ...) attribute support. SAVED_CFLAGS="${CFLAGS}" JE_CFLAGS_APPEND([-Werror]) +JE_CFLAGS_APPEND([-herror_on_warning]) JE_COMPILABLE([format(gnu_printf, ...) attribute], [#include ], [void *foo(const char *format, ...) __attribute__((format(gnu_printf, 1, 2)));], [je_cv_format_gnu_printf]) @@ -539,6 +542,7 @@ fi dnl Check for format(printf, ...) attribute support. SAVED_CFLAGS="${CFLAGS}" JE_CFLAGS_APPEND([-Werror]) +JE_CFLAGS_APPEND([-herror_on_warning]) JE_COMPILABLE([format(printf, ...) attribute], [#include ], [void *foo(const char *format, ...) __attribute__((format(printf, 1, 2)));], [je_cv_format_printf]) -- GitLab From 47b34dd39850b8b157c67887d9b6bf7bd3095796 Mon Sep 17 00:00:00 2001 From: Elliot Ronaghan Date: Thu, 7 Jul 2016 15:06:01 -0700 Subject: [PATCH 092/544] Disable irrelevant Cray compiler warnings if cc-silence is enabled Cray is pretty warning-happy, so disable ones that aren't helpful. Each warning has a numeric value instead of having named flags to disable specific warnings. Disable warnings 128 and 1357. 128: Ignore unreachable code warning. Cray warns about `not_reached()` not being reachable in a couple of places because it detects that some loops will never terminate. 1357: Ignore warning about redefinition of malloc and friends With this patch, Cray 8.4.0 and 8.5.1 build cleanly and pass `make check` --- configure.ac | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/configure.ac b/configure.ac index 13ce6860..e1639d51 100644 --- a/configure.ac +++ b/configure.ac @@ -195,6 +195,12 @@ if test "x$CFLAGS" = "x" ; then JE_CFLAGS_APPEND([-hipa2]) JE_CFLAGS_APPEND([-hnognu]) fi + if test "x$enable_cc_silence" != "xno" ; then + dnl ignore unreachable code warning + JE_CFLAGS_APPEND([-hnomessage=128]) + dnl ignore redefinition of "malloc", "free", etc warning + JE_CFLAGS_APPEND([-hnomessage=1357]) + fi fi fi dnl Append EXTRA_CFLAGS to CFLAGS, if defined. -- GitLab From 4abaee5d13a54c677cd132c481dbf7621f785fec Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 8 Jul 2016 13:28:16 +0900 Subject: [PATCH 093/544] Avoid getting the same default zone twice in a row. 847ff22 added a call to malloc_default_zone() before the main loop in register_zone, effectively making malloc_default_zone() called twice without any different outcome expected in the returned result. It is also called once at the beginning, and a second time at the end of the loop block. Instead, call it only once per iteration. --- src/zone.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/zone.c b/src/zone.c index ca235da4..9432f45a 100644 --- a/src/zone.c +++ b/src/zone.c @@ -246,7 +246,6 @@ register_zone(void) malloc_zone_register(&zone); do { - default_zone = malloc_default_zone(); /* * Unregister and reregister the default zone. On OSX >= 10.6, * unregistering takes the last registered zone and places it @@ -272,5 +271,7 @@ register_zone(void) malloc_zone_unregister(purgeable_zone); malloc_zone_register(purgeable_zone); } - } while (malloc_default_zone() != &zone); + + default_zone = malloc_default_zone(); + } while (default_zone != &zone); } -- GitLab From 19c9a3e828ed46f1576521c264640e60bd0cb01f Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 8 Jul 2016 13:35:35 +0900 Subject: [PATCH 094/544] Change how the default zone is found On OSX 10.12, malloc_default_zone returns a special zone that is not present in the list of registered zones. That zone uses a "lite zone" if one is present (apparently enabled when malloc stack logging is enabled), or the first registered zone otherwise. In practice this means unless malloc stack logging is enabled, the first registered zone is the default. So get the list of zones to get the first one, instead of relying on malloc_default_zone. --- src/zone.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/zone.c b/src/zone.c index 9432f45a..92381614 100644 --- a/src/zone.c +++ b/src/zone.c @@ -168,6 +168,33 @@ zone_force_unlock(malloc_zone_t *zone) jemalloc_postfork_parent(); } +static malloc_zone_t *get_default_zone() +{ + malloc_zone_t **zones = NULL; + unsigned int num_zones = 0; + + /* + * On OSX 10.12, malloc_default_zone returns a special zone that is not + * present in the list of registered zones. That zone uses a "lite zone" + * if one is present (apparently enabled when malloc stack logging is + * enabled), or the first registered zone otherwise. In practice this + * means unless malloc stack logging is enabled, the first registered + * zone is the default. + * So get the list of zones to get the first one, instead of relying on + * malloc_default_zone. + */ + if (KERN_SUCCESS != malloc_get_all_zones(0, NULL, (vm_address_t**) &zones, + &num_zones)) { + /* Reset the value in case the failure happened after it was set. */ + num_zones = 0; + } + + if (num_zones) + return zones[0]; + + return malloc_default_zone(); +} + JEMALLOC_ATTR(constructor) void register_zone(void) @@ -177,7 +204,7 @@ register_zone(void) * If something else replaced the system default zone allocator, don't * register jemalloc's. */ - malloc_zone_t *default_zone = malloc_default_zone(); + malloc_zone_t *default_zone = get_default_zone(); malloc_zone_t *purgeable_zone = NULL; if (!default_zone->zone_name || strcmp(default_zone->zone_name, "DefaultMallocZone") != 0) { @@ -272,6 +299,6 @@ register_zone(void) malloc_zone_register(purgeable_zone); } - default_zone = malloc_default_zone(); + default_zone = get_default_zone(); } while (default_zone != &zone); } -- GitLab From c716c1e5318c19569581637fd33220999c0d6a4b Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 12 Sep 2016 11:56:24 -0700 Subject: [PATCH 095/544] Update project URL. --- README | 2 +- doc/jemalloc.xml.in | 2 +- jemalloc.pc.in | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README b/README index 67cbf6da..3a6e0d27 100644 --- a/README +++ b/README @@ -17,4 +17,4 @@ jemalloc. The ChangeLog file contains a brief summary of changes for each release. -URL: http://www.canonware.com/jemalloc/ +URL: http://jemalloc.net/ diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index bfc0073b..006e9e06 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -52,7 +52,7 @@ LIBRARY This manual describes jemalloc @jemalloc_version@. More information can be found at the jemalloc website. + url="http://jemalloc.net/">jemalloc website. SYNOPSIS diff --git a/jemalloc.pc.in b/jemalloc.pc.in index 1a3ad9b3..a318e8dd 100644 --- a/jemalloc.pc.in +++ b/jemalloc.pc.in @@ -6,7 +6,7 @@ install_suffix=@install_suffix@ Name: jemalloc Description: A general purpose malloc(3) implementation that emphasizes fragmentation avoidance and scalable concurrency support. -URL: http://www.canonware.com/jemalloc +URL: http://jemalloc.net/ Version: @jemalloc_version@ Cflags: -I${includedir} Libs: -L${libdir} -ljemalloc${install_suffix} -- GitLab From d4ce47e7fb6af53fd0460052100382c728b58566 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 12 Sep 2016 16:12:15 -0700 Subject: [PATCH 096/544] Change html manual encoding to UTF-8. This works around GitHub's broken automatic reformatting from ISO-8859-1 to UTF-8 when serving static html. Remove from e.g. malloc, add a custom template that does not append parentheses, and manually specify them, e.g. malloc(). This works around apparently broken XSL formatting that causes to be emitted in html (rather than , or better yet, nothing). --- doc/html.xsl.in | 1 + doc/jemalloc.xml.in | 182 ++++++++++++++++++++++---------------------- doc/stylesheet.xsl | 5 +- 3 files changed, 96 insertions(+), 92 deletions(-) diff --git a/doc/html.xsl.in b/doc/html.xsl.in index a91d9746..ec4fa655 100644 --- a/doc/html.xsl.in +++ b/doc/html.xsl.in @@ -1,4 +1,5 @@ + diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 006e9e06..8000461f 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -180,20 +180,20 @@ Standard API - The malloc function allocates + The malloc() function allocates size bytes of uninitialized memory. The allocated space is suitably aligned (after possible pointer coercion) for storage of any type of object. - The calloc function allocates + The calloc() function allocates space for number objects, each size bytes in length. The result is identical to - calling malloc with an argument of + calling malloc() with an argument of number * size, with the exception that the allocated memory is explicitly initialized to zero bytes. - The posix_memalign function + The posix_memalign() function allocates size bytes of memory such that the allocation's base address is a multiple of alignment, and returns the allocation in the value @@ -201,7 +201,7 @@ alignment must be a power of 2 at least as large as sizeof(void *). - The aligned_alloc function + The aligned_alloc() function allocates size bytes of memory such that the allocation's base address is a multiple of alignment. The requested @@ -209,7 +209,7 @@ undefined if size is not an integral multiple of alignment. - The realloc function changes the + The realloc() function changes the size of the previously allocated memory referenced by ptr to size bytes. The contents of the memory are unchanged up to the lesser of the new and old @@ -217,26 +217,26 @@ portion of the memory are undefined. Upon success, the memory referenced by ptr is freed and a pointer to the newly allocated memory is returned. Note that - realloc may move the memory allocation, + realloc() may move the memory allocation, resulting in a different return value than ptr. If ptr is NULL, the - realloc function behaves identically to - malloc for the specified size. + realloc() function behaves identically to + malloc() for the specified size. - The free function causes the + The free() function causes the allocated memory referenced by ptr to be made available for future allocations. If ptr is NULL, no action occurs. Non-standard API - The mallocx, - rallocx, - xallocx, - sallocx, - dallocx, - sdallocx, and - nallocx functions all have a + The mallocx(), + rallocx(), + xallocx(), + sallocx(), + dallocx(), + sdallocx(), and + nallocx() functions all have a flags argument that can be used to specify options. The functions only check the options that are contextually relevant. Use bitwise or (|) operations to @@ -307,19 +307,19 @@ - The mallocx function allocates at + The mallocx() function allocates at least size bytes of memory, and returns a pointer to the base address of the allocation. Behavior is undefined if size is 0. - The rallocx function resizes the + The rallocx() function resizes the allocation at ptr to be at least size bytes, and returns a pointer to the base address of the resulting allocation, which may or may not have moved from its original location. Behavior is undefined if size is 0. - The xallocx function resizes the + The xallocx() function resizes the allocation at ptr in place to be at least size bytes, and returns the real size of the allocation. If extra is non-zero, an attempt is @@ -332,32 +332,32 @@ language="C">(size + extra > SIZE_T_MAX). - The sallocx function returns the + The sallocx() function returns the real size of the allocation at ptr. - The dallocx function causes the + The dallocx() function causes the memory referenced by ptr to be made available for future allocations. - The sdallocx function is an - extension of dallocx with a + The sdallocx() function is an + extension of dallocx() with a size parameter to allow the caller to pass in the allocation size as an optimization. The minimum valid input size is the original requested size of the allocation, and the maximum valid input size is the corresponding value returned by - nallocx or - sallocx. + nallocx() or + sallocx(). - The nallocx function allocates no + The nallocx() function allocates no memory, but it performs the same size computation as the - mallocx function, and returns the real + mallocx() function, and returns the real size of the allocation that would result from the equivalent - mallocx function call, or + mallocx() function call, or 0 if the inputs exceed the maximum supported size class and/or alignment. Behavior is undefined if size is 0. - The mallctl function provides a + The mallctl() function provides a general interface for introspecting the memory allocator, as well as setting modifiable parameters and triggering actions. The period-separated name argument specifies a @@ -372,12 +372,12 @@ newlen; otherwise pass NULL and 0. - The mallctlnametomib function + The mallctlnametomib() function provides a way to avoid repeated name lookups for applications that repeatedly query the same portion of the namespace, by translating a name to a “Management Information Base” (MIB) that can be passed - repeatedly to mallctlbymib. Upon - successful return from mallctlnametomib, + repeatedly to mallctlbymib(). Upon + successful return from mallctlnametomib(), mibp contains an array of *miblenp integers, where *miblenp is the lesser of the number of components @@ -410,18 +410,18 @@ for (i = 0; i < nbins; i++) { /* Do something with bin_size... */ }]]> - The malloc_stats_print function + The malloc_stats_print() function writes human-readable summary statistics via the write_cb callback function pointer and cbopaque data passed to write_cb, or - malloc_message if + malloc_message() if write_cb is NULL. This function can be called repeatedly. General information that never changes during execution can be omitted by specifying "g" as a character within the opts string. Note that - malloc_message uses the - mallctl* functions internally, so + malloc_message() uses the + mallctl*() functions internally, so inconsistent statistics can be reported if multiple threads use these functions simultaneously. If is specified during configuration, “m” and “a” can be specified @@ -433,15 +433,15 @@ for (i = 0; i < nbins; i++) { would be required to merge counters that track thread cache operations. - The malloc_usable_size function + The malloc_usable_size() function returns the usable size of the allocation pointed to by ptr. The return value may be larger than the size that was requested during allocation. The - malloc_usable_size function is not a - mechanism for in-place realloc; rather + malloc_usable_size() function is not a + mechanism for in-place realloc(); rather it is provided solely as a tool for introspection purposes. Any discrepancy between the requested allocation size and the size reported - by malloc_usable_size should not be + by malloc_usable_size() should not be depended on, since such behavior is entirely implementation-dependent. @@ -459,7 +459,7 @@ for (i = 0; i < nbins; i++) { environment variable MALLOC_CONF, will be interpreted, in that order, from left to right as options. Note that malloc_conf may be read before - main is entered, so the declaration of + main() is entered, so the declaration of malloc_conf should specify an initializer that contains the final value to be read by jemalloc. and malloc_conf are compile-time mechanisms, whereas @@ -540,14 +540,14 @@ for (i = 0; i < nbins; i++) { nearest multiple of the cacheline size, or specify cacheline alignment when allocating. - The realloc, - rallocx, and - xallocx functions may resize allocations + The realloc(), + rallocx(), and + xallocx() functions may resize allocations without moving them under limited circumstances. Unlike the - *allocx API, the standard API does not + *allocx() API, the standard API does not officially round up the usable size of an allocation to the nearest size class, so technically it is necessary to call - realloc to grow e.g. a 9-byte allocation to + realloc() to grow e.g. a 9-byte allocation to 16 bytes, or shrink a 16-byte allocation to 9 bytes. Growth and shrinkage trivially succeeds in place as long as the pre-size and post-size both round up to the same size class. No other API guarantees are made regarding @@ -686,7 +686,7 @@ for (i = 0; i < nbins; i++) { MALLCTL NAMESPACE The following names are defined in the namespace accessible via the - mallctl* functions. Value types are + mallctl*() functions. Value types are specified in parentheses, their readable/writable statuses are encoded as rw, r-, -w, or --, and required build configuration flags follow, if @@ -717,7 +717,7 @@ for (i = 0; i < nbins; i++) { rw If a value is passed in, refresh the data from which - the mallctl* functions report values, + the mallctl*() functions report values, and increment the epoch. Return the current epoch. This is useful for detecting whether another thread caused a refresh. @@ -987,19 +987,19 @@ for (i = 0; i < nbins; i++) { r- Enable/disable statistics printing at exit. If - enabled, the malloc_stats_print + enabled, the malloc_stats_print() function is called at program exit via an atexit 3 function. If is specified during configuration, this has the potential to cause deadlock for a multi-threaded process that exits while one or more threads are executing in the memory allocation - functions. Furthermore, atexit may + functions. Furthermore, atexit() may allocate memory during application initialization and then deadlock internally when jemalloc in turn calls - atexit, so this option is not + atexit(), so this option is not universally usable (though the application can register its own - atexit function with equivalent + atexit() function with equivalent functionality). Therefore, this option should only be used with care; it is primarily intended as a performance tuning aid during application development. This option is disabled by default. @@ -1034,8 +1034,8 @@ for (i = 0; i < nbins; i++) { Zero filling enabled/disabled. If enabled, each byte of uninitialized allocated memory will be initialized to 0. Note that this initialization only happens once for each byte, so - realloc and - rallocx calls do not zero memory that + realloc() and + rallocx() calls do not zero memory that was previously allocated. This is intended for debugging and will impact performance negatively. This option is disabled by default. @@ -1256,11 +1256,11 @@ malloc_conf = "xmalloc:true";]]> <prefix>.<pid>.<seq>.f.heap, where <prefix> is controlled by the opt.prof_prefix - option. Note that atexit may allocate + option. Note that atexit() may allocate memory during application initialization and then deadlock internally - when jemalloc in turn calls atexit, so + when jemalloc in turn calls atexit(), so this option is not universally usable (though the application can - register its own atexit function with + register its own atexit() function with equivalent functionality). This option is disabled by default. @@ -1319,7 +1319,7 @@ malloc_conf = "xmalloc:true";]]> thread.allocated mallctl. This is useful for avoiding the overhead of repeated - mallctl* calls. + mallctl*() calls. @@ -1346,7 +1346,7 @@ malloc_conf = "xmalloc:true";]]> thread.deallocated mallctl. This is useful for avoiding the overhead of repeated - mallctl* calls. + mallctl*() calls. @@ -2189,8 +2189,8 @@ struct extent_hooks_s { Number of pages within unused extents that are potentially dirty, and for which - madvise... - MADV_DONTNEED or + madvise(... + MADV_DONTNEED) or similar has not been called. @@ -2253,8 +2253,8 @@ struct extent_hooks_s { r- [] - Number of madvise... - MADV_DONTNEED or + Number of madvise(... + MADV_DONTNEED) or similar calls made to purge dirty pages. @@ -2579,10 +2579,10 @@ MAPPED_LIBRARIES: to override the function which emits the text strings forming the errors and warnings if for some reason the STDERR_FILENO file descriptor is not suitable for this. - malloc_message takes the + malloc_message() takes the cbopaque pointer argument that is NULL unless overridden by the arguments in a call to - malloc_stats_print, followed by a string + malloc_stats_print(), followed by a string pointer. Please note that doing anything which tries to allocate memory in this function is likely to result in a crash or deadlock. @@ -2593,15 +2593,15 @@ MAPPED_LIBRARIES: RETURN VALUES Standard API - The malloc and - calloc functions return a pointer to the + The malloc() and + calloc() functions return a pointer to the allocated memory if successful; otherwise a NULL pointer is returned and errno is set to ENOMEM. - The posix_memalign function + The posix_memalign() function returns the value 0 if successful; otherwise it returns an error value. - The posix_memalign function will fail + The posix_memalign() function will fail if: @@ -2620,11 +2620,11 @@ MAPPED_LIBRARIES: - The aligned_alloc function returns + The aligned_alloc() function returns a pointer to the allocated memory if successful; otherwise a NULL pointer is returned and errno is set. The - aligned_alloc function will fail if: + aligned_alloc() function will fail if: EINVAL @@ -2641,44 +2641,44 @@ MAPPED_LIBRARIES: - The realloc function returns a + The realloc() function returns a pointer, possibly identical to ptr, to the allocated memory if successful; otherwise a NULL pointer is returned, and errno is set to ENOMEM if the error was the result of an - allocation failure. The realloc + allocation failure. The realloc() function always leaves the original buffer intact when an error occurs. - The free function returns no + The free() function returns no value. Non-standard API - The mallocx and - rallocx functions return a pointer to + The mallocx() and + rallocx() functions return a pointer to the allocated memory if successful; otherwise a NULL pointer is returned to indicate insufficient contiguous memory was available to service the allocation request. - The xallocx function returns the + The xallocx() function returns the real size of the resulting resized allocation pointed to by ptr, which is a value less than size if the allocation could not be adequately grown in place. - The sallocx function returns the + The sallocx() function returns the real size of the allocation pointed to by ptr. - The nallocx returns the real size + The nallocx() returns the real size that would result from a successful equivalent - mallocx function call, or zero if + mallocx() function call, or zero if insufficient memory is available to perform the size computation. - The mallctl, - mallctlnametomib, and - mallctlbymib functions return 0 on + The mallctl(), + mallctlnametomib(), and + mallctlbymib() functions return 0 on success; otherwise they return an error value. The functions will fail if: @@ -2714,13 +2714,13 @@ MAPPED_LIBRARIES: EFAULT An interface with side effects failed in some way - not directly related to mallctl* + not directly related to mallctl*() read/write processing. - The malloc_usable_size function + The malloc_usable_size() function returns the usable size of the allocation pointed to by ptr. @@ -2769,13 +2769,13 @@ malloc_conf = "narenas:1";]]> STANDARDS - The malloc, - calloc, - realloc, and - free functions conform to ISO/IEC + The malloc(), + calloc(), + realloc(), and + free() functions conform to ISO/IEC 9899:1990 (“ISO C90”). - The posix_memalign function conforms + The posix_memalign() function conforms to IEEE Std 1003.1-2001 (“POSIX.1”). diff --git a/doc/stylesheet.xsl b/doc/stylesheet.xsl index 4e334a86..bc8bc2a9 100644 --- a/doc/stylesheet.xsl +++ b/doc/stylesheet.xsl @@ -1,6 +1,9 @@ ansi - + + + + "" -- GitLab From 17c4b8de5f4ef2732dfa83cbc86e2cf112f48635 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Thu, 15 Sep 2016 14:33:28 -0700 Subject: [PATCH 097/544] Fix -Wundef in _MSC_VER check. --- include/jemalloc/jemalloc_macros.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/jemalloc/jemalloc_macros.h.in b/include/jemalloc/jemalloc_macros.h.in index 129240ed..673ffd9b 100644 --- a/include/jemalloc/jemalloc_macros.h.in +++ b/include/jemalloc/jemalloc_macros.h.in @@ -37,7 +37,7 @@ # define JEMALLOC_CXX_THROW #endif -#if _MSC_VER +#if defined(_MSC_VER) # define JEMALLOC_ATTR(s) # define JEMALLOC_ALIGNED(s) __declspec(align(s)) # define JEMALLOC_ALLOC_SIZE(s) -- GitLab From 1cb399b630db16892069cb37b6b0853ca318bb77 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Thu, 22 Sep 2016 09:13:45 -0700 Subject: [PATCH 098/544] Fix arena_bind(). When tsd is not in nominal state (e.g. during thread termination), we should not increment nthreads. --- src/jemalloc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index 10074013..24158552 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -442,15 +442,16 @@ arena_bind(tsd_t *tsd, unsigned ind, bool internal) { arena_t *arena; + if (!tsd_nominal(tsd)) + return; + arena = arena_get(tsd_tsdn(tsd), ind, false); arena_nthreads_inc(arena, internal); - if (tsd_nominal(tsd)) { - if (internal) - tsd_iarena_set(tsd, arena); - else - tsd_arena_set(tsd, arena); - } + if (internal) + tsd_iarena_set(tsd, arena); + else + tsd_arena_set(tsd, arena); } void -- GitLab From bc49157d21e6ec14a41c7b852370d2e6d9509da2 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 22 Sep 2016 11:53:19 -0700 Subject: [PATCH 099/544] Fix extent_recycle() to exclude other arenas' extents. When attempting to recycle an extent at a specified address, check that the extent belongs to the correct arena. --- src/extent.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/extent.c b/src/extent.c index cb67a27c..29c9d2be 100644 --- a/src/extent.c +++ b/src/extent.c @@ -408,7 +408,8 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, if (elm != NULL) { extent = rtree_elm_read_acquired(tsdn, &extents_rtree, elm); - if (extent != NULL && (extent_active_get(extent) || + if (extent != NULL && (extent_arena_get(extent) != arena + || extent_active_get(extent) || extent_retained_get(extent) == cache)) extent = NULL; rtree_elm_release(tsdn, &extents_rtree, elm); -- GitLab From f6d01ff4b7322eeed56c61a11e3e3397765d3f22 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 22 Sep 2016 11:57:28 -0700 Subject: [PATCH 100/544] Protect extents_dirty access with extents_mtx. This fixes race conditions during purging. --- include/jemalloc/internal/arena.h | 21 ++-- include/jemalloc/internal/extent.h | 3 + include/jemalloc/internal/private_symbols.txt | 1 + src/arena.c | 29 +++-- src/extent.c | 116 ++++++++++++------ 5 files changed, 112 insertions(+), 58 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 3c931c34..cee90b50 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -176,12 +176,6 @@ struct arena_s { */ size_t ndirty; - /* - * Ring sentinel used to track unused dirty memory. Dirty memory is - * managed as an LRU of cached extents. - */ - extent_t extents_dirty; - /* * Approximate time in seconds from the creation of a set of unused * dirty pages until an equivalent set of unused dirty pages is purged @@ -240,7 +234,12 @@ struct arena_s { */ extent_heap_t extents_cached[NPSIZES]; extent_heap_t extents_retained[NPSIZES]; - /* Protects extents_cached and extents_retained. */ + /* + * Ring sentinel used to track unused dirty memory. Dirty memory is + * managed as an LRU of cached extents. + */ + extent_t extents_dirty; + /* Protects extents_{cached,retained,dirty}. */ malloc_mutex_t extents_mtx; /* User-configurable extent hook functions. */ @@ -287,10 +286,10 @@ extent_t *arena_extent_cache_alloc(tsdn_t *tsdn, arena_t *arena, size_t alignment, bool *zero); void arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent); -void arena_extent_cache_maybe_insert(arena_t *arena, extent_t *extent, - bool cache); -void arena_extent_cache_maybe_remove(arena_t *arena, extent_t *extent, - bool cache); +void arena_extent_cache_maybe_insert(tsdn_t *tsdn, arena_t *arena, + extent_t *extent, bool cache); +void arena_extent_cache_maybe_remove(tsdn_t *tsdn, arena_t *arena, + extent_t *extent, bool cache); extent_t *arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero); void arena_extent_dalloc_large(tsdn_t *tsdn, arena_t *arena, diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index dbdc8051..eeebdf0f 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -99,6 +99,9 @@ size_t extent_size_quantize_ceil(size_t size); ph_proto(, extent_heap_, extent_heap_t, extent_t) +extent_t *extent_alloc_cache_locked(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool slab); extent_t *extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool slab); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index a489e14a..ae60f6c4 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -145,6 +145,7 @@ extent_addr_randomize extent_addr_set extent_alloc extent_alloc_cache +extent_alloc_cache_locked extent_alloc_dss extent_alloc_mmap extent_alloc_wrapper diff --git a/src/arena.c b/src/arena.c index 7dcf12d5..da9e9859 100644 --- a/src/arena.c +++ b/src/arena.c @@ -101,9 +101,12 @@ arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, } void -arena_extent_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache) +arena_extent_cache_maybe_insert(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + bool cache) { + malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); + if (cache) { extent_ring_insert(&arena->extents_dirty, extent); arena->ndirty += arena_extent_dirty_npages(extent); @@ -111,9 +114,12 @@ arena_extent_cache_maybe_insert(arena_t *arena, extent_t *extent, bool cache) } void -arena_extent_cache_maybe_remove(arena_t *arena, extent_t *extent, bool dirty) +arena_extent_cache_maybe_remove(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + bool dirty) { + malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); + if (dirty) { extent_ring_remove(extent); assert(arena->ndirty >= arena_extent_dirty_npages(extent)); @@ -727,6 +733,8 @@ arena_dirty_count(tsdn_t *tsdn, arena_t *arena) extent_t *extent; size_t ndirty = 0; + malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); + for (extent = qr_next(&arena->extents_dirty, qr_link); extent != &arena->extents_dirty; extent = qr_next(extent, qr_link)) ndirty += extent_size_get(extent) >> LG_PAGE; @@ -741,6 +749,8 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, *next; size_t nstashed = 0; + malloc_mutex_lock(tsdn, &arena->extents_mtx); + /* Stash extents according to ndirty_limit. */ for (extent = qr_next(&arena->extents_dirty, qr_link); extent != &arena->extents_dirty; extent = next) { @@ -756,9 +766,9 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, next = qr_next(extent, qr_link); /* Allocate. */ zero = false; - textent = arena_extent_cache_alloc_locked(tsdn, arena, - r_extent_hooks, extent_base_get(extent), - extent_size_get(extent), 0, CACHELINE, &zero, false); + textent = extent_alloc_cache_locked(tsdn, arena, r_extent_hooks, + extent_base_get(extent), extent_size_get(extent), 0, + CACHELINE, &zero, false); assert(textent == extent); assert(zero == extent_zeroed_get(extent)); extent_ring_remove(extent); @@ -770,6 +780,7 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, break; } + malloc_mutex_unlock(tsdn, &arena->extents_mtx); return (nstashed); } @@ -1788,9 +1799,6 @@ arena_new(tsdn_t *tsdn, unsigned ind) arena->nactive = 0; arena->ndirty = 0; - extent_init(&arena->extents_dirty, arena, NULL, 0, 0, false, false, - false, false); - if (opt_purge == purge_mode_decay) arena_decay_init(arena, arena_decay_time_default_get()); @@ -1804,12 +1812,15 @@ arena_new(tsdn_t *tsdn, unsigned ind) extent_heap_new(&arena->extents_retained[i]); } - arena->extent_hooks = (extent_hooks_t *)&extent_hooks_default; + extent_init(&arena->extents_dirty, arena, NULL, 0, 0, false, false, + false, false); if (malloc_mutex_init(&arena->extents_mtx, "arena_extents", WITNESS_RANK_ARENA_EXTENTS)) return (NULL); + arena->extent_hooks = (extent_hooks_t *)&extent_hooks_default; + ql_new(&arena->extent_cache); if (malloc_mutex_init(&arena->extent_cache_mtx, "arena_extent_cache", WITNESS_RANK_ARENA_EXTENT_CACHE)) diff --git a/src/extent.c b/src/extent.c index 29c9d2be..522cbb9b 100644 --- a/src/extent.c +++ b/src/extent.c @@ -191,18 +191,26 @@ extent_ad_comp(const extent_t *a, const extent_t *b) ph_gen(, extent_heap_, extent_heap_t, extent_t, ph_link, extent_ad_comp) static void -extent_heaps_insert(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) +extent_heaps_insert(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES], + extent_t *extent) { size_t psz = extent_size_quantize_floor(extent_size_get(extent)); pszind_t pind = psz2ind(psz); + + malloc_mutex_assert_owner(tsdn, &extent_arena_get(extent)->extents_mtx); + extent_heap_insert(&extent_heaps[pind], extent); } static void -extent_heaps_remove(extent_heap_t extent_heaps[NPSIZES], extent_t *extent) +extent_heaps_remove(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES], + extent_t *extent) { size_t psz = extent_size_quantize_floor(extent_size_get(extent)); pszind_t pind = psz2ind(psz); + + malloc_mutex_assert_owner(tsdn, &extent_arena_get(extent)->extents_mtx); + extent_heap_remove(&extent_heaps[pind], extent); } @@ -381,9 +389,9 @@ extent_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, static extent_t * extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extent_heap_t extent_heaps[NPSIZES], bool cache, void *new_addr, - size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, - bool slab) + extent_heap_t extent_heaps[NPSIZES], bool locked, bool cache, + void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, + bool *commit, bool slab) { extent_t *extent; rtree_ctx_t rtree_ctx_fallback; @@ -398,7 +406,8 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, /* Beware size_t wrap-around. */ if (alloc_size < usize) return (NULL); - malloc_mutex_lock(tsdn, &arena->extents_mtx); + if (!locked) + malloc_mutex_lock(tsdn, &arena->extents_mtx); extent_hooks_assure_initialized(arena, r_extent_hooks); if (new_addr != NULL) { rtree_elm_t *elm; @@ -419,11 +428,12 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent = extent_first_best_fit(arena, extent_heaps, alloc_size); if (extent == NULL || (new_addr != NULL && extent_size_get(extent) < size)) { - malloc_mutex_unlock(tsdn, &arena->extents_mtx); + if (!locked) + malloc_mutex_unlock(tsdn, &arena->extents_mtx); return (NULL); } - extent_heaps_remove(extent_heaps, extent); - arena_extent_cache_maybe_remove(arena, extent, cache); + extent_heaps_remove(tsdn, extent_heaps, extent); + arena_extent_cache_maybe_remove(tsdn, arena, extent, cache); leadsize = ALIGNMENT_CEILING((uintptr_t)extent_base_get(extent), PAGE_CEILING(alignment)) - (uintptr_t)extent_base_get(extent); @@ -444,11 +454,12 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, if (extent == NULL) { extent_deregister(tsdn, lead); extent_leak(tsdn, arena, r_extent_hooks, cache, lead); - malloc_mutex_unlock(tsdn, &arena->extents_mtx); + if (!locked) + malloc_mutex_unlock(tsdn, &arena->extents_mtx); return (NULL); } - extent_heaps_insert(extent_heaps, lead); - arena_extent_cache_maybe_insert(arena, lead, cache); + extent_heaps_insert(tsdn, extent_heaps, lead); + arena_extent_cache_maybe_insert(tsdn, arena, lead, cache); } /* Split the trail. */ @@ -459,11 +470,12 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_deregister(tsdn, extent); extent_leak(tsdn, arena, r_extent_hooks, cache, extent); - malloc_mutex_unlock(tsdn, &arena->extents_mtx); + if (!locked) + malloc_mutex_unlock(tsdn, &arena->extents_mtx); return (NULL); } - extent_heaps_insert(extent_heaps, trail); - arena_extent_cache_maybe_insert(arena, trail, cache); + extent_heaps_insert(tsdn, extent_heaps, trail); + arena_extent_cache_maybe_insert(tsdn, arena, trail, cache); } else if (leadsize == 0) { /* * Splitting causes usize to be set as a side effect, but no @@ -474,7 +486,8 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, if (!extent_committed_get(extent) && extent_commit_wrapper(tsdn, arena, r_extent_hooks, extent, 0, extent_size_get(extent))) { - malloc_mutex_unlock(tsdn, &arena->extents_mtx); + if (!locked) + malloc_mutex_unlock(tsdn, &arena->extents_mtx); extent_record(tsdn, arena, r_extent_hooks, extent_heaps, cache, extent); return (NULL); @@ -488,7 +501,8 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_interior_register(tsdn, rtree_ctx, extent); } - malloc_mutex_unlock(tsdn, &arena->extents_mtx); + if (!locked) + malloc_mutex_unlock(tsdn, &arena->extents_mtx); if (*zero) { if (!extent_zeroed_get(extent)) { @@ -540,27 +554,51 @@ extent_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, return (NULL); } -extent_t * -extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool slab) +static extent_t * +extent_alloc_cache_impl(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, bool locked, void *new_addr, size_t usize, + size_t pad, size_t alignment, bool *zero, bool slab) { extent_t *extent; bool commit; assert(usize + pad != 0); assert(alignment != 0); + if (locked) + malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); commit = true; extent = extent_recycle(tsdn, arena, r_extent_hooks, - arena->extents_cached, true, new_addr, usize, pad, alignment, zero, - &commit, slab); + arena->extents_cached, locked, true, new_addr, usize, pad, + alignment, zero, &commit, slab); if (extent == NULL) return (NULL); assert(commit); return (extent); } +extent_t * +extent_alloc_cache_locked(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool slab) +{ + + malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); + + return (extent_alloc_cache_impl(tsdn, arena, r_extent_hooks, true, + new_addr, usize, pad, alignment, zero, slab)); +} + +extent_t * +extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool slab) +{ + + return (extent_alloc_cache_impl(tsdn, arena, r_extent_hooks, false, + new_addr, usize, pad, alignment, zero, slab)); +} + static void * extent_alloc_default_impl(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit) @@ -607,8 +645,8 @@ extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, assert(alignment != 0); extent = extent_recycle(tsdn, arena, r_extent_hooks, - arena->extents_retained, false, new_addr, usize, pad, alignment, - zero, commit, slab); + arena->extents_retained, false, false, new_addr, usize, pad, + alignment, zero, commit, slab); if (extent != NULL && config_stats) { size_t size = usize + pad; arena->stats.retained -= size; @@ -697,22 +735,24 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, if (!extent_can_coalesce(a, b)) return; - extent_heaps_remove(extent_heaps, a); - extent_heaps_remove(extent_heaps, b); + extent_heaps_remove(tsdn, extent_heaps, a); + extent_heaps_remove(tsdn, extent_heaps, b); - arena_extent_cache_maybe_remove(extent_arena_get(a), a, cache); - arena_extent_cache_maybe_remove(extent_arena_get(b), b, cache); + arena_extent_cache_maybe_remove(tsdn, extent_arena_get(a), a, cache); + arena_extent_cache_maybe_remove(tsdn, extent_arena_get(b), b, cache); if (extent_merge_wrapper(tsdn, arena, r_extent_hooks, a, b)) { - extent_heaps_insert(extent_heaps, a); - extent_heaps_insert(extent_heaps, b); - arena_extent_cache_maybe_insert(extent_arena_get(a), a, cache); - arena_extent_cache_maybe_insert(extent_arena_get(b), b, cache); + extent_heaps_insert(tsdn, extent_heaps, a); + extent_heaps_insert(tsdn, extent_heaps, b); + arena_extent_cache_maybe_insert(tsdn, extent_arena_get(a), a, + cache); + arena_extent_cache_maybe_insert(tsdn, extent_arena_get(b), b, + cache); return; } - extent_heaps_insert(extent_heaps, a); - arena_extent_cache_maybe_insert(extent_arena_get(a), a, cache); + extent_heaps_insert(tsdn, extent_heaps, a); + arena_extent_cache_maybe_insert(tsdn, extent_arena_get(a), a, cache); } static void @@ -737,8 +777,8 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, } assert(extent_lookup(tsdn, extent_base_get(extent), true) == extent); - extent_heaps_insert(extent_heaps, extent); - arena_extent_cache_maybe_insert(arena, extent, cache); + extent_heaps_insert(tsdn, extent_heaps, extent); + arena_extent_cache_maybe_insert(tsdn, arena, extent, cache); /* Try to coalesce forward. */ next = rtree_read(tsdn, &extents_rtree, rtree_ctx, @@ -1021,7 +1061,7 @@ extent_merge_default_impl(tsdn_t *tsdn, void *addr_a, void *addr_b) return (true); if (have_dss && extent_in_dss(tsdn, addr_a) != extent_in_dss(tsdn, addr_b)) - return (true); + return (true); return (false); } -- GitLab From fd96974040b54538a43951f630e9fea461408384 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 23 Sep 2016 12:11:01 -0700 Subject: [PATCH 101/544] Add new_addr validation in extent_recycle(). --- src/extent.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/extent.c b/src/extent.c index 522cbb9b..3ab48ca0 100644 --- a/src/extent.c +++ b/src/extent.c @@ -400,6 +400,25 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, assert(new_addr == NULL || !slab); assert(pad == 0 || !slab); + if (config_debug && new_addr != NULL) { + extent_t *prev; + + /* + * Non-NULL new_addr has two use cases: + * + * 1) Recycle a known-extant extent, e.g. during purging. + * 2) Perform in-place expanding reallocation. + * + * Regardless of use case, new_addr must either refer to a + * non-existing extent, or to the base of an extant extent, + * since only active slabs support interior lookups (which of + * course cannot be recycled). + */ + assert(PAGE_ADDR2BASE(new_addr) == new_addr); + prev = extent_lookup(tsdn, (void *)((uintptr_t)new_addr - PAGE), + false); + assert(prev == NULL || extent_past_get(prev) == new_addr); + } size = usize + pad; alloc_size = s2u(size + PAGE_CEILING(alignment) - PAGE); @@ -417,17 +436,20 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, if (elm != NULL) { extent = rtree_elm_read_acquired(tsdn, &extents_rtree, elm); - if (extent != NULL && (extent_arena_get(extent) != arena - || extent_active_get(extent) || - extent_retained_get(extent) == cache)) - extent = NULL; + if (extent != NULL) { + assert(extent_base_get(extent) == new_addr); + if (extent_arena_get(extent) != arena || + extent_size_get(extent) < size || + extent_active_get(extent) || + extent_retained_get(extent) == cache) + extent = NULL; + } rtree_elm_release(tsdn, &extents_rtree, elm); } else extent = NULL; } else extent = extent_first_best_fit(arena, extent_heaps, alloc_size); - if (extent == NULL || (new_addr != NULL && extent_size_get(extent) < - size)) { + if (extent == NULL) { if (!locked) malloc_mutex_unlock(tsdn, &arena->extents_mtx); return (NULL); -- GitLab From e3187ec6b6a349b3add5c27c470ff7f7f040c1d5 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 23 Sep 2016 12:16:55 -0700 Subject: [PATCH 102/544] Fix large_dalloc_impl() to always lock large_mtx. --- src/large.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/large.c b/src/large.c index 325b5f10..34b3bdb5 100644 --- a/src/large.c +++ b/src/large.c @@ -281,18 +281,21 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, return (ret); } +/* + * junked_locked indicates whether the extent's data have been junk-filled, and + * whether the arena's lock is currently held. The arena's large_mtx is + * independent of these considerations. + */ static void large_dalloc_impl(tsdn_t *tsdn, extent_t *extent, bool junked_locked) { arena_t *arena; arena = extent_arena_get(extent); - if (!junked_locked) - malloc_mutex_lock(tsdn, &arena->large_mtx); + malloc_mutex_lock(tsdn, &arena->large_mtx); ql_remove(&arena->large, extent, ql_link); + malloc_mutex_unlock(tsdn, &arena->large_mtx); if (!junked_locked) { - malloc_mutex_unlock(tsdn, &arena->large_mtx); - large_dalloc_maybe_junk(tsdn, extent_addr_get(extent), extent_usize_get(extent)); } -- GitLab From 73868b60f22d40404572d124aa7e08de1d70724f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 23 Sep 2016 12:17:42 -0700 Subject: [PATCH 103/544] Fix extent_{before,last,past}() to return page-aligned results. --- include/jemalloc/internal/extent.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index eeebdf0f..528759b0 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -227,22 +227,23 @@ JEMALLOC_INLINE void * extent_before_get(const extent_t *extent) { - return ((void *)((uintptr_t)extent->e_addr - PAGE)); + return ((void *)((uintptr_t)extent_base_get(extent) - PAGE)); } JEMALLOC_INLINE void * extent_last_get(const extent_t *extent) { - return ((void *)((uintptr_t)extent->e_addr + extent_size_get(extent) - - PAGE)); + return ((void *)((uintptr_t)extent_base_get(extent) + + extent_size_get(extent) - PAGE)); } JEMALLOC_INLINE void * extent_past_get(const extent_t *extent) { - return ((void *)((uintptr_t)extent->e_addr + extent_size_get(extent))); + return ((void *)((uintptr_t)extent_base_get(extent) + + extent_size_get(extent))); } JEMALLOC_INLINE bool -- GitLab From 0222fb41d1fc8e882f7872999ddaa09193d58912 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 23 Sep 2016 12:18:36 -0700 Subject: [PATCH 104/544] Add various mutex ownership assertions. --- include/jemalloc/internal/arena.h | 2 ++ src/arena.c | 2 ++ src/extent.c | 16 ++++++++++------ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index cee90b50..1758dd02 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -521,6 +521,8 @@ JEMALLOC_ALWAYS_INLINE void arena_decay_tick(tsdn_t *tsdn, arena_t *arena) { + malloc_mutex_assert_not_owner(tsdn, &arena->lock); + arena_decay_ticks(tsdn, arena, 1); } diff --git a/src/arena.c b/src/arena.c index da9e9859..42cd3b09 100644 --- a/src/arena.c +++ b/src/arena.c @@ -383,6 +383,8 @@ arena_extent_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, if (!locked) malloc_mutex_lock(tsdn, &arena->lock); + else + malloc_mutex_assert_owner(tsdn, &arena->lock); if (config_stats) { arena_large_dalloc_stats_update(arena, extent_usize_get(extent)); diff --git a/src/extent.c b/src/extent.c index 3ab48ca0..f88c4240 100644 --- a/src/extent.c +++ b/src/extent.c @@ -356,11 +356,13 @@ extent_deregister(tsdn_t *tsdn, extent_t *extent) * fits. */ static extent_t * -extent_first_best_fit(arena_t *arena, extent_heap_t extent_heaps[NPSIZES], - size_t size) +extent_first_best_fit(tsdn_t *tsdn, arena_t *arena, + extent_heap_t extent_heaps[NPSIZES], size_t size) { pszind_t pind, i; + malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); + pind = psz2ind(extent_size_quantize_ceil(size)); for (i = pind; i < NPSIZES; i++) { extent_t *extent = extent_heap_first(&extent_heaps[i]); @@ -398,6 +400,8 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); size_t size, alloc_size, leadsize, trailsize; + if (locked) + malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); assert(new_addr == NULL || !slab); assert(pad == 0 || !slab); if (config_debug && new_addr != NULL) { @@ -447,8 +451,10 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_elm_release(tsdn, &extents_rtree, elm); } else extent = NULL; - } else - extent = extent_first_best_fit(arena, extent_heaps, alloc_size); + } else { + extent = extent_first_best_fit(tsdn, arena, extent_heaps, + alloc_size); + } if (extent == NULL) { if (!locked) malloc_mutex_unlock(tsdn, &arena->extents_mtx); @@ -586,8 +592,6 @@ extent_alloc_cache_impl(tsdn_t *tsdn, arena_t *arena, assert(usize + pad != 0); assert(alignment != 0); - if (locked) - malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); commit = true; extent = extent_recycle(tsdn, arena, r_extent_hooks, -- GitLab From 61f467e16a2b925a0e77241b87b5d1f1fbcb96d0 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 23 Sep 2016 12:18:57 -0700 Subject: [PATCH 105/544] Avoid self assignment in tsd_set(). --- include/jemalloc/internal/tsd.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h index 2355f9c6..5df5f673 100644 --- a/include/jemalloc/internal/tsd.h +++ b/include/jemalloc/internal/tsd.h @@ -226,7 +226,8 @@ a_name##tsd_set(a_type *val) \ { \ \ assert(a_name##tsd_booted); \ - a_name##tsd_tls = (*val); \ + if (likely(&a_name##tsd_tls != val)) \ + a_name##tsd_tls = (*val); \ if (a_cleanup != malloc_tsd_no_cleanup) \ a_name##tsd_initialized = true; \ } @@ -277,7 +278,8 @@ a_name##tsd_set(a_type *val) \ { \ \ assert(a_name##tsd_booted); \ - a_name##tsd_tls = (*val); \ + if (likely(&a_name##tsd_tls != val)) \ + a_name##tsd_tls = (*val); \ if (a_cleanup != malloc_tsd_no_cleanup) { \ if (pthread_setspecific(a_name##tsd_tsd, \ (void *)(&a_name##tsd_tls))) { \ @@ -409,7 +411,8 @@ a_name##tsd_set(a_type *val) \ \ assert(a_name##tsd_booted); \ wrapper = a_name##tsd_wrapper_get(); \ - wrapper->val = *(val); \ + if (likely(&wrapper->val != val)) \ + wrapper->val = *(val); \ if (a_cleanup != malloc_tsd_no_cleanup) \ wrapper->initialized = true; \ } @@ -537,7 +540,8 @@ a_name##tsd_set(a_type *val) \ \ assert(a_name##tsd_booted); \ wrapper = a_name##tsd_wrapper_get(); \ - wrapper->val = *(val); \ + if (likely(&wrapper->val != val)) \ + wrapper->val = *(val); \ if (a_cleanup != malloc_tsd_no_cleanup) \ wrapper->initialized = true; \ } -- GitLab From c096ccfe111ca3c849a0104517a2a1f123985307 Mon Sep 17 00:00:00 2001 From: Elliot Ronaghan Date: Tue, 12 Jul 2016 15:52:18 -0700 Subject: [PATCH 106/544] Fix a bug in __builtin_unreachable configure check In 1167e9e, I accidentally tested je_cv_gcc_builtin_ffsl instead of je_cv_gcc_builtin_unreachable (copy-paste error), which meant that JEMALLOC_INTERNAL_UNREACHABLE was always getting defined as abort even if __builtin_unreachable support was detected. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index e1639d51..1e85101b 100644 --- a/configure.ac +++ b/configure.ac @@ -1095,7 +1095,7 @@ void foo (void) { foo(); } ], [je_cv_gcc_builtin_unreachable]) -if test "x${je_cv_gcc_builtin_ffsl}" = "xyes" ; then +if test "x${je_cv_gcc_builtin_unreachable}" = "xyes" ; then AC_DEFINE([JEMALLOC_INTERNAL_UNREACHABLE], [__builtin_unreachable]) else AC_DEFINE([JEMALLOC_INTERNAL_UNREACHABLE], [abort]) -- GitLab From 5ff18391331a0d56b01ddce3e37cd1c7a2b439a2 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 26 Sep 2016 11:00:32 -0700 Subject: [PATCH 107/544] Formatting fixes. --- src/zone.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/zone.c b/src/zone.c index 92381614..52d07f30 100644 --- a/src/zone.c +++ b/src/zone.c @@ -168,7 +168,8 @@ zone_force_unlock(malloc_zone_t *zone) jemalloc_postfork_parent(); } -static malloc_zone_t *get_default_zone() +static malloc_zone_t * +get_default_zone(void) { malloc_zone_t **zones = NULL; unsigned int num_zones = 0; @@ -179,20 +180,22 @@ static malloc_zone_t *get_default_zone() * if one is present (apparently enabled when malloc stack logging is * enabled), or the first registered zone otherwise. In practice this * means unless malloc stack logging is enabled, the first registered - * zone is the default. - * So get the list of zones to get the first one, instead of relying on - * malloc_default_zone. + * zone is the default. So get the list of zones to get the first one, + * instead of relying on malloc_default_zone. */ - if (KERN_SUCCESS != malloc_get_all_zones(0, NULL, (vm_address_t**) &zones, - &num_zones)) { - /* Reset the value in case the failure happened after it was set. */ + if (KERN_SUCCESS != malloc_get_all_zones(0, NULL, + (vm_address_t**)&zones, &num_zones)) { + /* + * Reset the value in case the failure happened after it was + * set. + */ num_zones = 0; } if (num_zones) - return zones[0]; + return (zones[0]); - return malloc_default_zone(); + return (malloc_default_zone()); } JEMALLOC_ATTR(constructor) -- GitLab From df0d273a07b0ca5ea4a9d8e140e1fa6425430e4a Mon Sep 17 00:00:00 2001 From: Eric Le Bihan Date: Thu, 14 Jul 2016 22:44:01 +0200 Subject: [PATCH 108/544] Fix LG_QUANTUM definition for sparc64 GCC 4.9.3 cross-compiled for sparc64 defines __sparc_v9__, not __sparc64__ nor __sparcv9. This prevents LG_QUANTUM from being defined properly. Adding this new value to the check solves the issue. --- include/jemalloc/internal/jemalloc_internal.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index c35280fa..086726d3 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -232,7 +232,7 @@ typedef unsigned szind_t; # ifdef __alpha__ # define LG_QUANTUM 4 # endif -# if (defined(__sparc64__) || defined(__sparcv9)) +# if (defined(__sparc64__) || defined(__sparcv9) || defined(__sparc_v9__)) # define LG_QUANTUM 4 # endif # if (defined(__amd64__) || defined(__x86_64__) || defined(_M_X64)) -- GitLab From 020c32859d19873e8555d848785f0b584d4249f9 Mon Sep 17 00:00:00 2001 From: Bai Date: Sun, 28 Aug 2016 13:51:57 +0800 Subject: [PATCH 109/544] Readme.txt error for building in the Windows The command can't work using sh -C sh -c "./autogen.sh CC=cl --enable-lazy-lock=no". Change the position of the colon, the command of autogen work. --- msvc/ReadMe.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/msvc/ReadMe.txt b/msvc/ReadMe.txt index 02b97f74..b1c2fc5c 100644 --- a/msvc/ReadMe.txt +++ b/msvc/ReadMe.txt @@ -17,7 +17,7 @@ How to build jemalloc for Windows (note: x86/x64 doesn't matter at this point) 5. Generate header files: - sh -c "./autogen.sh CC=cl --enable-lazy-lock=no" + sh -c "./autogen.sh" CC=cl --enable-lazy-lock=no 6. Now the project can be opened and built in Visual Studio: msvc\jemalloc_vc2015.sln -- GitLab From ea68cd25b6455b2c408200c3947c0715f6a7e4a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20K=C3=B6ckerbauer?= Date: Wed, 7 Sep 2016 08:34:17 +0200 Subject: [PATCH 110/544] use install command determined by configure --- Makefile.in | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/Makefile.in b/Makefile.in index b78e1500..ec863079 100644 --- a/Makefile.in +++ b/Makefile.in @@ -61,6 +61,7 @@ MKLIB = @MKLIB@ AR = @AR@ ARFLAGS = @ARFLAGS@ CC_MM = @CC_MM@ +INSTALL = @INSTALL@ ifeq (macho, $(ABI)) TEST_LIBRARY_PATH := DYLD_FALLBACK_LIBRARY_PATH="$(objroot)lib" @@ -305,54 +306,54 @@ build_lib_static: $(STATIC_LIBS) build_lib: build_lib_shared build_lib_static install_bin: - install -d $(BINDIR) + $(INSTALL) -d $(BINDIR) @for b in $(BINS); do \ - echo "install -m 755 $$b $(BINDIR)"; \ - install -m 755 $$b $(BINDIR); \ + echo "$(INSTALL) -m 755 $$b $(BINDIR)"; \ + $(INSTALL) -m 755 $$b $(BINDIR); \ done install_include: - install -d $(INCLUDEDIR)/jemalloc + $(INSTALL) -d $(INCLUDEDIR)/jemalloc @for h in $(C_HDRS); do \ - echo "install -m 644 $$h $(INCLUDEDIR)/jemalloc"; \ - install -m 644 $$h $(INCLUDEDIR)/jemalloc; \ + echo "$(INSTALL) -m 644 $$h $(INCLUDEDIR)/jemalloc"; \ + $(INSTALL) -m 644 $$h $(INCLUDEDIR)/jemalloc; \ done install_lib_shared: $(DSOS) - install -d $(LIBDIR) - install -m 755 $(objroot)lib/$(LIBJEMALLOC).$(SOREV) $(LIBDIR) + $(INSTALL) -d $(LIBDIR) + $(INSTALL) -m 755 $(objroot)lib/$(LIBJEMALLOC).$(SOREV) $(LIBDIR) ifneq ($(SOREV),$(SO)) ln -sf $(LIBJEMALLOC).$(SOREV) $(LIBDIR)/$(LIBJEMALLOC).$(SO) endif install_lib_static: $(STATIC_LIBS) - install -d $(LIBDIR) + $(INSTALL) -d $(LIBDIR) @for l in $(STATIC_LIBS); do \ - echo "install -m 755 $$l $(LIBDIR)"; \ - install -m 755 $$l $(LIBDIR); \ + echo "$(INSTALL) -m 755 $$l $(LIBDIR)"; \ + $(INSTALL) -m 755 $$l $(LIBDIR); \ done install_lib_pc: $(PC) - install -d $(LIBDIR)/pkgconfig + $(INSTALL) -d $(LIBDIR)/pkgconfig @for l in $(PC); do \ - echo "install -m 644 $$l $(LIBDIR)/pkgconfig"; \ - install -m 644 $$l $(LIBDIR)/pkgconfig; \ + echo "$(INSTALL) -m 644 $$l $(LIBDIR)/pkgconfig"; \ + $(INSTALL) -m 644 $$l $(LIBDIR)/pkgconfig; \ done install_lib: install_lib_shared install_lib_static install_lib_pc install_doc_html: - install -d $(DATADIR)/doc/jemalloc$(install_suffix) + $(INSTALL) -d $(DATADIR)/doc/jemalloc$(install_suffix) @for d in $(DOCS_HTML); do \ - echo "install -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix)"; \ - install -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix); \ + echo "$(INSTALL) -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix)"; \ + $(INSTALL) -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix); \ done install_doc_man: - install -d $(MANDIR)/man3 + $(INSTALL) -d $(MANDIR)/man3 @for d in $(DOCS_MAN3); do \ - echo "install -m 644 $$d $(MANDIR)/man3"; \ - install -m 644 $$d $(MANDIR)/man3; \ + echo "$(INSTALL) -m 644 $$d $(MANDIR)/man3"; \ + $(INSTALL) -m 644 $$d $(MANDIR)/man3; \ done install_doc: install_doc_html install_doc_man -- GitLab From 3c8c3e9e9b59b6e34a222816a05f0a01a68919b3 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 26 Sep 2016 15:55:40 -0700 Subject: [PATCH 111/544] Close file descriptor after reading "/proc/sys/vm/overcommit_memory". This bug was introduced by c2f970c32b527660a33fa513a76d913c812dcf7c (Modify pages_map() to support mapping uncommitted virtual memory.). This resolves #399. --- src/pages.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages.c b/src/pages.c index 2a9b7e37..05b0d690 100644 --- a/src/pages.c +++ b/src/pages.c @@ -219,6 +219,7 @@ os_overcommits_proc(void) return (false); /* Error. */ nread = read(fd, &buf, sizeof(buf)); + close(fd); if (nread < 1) return (false); /* Error. */ /* -- GitLab From 42e79c58a0fb2c9ba87771523f3fc00e44876d20 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 29 Sep 2016 09:49:19 -0700 Subject: [PATCH 112/544] Update extent hook function prototype comments. --- include/jemalloc/jemalloc_typedefs.h.in | 27 +++++++++++++------------ 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/include/jemalloc/jemalloc_typedefs.h.in b/include/jemalloc/jemalloc_typedefs.h.in index e5ba7166..1049d7c7 100644 --- a/include/jemalloc/jemalloc_typedefs.h.in +++ b/include/jemalloc/jemalloc_typedefs.h.in @@ -2,55 +2,56 @@ typedef struct extent_hooks_s extent_hooks_t; /* * void * - * extent_alloc(void *new_addr, size_t size, size_t alignment, bool *zero, - * bool *commit, unsigned arena_ind); + * extent_alloc(extent_hooks_t *extent_hooks, void *new_addr, size_t size, + * size_t alignment, bool *zero, bool *commit, unsigned arena_ind); */ typedef void *(extent_alloc_t)(extent_hooks_t *, void *, size_t, size_t, bool *, bool *, unsigned); /* * bool - * extent_dalloc(void *addr, size_t size, bool committed, unsigned arena_ind); + * extent_dalloc(extent_hooks_t *extent_hooks, void *addr, size_t size, + * bool committed, unsigned arena_ind); */ typedef bool (extent_dalloc_t)(extent_hooks_t *, void *, size_t, bool, unsigned); /* * bool - * extent_commit(void *addr, size_t size, size_t offset, size_t length, - * unsigned arena_ind); + * extent_commit(extent_hooks_t *extent_hooks, void *addr, size_t size, + * size_t offset, size_t length, unsigned arena_ind); */ typedef bool (extent_commit_t)(extent_hooks_t *, void *, size_t, size_t, size_t, unsigned); /* * bool - * extent_decommit(void *addr, size_t size, size_t offset, size_t length, - * unsigned arena_ind); + * extent_decommit(extent_hooks_t *extent_hooks, void *addr, size_t size, + * size_t offset, size_t length, unsigned arena_ind); */ typedef bool (extent_decommit_t)(extent_hooks_t *, void *, size_t, size_t, size_t, unsigned); /* * bool - * extent_purge(void *addr, size_t size, size_t offset, size_t length, - * unsigned arena_ind); + * extent_purge(extent_hooks_t *extent_hooks, void *addr, size_t size, + * size_t offset, size_t length, unsigned arena_ind); */ typedef bool (extent_purge_t)(extent_hooks_t *, void *, size_t, size_t, size_t, unsigned); /* * bool - * extent_split(void *addr, size_t size, size_t size_a, size_t size_b, - * bool committed, unsigned arena_ind); + * extent_split(extent_hooks_t *extent_hooks, void *addr, size_t size, + * size_t size_a, size_t size_b, bool committed, unsigned arena_ind); */ typedef bool (extent_split_t)(extent_hooks_t *, void *, size_t, size_t, size_t, bool, unsigned); /* * bool - * extent_merge(void *addr_a, size_t size_a, void *addr_b, size_t size_b, - * bool committed, unsigned arena_ind); + * extent_merge(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, + * void *addr_b, size_t size_b, bool committed, unsigned arena_ind); */ typedef bool (extent_merge_t)(extent_hooks_t *, void *, size_t, void *, size_t, bool, unsigned); -- GitLab From d51139c33c180a59dcee0c3880b8261f075139b3 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 29 Sep 2016 09:50:35 -0700 Subject: [PATCH 113/544] Verify extent hook functions receive correct extent_hooks pointer. --- test/integration/extent.c | 69 +++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/test/integration/extent.c b/test/integration/extent.c index 10de8bbf..8acdad82 100644 --- a/test/integration/extent.c +++ b/test/integration/extent.c @@ -4,6 +4,34 @@ const char *malloc_conf = "junk:false"; #endif +static void *extent_alloc(extent_hooks_t *extent_hooks, void *new_addr, + size_t size, size_t alignment, bool *zero, bool *commit, + unsigned arena_ind); +static bool extent_dalloc(extent_hooks_t *extent_hooks, void *addr, + size_t size, bool committed, unsigned arena_ind); +static bool extent_commit(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t offset, size_t length, unsigned arena_ind); +static bool extent_decommit(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t offset, size_t length, unsigned arena_ind); +static bool extent_purge(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t offset, size_t length, unsigned arena_ind); +static bool extent_split(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t size_a, size_t size_b, bool committed, + unsigned arena_ind); +static bool extent_merge(extent_hooks_t *extent_hooks, void *addr_a, + size_t size_a, void *addr_b, size_t size_b, bool committed, + unsigned arena_ind); + +static extent_hooks_t hooks = { + extent_alloc, + extent_dalloc, + extent_commit, + extent_decommit, + extent_purge, + extent_split, + extent_merge +}; +static extent_hooks_t *new_hooks = &hooks; static extent_hooks_t *orig_hooks; static extent_hooks_t *old_hooks; @@ -34,7 +62,9 @@ extent_alloc(extent_hooks_t *extent_hooks, void *new_addr, size_t size, "*zero=%s, *commit=%s, arena_ind=%u)\n", __func__, extent_hooks, new_addr, size, alignment, *zero ? "true" : "false", *commit ? "true" : "false", arena_ind); - assert(extent_hooks->alloc == extent_alloc); + assert_ptr_eq(extent_hooks, new_hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->alloc, extent_alloc, "Wrong hook function"); did_alloc = true; return (old_hooks->alloc(old_hooks, new_addr, size, alignment, zero, commit, arena_ind)); @@ -48,7 +78,10 @@ extent_dalloc(extent_hooks_t *extent_hooks, void *addr, size_t size, TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, " "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ? "true" : "false", arena_ind); - assert(extent_hooks->dalloc == extent_dalloc); + assert_ptr_eq(extent_hooks, new_hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->dalloc, extent_dalloc, + "Wrong hook function"); did_dalloc = true; if (!do_dalloc) return (true); @@ -64,7 +97,10 @@ extent_commit(extent_hooks_t *extent_hooks, void *addr, size_t size, TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " "length=%zu, arena_ind=%u)\n", __func__, extent_hooks, addr, size, offset, length, arena_ind); - assert(extent_hooks->commit == extent_commit); + assert_ptr_eq(extent_hooks, new_hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->commit, extent_commit, + "Wrong hook function"); err = old_hooks->commit(old_hooks, addr, size, offset, length, arena_ind); did_commit = !err; @@ -80,7 +116,10 @@ extent_decommit(extent_hooks_t *extent_hooks, void *addr, size_t size, TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " "length=%zu, arena_ind=%u)\n", __func__, extent_hooks, addr, size, offset, length, arena_ind); - assert(extent_hooks->decommit == extent_decommit); + assert_ptr_eq(extent_hooks, new_hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->decommit, extent_decommit, + "Wrong hook function"); if (!do_decommit) return (true); err = old_hooks->decommit(old_hooks, addr, size, offset, length, @@ -97,7 +136,9 @@ extent_purge(extent_hooks_t *extent_hooks, void *addr, size_t size, TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " "length=%zu arena_ind=%u)\n", __func__, extent_hooks, addr, size, offset, length, arena_ind); - assert(extent_hooks->purge == extent_purge); + assert_ptr_eq(extent_hooks, new_hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->purge, extent_purge, "Wrong hook function"); did_purge = true; return (old_hooks->purge(old_hooks, addr, size, offset, length, arena_ind)); @@ -113,7 +154,9 @@ extent_split(extent_hooks_t *extent_hooks, void *addr, size_t size, "size_b=%zu, committed=%s, arena_ind=%u)\n", __func__, extent_hooks, addr, size, size_a, size_b, committed ? "true" : "false", arena_ind); - assert(extent_hooks->split == extent_split); + assert_ptr_eq(extent_hooks, new_hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->split, extent_split, "Wrong hook function"); tried_split = true; err = old_hooks->split(old_hooks, addr, size, size_a, size_b, committed, arena_ind); @@ -131,7 +174,9 @@ extent_merge(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, "size_b=%zu, committed=%s, arena_ind=%u)\n", __func__, extent_hooks, addr_a, size_a, addr_b, size_b, committed ? "true" : "false", arena_ind); - assert(extent_hooks->merge == extent_merge); + assert_ptr_eq(extent_hooks, new_hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->merge, extent_merge, "Wrong hook function"); err = old_hooks->merge(old_hooks, addr_a, size_a, addr_b, size_b, committed, arena_ind); did_merge = !err; @@ -146,16 +191,6 @@ TEST_BEGIN(test_extent) int flags; size_t hooks_mib[3], purge_mib[3]; size_t hooks_miblen, purge_miblen; - extent_hooks_t hooks = { - extent_alloc, - extent_dalloc, - extent_commit, - extent_decommit, - extent_purge, - extent_split, - extent_merge - }; - extent_hooks_t *new_hooks = &hooks; bool xallocx_success_a, xallocx_success_b, xallocx_success_c; sz = sizeof(unsigned); -- GitLab From 871a9498e13572f99451ed88db36cda6c9fecf8f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 3 Oct 2016 14:18:55 -0700 Subject: [PATCH 114/544] Fix size class overflow bugs. Avoid calling s2u() on raw extent sizes in extent_recycle(). Clamp psz2ind() (implemented as psz2ind_clamp()) when inserting/removing into/from size-segregated extent heaps. --- .../jemalloc/internal/jemalloc_internal.h.in | 22 ++++++++++++++++--- include/jemalloc/internal/private_symbols.txt | 2 ++ src/arena.c | 4 ++-- src/extent.c | 10 ++++++--- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 086726d3..ba8a9296 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -516,7 +516,9 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/large.h" #ifndef JEMALLOC_ENABLE_INLINE +pszind_t psz2ind_impl(size_t psz, bool clamp); pszind_t psz2ind(size_t psz); +pszind_t psz2ind_clamp(size_t psz); size_t pind2sz_compute(pszind_t pind); size_t pind2sz_lookup(pszind_t pind); size_t pind2sz(pszind_t pind); @@ -541,12 +543,12 @@ ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) -JEMALLOC_INLINE pszind_t -psz2ind(size_t psz) +JEMALLOC_ALWAYS_INLINE pszind_t +psz2ind_impl(size_t psz, bool clamp) { if (unlikely(psz > LARGE_MAXCLASS)) - return (NPSIZES); + return (clamp ? NPSIZES-1 : NPSIZES); { pszind_t x = lg_floor((psz<<1)-1); pszind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_PAGE) ? 0 : x - @@ -565,6 +567,20 @@ psz2ind(size_t psz) } } +JEMALLOC_INLINE pszind_t +psz2ind(size_t psz) +{ + + return (psz2ind_impl(psz, false)); +} + +JEMALLOC_INLINE pszind_t +psz2ind_clamp(size_t psz) +{ + + return (psz2ind_impl(psz, true)); +} + JEMALLOC_INLINE size_t pind2sz_compute(pszind_t pind) { diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index ae60f6c4..d633272a 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -395,6 +395,8 @@ prof_thread_active_set prof_thread_name_get prof_thread_name_set psz2ind +psz2ind_clamp +psz2ind_impl psz2u purge_mode_names register_zone diff --git a/src/arena.c b/src/arena.c index 42cd3b09..2e23c0b7 100644 --- a/src/arena.c +++ b/src/arena.c @@ -769,8 +769,8 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, /* Allocate. */ zero = false; textent = extent_alloc_cache_locked(tsdn, arena, r_extent_hooks, - extent_base_get(extent), extent_size_get(extent), 0, - CACHELINE, &zero, false); + extent_base_get(extent), extent_size_get(extent), 0, PAGE, + &zero, false); assert(textent == extent); assert(zero == extent_zeroed_get(extent)); extent_ring_remove(extent); diff --git a/src/extent.c b/src/extent.c index f88c4240..63516c68 100644 --- a/src/extent.c +++ b/src/extent.c @@ -195,7 +195,7 @@ extent_heaps_insert(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES], extent_t *extent) { size_t psz = extent_size_quantize_floor(extent_size_get(extent)); - pszind_t pind = psz2ind(psz); + pszind_t pind = psz2ind_clamp(psz); malloc_mutex_assert_owner(tsdn, &extent_arena_get(extent)->extents_mtx); @@ -207,7 +207,7 @@ extent_heaps_remove(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES], extent_t *extent) { size_t psz = extent_size_quantize_floor(extent_size_get(extent)); - pszind_t pind = psz2ind(psz); + pszind_t pind = psz2ind_clamp(psz); malloc_mutex_assert_owner(tsdn, &extent_arena_get(extent)->extents_mtx); @@ -364,6 +364,7 @@ extent_first_best_fit(tsdn_t *tsdn, arena_t *arena, malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); pind = psz2ind(extent_size_quantize_ceil(size)); + assert(pind < NPSIZES); for (i = pind; i < NPSIZES; i++) { extent_t *extent = extent_heap_first(&extent_heaps[i]); if (extent != NULL) @@ -419,13 +420,16 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, * course cannot be recycled). */ assert(PAGE_ADDR2BASE(new_addr) == new_addr); + assert(pad == 0); + assert(alignment <= PAGE); prev = extent_lookup(tsdn, (void *)((uintptr_t)new_addr - PAGE), false); assert(prev == NULL || extent_past_get(prev) == new_addr); } size = usize + pad; - alloc_size = s2u(size + PAGE_CEILING(alignment) - PAGE); + alloc_size = (new_addr != NULL) ? size : s2u(size + + PAGE_CEILING(alignment) - PAGE); /* Beware size_t wrap-around. */ if (alloc_size < usize) return (NULL); -- GitLab From a5a8d7ae8dd638cf538cae3b340afe6d1d787954 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 3 Oct 2016 14:45:27 -0700 Subject: [PATCH 115/544] Remove a size class assertion from extent_size_quantize_floor(). Extent coalescence can result in legitimate calls to extent_size_quantize_floor() with size larger than LARGE_MAXCLASS. --- src/extent.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/extent.c b/src/extent.c index 63516c68..e4d3ccdb 100644 --- a/src/extent.c +++ b/src/extent.c @@ -117,7 +117,6 @@ extent_size_quantize_floor(size_t size) pszind_t pind; assert(size > 0); - assert(size - large_pad <= LARGE_MAXCLASS); assert((size & PAGE_MASK) == 0); assert(size != 0); -- GitLab From b6c0867142ced63a21003b2f449b20b248e1cc4a Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 3 Oct 2016 10:37:12 -0700 Subject: [PATCH 116/544] Reduce "thread.arena" mallctl contention. This resolves #460. --- src/ctl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ctl.c b/src/ctl.c index 535f1eab..87fd8c75 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1186,14 +1186,13 @@ thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, if (oldarena == NULL) return (EAGAIN); - malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); newind = oldind = oldarena->ind; WRITE(newind, unsigned); READ(oldind, unsigned); if (newind != oldind) { arena_t *newarena; - if (newind >= ctl_stats.narenas) { + if (newind >= narenas_total_get()) { /* New arena index is out of range. */ ret = EFAULT; goto label_return; @@ -1218,7 +1217,6 @@ thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); return (ret); } -- GitLab From e0164bc63c25d6f7b02ef69c3e4f307ce395cf71 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 7 Oct 2016 08:47:16 -0700 Subject: [PATCH 117/544] Refine nstime_update(). Add missing #include . The critical time facilities appear to have been transitively included via unistd.h and sys/time.h, but in principle this omission was capable of having caused clock_gettime(CLOCK_MONOTONIC, ...) to have been overlooked in favor of gettimeofday(), which in turn could cause spurious non-monotonic time updates. Refactor nstime_get() out of nstime_update() and add configure tests for all variants. Add CLOCK_MONOTONIC_RAW support (Linux-specific) and mach_absolute_time() support (OS X-specific). Do not fall back to clock_gettime(CLOCK_REALTIME, ...). This was a fragile Linux-specific workaround, which we're unlikely to use at all now that clock_gettime(CLOCK_MONOTONIC_RAW, ...) is supported, and if we have no choice besides non-monotonic clocks, gettimeofday() is only incrementally worse. --- configure.ac | 49 ++++++++++-- .../internal/jemalloc_internal_decls.h | 4 + .../internal/jemalloc_internal_defs.h.in | 15 ++++ include/jemalloc/internal/nstime.h | 3 - src/nstime.c | 76 ++++++++++++------- 5 files changed, 109 insertions(+), 38 deletions(-) diff --git a/configure.ac b/configure.ac index 1e85101b..0ec710a9 100644 --- a/configure.ac +++ b/configure.ac @@ -345,11 +345,11 @@ dnl dnl Define cpp macros in CPPFLAGS, rather than doing AC_DEFINE(macro), since the dnl definitions need to be seen before any headers are included, which is a pain dnl to make happen otherwise. +CFLAGS="$CFLAGS" default_munmap="1" maps_coalesce="1" case "${host}" in *-*-darwin* | *-*-ios*) - CFLAGS="$CFLAGS" abi="macho" AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) RPATH="" @@ -362,30 +362,26 @@ case "${host}" in sbrk_deprecated="1" ;; *-*-freebsd*) - CFLAGS="$CFLAGS" abi="elf" AC_DEFINE([JEMALLOC_SYSCTL_VM_OVERCOMMIT], [ ]) AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) force_lazy_lock="1" ;; *-*-dragonfly*) - CFLAGS="$CFLAGS" abi="elf" AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) ;; *-*-openbsd*) - CFLAGS="$CFLAGS" abi="elf" AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) force_tls="0" ;; *-*-bitrig*) - CFLAGS="$CFLAGS" abi="elf" AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) ;; *-*-linux*) - CFLAGS="$CFLAGS" + dnl secure_getenv() is exposed by _GNU_SOURCE. CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" abi="elf" AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) @@ -404,13 +400,12 @@ case "${host}" in #error aout #endif ]])], - [CFLAGS="$CFLAGS"; abi="elf"], + [abi="elf"], [abi="aout"]) AC_MSG_RESULT([$abi]) AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) ;; *-*-solaris2*) - CFLAGS="$CFLAGS" abi="elf" AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) RPATH='-Wl,-R,$(1)' @@ -1309,6 +1304,44 @@ if test "x$je_cv_cray_prgenv_wrapper" = "xyes" ; then fi fi +dnl check for CLOCK_MONOTONIC_RAW (Linux-specific). +JE_COMPILABLE([clock_gettime(CLOCK_MONOTONIC_RAW, ...)], [ +#include +], [ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); +], [je_cv_clock_monotonic_raw]) +if test "x${je_cv_clock_monotonic_raw}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_CLOCK_MONOTONIC_RAW]) +fi + +dnl check for CLOCK_MONOTONIC. +JE_COMPILABLE([clock_gettime(CLOCK_MONOTONIC, ...)], [ +#include +#include +], [ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); +#if !defined(_POSIX_MONOTONIC_CLOCK) || _POSIX_MONOTONIC_CLOCK < 0 +# error _POSIX_MONOTONIC_CLOCK missing/invalid +#endif +], [je_cv_clock_monotonic]) +if test "x${je_cv_clock_monotonic}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_CLOCK_MONOTONIC]) +fi + +dnl Check for mach_absolute_time(). +JE_COMPILABLE([mach_absolute_time()], [ +#include +], [ + mach_absolute_time(); +], [je_cv_mach_absolute_time]) +if test "x${je_cv_mach_absolute_time}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_MACH_ABSOLUTE_TIME]) +fi + dnl Check if the GNU-specific secure_getenv function exists. AC_CHECK_FUNC([secure_getenv], [have_secure_getenv="1"], diff --git a/include/jemalloc/internal/jemalloc_internal_decls.h b/include/jemalloc/internal/jemalloc_internal_decls.h index 2b8ca5d0..910b2fc6 100644 --- a/include/jemalloc/internal/jemalloc_internal_decls.h +++ b/include/jemalloc/internal/jemalloc_internal_decls.h @@ -19,6 +19,10 @@ # include # include # include +# include +# ifdef JEMALLOC_HAVE_MACH_ABSOLUTE_TIME +# include +# endif #endif #include diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index cebd6a53..70b32871 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -76,6 +76,21 @@ */ #undef JEMALLOC_HAVE_ISSETUGID +/* + * Defined if clock_gettime(CLOCK_MONOTONIC_RAW, ...) is available. + */ +#undef JEMALLOC_HAVE_CLOCK_MONOTONIC_RAW + +/* + * Defined if clock_gettime(CLOCK_MONOTONIC, ...) is available. + */ +#undef JEMALLOC_HAVE_CLOCK_MONOTONIC + +/* + * Defined if mach_absolute_time() is available. + */ +#undef JEMALLOC_HAVE_MACH_ABSOLUTE_TIME + /* * Defined if _malloc_thread_cleanup() exists. At least in the case of * FreeBSD, pthread_key_create() allocates, which if used during malloc diff --git a/include/jemalloc/internal/nstime.h b/include/jemalloc/internal/nstime.h index dc293b73..c892bac8 100644 --- a/include/jemalloc/internal/nstime.h +++ b/include/jemalloc/internal/nstime.h @@ -1,9 +1,6 @@ /******************************************************************************/ #ifdef JEMALLOC_H_TYPES -#define JEMALLOC_CLOCK_GETTIME defined(_POSIX_MONOTONIC_CLOCK) \ - && _POSIX_MONOTONIC_CLOCK >= 0 - typedef struct nstime_s nstime_t; /* Maximum supported number of seconds (~584 years). */ diff --git a/src/nstime.c b/src/nstime.c index aad2c260..cfb1c8e1 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -97,6 +97,54 @@ nstime_divide(const nstime_t *time, const nstime_t *divisor) return (time->ns / divisor->ns); } +#ifdef _WIN32 +static void +nstime_get(nstime_t *time) +{ + FILETIME ft; + uint64_t ticks_100ns; + + GetSystemTimeAsFileTime(&ft); + ticks_100ns = (((uint64_t)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + nstime_init(time, ticks_100ns * 100); +} +#elif JEMALLOC_HAVE_CLOCK_MONOTONIC_RAW +static void +nstime_get(nstime_t *time) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + nstime_init2(time, ts.tv_sec, ts.tv_nsec); +} +#elif JEMALLOC_HAVE_CLOCK_MONOTONIC +static void +nstime_get(nstime_t *time) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + nstime_init2(time, ts.tv_sec, ts.tv_nsec); +} +#elif JEMALLOC_HAVE_MACH_ABSOLUTE_TIME +static void +nstime_get(nstime_t *time) +{ + + nstime_init(time, mach_absolute_time()); +} +#else +static void +nstime_get(nstime_t *time) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + nstime_init2(time, tv.tv_sec, tv.tv_usec * 1000); +} +#endif + #ifdef JEMALLOC_JET #undef nstime_update #define nstime_update JEMALLOC_N(n_nstime_update) @@ -107,33 +155,7 @@ nstime_update(nstime_t *time) nstime_t old_time; nstime_copy(&old_time, time); - -#ifdef _WIN32 - { - FILETIME ft; - uint64_t ticks; - GetSystemTimeAsFileTime(&ft); - ticks = (((uint64_t)ft.dwHighDateTime) << 32) | - ft.dwLowDateTime; - time->ns = ticks * 100; - } -#elif JEMALLOC_CLOCK_GETTIME - { - struct timespec ts; - - if (sysconf(_SC_MONOTONIC_CLOCK) > 0) - clock_gettime(CLOCK_MONOTONIC, &ts); - else - clock_gettime(CLOCK_REALTIME, &ts); - time->ns = ts.tv_sec * BILLION + ts.tv_nsec; - } -#else - { - struct timeval tv; - gettimeofday(&tv, NULL); - time->ns = tv.tv_sec * BILLION + tv.tv_usec * 1000; - } -#endif + nstime_get(time); /* Handle non-monotonic clocks. */ if (unlikely(nstime_compare(&old_time, time) > 0)) { -- GitLab From ee0c74b77a24dc4fdaad2c950bcf621b6fa54095 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 10 Oct 2016 20:32:19 -0700 Subject: [PATCH 118/544] Refactor arena->decay_* into arena->decay.* (arena_decay_t). --- include/jemalloc/internal/arena.h | 99 +++++++++++++++++-------------- src/arena.c | 76 ++++++++++++------------ 2 files changed, 91 insertions(+), 84 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 1758dd02..3830e548 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -31,6 +31,7 @@ typedef enum { typedef struct arena_slab_data_s arena_slab_data_t; typedef struct arena_bin_info_s arena_bin_info_t; +typedef struct arena_decay_s arena_decay_t; typedef struct arena_bin_s arena_bin_t; typedef struct arena_s arena_t; typedef struct arena_tdata_s arena_tdata_t; @@ -89,6 +90,56 @@ struct arena_bin_info_s { bitmap_info_t bitmap_info; }; +struct arena_decay_s { + /* + * Approximate time in seconds from the creation of a set of unused + * dirty pages until an equivalent set of unused dirty pages is purged + * and/or reused. + */ + ssize_t time; + /* decay_time / SMOOTHSTEP_NSTEPS. */ + nstime_t interval; + /* + * Time at which the current decay interval logically started. We do + * not actually advance to a new epoch until sometime after it starts + * because of scheduling and computation delays, and it is even possible + * to completely skip epochs. In all cases, during epoch advancement we + * merge all relevant activity into the most recently recorded epoch. + */ + nstime_t epoch; + /* decay_deadline randomness generator. */ + uint64_t jitter_state; + /* + * Deadline for current epoch. This is the sum of decay_interval and + * per epoch jitter which is a uniform random variable in + * [0..decay_interval). Epochs always advance by precise multiples of + * decay_interval, but we randomize the deadline to reduce the + * likelihood of arenas purging in lockstep. + */ + nstime_t deadline; + /* + * Number of dirty pages at beginning of current epoch. During epoch + * advancement we use the delta between decay_ndirty and ndirty to + * determine how many dirty pages, if any, were generated, and record + * the result in decay_backlog. + */ + size_t ndirty; + /* + * Memoized result of arena_decay_backlog_npages_limit() corresponding + * to the current contents of decay_backlog, i.e. the limit on how many + * pages are allowed to exist for the decay epochs. + */ + size_t backlog_npages_limit; + /* + * Trailing log of how many unused dirty pages were generated during + * each of the past SMOOTHSTEP_NSTEPS decay epochs, where the last + * element is the most recent epoch. Corresponding epoch times are + * relative to decay_epoch. + */ + size_t backlog[SMOOTHSTEP_NSTEPS]; + +}; + struct arena_bin_s { /* All operations on arena_bin_t fields require lock ownership. */ malloc_mutex_t lock; @@ -176,52 +227,8 @@ struct arena_s { */ size_t ndirty; - /* - * Approximate time in seconds from the creation of a set of unused - * dirty pages until an equivalent set of unused dirty pages is purged - * and/or reused. - */ - ssize_t decay_time; - /* decay_time / SMOOTHSTEP_NSTEPS. */ - nstime_t decay_interval; - /* - * Time at which the current decay interval logically started. We do - * not actually advance to a new epoch until sometime after it starts - * because of scheduling and computation delays, and it is even possible - * to completely skip epochs. In all cases, during epoch advancement we - * merge all relevant activity into the most recently recorded epoch. - */ - nstime_t decay_epoch; - /* decay_deadline randomness generator. */ - uint64_t decay_jitter_state; - /* - * Deadline for current epoch. This is the sum of decay_interval and - * per epoch jitter which is a uniform random variable in - * [0..decay_interval). Epochs always advance by precise multiples of - * decay_interval, but we randomize the deadline to reduce the - * likelihood of arenas purging in lockstep. - */ - nstime_t decay_deadline; - /* - * Number of dirty pages at beginning of current epoch. During epoch - * advancement we use the delta between decay_ndirty and ndirty to - * determine how many dirty pages, if any, were generated, and record - * the result in decay_backlog. - */ - size_t decay_ndirty; - /* - * Memoized result of arena_decay_backlog_npages_limit() corresponding - * to the current contents of decay_backlog, i.e. the limit on how many - * pages are allowed to exist for the decay epochs. - */ - size_t decay_backlog_npages_limit; - /* - * Trailing log of how many unused dirty pages were generated during - * each of the past SMOOTHSTEP_NSTEPS decay epochs, where the last - * element is the most recent epoch. Corresponding epoch times are - * relative to decay_epoch. - */ - size_t decay_backlog[SMOOTHSTEP_NSTEPS]; + /* Decay-based purging state. */ + arena_decay_t decay; /* Extant large allocations. */ ql_head(extent_t) large; diff --git a/src/arena.c b/src/arena.c index 2e23c0b7..9750208d 100644 --- a/src/arena.c +++ b/src/arena.c @@ -474,14 +474,14 @@ arena_decay_deadline_init(arena_t *arena) * Generate a new deadline that is uniformly random within the next * epoch after the current one. */ - nstime_copy(&arena->decay_deadline, &arena->decay_epoch); - nstime_add(&arena->decay_deadline, &arena->decay_interval); - if (arena->decay_time > 0) { + nstime_copy(&arena->decay.deadline, &arena->decay.epoch); + nstime_add(&arena->decay.deadline, &arena->decay.interval); + if (arena->decay.time > 0) { nstime_t jitter; - nstime_init(&jitter, prng_range(&arena->decay_jitter_state, - nstime_ns(&arena->decay_interval), false)); - nstime_add(&arena->decay_deadline, &jitter); + nstime_init(&jitter, prng_range(&arena->decay.jitter_state, + nstime_ns(&arena->decay.interval), false)); + nstime_add(&arena->decay.deadline, &jitter); } } @@ -491,7 +491,7 @@ arena_decay_deadline_reached(const arena_t *arena, const nstime_t *time) assert(opt_purge == purge_mode_decay); - return (nstime_compare(&arena->decay_deadline, time) <= 0); + return (nstime_compare(&arena->decay.deadline, time) <= 0); } static size_t @@ -516,7 +516,7 @@ arena_decay_backlog_npages_limit(const arena_t *arena) */ sum = 0; for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) - sum += arena->decay_backlog[i] * h_steps[i]; + sum += arena->decay.backlog[i] * h_steps[i]; npages_limit_backlog = (size_t)(sum >> SMOOTHSTEP_BFP); return (npages_limit_backlog); @@ -533,39 +533,39 @@ arena_decay_epoch_advance(arena_t *arena, const nstime_t *time) assert(arena_decay_deadline_reached(arena, time)); nstime_copy(&delta, time); - nstime_subtract(&delta, &arena->decay_epoch); - nadvance_u64 = nstime_divide(&delta, &arena->decay_interval); + nstime_subtract(&delta, &arena->decay.epoch); + nadvance_u64 = nstime_divide(&delta, &arena->decay.interval); assert(nadvance_u64 > 0); /* Add nadvance_u64 decay intervals to epoch. */ - nstime_copy(&delta, &arena->decay_interval); + nstime_copy(&delta, &arena->decay.interval); nstime_imultiply(&delta, nadvance_u64); - nstime_add(&arena->decay_epoch, &delta); + nstime_add(&arena->decay.epoch, &delta); /* Set a new deadline. */ arena_decay_deadline_init(arena); /* Update the backlog. */ if (nadvance_u64 >= SMOOTHSTEP_NSTEPS) { - memset(arena->decay_backlog, 0, (SMOOTHSTEP_NSTEPS-1) * + memset(arena->decay.backlog, 0, (SMOOTHSTEP_NSTEPS-1) * sizeof(size_t)); } else { size_t nadvance_z = (size_t)nadvance_u64; assert((uint64_t)nadvance_z == nadvance_u64); - memmove(arena->decay_backlog, &arena->decay_backlog[nadvance_z], + memmove(arena->decay.backlog, &arena->decay.backlog[nadvance_z], (SMOOTHSTEP_NSTEPS - nadvance_z) * sizeof(size_t)); if (nadvance_z > 1) { - memset(&arena->decay_backlog[SMOOTHSTEP_NSTEPS - + memset(&arena->decay.backlog[SMOOTHSTEP_NSTEPS - nadvance_z], 0, (nadvance_z-1) * sizeof(size_t)); } } - ndirty_delta = (arena->ndirty > arena->decay_ndirty) ? arena->ndirty - - arena->decay_ndirty : 0; - arena->decay_ndirty = arena->ndirty; - arena->decay_backlog[SMOOTHSTEP_NSTEPS-1] = ndirty_delta; - arena->decay_backlog_npages_limit = + ndirty_delta = (arena->ndirty > arena->decay.ndirty) ? arena->ndirty - + arena->decay.ndirty : 0; + arena->decay.ndirty = arena->ndirty; + arena->decay.backlog[SMOOTHSTEP_NSTEPS-1] = ndirty_delta; + arena->decay.backlog_npages_limit = arena_decay_backlog_npages_limit(arena); } @@ -576,11 +576,11 @@ arena_decay_npages_limit(arena_t *arena) assert(opt_purge == purge_mode_decay); - npages_limit = arena->decay_backlog_npages_limit; + npages_limit = arena->decay.backlog_npages_limit; /* Add in any dirty pages created during the current epoch. */ - if (arena->ndirty > arena->decay_ndirty) - npages_limit += arena->ndirty - arena->decay_ndirty; + if (arena->ndirty > arena->decay.ndirty) + npages_limit += arena->ndirty - arena->decay.ndirty; return (npages_limit); } @@ -589,19 +589,19 @@ static void arena_decay_init(arena_t *arena, ssize_t decay_time) { - arena->decay_time = decay_time; + arena->decay.time = decay_time; if (decay_time > 0) { - nstime_init2(&arena->decay_interval, decay_time, 0); - nstime_idivide(&arena->decay_interval, SMOOTHSTEP_NSTEPS); + nstime_init2(&arena->decay.interval, decay_time, 0); + nstime_idivide(&arena->decay.interval, SMOOTHSTEP_NSTEPS); } - nstime_init(&arena->decay_epoch, 0); - nstime_update(&arena->decay_epoch); - arena->decay_jitter_state = (uint64_t)(uintptr_t)arena; + nstime_init(&arena->decay.epoch, 0); + nstime_update(&arena->decay.epoch); + arena->decay.jitter_state = (uint64_t)(uintptr_t)arena; arena_decay_deadline_init(arena); - arena->decay_ndirty = arena->ndirty; - arena->decay_backlog_npages_limit = 0; - memset(arena->decay_backlog, 0, SMOOTHSTEP_NSTEPS * sizeof(size_t)); + arena->decay.ndirty = arena->ndirty; + arena->decay.backlog_npages_limit = 0; + memset(arena->decay.backlog, 0, SMOOTHSTEP_NSTEPS * sizeof(size_t)); } static bool @@ -621,7 +621,7 @@ arena_decay_time_get(tsdn_t *tsdn, arena_t *arena) ssize_t decay_time; malloc_mutex_lock(tsdn, &arena->lock); - decay_time = arena->decay_time; + decay_time = arena->decay.time; malloc_mutex_unlock(tsdn, &arena->lock); return (decay_time); @@ -687,16 +687,16 @@ arena_maybe_purge_decay(tsdn_t *tsdn, arena_t *arena) assert(opt_purge == purge_mode_decay); /* Purge all or nothing if the option is disabled. */ - if (arena->decay_time <= 0) { - if (arena->decay_time == 0) + if (arena->decay.time <= 0) { + if (arena->decay.time == 0) arena_purge_to_limit(tsdn, arena, 0); return; } - nstime_copy(&time, &arena->decay_epoch); + nstime_copy(&time, &arena->decay.epoch); if (unlikely(nstime_update(&time))) { /* Time went backwards. Force an epoch advance. */ - nstime_copy(&time, &arena->decay_deadline); + nstime_copy(&time, &arena->decay.deadline); } if (arena_decay_deadline_reached(arena, &time)) @@ -1671,7 +1671,7 @@ arena_basic_stats_merge_locked(arena_t *arena, unsigned *nthreads, *nthreads += arena_nthreads_get(arena, false); *dss = dss_prec_names[arena->dss_prec]; *lg_dirty_mult = arena->lg_dirty_mult; - *decay_time = arena->decay_time; + *decay_time = arena->decay.time; *nactive += arena->nactive; *ndirty += arena->ndirty; } -- GitLab From 5f11fb7d43795e9e2f5d72c8a43a042baaee9b63 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 10 Oct 2016 22:15:10 -0700 Subject: [PATCH 119/544] Do not advance decay epoch when time goes backwards. Instead, move the epoch backward in time. Additionally, add nstime_monotonic() and use it in debug builds to assert that time only goes backward if nstime_update() is using a non-monotonic time source. --- include/jemalloc/internal/nstime.h | 3 +++ include/jemalloc/internal/private_symbols.txt | 1 + src/arena.c | 21 ++++++++++++++---- src/nstime.c | 22 +++++++++++++++++++ test/unit/decay.c | 13 ++++++++++- test/unit/nstime.c | 9 +++++++- 6 files changed, 63 insertions(+), 6 deletions(-) diff --git a/include/jemalloc/internal/nstime.h b/include/jemalloc/internal/nstime.h index c892bac8..93b27dc8 100644 --- a/include/jemalloc/internal/nstime.h +++ b/include/jemalloc/internal/nstime.h @@ -31,9 +31,12 @@ void nstime_imultiply(nstime_t *time, uint64_t multiplier); void nstime_idivide(nstime_t *time, uint64_t divisor); uint64_t nstime_divide(const nstime_t *time, const nstime_t *divisor); #ifdef JEMALLOC_JET +typedef bool (nstime_monotonic_t)(void); +extern nstime_monotonic_t *nstime_monotonic; typedef bool (nstime_update_t)(nstime_t *); extern nstime_update_t *nstime_update; #else +bool nstime_monotonic(void); bool nstime_update(nstime_t *time); #endif diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index d633272a..f9d6e9a7 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -298,6 +298,7 @@ nstime_idivide nstime_imultiply nstime_init nstime_init2 +nstime_monotonic nstime_ns nstime_nsec nstime_sec diff --git a/src/arena.c b/src/arena.c index 9750208d..f53a4643 100644 --- a/src/arena.c +++ b/src/arena.c @@ -693,10 +693,23 @@ arena_maybe_purge_decay(tsdn_t *tsdn, arena_t *arena) return; } - nstime_copy(&time, &arena->decay.epoch); - if (unlikely(nstime_update(&time))) { - /* Time went backwards. Force an epoch advance. */ - nstime_copy(&time, &arena->decay.deadline); + nstime_init(&time, 0); + nstime_update(&time); + if (unlikely(!nstime_monotonic() && nstime_compare(&arena->decay.epoch, + &time) > 0)) { + /* + * Time went backwards. Move the epoch back in time, with the + * expectation that time typically flows forward for long enough + * periods of time that epochs complete. Unfortunately, + * this strategy is susceptible to clock jitter triggering + * premature epoch advances, but clock jitter estimation and + * compensation isn't feasible here because calls into this code + * are event-driven. + */ + nstime_copy(&arena->decay.epoch, &time); + } else { + /* Verify that time does not go backwards. */ + assert(nstime_compare(&arena->decay.epoch, &time) <= 0); } if (arena_decay_deadline_reached(arena, &time)) diff --git a/src/nstime.c b/src/nstime.c index cfb1c8e1..c420c88d 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -98,6 +98,7 @@ nstime_divide(const nstime_t *time, const nstime_t *divisor) } #ifdef _WIN32 +# define NSTIME_MONOTONIC true static void nstime_get(nstime_t *time) { @@ -110,6 +111,7 @@ nstime_get(nstime_t *time) nstime_init(time, ticks_100ns * 100); } #elif JEMALLOC_HAVE_CLOCK_MONOTONIC_RAW +# define NSTIME_MONOTONIC true static void nstime_get(nstime_t *time) { @@ -119,6 +121,7 @@ nstime_get(nstime_t *time) nstime_init2(time, ts.tv_sec, ts.tv_nsec); } #elif JEMALLOC_HAVE_CLOCK_MONOTONIC +# define NSTIME_MONOTONIC true static void nstime_get(nstime_t *time) { @@ -128,6 +131,7 @@ nstime_get(nstime_t *time) nstime_init2(time, ts.tv_sec, ts.tv_nsec); } #elif JEMALLOC_HAVE_MACH_ABSOLUTE_TIME +# define NSTIME_MONOTONIC true static void nstime_get(nstime_t *time) { @@ -135,6 +139,7 @@ nstime_get(nstime_t *time) nstime_init(time, mach_absolute_time()); } #else +# define NSTIME_MONOTONIC false static void nstime_get(nstime_t *time) { @@ -145,6 +150,23 @@ nstime_get(nstime_t *time) } #endif +#ifdef JEMALLOC_JET +#undef nstime_monotonic +#define nstime_monotonic JEMALLOC_N(n_nstime_monotonic) +#endif +bool +nstime_monotonic(void) +{ + + return (NSTIME_MONOTONIC); +#undef NSTIME_MONOTONIC +} +#ifdef JEMALLOC_JET +#undef nstime_monotonic +#define nstime_monotonic JEMALLOC_N(nstime_monotonic) +nstime_monotonic_t *nstime_monotonic = JEMALLOC_N(n_nstime_monotonic); +#endif + #ifdef JEMALLOC_JET #undef nstime_update #define nstime_update JEMALLOC_N(n_nstime_update) diff --git a/test/unit/decay.c b/test/unit/decay.c index 592935d3..b465a5a2 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -2,12 +2,20 @@ const char *malloc_conf = "purge:decay,decay_time:1,lg_tcache_max:0"; +static nstime_monotonic_t *nstime_monotonic_orig; static nstime_update_t *nstime_update_orig; static unsigned nupdates_mock; static nstime_t time_mock; static bool nonmonotonic_mock; +static bool +nstime_monotonic_mock(void) +{ + + return (false); +} + static bool nstime_update_mock(nstime_t *time) { @@ -315,7 +323,9 @@ TEST_BEGIN(test_decay_nonmonotonic) nstime_update(&time_mock); nonmonotonic_mock = true; + nstime_monotonic_orig = nstime_monotonic; nstime_update_orig = nstime_update; + nstime_monotonic = nstime_monotonic_mock; nstime_update = nstime_update_mock; for (i = 0; i < NPS; i++) { @@ -339,8 +349,9 @@ TEST_BEGIN(test_decay_nonmonotonic) config_stats ? 0 : ENOENT, "Unexpected mallctl result"); if (config_stats) - assert_u64_gt(npurge1, npurge0, "Expected purging to occur"); + assert_u64_eq(npurge0, npurge1, "Unexpected purging occurred"); + nstime_monotonic = nstime_monotonic_orig; nstime_update = nstime_update_orig; #undef NPS } diff --git a/test/unit/nstime.c b/test/unit/nstime.c index cd7d9a6d..0368bc26 100644 --- a/test/unit/nstime.c +++ b/test/unit/nstime.c @@ -176,6 +176,13 @@ TEST_BEGIN(test_nstime_divide) } TEST_END +TEST_BEGIN(test_nstime_monotonic) +{ + + nstime_monotonic(); +} +TEST_END + TEST_BEGIN(test_nstime_update) { nstime_t nst; @@ -198,7 +205,6 @@ TEST_BEGIN(test_nstime_update) assert_d_eq(nstime_compare(&nst, &nst0), 0, "Time should not have been modified"); } - } TEST_END @@ -216,5 +222,6 @@ main(void) test_nstime_imultiply, test_nstime_idivide, test_nstime_divide, + test_nstime_monotonic, test_nstime_update)); } -- GitLab From 48993ed5368506013fa1dcbc72b299409b7f5716 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 11 Oct 2016 15:28:43 -0700 Subject: [PATCH 120/544] Fix decay tests to all adapt to nstime_monotonic(). --- test/unit/decay.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/test/unit/decay.c b/test/unit/decay.c index b465a5a2..333a722c 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -7,13 +7,13 @@ static nstime_update_t *nstime_update_orig; static unsigned nupdates_mock; static nstime_t time_mock; -static bool nonmonotonic_mock; +static bool monotonic_mock; static bool nstime_monotonic_mock(void) { - return (false); + return (monotonic_mock); } static bool @@ -21,9 +21,9 @@ nstime_update_mock(nstime_t *time) { nupdates_mock++; - if (!nonmonotonic_mock) + if (monotonic_mock) nstime_copy(time, &time_mock); - return (nonmonotonic_mock); + return (!monotonic_mock); } TEST_BEGIN(test_decay_ticks) @@ -250,9 +250,11 @@ TEST_BEGIN(test_decay_ticker) nupdates_mock = 0; nstime_init(&time_mock, 0); nstime_update(&time_mock); - nonmonotonic_mock = false; + monotonic_mock = true; + nstime_monotonic_orig = nstime_monotonic; nstime_update_orig = nstime_update; + nstime_monotonic = nstime_monotonic_mock; nstime_update = nstime_update_mock; for (i = 0; i < NPS; i++) { @@ -264,6 +266,7 @@ TEST_BEGIN(test_decay_ticker) "Expected nstime_update() to be called"); } + nstime_monotonic = nstime_monotonic_orig; nstime_update = nstime_update_orig; nstime_init(&time, 0); @@ -321,7 +324,7 @@ TEST_BEGIN(test_decay_nonmonotonic) nupdates_mock = 0; nstime_init(&time_mock, 0); nstime_update(&time_mock); - nonmonotonic_mock = true; + monotonic_mock = false; nstime_monotonic_orig = nstime_monotonic; nstime_update_orig = nstime_update; -- GitLab From b4b4a77848f1c726134ace82509b6adb9f8e7055 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 11 Oct 2016 15:30:01 -0700 Subject: [PATCH 121/544] Fix and simplify decay-based purging. Simplify decay-based purging attempts to only be triggered when the epoch is advanced, rather than every time purgeable memory increases. In a correctly functioning system (not previously the case; see below), this only causes a behavior difference if during subsequent purge attempts the least recently used (LRU) purgeable memory extent is initially too large to be purged, but that memory is reused between attempts and one or more of the next LRU purgeable memory extents are small enough to be purged. In practice this is an arbitrary behavior change that is within the set of acceptable behaviors. As for the purging fix, assure that arena->decay.ndirty is recorded *after* the epoch advance and associated purging occurs. Prior to this fix, it was possible for purging during epoch advance to cause a substantially underrepresentative (arena->ndirty - arena->decay.ndirty), i.e. the number of dirty pages attributed to the current epoch was too low, and a series of unintended purges could result. This fix is also relevant in the context of the simplification described above, but the bug's impact would be limited to over-purging at epoch advances. --- include/jemalloc/internal/arena.h | 29 +++----- src/arena.c | 109 ++++++++++++++++-------------- 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 3830e548..3bb1f19c 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -97,7 +97,7 @@ struct arena_decay_s { * and/or reused. */ ssize_t time; - /* decay_time / SMOOTHSTEP_NSTEPS. */ + /* time / SMOOTHSTEP_NSTEPS. */ nstime_t interval; /* * Time at which the current decay interval logically started. We do @@ -107,37 +107,30 @@ struct arena_decay_s { * merge all relevant activity into the most recently recorded epoch. */ nstime_t epoch; - /* decay_deadline randomness generator. */ + /* Deadline randomness generator. */ uint64_t jitter_state; /* - * Deadline for current epoch. This is the sum of decay_interval and - * per epoch jitter which is a uniform random variable in - * [0..decay_interval). Epochs always advance by precise multiples of - * decay_interval, but we randomize the deadline to reduce the - * likelihood of arenas purging in lockstep. + * Deadline for current epoch. This is the sum of interval and per + * epoch jitter which is a uniform random variable in [0..interval). + * Epochs always advance by precise multiples of interval, but we + * randomize the deadline to reduce the likelihood of arenas purging in + * lockstep. */ nstime_t deadline; /* * Number of dirty pages at beginning of current epoch. During epoch - * advancement we use the delta between decay_ndirty and ndirty to - * determine how many dirty pages, if any, were generated, and record - * the result in decay_backlog. + * advancement we use the delta between arena->decay.ndirty and + * arena->ndirty to determine how many dirty pages, if any, were + * generated. */ size_t ndirty; - /* - * Memoized result of arena_decay_backlog_npages_limit() corresponding - * to the current contents of decay_backlog, i.e. the limit on how many - * pages are allowed to exist for the decay epochs. - */ - size_t backlog_npages_limit; /* * Trailing log of how many unused dirty pages were generated during * each of the past SMOOTHSTEP_NSTEPS decay epochs, where the last * element is the most recent epoch. Corresponding epoch times are - * relative to decay_epoch. + * relative to epoch. */ size_t backlog[SMOOTHSTEP_NSTEPS]; - }; struct arena_bin_s { diff --git a/src/arena.c b/src/arena.c index f53a4643..2f0291e5 100644 --- a/src/arena.c +++ b/src/arena.c @@ -523,11 +523,41 @@ arena_decay_backlog_npages_limit(const arena_t *arena) } static void -arena_decay_epoch_advance(arena_t *arena, const nstime_t *time) +arena_decay_backlog_update_last(arena_t *arena) +{ + size_t ndirty_delta = (arena->ndirty > arena->decay.ndirty) ? + arena->ndirty - arena->decay.ndirty : 0; + arena->decay.backlog[SMOOTHSTEP_NSTEPS-1] = ndirty_delta; +} + +static void +arena_decay_backlog_update(arena_t *arena, uint64_t nadvance_u64) +{ + + if (nadvance_u64 >= SMOOTHSTEP_NSTEPS) { + memset(arena->decay.backlog, 0, (SMOOTHSTEP_NSTEPS-1) * + sizeof(size_t)); + } else { + size_t nadvance_z = (size_t)nadvance_u64; + + assert((uint64_t)nadvance_z == nadvance_u64); + + memmove(arena->decay.backlog, &arena->decay.backlog[nadvance_z], + (SMOOTHSTEP_NSTEPS - nadvance_z) * sizeof(size_t)); + if (nadvance_z > 1) { + memset(&arena->decay.backlog[SMOOTHSTEP_NSTEPS - + nadvance_z], 0, (nadvance_z-1) * sizeof(size_t)); + } + } + + arena_decay_backlog_update_last(arena); +} + +static void +arena_decay_epoch_advance_helper(arena_t *arena, const nstime_t *time) { uint64_t nadvance_u64; nstime_t delta; - size_t ndirty_delta; assert(opt_purge == purge_mode_decay); assert(arena_decay_deadline_reached(arena, time)); @@ -546,43 +576,25 @@ arena_decay_epoch_advance(arena_t *arena, const nstime_t *time) arena_decay_deadline_init(arena); /* Update the backlog. */ - if (nadvance_u64 >= SMOOTHSTEP_NSTEPS) { - memset(arena->decay.backlog, 0, (SMOOTHSTEP_NSTEPS-1) * - sizeof(size_t)); - } else { - size_t nadvance_z = (size_t)nadvance_u64; + arena_decay_backlog_update(arena, nadvance_u64); +} - assert((uint64_t)nadvance_z == nadvance_u64); +static void +arena_decay_epoch_advance_purge(tsdn_t *tsdn, arena_t *arena) +{ + size_t ndirty_limit = arena_decay_backlog_npages_limit(arena); - memmove(arena->decay.backlog, &arena->decay.backlog[nadvance_z], - (SMOOTHSTEP_NSTEPS - nadvance_z) * sizeof(size_t)); - if (nadvance_z > 1) { - memset(&arena->decay.backlog[SMOOTHSTEP_NSTEPS - - nadvance_z], 0, (nadvance_z-1) * sizeof(size_t)); - } - } - ndirty_delta = (arena->ndirty > arena->decay.ndirty) ? arena->ndirty - - arena->decay.ndirty : 0; + if (arena->ndirty > ndirty_limit) + arena_purge_to_limit(tsdn, arena, ndirty_limit); arena->decay.ndirty = arena->ndirty; - arena->decay.backlog[SMOOTHSTEP_NSTEPS-1] = ndirty_delta; - arena->decay.backlog_npages_limit = - arena_decay_backlog_npages_limit(arena); } -static size_t -arena_decay_npages_limit(arena_t *arena) +static void +arena_decay_epoch_advance(tsdn_t *tsdn, arena_t *arena, const nstime_t *time) { - size_t npages_limit; - - assert(opt_purge == purge_mode_decay); - - npages_limit = arena->decay.backlog_npages_limit; - /* Add in any dirty pages created during the current epoch. */ - if (arena->ndirty > arena->decay.ndirty) - npages_limit += arena->ndirty - arena->decay.ndirty; - - return (npages_limit); + arena_decay_epoch_advance_helper(arena, time); + arena_decay_epoch_advance_purge(tsdn, arena); } static void @@ -600,7 +612,6 @@ arena_decay_init(arena_t *arena, ssize_t decay_time) arena->decay.jitter_state = (uint64_t)(uintptr_t)arena; arena_decay_deadline_init(arena); arena->decay.ndirty = arena->ndirty; - arena->decay.backlog_npages_limit = 0; memset(arena->decay.backlog, 0, SMOOTHSTEP_NSTEPS * sizeof(size_t)); } @@ -682,7 +693,6 @@ static void arena_maybe_purge_decay(tsdn_t *tsdn, arena_t *arena) { nstime_t time; - size_t ndirty_limit; assert(opt_purge == purge_mode_decay); @@ -698,32 +708,29 @@ arena_maybe_purge_decay(tsdn_t *tsdn, arena_t *arena) if (unlikely(!nstime_monotonic() && nstime_compare(&arena->decay.epoch, &time) > 0)) { /* - * Time went backwards. Move the epoch back in time, with the - * expectation that time typically flows forward for long enough - * periods of time that epochs complete. Unfortunately, - * this strategy is susceptible to clock jitter triggering - * premature epoch advances, but clock jitter estimation and - * compensation isn't feasible here because calls into this code - * are event-driven. + * Time went backwards. Move the epoch back in time and + * generate a new deadline, with the expectation that time + * typically flows forward for long enough periods of time that + * epochs complete. Unfortunately, this strategy is susceptible + * to clock jitter triggering premature epoch advances, but + * clock jitter estimation and compensation isn't feasible here + * because calls into this code are event-driven. */ nstime_copy(&arena->decay.epoch, &time); + arena_decay_deadline_init(arena); } else { /* Verify that time does not go backwards. */ assert(nstime_compare(&arena->decay.epoch, &time) <= 0); } - if (arena_decay_deadline_reached(arena, &time)) - arena_decay_epoch_advance(arena, &time); - - ndirty_limit = arena_decay_npages_limit(arena); - /* - * Don't try to purge unless the number of purgeable pages exceeds the - * current limit. + * If the deadline has been reached, advance to the current epoch and + * purge to the new limit if necessary. Note that dirty pages created + * during the current epoch are not subject to purge until a future + * epoch, so as a result purging only happens during epoch advances. */ - if (arena->ndirty <= ndirty_limit) - return; - arena_purge_to_limit(tsdn, arena, ndirty_limit); + if (arena_decay_deadline_reached(arena, &time)) + arena_decay_epoch_advance(tsdn, arena, &time); } void -- GitLab From 63b5657aa566ceab270ff6e9d4f366233d2d0b79 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 12 Oct 2016 10:40:27 -0700 Subject: [PATCH 122/544] Remove ratio-based purging. Make decay-based purging the default (and only) mode. Remove associated mallctls: - opt.purge - opt.lg_dirty_mult - arena..lg_dirty_mult - arenas.lg_dirty_mult - stats.arenas..lg_dirty_mult This resolves #385. --- Makefile.in | 8 +- doc/jemalloc.xml.in | 76 --------- include/jemalloc/internal/arena.h | 38 +---- include/jemalloc/internal/ctl.h | 1 - include/jemalloc/internal/private_symbols.txt | 7 - src/arena.c | 152 ++---------------- src/ctl.c | 85 +--------- src/jemalloc.c | 19 --- src/stats.c | 52 ++---- test/unit/decay.c | 8 +- test/unit/mallctl.c | 77 --------- 11 files changed, 38 insertions(+), 485 deletions(-) diff --git a/Makefile.in b/Makefile.in index ec863079..5feb71d1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -374,17 +374,15 @@ stress_dir: check_dir: check_unit_dir check_integration_dir check_unit: tests_unit check_unit_dir - $(MALLOC_CONF)="purge:ratio" $(SHELL) $(objroot)test/test.sh $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%) - $(MALLOC_CONF)="purge:decay" $(SHELL) $(objroot)test/test.sh $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%) + $(SHELL) $(objroot)test/test.sh $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%) check_integration_prof: tests_integration check_integration_dir ifeq ($(enable_prof), 1) $(MALLOC_CONF)="prof:true" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(MALLOC_CONF)="prof:true,prof_active:false" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) endif check_integration_decay: tests_integration check_integration_dir - $(MALLOC_CONF)="purge:decay,decay_time:-1" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) - $(MALLOC_CONF)="purge:decay,decay_time:0" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) - $(MALLOC_CONF)="purge:decay" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) + $(MALLOC_CONF)="decay_time:-1" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) + $(MALLOC_CONF)="decay_time:0" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) check_integration: tests_integration check_integration_dir $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) stress: tests_stress stress_dir diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 8000461f..f5a72473 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -924,42 +924,6 @@ for (i = 0; i < nbins; i++) { number of CPUs, or one if there is a single CPU. - - - opt.purge - (const char *) - r- - - Purge mode is “ratio” (default) or - “decay”. See opt.lg_dirty_mult - for details of the ratio mode. See opt.decay_time for - details of the decay mode. - - - - - opt.lg_dirty_mult - (ssize_t) - r- - - Per-arena minimum ratio (log base 2) of active to dirty - pages. Some dirty unused pages may be allowed to accumulate, within - the limit set by the ratio (or one chunk worth of dirty pages, - whichever is greater), before informing the kernel about some of those - pages via madvise - 2 or a similar system call. This - provides the kernel with sufficient information to recycle dirty pages - if physical memory becomes scarce and the pages remain unused. The - default minimum ratio is 8:1 (2^3:1); an option value of -1 will - disable dirty page purging. See arenas.lg_dirty_mult - and arena.<i>.lg_dirty_mult - for related dynamic control options. - - opt.decay_time @@ -1518,20 +1482,6 @@ malloc_conf = "xmalloc:true";]]> settings. - - - arena.<i>.lg_dirty_mult - (ssize_t) - rw - - Current per-arena minimum ratio (log base 2) of active - to dirty pages for arena <i>. Each time this interface is set and - the ratio is increased, pages are synchronously purged as necessary to - impose the new ratio. See opt.lg_dirty_mult - for additional information. - - arena.<i>.decay_time @@ -1778,20 +1728,6 @@ struct extent_hooks_s { initialized. - - - arenas.lg_dirty_mult - (ssize_t) - rw - - Current default per-arena minimum ratio (log base 2) of - active to dirty pages, used to initialize arena.<i>.lg_dirty_mult - during arena creation. See opt.lg_dirty_mult - for additional information. - - arenas.decay_time @@ -2137,18 +2073,6 @@ struct extent_hooks_s { - - - stats.arenas.<i>.lg_dirty_mult - (ssize_t) - r- - - Minimum ratio (log base 2) of active to dirty pages. - See opt.lg_dirty_mult - for details. - - stats.arenas.<i>.decay_time diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 3bb1f19c..4e20af48 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -7,23 +7,6 @@ #define LG_SLAB_MAXREGS (LG_PAGE - LG_TINY_MIN) #define SLAB_MAXREGS (1U << LG_SLAB_MAXREGS) -/* - * The minimum ratio of active:dirty pages per arena is computed as: - * - * (nactive >> lg_dirty_mult) >= ndirty - * - * So, supposing that lg_dirty_mult is 3, there can be no less than 8 times as - * many active pages as dirty pages. - */ -#define LG_DIRTY_MULT_DEFAULT 3 - -typedef enum { - purge_mode_ratio = 0, - purge_mode_decay = 1, - - purge_mode_limit = 2 -} purge_mode_t; -#define PURGE_DEFAULT purge_mode_ratio /* Default decay time in seconds. */ #define DECAY_TIME_DEFAULT 10 /* Number of event ticks between time checks. */ @@ -203,9 +186,6 @@ struct arena_s { dss_prec_t dss_prec; - /* Minimum ratio (log base 2) of nactive:ndirty. */ - ssize_t lg_dirty_mult; - /* True if a thread is currently executing arena_purge_to_limit(). */ bool purging; @@ -274,9 +254,6 @@ static const size_t large_pad = #endif ; -extern purge_mode_t opt_purge; -extern const char *purge_mode_names[]; -extern ssize_t opt_lg_dirty_mult; extern ssize_t opt_decay_time; extern const arena_bin_info_t arena_bin_info[NBINS]; @@ -298,9 +275,6 @@ void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); -ssize_t arena_lg_dirty_mult_get(tsdn_t *tsdn, arena_t *arena); -bool arena_lg_dirty_mult_set(tsdn_t *tsdn, arena_t *arena, - ssize_t lg_dirty_mult); ssize_t arena_decay_time_get(tsdn_t *tsdn, arena_t *arena); bool arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time); void arena_purge(tsdn_t *tsdn, arena_t *arena, bool all); @@ -334,17 +308,15 @@ void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache); dss_prec_t arena_dss_prec_get(tsdn_t *tsdn, arena_t *arena); bool arena_dss_prec_set(tsdn_t *tsdn, arena_t *arena, dss_prec_t dss_prec); -ssize_t arena_lg_dirty_mult_default_get(void); -bool arena_lg_dirty_mult_default_set(ssize_t lg_dirty_mult); ssize_t arena_decay_time_default_get(void); bool arena_decay_time_default_set(ssize_t decay_time); void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, - unsigned *nthreads, const char **dss, ssize_t *lg_dirty_mult, - ssize_t *decay_time, size_t *nactive, size_t *ndirty); + unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, + size_t *ndirty); void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *lg_dirty_mult, ssize_t *decay_time, - size_t *nactive, size_t *ndirty, arena_stats_t *astats, - malloc_bin_stats_t *bstats, malloc_large_stats_t *lstats); + const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty, + arena_stats_t *astats, malloc_bin_stats_t *bstats, + malloc_large_stats_t *lstats); unsigned arena_nthreads_get(arena_t *arena, bool internal); void arena_nthreads_inc(arena_t *arena, bool internal); void arena_nthreads_dec(arena_t *arena, bool internal); diff --git a/include/jemalloc/internal/ctl.h b/include/jemalloc/internal/ctl.h index 3fbac205..4d4f3043 100644 --- a/include/jemalloc/internal/ctl.h +++ b/include/jemalloc/internal/ctl.h @@ -35,7 +35,6 @@ struct ctl_arena_stats_s { bool initialized; unsigned nthreads; const char *dss; - ssize_t lg_dirty_mult; ssize_t decay_time; size_t pactive; size_t pdirty; diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index f9d6e9a7..e52e7fed 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -34,10 +34,6 @@ arena_extent_ralloc_large_shrink arena_get arena_ichoose arena_init -arena_lg_dirty_mult_default_get -arena_lg_dirty_mult_default_set -arena_lg_dirty_mult_get -arena_lg_dirty_mult_set arena_malloc arena_malloc_hard arena_maybe_purge @@ -311,7 +307,6 @@ opt_junk opt_junk_alloc opt_junk_free opt_lg_chunk -opt_lg_dirty_mult opt_lg_prof_interval opt_lg_prof_sample opt_lg_tcache_max @@ -324,7 +319,6 @@ opt_prof_gdump opt_prof_leak opt_prof_prefix opt_prof_thread_active_init -opt_purge opt_stats_print opt_tcache opt_utrace @@ -399,7 +393,6 @@ psz2ind psz2ind_clamp psz2ind_impl psz2u -purge_mode_names register_zone rtree_child_read rtree_child_read_hard diff --git a/src/arena.c b/src/arena.c index 2f0291e5..3de02373 100644 --- a/src/arena.c +++ b/src/arena.c @@ -4,14 +4,6 @@ /******************************************************************************/ /* Data. */ -purge_mode_t opt_purge = PURGE_DEFAULT; -const char *purge_mode_names[] = { - "ratio", - "decay", - "N/A" -}; -ssize_t opt_lg_dirty_mult = LG_DIRTY_MULT_DEFAULT; -static ssize_t lg_dirty_mult_default; ssize_t opt_decay_time = DECAY_TIME_DEFAULT; static ssize_t decay_time_default; @@ -429,47 +421,10 @@ arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, malloc_mutex_unlock(tsdn, &arena->lock); } -static bool -arena_lg_dirty_mult_valid(ssize_t lg_dirty_mult) -{ - - return (lg_dirty_mult >= -1 && lg_dirty_mult < (ssize_t)(sizeof(size_t) - << 3)); -} - -ssize_t -arena_lg_dirty_mult_get(tsdn_t *tsdn, arena_t *arena) -{ - ssize_t lg_dirty_mult; - - malloc_mutex_lock(tsdn, &arena->lock); - lg_dirty_mult = arena->lg_dirty_mult; - malloc_mutex_unlock(tsdn, &arena->lock); - - return (lg_dirty_mult); -} - -bool -arena_lg_dirty_mult_set(tsdn_t *tsdn, arena_t *arena, ssize_t lg_dirty_mult) -{ - - if (!arena_lg_dirty_mult_valid(lg_dirty_mult)) - return (true); - - malloc_mutex_lock(tsdn, &arena->lock); - arena->lg_dirty_mult = lg_dirty_mult; - arena_maybe_purge(tsdn, arena); - malloc_mutex_unlock(tsdn, &arena->lock); - - return (false); -} - static void arena_decay_deadline_init(arena_t *arena) { - assert(opt_purge == purge_mode_decay); - /* * Generate a new deadline that is uniformly random within the next * epoch after the current one. @@ -489,8 +444,6 @@ static bool arena_decay_deadline_reached(const arena_t *arena, const nstime_t *time) { - assert(opt_purge == purge_mode_decay); - return (nstime_compare(&arena->decay.deadline, time) <= 0); } @@ -507,8 +460,6 @@ arena_decay_backlog_npages_limit(const arena_t *arena) size_t npages_limit_backlog; unsigned i; - assert(opt_purge == purge_mode_decay); - /* * For each element of decay_backlog, multiply by the corresponding * fixed-point smoothstep decay factor. Sum the products, then divide @@ -559,7 +510,6 @@ arena_decay_epoch_advance_helper(arena_t *arena, const nstime_t *time) uint64_t nadvance_u64; nstime_t delta; - assert(opt_purge == purge_mode_decay); assert(arena_decay_deadline_reached(arena, time)); nstime_copy(&delta, time); @@ -662,40 +612,10 @@ arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) } static void -arena_maybe_purge_ratio(tsdn_t *tsdn, arena_t *arena) -{ - - assert(opt_purge == purge_mode_ratio); - - /* Don't purge if the option is disabled. */ - if (arena->lg_dirty_mult < 0) - return; - - /* - * Iterate, since preventing recursive purging could otherwise leave too - * many dirty pages. - */ - while (true) { - size_t threshold = (arena->nactive >> arena->lg_dirty_mult); - if (threshold < chunk_npages) - threshold = chunk_npages; - /* - * Don't purge unless the number of purgeable pages exceeds the - * threshold. - */ - if (arena->ndirty <= threshold) - return; - arena_purge_to_limit(tsdn, arena, threshold); - } -} - -static void -arena_maybe_purge_decay(tsdn_t *tsdn, arena_t *arena) +arena_maybe_purge_helper(tsdn_t *tsdn, arena_t *arena) { nstime_t time; - assert(opt_purge == purge_mode_decay); - /* Purge all or nothing if the option is disabled. */ if (arena->decay.time <= 0) { if (arena->decay.time == 0) @@ -743,10 +663,7 @@ arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) if (arena->purging) return; - if (opt_purge == purge_mode_ratio) - arena_maybe_purge_ratio(tsdn, arena); - else - arena_maybe_purge_decay(tsdn, arena); + arena_maybe_purge_helper(tsdn, arena); } static size_t @@ -781,8 +698,7 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, UNUSED extent_t *textent; npages = extent_size_get(extent) >> LG_PAGE; - if (opt_purge == purge_mode_decay && arena->ndirty - (nstashed + - npages) < ndirty_limit) + if (arena->ndirty - (nstashed + npages) < ndirty_limit) break; next = qr_next(extent, qr_link); @@ -797,9 +713,6 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_ring_insert(purge_extents_sentinel, extent); nstashed += npages; - if (opt_purge == purge_mode_ratio && arena->ndirty - nstashed <= - ndirty_limit) - break; } malloc_mutex_unlock(tsdn, &arena->extents_mtx); @@ -838,13 +751,8 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, } /* - * NB: ndirty_limit is interpreted differently depending on opt_purge: - * - purge_mode_ratio: Purge as few dirty extents as possible to reach the - * desired state: - * (arena->ndirty <= ndirty_limit) - * - purge_mode_decay: Purge as many dirty extents as possible without - * violating the invariant: - * (arena->ndirty >= ndirty_limit) + * ndirty_limit: Purge as many dirty extents as possible without violating the + * invariant: (arena->ndirty >= ndirty_limit) */ static void arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) @@ -863,9 +771,6 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) size_t ndirty = arena_dirty_count(tsdn, arena); assert(ndirty == arena->ndirty); } - assert(opt_purge != purge_mode_ratio || (arena->nactive >> - arena->lg_dirty_mult) < arena->ndirty || ndirty_limit == 0); - extent_init(&purge_extents_sentinel, arena, NULL, 0, 0, false, false, false, false); @@ -1644,25 +1549,6 @@ arena_dss_prec_set(tsdn_t *tsdn, arena_t *arena, dss_prec_t dss_prec) return (false); } -ssize_t -arena_lg_dirty_mult_default_get(void) -{ - - return ((ssize_t)atomic_read_z((size_t *)&lg_dirty_mult_default)); -} - -bool -arena_lg_dirty_mult_default_set(ssize_t lg_dirty_mult) -{ - - if (opt_purge != purge_mode_ratio) - return (true); - if (!arena_lg_dirty_mult_valid(lg_dirty_mult)) - return (true); - atomic_write_z((size_t *)&lg_dirty_mult_default, (size_t)lg_dirty_mult); - return (false); -} - ssize_t arena_decay_time_default_get(void) { @@ -1674,8 +1560,6 @@ bool arena_decay_time_default_set(ssize_t decay_time) { - if (opt_purge != purge_mode_decay) - return (true); if (!arena_decay_time_valid(decay_time)) return (true); atomic_write_z((size_t *)&decay_time_default, (size_t)decay_time); @@ -1684,13 +1568,11 @@ arena_decay_time_default_set(ssize_t decay_time) static void arena_basic_stats_merge_locked(arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *lg_dirty_mult, ssize_t *decay_time, - size_t *nactive, size_t *ndirty) + const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) { *nthreads += arena_nthreads_get(arena, false); *dss = dss_prec_names[arena->dss_prec]; - *lg_dirty_mult = arena->lg_dirty_mult; *decay_time = arena->decay.time; *nactive += arena->nactive; *ndirty += arena->ndirty; @@ -1698,29 +1580,28 @@ arena_basic_stats_merge_locked(arena_t *arena, unsigned *nthreads, void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *lg_dirty_mult, ssize_t *decay_time, - size_t *nactive, size_t *ndirty) + const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) { malloc_mutex_lock(tsdn, &arena->lock); - arena_basic_stats_merge_locked(arena, nthreads, dss, lg_dirty_mult, - decay_time, nactive, ndirty); + arena_basic_stats_merge_locked(arena, nthreads, dss, decay_time, + nactive, ndirty); malloc_mutex_unlock(tsdn, &arena->lock); } void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *lg_dirty_mult, ssize_t *decay_time, - size_t *nactive, size_t *ndirty, arena_stats_t *astats, - malloc_bin_stats_t *bstats, malloc_large_stats_t *lstats) + const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty, + arena_stats_t *astats, malloc_bin_stats_t *bstats, + malloc_large_stats_t *lstats) { unsigned i; cassert(config_stats); malloc_mutex_lock(tsdn, &arena->lock); - arena_basic_stats_merge_locked(arena, nthreads, dss, lg_dirty_mult, - decay_time, nactive, ndirty); + arena_basic_stats_merge_locked(arena, nthreads, dss, decay_time, + nactive, ndirty); astats->mapped += arena->stats.mapped; astats->retained += arena->stats.retained; @@ -1816,13 +1697,11 @@ arena_new(tsdn_t *tsdn, unsigned ind) arena->dss_prec = extent_dss_prec_get(tsdn); - arena->lg_dirty_mult = arena_lg_dirty_mult_default_get(); arena->purging = false; arena->nactive = 0; arena->ndirty = 0; - if (opt_purge == purge_mode_decay) - arena_decay_init(arena, arena_decay_time_default_get()); + arena_decay_init(arena, arena_decay_time_default_get()); ql_new(&arena->large); if (malloc_mutex_init(&arena->large_mtx, "arena_large", @@ -1869,7 +1748,6 @@ void arena_boot(void) { - arena_lg_dirty_mult_default_set(opt_lg_dirty_mult); arena_decay_time_default_set(opt_decay_time); } diff --git a/src/ctl.c b/src/ctl.c index 87fd8c75..b00991a6 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -90,8 +90,6 @@ CTL_PROTO(opt_abort) CTL_PROTO(opt_dss) CTL_PROTO(opt_lg_chunk) CTL_PROTO(opt_narenas) -CTL_PROTO(opt_purge) -CTL_PROTO(opt_lg_dirty_mult) CTL_PROTO(opt_decay_time) CTL_PROTO(opt_stats_print) CTL_PROTO(opt_junk) @@ -118,7 +116,6 @@ CTL_PROTO(arena_i_purge) CTL_PROTO(arena_i_decay) CTL_PROTO(arena_i_reset) CTL_PROTO(arena_i_dss) -CTL_PROTO(arena_i_lg_dirty_mult) CTL_PROTO(arena_i_decay_time) CTL_PROTO(arena_i_extent_hooks) INDEX_PROTO(arena_i) @@ -130,7 +127,6 @@ CTL_PROTO(arenas_lextent_i_size) INDEX_PROTO(arenas_lextent_i) CTL_PROTO(arenas_narenas) CTL_PROTO(arenas_initialized) -CTL_PROTO(arenas_lg_dirty_mult) CTL_PROTO(arenas_decay_time) CTL_PROTO(arenas_quantum) CTL_PROTO(arenas_page) @@ -171,7 +167,6 @@ CTL_PROTO(stats_arenas_i_lextents_j_curlextents) INDEX_PROTO(stats_arenas_i_lextents_j) CTL_PROTO(stats_arenas_i_nthreads) CTL_PROTO(stats_arenas_i_dss) -CTL_PROTO(stats_arenas_i_lg_dirty_mult) CTL_PROTO(stats_arenas_i_decay_time) CTL_PROTO(stats_arenas_i_pactive) CTL_PROTO(stats_arenas_i_pdirty) @@ -251,8 +246,6 @@ static const ctl_named_node_t opt_node[] = { {NAME("dss"), CTL(opt_dss)}, {NAME("lg_chunk"), CTL(opt_lg_chunk)}, {NAME("narenas"), CTL(opt_narenas)}, - {NAME("purge"), CTL(opt_purge)}, - {NAME("lg_dirty_mult"), CTL(opt_lg_dirty_mult)}, {NAME("decay_time"), CTL(opt_decay_time)}, {NAME("stats_print"), CTL(opt_stats_print)}, {NAME("junk"), CTL(opt_junk)}, @@ -284,7 +277,6 @@ static const ctl_named_node_t arena_i_node[] = { {NAME("decay"), CTL(arena_i_decay)}, {NAME("reset"), CTL(arena_i_reset)}, {NAME("dss"), CTL(arena_i_dss)}, - {NAME("lg_dirty_mult"), CTL(arena_i_lg_dirty_mult)}, {NAME("decay_time"), CTL(arena_i_decay_time)}, {NAME("extent_hooks"), CTL(arena_i_extent_hooks)} }; @@ -323,7 +315,6 @@ static const ctl_indexed_node_t arenas_lextent_node[] = { static const ctl_named_node_t arenas_node[] = { {NAME("narenas"), CTL(arenas_narenas)}, {NAME("initialized"), CTL(arenas_initialized)}, - {NAME("lg_dirty_mult"), CTL(arenas_lg_dirty_mult)}, {NAME("decay_time"), CTL(arenas_decay_time)}, {NAME("quantum"), CTL(arenas_quantum)}, {NAME("page"), CTL(arenas_page)}, @@ -396,7 +387,6 @@ static const ctl_indexed_node_t stats_arenas_i_lextents_node[] = { static const ctl_named_node_t stats_arenas_i_node[] = { {NAME("nthreads"), CTL(stats_arenas_i_nthreads)}, {NAME("dss"), CTL(stats_arenas_i_dss)}, - {NAME("lg_dirty_mult"), CTL(stats_arenas_i_lg_dirty_mult)}, {NAME("decay_time"), CTL(stats_arenas_i_decay_time)}, {NAME("pactive"), CTL(stats_arenas_i_pactive)}, {NAME("pdirty"), CTL(stats_arenas_i_pdirty)}, @@ -459,7 +449,6 @@ ctl_arena_clear(ctl_arena_stats_t *astats) astats->nthreads = 0; astats->dss = dss_prec_names[dss_prec_limit]; - astats->lg_dirty_mult = -1; astats->decay_time = -1; astats->pactive = 0; astats->pdirty = 0; @@ -482,9 +471,8 @@ ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_stats_t *cstats, arena_t *arena) if (config_stats) { arena_stats_merge(tsdn, arena, &cstats->nthreads, &cstats->dss, - &cstats->lg_dirty_mult, &cstats->decay_time, - &cstats->pactive, &cstats->pdirty, &cstats->astats, - cstats->bstats, cstats->lstats); + &cstats->decay_time, &cstats->pactive, &cstats->pdirty, + &cstats->astats, cstats->bstats, cstats->lstats); for (i = 0; i < NBINS; i++) { cstats->allocated_small += cstats->bstats[i].curregs * @@ -495,8 +483,8 @@ ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_stats_t *cstats, arena_t *arena) } } else { arena_basic_stats_merge(tsdn, arena, &cstats->nthreads, - &cstats->dss, &cstats->lg_dirty_mult, &cstats->decay_time, - &cstats->pactive, &cstats->pdirty); + &cstats->dss, &cstats->decay_time, &cstats->pactive, + &cstats->pdirty); } } @@ -1150,8 +1138,6 @@ CTL_RO_NL_GEN(opt_abort, opt_abort, bool) CTL_RO_NL_GEN(opt_dss, opt_dss, const char *) CTL_RO_NL_GEN(opt_lg_chunk, opt_lg_chunk, size_t) CTL_RO_NL_GEN(opt_narenas, opt_narenas, unsigned) -CTL_RO_NL_GEN(opt_purge, purge_mode_names[opt_purge], const char *) -CTL_RO_NL_GEN(opt_lg_dirty_mult, opt_lg_dirty_mult, ssize_t) CTL_RO_NL_GEN(opt_decay_time, opt_decay_time, ssize_t) CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool) CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *) @@ -1562,41 +1548,6 @@ label_return: return (ret); } -static int -arena_i_lg_dirty_mult_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, - void *oldp, size_t *oldlenp, void *newp, size_t newlen) -{ - int ret; - unsigned arena_ind = (unsigned)mib[1]; - arena_t *arena; - - arena = arena_get(tsd_tsdn(tsd), arena_ind, false); - if (arena == NULL) { - ret = EFAULT; - goto label_return; - } - - if (oldp != NULL && oldlenp != NULL) { - size_t oldval = arena_lg_dirty_mult_get(tsd_tsdn(tsd), arena); - READ(oldval, ssize_t); - } - if (newp != NULL) { - if (newlen != sizeof(ssize_t)) { - ret = EINVAL; - goto label_return; - } - if (arena_lg_dirty_mult_set(tsd_tsdn(tsd), arena, - *(ssize_t *)newp)) { - ret = EFAULT; - goto label_return; - } - } - - ret = 0; -label_return: - return (ret); -} - static int arena_i_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) @@ -1733,32 +1684,6 @@ label_return: return (ret); } -static int -arenas_lg_dirty_mult_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, - void *oldp, size_t *oldlenp, void *newp, size_t newlen) -{ - int ret; - - if (oldp != NULL && oldlenp != NULL) { - size_t oldval = arena_lg_dirty_mult_default_get(); - READ(oldval, ssize_t); - } - if (newp != NULL) { - if (newlen != sizeof(ssize_t)) { - ret = EINVAL; - goto label_return; - } - if (arena_lg_dirty_mult_default_set(*(ssize_t *)newp)) { - ret = EFAULT; - goto label_return; - } - } - - ret = 0; -label_return: - return (ret); -} - static int arenas_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) @@ -1972,8 +1897,6 @@ CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats.mapped, size_t) CTL_RO_CGEN(config_stats, stats_retained, ctl_stats.retained, size_t) CTL_RO_GEN(stats_arenas_i_dss, ctl_stats.arenas[mib[2]].dss, const char *) -CTL_RO_GEN(stats_arenas_i_lg_dirty_mult, ctl_stats.arenas[mib[2]].lg_dirty_mult, - ssize_t) CTL_RO_GEN(stats_arenas_i_decay_time, ctl_stats.arenas[mib[2]].decay_time, ssize_t) CTL_RO_GEN(stats_arenas_i_nthreads, ctl_stats.arenas[mib[2]].nthreads, unsigned) diff --git a/src/jemalloc.c b/src/jemalloc.c index 24158552..580b23f9 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1053,25 +1053,6 @@ malloc_conf_init(void) } CONF_HANDLE_UNSIGNED(opt_narenas, "narenas", 1, UINT_MAX, false) - if (strncmp("purge", k, klen) == 0) { - int i; - bool match = false; - for (i = 0; i < purge_mode_limit; i++) { - if (strncmp(purge_mode_names[i], v, - vlen) == 0) { - opt_purge = (purge_mode_t)i; - match = true; - break; - } - } - if (!match) { - malloc_conf_error("Invalid conf value", - k, klen, v, vlen); - } - continue; - } - CONF_HANDLE_SSIZE_T(opt_lg_dirty_mult, "lg_dirty_mult", - -1, (sizeof(size_t) << 3) - 1) CONF_HANDLE_SSIZE_T(opt_decay_time, "decay_time", -1, NSTIME_SEC_MAX); CONF_HANDLE_BOOL(opt_stats_print, "stats_print", true) diff --git a/src/stats.c b/src/stats.c index d8815855..185ccac6 100644 --- a/src/stats.c +++ b/src/stats.c @@ -210,7 +210,7 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, { unsigned nthreads; const char *dss; - ssize_t lg_dirty_mult, decay_time; + ssize_t decay_time; size_t page, pactive, pdirty, mapped, retained, metadata; uint64_t npurge, nmadvise, purged; size_t small_allocated; @@ -226,25 +226,12 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, CTL_M2_GET("stats.arenas.0.dss", i, &dss, const char *); malloc_cprintf(write_cb, cbopaque, "dss allocation precedence: %s\n", dss); - CTL_M2_GET("stats.arenas.0.lg_dirty_mult", i, &lg_dirty_mult, ssize_t); - if (opt_purge == purge_mode_ratio) { - if (lg_dirty_mult >= 0) { - malloc_cprintf(write_cb, cbopaque, - "min active:dirty page ratio: %u:1\n", - (1U << lg_dirty_mult)); - } else { - malloc_cprintf(write_cb, cbopaque, - "min active:dirty page ratio: N/A\n"); - } - } CTL_M2_GET("stats.arenas.0.decay_time", i, &decay_time, ssize_t); - if (opt_purge == purge_mode_decay) { - if (decay_time >= 0) { - malloc_cprintf(write_cb, cbopaque, "decay time: %zd\n", - decay_time); - } else - malloc_cprintf(write_cb, cbopaque, "decay time: N/A\n"); - } + if (decay_time >= 0) { + malloc_cprintf(write_cb, cbopaque, "decay time: %zd\n", + decay_time); + } else + malloc_cprintf(write_cb, cbopaque, "decay time: N/A\n"); CTL_M2_GET("stats.arenas.0.pactive", i, &pactive, size_t); CTL_M2_GET("stats.arenas.0.pdirty", i, &pdirty, size_t); CTL_M2_GET("stats.arenas.0.npurge", i, &npurge, uint64_t); @@ -433,12 +420,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, OPT_WRITE_CHAR_P(dss) OPT_WRITE_UNSIGNED(narenas) OPT_WRITE_CHAR_P(purge) - if (opt_purge == purge_mode_ratio) { - OPT_WRITE_SSIZE_T_MUTABLE(lg_dirty_mult, - arenas.lg_dirty_mult) - } - if (opt_purge == purge_mode_decay) - OPT_WRITE_SSIZE_T_MUTABLE(decay_time, arenas.decay_time) + OPT_WRITE_SSIZE_T_MUTABLE(decay_time, arenas.decay_time) OPT_WRITE_BOOL(stats_print) OPT_WRITE_CHAR_P(junk) OPT_WRITE_BOOL(zero) @@ -479,24 +461,10 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, CTL_GET("arenas.page", &sv, size_t); malloc_cprintf(write_cb, cbopaque, "Page size: %zu\n", sv); - CTL_GET("arenas.lg_dirty_mult", &ssv, ssize_t); - if (opt_purge == purge_mode_ratio) { - if (ssv >= 0) { - malloc_cprintf(write_cb, cbopaque, - "Min active:dirty page ratio per arena: " - "%u:1\n", (1U << ssv)); - } else { - malloc_cprintf(write_cb, cbopaque, - "Min active:dirty page ratio per arena: " - "N/A\n"); - } - } CTL_GET("arenas.decay_time", &ssv, ssize_t); - if (opt_purge == purge_mode_decay) { - malloc_cprintf(write_cb, cbopaque, - "Unused dirty page decay time: %zd%s\n", - ssv, (ssv < 0) ? " (no decay)" : ""); - } + malloc_cprintf(write_cb, cbopaque, + "Unused dirty page decay time: %zd%s\n", ssv, (ssv < 0) ? + " (no decay)" : ""); if (je_mallctl("arenas.tcache_max", &sv, &ssz, NULL, 0) == 0) { malloc_cprintf(write_cb, cbopaque, "Maximum thread-cached size class: %zu\n", sv); diff --git a/test/unit/decay.c b/test/unit/decay.c index 333a722c..058a58cb 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -1,6 +1,6 @@ #include "test/jemalloc_test.h" -const char *malloc_conf = "purge:decay,decay_time:1,lg_tcache_max:0"; +const char *malloc_conf = "decay_time:1,lg_tcache_max:0"; static nstime_monotonic_t *nstime_monotonic_orig; static nstime_update_t *nstime_update_orig; @@ -33,8 +33,6 @@ TEST_BEGIN(test_decay_ticks) size_t sz, large0; void *p; - test_skip_if(opt_purge != purge_mode_decay); - decay_ticker = decay_ticker_get(tsd_fetch(), 0); assert_ptr_not_null(decay_ticker, "Unexpected failure getting decay ticker"); @@ -213,8 +211,6 @@ TEST_BEGIN(test_decay_ticker) unsigned i, nupdates0; nstime_t time, decay_time, deadline; - test_skip_if(opt_purge != purge_mode_decay); - /* * Allocate a bunch of large objects, pause the clock, deallocate the * objects, restore the clock, then [md]allocx() in a tight loop to @@ -307,8 +303,6 @@ TEST_BEGIN(test_decay_nonmonotonic) size_t sz, large0; unsigned i, nupdates0; - test_skip_if(opt_purge != purge_mode_decay); - sz = sizeof(size_t); assert_d_eq(mallctl("arenas.lextent.0.size", &large0, &sz, NULL, 0), 0, "Unexpected mallctl failure"); diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 1954bfc5..ee57dd5c 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -163,8 +163,6 @@ TEST_BEGIN(test_mallctl_opt) TEST_MALLCTL_OPT(size_t, lg_chunk, always); TEST_MALLCTL_OPT(const char *, dss, always); TEST_MALLCTL_OPT(unsigned, narenas, always); - TEST_MALLCTL_OPT(const char *, purge, always); - TEST_MALLCTL_OPT(ssize_t, lg_dirty_mult, always); TEST_MALLCTL_OPT(ssize_t, decay_time, always); TEST_MALLCTL_OPT(bool, stats_print, always); TEST_MALLCTL_OPT(const char *, junk, fill); @@ -349,47 +347,11 @@ TEST_BEGIN(test_thread_arena) } TEST_END -TEST_BEGIN(test_arena_i_lg_dirty_mult) -{ - ssize_t lg_dirty_mult, orig_lg_dirty_mult, prev_lg_dirty_mult; - size_t sz = sizeof(ssize_t); - - test_skip_if(opt_purge != purge_mode_ratio); - - assert_d_eq(mallctl("arena.0.lg_dirty_mult", &orig_lg_dirty_mult, &sz, - NULL, 0), 0, "Unexpected mallctl() failure"); - - lg_dirty_mult = -2; - assert_d_eq(mallctl("arena.0.lg_dirty_mult", NULL, NULL, - &lg_dirty_mult, sizeof(ssize_t)), EFAULT, - "Unexpected mallctl() success"); - - lg_dirty_mult = (sizeof(size_t) << 3); - assert_d_eq(mallctl("arena.0.lg_dirty_mult", NULL, NULL, - &lg_dirty_mult, sizeof(ssize_t)), EFAULT, - "Unexpected mallctl() success"); - - for (prev_lg_dirty_mult = orig_lg_dirty_mult, lg_dirty_mult = -1; - lg_dirty_mult < (ssize_t)(sizeof(size_t) << 3); prev_lg_dirty_mult - = lg_dirty_mult, lg_dirty_mult++) { - ssize_t old_lg_dirty_mult; - - assert_d_eq(mallctl("arena.0.lg_dirty_mult", &old_lg_dirty_mult, - &sz, &lg_dirty_mult, sizeof(ssize_t)), 0, - "Unexpected mallctl() failure"); - assert_zd_eq(old_lg_dirty_mult, prev_lg_dirty_mult, - "Unexpected old arena.0.lg_dirty_mult"); - } -} -TEST_END - TEST_BEGIN(test_arena_i_decay_time) { ssize_t decay_time, orig_decay_time, prev_decay_time; size_t sz = sizeof(ssize_t); - test_skip_if(opt_purge != purge_mode_decay); - assert_d_eq(mallctl("arena.0.decay_time", &orig_decay_time, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); @@ -515,47 +477,11 @@ TEST_BEGIN(test_arenas_initialized) } TEST_END -TEST_BEGIN(test_arenas_lg_dirty_mult) -{ - ssize_t lg_dirty_mult, orig_lg_dirty_mult, prev_lg_dirty_mult; - size_t sz = sizeof(ssize_t); - - test_skip_if(opt_purge != purge_mode_ratio); - - assert_d_eq(mallctl("arenas.lg_dirty_mult", &orig_lg_dirty_mult, &sz, - NULL, 0), 0, "Unexpected mallctl() failure"); - - lg_dirty_mult = -2; - assert_d_eq(mallctl("arenas.lg_dirty_mult", NULL, NULL, - &lg_dirty_mult, sizeof(ssize_t)), EFAULT, - "Unexpected mallctl() success"); - - lg_dirty_mult = (sizeof(size_t) << 3); - assert_d_eq(mallctl("arenas.lg_dirty_mult", NULL, NULL, - &lg_dirty_mult, sizeof(ssize_t)), EFAULT, - "Unexpected mallctl() success"); - - for (prev_lg_dirty_mult = orig_lg_dirty_mult, lg_dirty_mult = -1; - lg_dirty_mult < (ssize_t)(sizeof(size_t) << 3); prev_lg_dirty_mult = - lg_dirty_mult, lg_dirty_mult++) { - ssize_t old_lg_dirty_mult; - - assert_d_eq(mallctl("arenas.lg_dirty_mult", &old_lg_dirty_mult, - &sz, &lg_dirty_mult, sizeof(ssize_t)), 0, - "Unexpected mallctl() failure"); - assert_zd_eq(old_lg_dirty_mult, prev_lg_dirty_mult, - "Unexpected old arenas.lg_dirty_mult"); - } -} -TEST_END - TEST_BEGIN(test_arenas_decay_time) { ssize_t decay_time, orig_decay_time, prev_decay_time; size_t sz = sizeof(ssize_t); - test_skip_if(opt_purge != purge_mode_decay); - assert_d_eq(mallctl("arenas.decay_time", &orig_decay_time, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); @@ -669,7 +595,6 @@ TEST_BEGIN(test_stats_arenas) TEST_STATS_ARENAS(unsigned, nthreads); TEST_STATS_ARENAS(const char *, dss); - TEST_STATS_ARENAS(ssize_t, lg_dirty_mult); TEST_STATS_ARENAS(ssize_t, decay_time); TEST_STATS_ARENAS(size_t, pactive); TEST_STATS_ARENAS(size_t, pdirty); @@ -694,13 +619,11 @@ main(void) test_tcache_none, test_tcache, test_thread_arena, - test_arena_i_lg_dirty_mult, test_arena_i_decay_time, test_arena_i_purge, test_arena_i_decay, test_arena_i_dss, test_arenas_initialized, - test_arenas_lg_dirty_mult, test_arenas_decay_time, test_arenas_constants, test_arenas_bin_constants, -- GitLab From 9acd5cf178eca9bc8a7f36a8c392b799a120bcbf Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 12 Oct 2016 11:49:19 -0700 Subject: [PATCH 123/544] Remove all vestiges of chunks. Remove mallctls: - opt.lg_chunk - stats.cactive This resolves #464. --- INSTALL | 6 +-- Makefile.in | 2 - doc/jemalloc.xml.in | 31 ----------- include/jemalloc/internal/chunk.h | 36 ------------- include/jemalloc/internal/extent_dss.h | 2 + .../jemalloc/internal/jemalloc_internal.h.in | 4 -- include/jemalloc/internal/private_symbols.txt | 9 ---- include/jemalloc/internal/stats.h | 41 --------------- .../projects/vc2015/jemalloc/jemalloc.vcxproj | 4 +- .../vc2015/jemalloc/jemalloc.vcxproj.filters | 8 +-- src/arena.c | 13 ----- src/base.c | 12 ++--- src/chunk.c | 51 ------------------- src/ctl.c | 6 --- src/extent_dss.c | 2 + src/jemalloc.c | 4 -- src/stats.c | 11 ---- test/unit/junk.c | 2 +- test/unit/lg_chunk.c | 26 ---------- test/unit/mallctl.c | 1 - test/unit/prof_gdump.c | 8 +-- test/unit/stats.c | 15 ++---- test/unit/zero.c | 2 +- 23 files changed, 26 insertions(+), 270 deletions(-) delete mode 100644 include/jemalloc/internal/chunk.h delete mode 100644 src/chunk.c delete mode 100644 test/unit/lg_chunk.c diff --git a/INSTALL b/INSTALL index 00c428b1..a31871b0 100644 --- a/INSTALL +++ b/INSTALL @@ -91,10 +91,10 @@ any of the following arguments (not a definitive list) to 'configure': --with-malloc-conf= Embed as a run-time options string that is processed prior to the malloc_conf global variable, the /etc/malloc.conf symlink, and the - MALLOC_CONF environment variable. For example, to change the default chunk - size to 256 KiB: + MALLOC_CONF environment variable. For example, to change the default decay + time to 30 seconds: - --with-malloc-conf=lg_chunk:18 + --with-malloc-conf=decay_time:30 --disable-cc-silence Disable code that silences non-useful compiler warnings. This is mainly diff --git a/Makefile.in b/Makefile.in index 5feb71d1..f6f06211 100644 --- a/Makefile.in +++ b/Makefile.in @@ -83,7 +83,6 @@ C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/atomic.c \ $(srcroot)src/base.c \ $(srcroot)src/bitmap.c \ - $(srcroot)src/chunk.c \ $(srcroot)src/ckh.c \ $(srcroot)src/ctl.c \ $(srcroot)src/extent.c \ @@ -144,7 +143,6 @@ TESTS_UNIT := \ $(srcroot)test/unit/junk.c \ $(srcroot)test/unit/junk_alloc.c \ $(srcroot)test/unit/junk_free.c \ - $(srcroot)test/unit/lg_chunk.c \ $(srcroot)test/unit/mallctl.c \ $(srcroot)test/unit/math.c \ $(srcroot)test/unit/mq.c \ diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index f5a72473..5ba44d23 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -900,19 +900,6 @@ for (i = 0; i < nbins; i++) { - - - opt.lg_chunk - (size_t) - r- - - Virtual memory chunk size (log base 2). If a chunk - size outside the supported size range is specified, the size is - silently clipped to the minimum/maximum supported size. The default - chunk size is 2 MiB (2^21). - - - opt.narenas @@ -1949,24 +1936,6 @@ struct extent_hooks_s { option for additional information. - - - stats.cactive - (size_t *) - r- - [] - - Pointer to a counter that contains an approximate count - of the current number of bytes in active pages. The estimate may be - high, but never low, because each arena rounds up when computing its - contribution to the counter. Note that the epoch mallctl has no bearing - on this counter. Furthermore, counter consistency is maintained via - atomic operations, so it is necessary to use an atomic operation in - order to guarantee a consistent read when dereferencing the pointer. - - - stats.allocated diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h deleted file mode 100644 index 7a5ebbca..00000000 --- a/include/jemalloc/internal/chunk.h +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -/* - * Size and alignment of memory chunks that are allocated by the OS's virtual - * memory system. - */ -#define LG_CHUNK_DEFAULT 21 - -/* Return the smallest chunk multiple that is >= s. */ -#define CHUNK_CEILING(s) \ - (((s) + chunksize_mask) & ~chunksize_mask) - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -extern size_t opt_lg_chunk; -extern const char *opt_dss; - -extern size_t chunksize; -extern size_t chunksize_mask; /* (chunksize - 1). */ -extern size_t chunk_npages; - -bool chunk_boot(void); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ diff --git a/include/jemalloc/internal/extent_dss.h b/include/jemalloc/internal/extent_dss.h index 43573775..0aabc2ec 100644 --- a/include/jemalloc/internal/extent_dss.h +++ b/include/jemalloc/internal/extent_dss.h @@ -21,6 +21,8 @@ extern const char *dss_prec_names[]; /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS +extern const char *opt_dss; + dss_prec_t extent_dss_prec_get(tsdn_t *tsdn); bool extent_dss_prec_set(tsdn_t *tsdn, dss_prec_t dss_prec); void *extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index ba8a9296..b69ddb18 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -363,7 +363,6 @@ typedef unsigned szind_t; #include "jemalloc/internal/base.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/pages.h" -#include "jemalloc/internal/chunk.h" #include "jemalloc/internal/large.h" #include "jemalloc/internal/tcache.h" #include "jemalloc/internal/hash.h" @@ -397,7 +396,6 @@ typedef unsigned szind_t; #include "jemalloc/internal/base.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/pages.h" -#include "jemalloc/internal/chunk.h" #include "jemalloc/internal/large.h" #include "jemalloc/internal/tcache.h" #include "jemalloc/internal/hash.h" @@ -483,7 +481,6 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/base.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/pages.h" -#include "jemalloc/internal/chunk.h" #include "jemalloc/internal/large.h" #include "jemalloc/internal/tcache.h" #include "jemalloc/internal/hash.h" @@ -512,7 +509,6 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/extent.h" #include "jemalloc/internal/base.h" #include "jemalloc/internal/pages.h" -#include "jemalloc/internal/chunk.h" #include "jemalloc/internal/large.h" #ifndef JEMALLOC_ENABLE_INLINE diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index e52e7fed..d1f39cff 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -110,10 +110,6 @@ bootstrap_free bootstrap_malloc bt_init buferror -chunk_boot -chunk_npages -chunksize -chunksize_mask ckh_count ckh_delete ckh_insert @@ -306,7 +302,6 @@ opt_dss opt_junk opt_junk_alloc opt_junk_free -opt_lg_chunk opt_lg_prof_interval opt_lg_prof_sample opt_lg_tcache_max @@ -430,10 +425,6 @@ size2index size2index_compute size2index_lookup size2index_tab -stats_cactive -stats_cactive_add -stats_cactive_get -stats_cactive_sub stats_print tcache_alloc_easy tcache_alloc_large diff --git a/include/jemalloc/internal/stats.h b/include/jemalloc/internal/stats.h index da019605..52279f56 100644 --- a/include/jemalloc/internal/stats.h +++ b/include/jemalloc/internal/stats.h @@ -118,8 +118,6 @@ struct arena_stats_s { extern bool opt_stats_print; -extern size_t stats_cactive; - void stats_print(void (*write)(void *, const char *), void *cbopaque, const char *opts); @@ -127,44 +125,5 @@ void stats_print(void (*write)(void *, const char *), void *cbopaque, /******************************************************************************/ #ifdef JEMALLOC_H_INLINES -#ifndef JEMALLOC_ENABLE_INLINE -size_t stats_cactive_get(void); -void stats_cactive_add(size_t size); -void stats_cactive_sub(size_t size); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_STATS_C_)) -JEMALLOC_INLINE size_t -stats_cactive_get(void) -{ - - return (atomic_read_z(&stats_cactive)); -} - -JEMALLOC_INLINE void -stats_cactive_add(size_t size) -{ - UNUSED size_t cactive; - - assert(size > 0); - assert((size & chunksize_mask) == 0); - - cactive = atomic_add_z(&stats_cactive, size); - assert(cactive - size < cactive); -} - -JEMALLOC_INLINE void -stats_cactive_sub(size_t size) -{ - UNUSED size_t cactive; - - assert(size > 0); - assert((size & chunksize_mask) == 0); - - cactive = atomic_sub_z(&stats_cactive, size); - assert(cactive + size > cactive); -} -#endif - #endif /* JEMALLOC_H_INLINES */ /******************************************************************************/ diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj index da75a968..e5ecb351 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj @@ -40,7 +40,6 @@ - @@ -93,7 +92,6 @@ - @@ -395,4 +393,4 @@ - \ No newline at end of file + diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters index 57395e70..74b45112 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters @@ -59,9 +59,6 @@ Header Files\internal - - Header Files\internal - Header Files\internal @@ -190,9 +187,6 @@ Source Files - - Source Files - Source Files @@ -257,4 +251,4 @@ Source Files - \ No newline at end of file + diff --git a/src/arena.c b/src/arena.c index 3de02373..2b8aead7 100644 --- a/src/arena.c +++ b/src/arena.c @@ -229,13 +229,6 @@ static void arena_nactive_add(arena_t *arena, size_t add_pages) { - if (config_stats) { - size_t cactive_add = CHUNK_CEILING((arena->nactive + - add_pages) << LG_PAGE) - CHUNK_CEILING(arena->nactive << - LG_PAGE); - if (cactive_add != 0) - stats_cactive_add(cactive_add); - } arena->nactive += add_pages; } @@ -244,12 +237,6 @@ arena_nactive_sub(arena_t *arena, size_t sub_pages) { assert(arena->nactive >= sub_pages); - if (config_stats) { - size_t cactive_sub = CHUNK_CEILING(arena->nactive << LG_PAGE) - - CHUNK_CEILING((arena->nactive - sub_pages) << LG_PAGE); - if (cactive_sub != 0) - stats_cactive_sub(cactive_sub); - } arena->nactive -= sub_pages; } diff --git a/src/base.c b/src/base.c index 667786e1..9c3f36cd 100644 --- a/src/base.c +++ b/src/base.c @@ -41,7 +41,7 @@ static extent_t * base_extent_alloc(tsdn_t *tsdn, size_t minsize) { extent_t *extent; - size_t csize, nsize; + size_t esize, nsize; void *addr; malloc_mutex_assert_owner(tsdn, &base_mtx); @@ -49,7 +49,7 @@ base_extent_alloc(tsdn_t *tsdn, size_t minsize) extent = base_extent_try_alloc(tsdn); /* Allocate enough space to also carve an extent out if necessary. */ nsize = (extent == NULL) ? CACHELINE_CEILING(sizeof(extent_t)) : 0; - csize = CHUNK_CEILING(minsize + nsize); + esize = PAGE_CEILING(minsize + nsize); /* * Directly call extent_alloc_mmap() because it's critical to allocate * untouched demand-zeroed virtual memory. @@ -57,24 +57,24 @@ base_extent_alloc(tsdn_t *tsdn, size_t minsize) { bool zero = true; bool commit = true; - addr = extent_alloc_mmap(NULL, csize, PAGE, &zero, &commit); + addr = extent_alloc_mmap(NULL, esize, PAGE, &zero, &commit); } if (addr == NULL) { if (extent != NULL) base_extent_dalloc(tsdn, extent); return (NULL); } - base_mapped += csize; + base_mapped += esize; if (extent == NULL) { extent = (extent_t *)addr; addr = (void *)((uintptr_t)addr + nsize); - csize -= nsize; + esize -= nsize; if (config_stats) { base_allocated += nsize; base_resident += PAGE_CEILING(nsize); } } - extent_init(extent, NULL, addr, csize, 0, true, true, true, false); + extent_init(extent, NULL, addr, esize, 0, true, true, true, false); return (extent); } diff --git a/src/chunk.c b/src/chunk.c deleted file mode 100644 index d750f715..00000000 --- a/src/chunk.c +++ /dev/null @@ -1,51 +0,0 @@ -#define JEMALLOC_CHUNK_C_ -#include "jemalloc/internal/jemalloc_internal.h" - -/******************************************************************************/ -/* Data. */ - -const char *opt_dss = DSS_DEFAULT; -size_t opt_lg_chunk = 0; - -/* Various chunk-related settings. */ -size_t chunksize; -size_t chunksize_mask; /* (chunksize - 1). */ -size_t chunk_npages; - -/******************************************************************************/ - -bool -chunk_boot(void) -{ -#ifdef _WIN32 - SYSTEM_INFO info; - GetSystemInfo(&info); - - /* - * Verify actual page size is equal to or an integral multiple of - * configured page size. - */ - if (info.dwPageSize & ((1U << LG_PAGE) - 1)) - return (true); - - /* - * Configure chunksize (if not set) to match granularity (usually 64K), - * so pages_map will always take fast path. - */ - if (!opt_lg_chunk) { - opt_lg_chunk = ffs_u((unsigned)info.dwAllocationGranularity) - - 1; - } -#else - if (!opt_lg_chunk) - opt_lg_chunk = LG_CHUNK_DEFAULT; -#endif - - /* Set variables according to the value of opt_lg_chunk. */ - chunksize = (ZU(1) << opt_lg_chunk); - assert(chunksize >= PAGE); - chunksize_mask = chunksize - 1; - chunk_npages = (chunksize >> LG_PAGE); - - return (false); -} diff --git a/src/ctl.c b/src/ctl.c index b00991a6..b4e2208c 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -88,7 +88,6 @@ CTL_PROTO(config_utrace) CTL_PROTO(config_xmalloc) CTL_PROTO(opt_abort) CTL_PROTO(opt_dss) -CTL_PROTO(opt_lg_chunk) CTL_PROTO(opt_narenas) CTL_PROTO(opt_decay_time) CTL_PROTO(opt_stats_print) @@ -177,7 +176,6 @@ CTL_PROTO(stats_arenas_i_nmadvise) CTL_PROTO(stats_arenas_i_purged) CTL_PROTO(stats_arenas_i_metadata) INDEX_PROTO(stats_arenas_i) -CTL_PROTO(stats_cactive) CTL_PROTO(stats_allocated) CTL_PROTO(stats_active) CTL_PROTO(stats_metadata) @@ -244,7 +242,6 @@ static const ctl_named_node_t config_node[] = { static const ctl_named_node_t opt_node[] = { {NAME("abort"), CTL(opt_abort)}, {NAME("dss"), CTL(opt_dss)}, - {NAME("lg_chunk"), CTL(opt_lg_chunk)}, {NAME("narenas"), CTL(opt_narenas)}, {NAME("decay_time"), CTL(opt_decay_time)}, {NAME("stats_print"), CTL(opt_stats_print)}, @@ -410,7 +407,6 @@ static const ctl_indexed_node_t stats_arenas_node[] = { }; static const ctl_named_node_t stats_node[] = { - {NAME("cactive"), CTL(stats_cactive)}, {NAME("allocated"), CTL(stats_allocated)}, {NAME("active"), CTL(stats_active)}, {NAME("metadata"), CTL(stats_metadata)}, @@ -1136,7 +1132,6 @@ CTL_RO_CONFIG_GEN(config_xmalloc, bool) CTL_RO_NL_GEN(opt_abort, opt_abort, bool) CTL_RO_NL_GEN(opt_dss, opt_dss, const char *) -CTL_RO_NL_GEN(opt_lg_chunk, opt_lg_chunk, size_t) CTL_RO_NL_GEN(opt_narenas, opt_narenas, unsigned) CTL_RO_NL_GEN(opt_decay_time, opt_decay_time, ssize_t) CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool) @@ -1888,7 +1883,6 @@ CTL_RO_NL_CGEN(config_prof, lg_prof_sample, lg_prof_sample, size_t) /******************************************************************************/ -CTL_RO_CGEN(config_stats, stats_cactive, &stats_cactive, size_t *) CTL_RO_CGEN(config_stats, stats_allocated, ctl_stats.allocated, size_t) CTL_RO_CGEN(config_stats, stats_active, ctl_stats.active, size_t) CTL_RO_CGEN(config_stats, stats_metadata, ctl_stats.metadata, size_t) diff --git a/src/extent_dss.c b/src/extent_dss.c index 9c5cd25a..e0e6635d 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -3,6 +3,8 @@ /******************************************************************************/ /* Data. */ +const char *opt_dss = DSS_DEFAULT; + const char *dss_prec_names[] = { "disabled", "primary", diff --git a/src/jemalloc.c b/src/jemalloc.c index 580b23f9..95cd0545 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1024,8 +1024,6 @@ malloc_conf_init(void) } CONF_HANDLE_BOOL(opt_abort, "abort", true) - CONF_HANDLE_SIZE_T(opt_lg_chunk, "lg_chunk", LG_PAGE, - (sizeof(size_t) << 3) - 1, true) if (strncmp("dss", k, klen) == 0) { int i; bool match = false; @@ -1176,8 +1174,6 @@ malloc_init_hard_a0_locked() pages_boot(); if (base_boot()) return (true); - if (chunk_boot()) - return (true); if (extent_boot()) return (true); if (ctl_boot()) diff --git a/src/stats.c b/src/stats.c index 185ccac6..ca716d5e 100644 --- a/src/stats.c +++ b/src/stats.c @@ -30,8 +30,6 @@ bool opt_stats_print = false; -size_t stats_cactive = 0; - /******************************************************************************/ /* Function prototypes for non-inline static functions. */ @@ -416,7 +414,6 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "Run-time option settings:\n"); OPT_WRITE_BOOL(abort) - OPT_WRITE_SIZE_T(lg_chunk) OPT_WRITE_CHAR_P(dss) OPT_WRITE_UNSIGNED(narenas) OPT_WRITE_CHAR_P(purge) @@ -486,16 +483,11 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, "Average profile dump interval: N/A\n"); } } - CTL_GET("opt.lg_chunk", &sv, size_t); - malloc_cprintf(write_cb, cbopaque, - "Chunk size: %zu (2^%zu)\n", (ZU(1) << sv), sv); } if (config_stats) { - size_t *cactive; size_t allocated, active, metadata, resident, mapped, retained; - CTL_GET("stats.cactive", &cactive, size_t *); CTL_GET("stats.allocated", &allocated, size_t); CTL_GET("stats.active", &active, size_t); CTL_GET("stats.metadata", &metadata, size_t); @@ -506,9 +498,6 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, "Allocated: %zu, active: %zu, metadata: %zu," " resident: %zu, mapped: %zu, retained: %zu\n", allocated, active, metadata, resident, mapped, retained); - malloc_cprintf(write_cb, cbopaque, - "Current active ceiling: %zu\n", - atomic_read_z(cactive)); if (merged) { unsigned narenas; diff --git a/test/unit/junk.c b/test/unit/junk.c index dea0f615..fe453b6c 100644 --- a/test/unit/junk.c +++ b/test/unit/junk.c @@ -140,7 +140,7 @@ TEST_BEGIN(test_junk_large) { test_skip_if(!config_fill); - test_junk(SMALL_MAXCLASS+1, chunksize*2); + test_junk(SMALL_MAXCLASS+1, (1U << (LG_LARGE_MINCLASS+1))); } TEST_END diff --git a/test/unit/lg_chunk.c b/test/unit/lg_chunk.c deleted file mode 100644 index 7e5df381..00000000 --- a/test/unit/lg_chunk.c +++ /dev/null @@ -1,26 +0,0 @@ -#include "test/jemalloc_test.h" - -/* - * Make sure that opt.lg_chunk clamping is sufficient. In practice, this test - * program will fail a debug assertion during initialization and abort (rather - * than the test soft-failing) if clamping is insufficient. - */ -const char *malloc_conf = "lg_chunk:0"; - -TEST_BEGIN(test_lg_chunk_clamp) -{ - void *p; - - p = mallocx(1, 0); - assert_ptr_not_null(p, "Unexpected mallocx() failure"); - dallocx(p, 0); -} -TEST_END - -int -main(void) -{ - - return (test( - test_lg_chunk_clamp)); -} diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index ee57dd5c..0e979a11 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -160,7 +160,6 @@ TEST_BEGIN(test_mallctl_opt) } while (0) TEST_MALLCTL_OPT(bool, abort, always); - TEST_MALLCTL_OPT(size_t, lg_chunk, always); TEST_MALLCTL_OPT(const char *, dss, always); TEST_MALLCTL_OPT(unsigned, narenas, always); TEST_MALLCTL_OPT(ssize_t, decay_time, always); diff --git a/test/unit/prof_gdump.c b/test/unit/prof_gdump.c index a0e6ee92..ca93f300 100644 --- a/test/unit/prof_gdump.c +++ b/test/unit/prof_gdump.c @@ -34,12 +34,12 @@ TEST_BEGIN(test_gdump) prof_dump_open = prof_dump_open_intercept; did_prof_dump_open = false; - p = mallocx(chunksize, 0); + p = mallocx((1U << LG_LARGE_MINCLASS), 0); assert_ptr_not_null(p, "Unexpected mallocx() failure"); assert_true(did_prof_dump_open, "Expected a profile dump"); did_prof_dump_open = false; - q = mallocx(chunksize, 0); + q = mallocx((1U << LG_LARGE_MINCLASS), 0); assert_ptr_not_null(q, "Unexpected mallocx() failure"); assert_true(did_prof_dump_open, "Expected a profile dump"); @@ -50,7 +50,7 @@ TEST_BEGIN(test_gdump) "Unexpected mallctl failure while disabling prof.gdump"); assert(gdump_old); did_prof_dump_open = false; - r = mallocx(chunksize, 0); + r = mallocx((1U << LG_LARGE_MINCLASS), 0); assert_ptr_not_null(q, "Unexpected mallocx() failure"); assert_false(did_prof_dump_open, "Unexpected profile dump"); @@ -61,7 +61,7 @@ TEST_BEGIN(test_gdump) "Unexpected mallctl failure while enabling prof.gdump"); assert(!gdump_old); did_prof_dump_open = false; - s = mallocx(chunksize, 0); + s = mallocx((1U << LG_LARGE_MINCLASS), 0); assert_ptr_not_null(q, "Unexpected mallocx() failure"); assert_true(did_prof_dump_open, "Expected a profile dump"); diff --git a/test/unit/stats.c b/test/unit/stats.c index 9fa9cead..ed0d3fe9 100644 --- a/test/unit/stats.c +++ b/test/unit/stats.c @@ -2,14 +2,9 @@ TEST_BEGIN(test_stats_summary) { - size_t *cactive; size_t sz, allocated, active, resident, mapped; int expected = config_stats ? 0 : ENOENT; - sz = sizeof(cactive); - assert_d_eq(mallctl("stats.cactive", &cactive, &sz, NULL, 0), expected, - "Unexpected mallctl() result"); - sz = sizeof(size_t); assert_d_eq(mallctl("stats.allocated", &allocated, &sz, NULL, 0), expected, "Unexpected mallctl() result"); @@ -21,8 +16,6 @@ TEST_BEGIN(test_stats_summary) "Unexpected mallctl() result"); if (config_stats) { - assert_zu_le(active, *cactive, - "active should be no larger than cactive"); assert_zu_le(allocated, active, "allocated should be no larger than active"); assert_zu_lt(active, resident, @@ -88,12 +81,14 @@ TEST_BEGIN(test_stats_arenas_summary) little = mallocx(SMALL_MAXCLASS, 0); assert_ptr_not_null(little, "Unexpected mallocx() failure"); - large = mallocx(chunksize, 0); + large = mallocx((1U << LG_LARGE_MINCLASS), 0); assert_ptr_not_null(large, "Unexpected mallocx() failure"); dallocx(little, 0); dallocx(large, 0); + assert_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), + config_tcache ? 0 : ENOENT, "Unexpected mallctl() result"); assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl() failure"); @@ -197,7 +192,7 @@ TEST_BEGIN(test_stats_arenas_large) assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)), 0, "Unexpected mallctl() failure"); - p = mallocx(chunksize, 0); + p = mallocx((1U << LG_LARGE_MINCLASS), 0); assert_ptr_not_null(p, "Unexpected mallocx() failure"); assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, @@ -336,7 +331,7 @@ TEST_BEGIN(test_stats_arenas_lextents) assert_u64_ge(nmalloc, ndalloc, "nmalloc should be at least as large as ndalloc"); assert_u64_gt(curlextents, 0, - "At least one chunk should be currently allocated"); + "At least one extent should be currently allocated"); } dallocx(p, 0); diff --git a/test/unit/zero.c b/test/unit/zero.c index 3c35f4bd..c025c831 100644 --- a/test/unit/zero.c +++ b/test/unit/zero.c @@ -57,7 +57,7 @@ TEST_BEGIN(test_zero_large) { test_skip_if(!config_fill); - test_zero(SMALL_MAXCLASS+1, chunksize*2); + test_zero(SMALL_MAXCLASS+1, (1U << (LG_LARGE_MINCLASS+1))); } TEST_END -- GitLab From e5effef428b5bf941e1697f6000c97f1ce734756 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 13 Oct 2016 14:47:50 -0700 Subject: [PATCH 124/544] Add/use adaptive spinning. Add spin_t and spin_{init,adaptive}(), which provide a simple abstraction for adaptive spinning. Adaptively spin during busy waits in bootstrapping and rtree node initialization. --- Makefile.in | 1 + .../jemalloc/internal/jemalloc_internal.h.in | 4 ++ include/jemalloc/internal/spin.h | 51 +++++++++++++++++++ src/jemalloc.c | 5 +- src/rtree.c | 5 +- src/spin.c | 2 + 6 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 include/jemalloc/internal/spin.h create mode 100644 src/spin.c diff --git a/Makefile.in b/Makefile.in index f6f06211..9e063095 100644 --- a/Makefile.in +++ b/Makefile.in @@ -98,6 +98,7 @@ C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/prof.c \ $(srcroot)src/rtree.c \ $(srcroot)src/stats.c \ + $(srcroot)src/spin.c \ $(srcroot)src/tcache.c \ $(srcroot)src/ticker.c \ $(srcroot)src/tsd.c \ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index b69ddb18..1d02c20e 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -346,6 +346,7 @@ typedef unsigned szind_t; #include "jemalloc/internal/nstime.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/spin.h" #include "jemalloc/internal/prng.h" #include "jemalloc/internal/ticker.h" #include "jemalloc/internal/ckh.h" @@ -375,6 +376,7 @@ typedef unsigned szind_t; #include "jemalloc/internal/nstime.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/spin.h" #include "jemalloc/internal/prng.h" #include "jemalloc/internal/ticker.h" #include "jemalloc/internal/ckh.h" @@ -465,6 +467,7 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/nstime.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/spin.h" #include "jemalloc/internal/prng.h" #include "jemalloc/internal/ticker.h" #include "jemalloc/internal/ckh.h" @@ -494,6 +497,7 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/nstime.h" #include "jemalloc/internal/util.h" #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/spin.h" #include "jemalloc/internal/prng.h" #include "jemalloc/internal/ticker.h" #include "jemalloc/internal/ckh.h" diff --git a/include/jemalloc/internal/spin.h b/include/jemalloc/internal/spin.h new file mode 100644 index 00000000..9ef5ceb9 --- /dev/null +++ b/include/jemalloc/internal/spin.h @@ -0,0 +1,51 @@ +/******************************************************************************/ +#ifdef JEMALLOC_H_TYPES + +typedef struct spin_s spin_t; + +#endif /* JEMALLOC_H_TYPES */ +/******************************************************************************/ +#ifdef JEMALLOC_H_STRUCTS + +struct spin_s { + unsigned iteration; +}; + +#endif /* JEMALLOC_H_STRUCTS */ +/******************************************************************************/ +#ifdef JEMALLOC_H_EXTERNS + +#endif /* JEMALLOC_H_EXTERNS */ +/******************************************************************************/ +#ifdef JEMALLOC_H_INLINES + +#ifndef JEMALLOC_ENABLE_INLINE +void spin_init(spin_t *spin); +void spin_adaptive(spin_t *spin); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_SPIN_C_)) +JEMALLOC_INLINE void +spin_init(spin_t *spin) +{ + + spin->iteration = 0; +} + +JEMALLOC_INLINE void +spin_adaptive(spin_t *spin) +{ + volatile uint64_t i; + + for (i = 0; i < (KQU(1) << spin->iteration); i++) + CPU_SPINWAIT; + + if (spin->iteration < 63) + spin->iteration++; +} + +#endif + +#endif /* JEMALLOC_H_INLINES */ +/******************************************************************************/ + diff --git a/src/jemalloc.c b/src/jemalloc.c index 95cd0545..0348b8ac 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1142,10 +1142,13 @@ malloc_init_hard_needed(void) } #ifdef JEMALLOC_THREADED_INIT if (malloc_initializer != NO_INITIALIZER && !IS_INITIALIZER) { + spin_t spinner; + /* Busy-wait until the initializing thread completes. */ + spin_init(&spinner); do { malloc_mutex_unlock(TSDN_NULL, &init_lock); - CPU_SPINWAIT; + spin_adaptive(&spinner); malloc_mutex_lock(TSDN_NULL, &init_lock); } while (!malloc_initialized()); return (false); diff --git a/src/rtree.c b/src/rtree.c index 421de3e8..d4a705ae 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -136,12 +136,15 @@ rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level, rtree_elm_t *node; if (atomic_cas_p((void **)elmp, NULL, RTREE_NODE_INITIALIZING)) { + spin_t spinner; + /* * Another thread is already in the process of initializing. * Spin-wait until initialization is complete. */ + spin_init(&spinner); do { - CPU_SPINWAIT; + spin_adaptive(&spinner); node = atomic_read_p((void **)elmp); } while (node == RTREE_NODE_INITIALIZING); } else { diff --git a/src/spin.c b/src/spin.c new file mode 100644 index 00000000..5242d95a --- /dev/null +++ b/src/spin.c @@ -0,0 +1,2 @@ +#define JEMALLOC_SPIN_C_ +#include "jemalloc/internal/jemalloc_internal.h" -- GitLab From 577d4572b0821a15e5370f9bf566d884b7cf707c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 13 Oct 2016 12:18:38 -0700 Subject: [PATCH 125/544] Make dss operations lockless. Rather than protecting dss operations with a mutex, use atomic operations. This has negligible impact on synchronization overhead during typical dss allocation, but is a substantial improvement for extent_in_dss() and the newly added extent_dss_mergeable(), which can be called multiple times during extent deallocations. This change also has the advantage of avoiding tsd in deallocation paths associated with purging, which resolves potential deadlocks during thread exit due to attempted tsd resurrection. This resolves #425. --- include/jemalloc/internal/extent.h | 3 - include/jemalloc/internal/extent_dss.h | 12 +- include/jemalloc/internal/large.h | 4 +- include/jemalloc/internal/private_symbols.txt | 7 +- src/arena.c | 2 +- src/ctl.c | 4 +- src/extent.c | 48 +---- src/extent_dss.c | 180 ++++++++++-------- src/jemalloc.c | 6 +- src/large.c | 8 +- test/unit/junk.c | 4 +- 11 files changed, 131 insertions(+), 147 deletions(-) diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 528759b0..08d30365 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -127,9 +127,6 @@ extent_t *extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, size_t usize_a, size_t size_b, size_t usize_b); bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b); -void extent_prefork(tsdn_t *tsdn); -void extent_postfork_parent(tsdn_t *tsdn); -void extent_postfork_child(tsdn_t *tsdn); bool extent_boot(void); diff --git a/include/jemalloc/internal/extent_dss.h b/include/jemalloc/internal/extent_dss.h index 0aabc2ec..f2dac52e 100644 --- a/include/jemalloc/internal/extent_dss.h +++ b/include/jemalloc/internal/extent_dss.h @@ -23,15 +23,13 @@ extern const char *dss_prec_names[]; extern const char *opt_dss; -dss_prec_t extent_dss_prec_get(tsdn_t *tsdn); -bool extent_dss_prec_set(tsdn_t *tsdn, dss_prec_t dss_prec); +dss_prec_t extent_dss_prec_get(void); +bool extent_dss_prec_set(dss_prec_t dss_prec); void *extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit); -bool extent_in_dss(tsdn_t *tsdn, void *addr); -bool extent_dss_boot(void); -void extent_dss_prefork(tsdn_t *tsdn); -void extent_dss_postfork_parent(tsdn_t *tsdn); -void extent_dss_postfork_child(tsdn_t *tsdn); +bool extent_in_dss(void *addr); +bool extent_dss_mergeable(void *addr_a, void *addr_b); +void extent_dss_boot(void); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ diff --git a/include/jemalloc/internal/large.h b/include/jemalloc/internal/large.h index 8345f89e..f3d382b5 100644 --- a/include/jemalloc/internal/large.h +++ b/include/jemalloc/internal/large.h @@ -19,11 +19,11 @@ void *large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, #ifdef JEMALLOC_JET typedef void (large_dalloc_junk_t)(void *, size_t); extern large_dalloc_junk_t *large_dalloc_junk; -typedef void (large_dalloc_maybe_junk_t)(tsdn_t *, void *, size_t); +typedef void (large_dalloc_maybe_junk_t)(void *, size_t); extern large_dalloc_maybe_junk_t *large_dalloc_maybe_junk; #else void large_dalloc_junk(void *ptr, size_t usize); -void large_dalloc_maybe_junk(tsdn_t *tsdn, void *ptr, size_t usize); +void large_dalloc_maybe_junk(void *ptr, size_t usize); #endif void large_dalloc_junked_locked(tsdn_t *tsdn, extent_t *extent); void large_dalloc(tsdn_t *tsdn, extent_t *extent); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index d1f39cff..8d573b76 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -156,11 +156,9 @@ extent_dalloc_mmap extent_dalloc_wrapper extent_decommit_wrapper extent_dss_boot -extent_dss_postfork_child -extent_dss_postfork_parent +extent_dss_mergeable extent_dss_prec_get extent_dss_prec_set -extent_dss_prefork extent_heap_empty extent_heap_first extent_heap_insert @@ -176,9 +174,6 @@ extent_last_get extent_lookup extent_merge_wrapper extent_past_get -extent_postfork_child -extent_postfork_parent -extent_prefork extent_prof_tctx_get extent_prof_tctx_set extent_purge_wrapper diff --git a/src/arena.c b/src/arena.c index 2b8aead7..ce289594 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1682,7 +1682,7 @@ arena_new(tsdn_t *tsdn, unsigned ind) (uint64_t)(uintptr_t)arena; } - arena->dss_prec = extent_dss_prec_get(tsdn); + arena->dss_prec = extent_dss_prec_get(); arena->purging = false; arena->nactive = 0; diff --git a/src/ctl.c b/src/ctl.c index b4e2208c..067b6772 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1527,11 +1527,11 @@ arena_i_dss_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, dss_prec_old = arena_dss_prec_get(tsd_tsdn(tsd), arena); } else { if (dss_prec != dss_prec_limit && - extent_dss_prec_set(tsd_tsdn(tsd), dss_prec)) { + extent_dss_prec_set(dss_prec)) { ret = EFAULT; goto label_return; } - dss_prec_old = extent_dss_prec_get(tsd_tsdn(tsd)); + dss_prec_old = extent_dss_prec_get(); } dss = dss_prec_names[dss_prec_old]; diff --git a/src/extent.c b/src/extent.c index e4d3ccdb..e4ceb8fd 100644 --- a/src/extent.c +++ b/src/extent.c @@ -856,10 +856,10 @@ extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, } static bool -extent_dalloc_default_impl(tsdn_t *tsdn, void *addr, size_t size) +extent_dalloc_default_impl(void *addr, size_t size) { - if (!have_dss || !extent_in_dss(tsdn, addr)) + if (!have_dss || !extent_in_dss(addr)) return (extent_dalloc_mmap(addr, size)); return (true); } @@ -869,13 +869,10 @@ static bool extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, size_t size, bool committed, unsigned arena_ind) { - tsdn_t *tsdn; assert(extent_hooks == &extent_hooks_default); - tsdn = tsdn_fetch(); - - return (extent_dalloc_default_impl(tsdn, addr, size)); + return (extent_dalloc_default_impl(addr, size)); } void @@ -897,7 +894,7 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_deregister(tsdn, extent); if (*r_extent_hooks == &extent_hooks_default) { /* Call directly to propagate tsdn. */ - err = extent_dalloc_default_impl(tsdn, extent_base_get(extent), + err = extent_dalloc_default_impl(extent_base_get(extent), extent_size_get(extent)); } else { err = (*r_extent_hooks)->dalloc(*r_extent_hooks, @@ -1083,13 +1080,12 @@ label_error_a: } static bool -extent_merge_default_impl(tsdn_t *tsdn, void *addr_a, void *addr_b) +extent_merge_default_impl(void *addr_a, void *addr_b) { if (!maps_coalesce) return (true); - if (have_dss && extent_in_dss(tsdn, addr_a) != extent_in_dss(tsdn, - addr_b)) + if (have_dss && !extent_dss_mergeable(addr_a, addr_b)) return (true); return (false); @@ -1099,13 +1095,10 @@ static bool extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, void *addr_b, size_t size_b, bool committed, unsigned arena_ind) { - tsdn_t *tsdn; assert(extent_hooks == &extent_hooks_default); - tsdn = tsdn_fetch(); - - return (extent_merge_default_impl(tsdn, addr_a, addr_b)); + return (extent_merge_default_impl(addr_a, addr_b)); } bool @@ -1120,7 +1113,7 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_assure_initialized(arena, r_extent_hooks); if (*r_extent_hooks == &extent_hooks_default) { /* Call directly to propagate tsdn. */ - err = extent_merge_default_impl(tsdn, extent_base_get(a), + err = extent_merge_default_impl(extent_base_get(a), extent_base_get(b)); } else { err = (*r_extent_hooks)->merge(*r_extent_hooks, @@ -1171,29 +1164,8 @@ extent_boot(void) LG_PAGE))) return (true); - if (have_dss && extent_dss_boot()) - return (true); + if (have_dss) + extent_dss_boot(); return (false); } - -void -extent_prefork(tsdn_t *tsdn) -{ - - extent_dss_prefork(tsdn); -} - -void -extent_postfork_parent(tsdn_t *tsdn) -{ - - extent_dss_postfork_parent(tsdn); -} - -void -extent_postfork_child(tsdn_t *tsdn) -{ - - extent_dss_postfork_child(tsdn); -} diff --git a/src/extent_dss.c b/src/extent_dss.c index e0e6635d..31fe8fe2 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -12,20 +12,19 @@ const char *dss_prec_names[] = { "N/A" }; -/* Current dss precedence default, used when creating new arenas. */ -static dss_prec_t dss_prec_default = DSS_PREC_DEFAULT; - /* - * Protects sbrk() calls. This avoids malloc races among threads, though it - * does not protect against races with threads that call sbrk() directly. + * Current dss precedence default, used when creating new arenas. NB: This is + * stored as unsigned rather than dss_prec_t because in principle there's no + * guarantee that sizeof(dss_prec_t) is the same as sizeof(unsigned), and we use + * atomic operations to synchronize the setting. */ -static malloc_mutex_t dss_mtx; +static unsigned dss_prec_default = (unsigned)DSS_PREC_DEFAULT; /* Base address of the DSS. */ static void *dss_base; -/* Current end of the DSS, or ((void *)-1) if the DSS is exhausted. */ -static void *dss_prev; -/* Current upper limit on DSS addresses. */ +/* Atomic boolean indicating whether the DSS is exhausted. */ +static unsigned dss_exhausted; +/* Atomic current upper limit on DSS addresses. */ static void *dss_max; /******************************************************************************/ @@ -43,35 +42,63 @@ extent_dss_sbrk(intptr_t increment) } dss_prec_t -extent_dss_prec_get(tsdn_t *tsdn) +extent_dss_prec_get(void) { dss_prec_t ret; if (!have_dss) return (dss_prec_disabled); - malloc_mutex_lock(tsdn, &dss_mtx); - ret = dss_prec_default; - malloc_mutex_unlock(tsdn, &dss_mtx); + ret = (dss_prec_t)atomic_read_u(&dss_prec_default); return (ret); } bool -extent_dss_prec_set(tsdn_t *tsdn, dss_prec_t dss_prec) +extent_dss_prec_set(dss_prec_t dss_prec) { if (!have_dss) return (dss_prec != dss_prec_disabled); - malloc_mutex_lock(tsdn, &dss_mtx); - dss_prec_default = dss_prec; - malloc_mutex_unlock(tsdn, &dss_mtx); + atomic_write_u(&dss_prec_default, (unsigned)dss_prec); return (false); } +static void * +extent_dss_max_update(void *new_addr) +{ + void *max_cur; + spin_t spinner; + + /* + * Get the current end of the DSS as max_cur and assure that dss_max is + * up to date. + */ + spin_init(&spinner); + while (true) { + void *max_prev = atomic_read_p(&dss_max); + + max_cur = extent_dss_sbrk(0); + if ((uintptr_t)max_prev > (uintptr_t)max_cur) { + /* + * Another thread optimistically updated dss_max. Wait + * for it to finish. + */ + spin_adaptive(&spinner); + continue; + } + if (!atomic_cas_p(&dss_max, max_prev, max_cur)) + break; + } + /* Fixed new_addr can only be supported if it is at the edge of DSS. */ + if (new_addr != NULL && max_cur != new_addr) + return (NULL); + + return (max_cur); +} + void * extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit) { - void *ret; extent_t *gap; cassert(have_dss); @@ -89,35 +116,27 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, if (gap == NULL) return (NULL); - malloc_mutex_lock(tsdn, &dss_mtx); - if (dss_prev != (void *)-1) { + if (!atomic_read_u(&dss_exhausted)) { /* * The loop is necessary to recover from races with other * threads that are using the DSS for something other than * malloc. */ while (true) { - void *gap_addr, *dss_next; + void *ret, *max_cur, *gap_addr, *dss_next, *dss_prev; size_t gap_size; intptr_t incr; - /* Avoid an unnecessary system call. */ - if (new_addr != NULL && dss_max != new_addr) - break; - - /* Get the current end of the DSS. */ - dss_max = extent_dss_sbrk(0); - - /* Make sure the earlier condition still holds. */ - if (new_addr != NULL && dss_max != new_addr) - break; + max_cur = extent_dss_max_update(new_addr); + if (max_cur == NULL) + goto label_oom; /* * Compute how much gap space (if any) is necessary to * satisfy alignment. This space can be recycled for * later use. */ - gap_addr = (void *)(PAGE_CEILING((uintptr_t)dss_max)); + gap_addr = (void *)(PAGE_CEILING((uintptr_t)max_cur)); ret = (void *)ALIGNMENT_CEILING((uintptr_t)gap_addr, PAGE_CEILING(alignment)); gap_size = (uintptr_t)ret - (uintptr_t)gap_addr; @@ -126,17 +145,24 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, gap_size, false, false, true, false); } dss_next = (void *)((uintptr_t)ret + size); - if ((uintptr_t)ret < (uintptr_t)dss_max || - (uintptr_t)dss_next < (uintptr_t)dss_max) - break; /* Wrap-around. */ + if ((uintptr_t)ret < (uintptr_t)max_cur || + (uintptr_t)dss_next < (uintptr_t)max_cur) + goto label_oom; /* Wrap-around. */ incr = gap_size + size; + + /* + * Optimistically update dss_max, and roll back below if + * sbrk() fails. No other thread will try to extend the + * DSS while dss_max is greater than the current DSS + * max reported by sbrk(0). + */ + if (atomic_cas_p(&dss_max, max_cur, dss_next)) + continue; + + /* Try to allocate. */ dss_prev = extent_dss_sbrk(incr); - if (dss_prev == (void *)-1) - break; - if (dss_prev == dss_max) { + if (dss_prev == max_cur) { /* Success. */ - dss_max = dss_next; - malloc_mutex_unlock(tsdn, &dss_mtx); if (gap_size != 0) extent_dalloc_gap(tsdn, arena, gap); else @@ -147,69 +173,69 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, *commit = pages_decommit(ret, size); return (ret); } + /* + * Failure, whether due to OOM or a race with a raw + * sbrk() call from outside the allocator. Try to roll + * back optimistic dss_max update; if rollback fails, + * it's due to another caller of this function having + * succeeded since this invocation started, in which + * case rollback is not necessary. + */ + atomic_cas_p(&dss_max, dss_next, max_cur); + if (dss_prev == (void *)-1) { + /* OOM. */ + atomic_write_u(&dss_exhausted, (unsigned)true); + goto label_oom; + } } } - /* OOM. */ - malloc_mutex_unlock(tsdn, &dss_mtx); +label_oom: extent_dalloc(tsdn, arena, gap); return (NULL); } -bool -extent_in_dss(tsdn_t *tsdn, void *addr) +static bool +extent_in_dss_helper(void *addr, void *max) { - bool ret; - - cassert(have_dss); - malloc_mutex_lock(tsdn, &dss_mtx); - if ((uintptr_t)addr >= (uintptr_t)dss_base - && (uintptr_t)addr < (uintptr_t)dss_max) - ret = true; - else - ret = false; - malloc_mutex_unlock(tsdn, &dss_mtx); - - return (ret); + return ((uintptr_t)addr >= (uintptr_t)dss_base && (uintptr_t)addr < + (uintptr_t)max); } bool -extent_dss_boot(void) +extent_in_dss(void *addr) { cassert(have_dss); - if (malloc_mutex_init(&dss_mtx, "dss", WITNESS_RANK_DSS)) - return (true); - dss_base = extent_dss_sbrk(0); - dss_prev = dss_base; - dss_max = dss_base; - - return (false); + return (extent_in_dss_helper(addr, atomic_read_p(&dss_max))); } -void -extent_dss_prefork(tsdn_t *tsdn) +bool +extent_dss_mergeable(void *addr_a, void *addr_b) { + void *max; - if (have_dss) - malloc_mutex_prefork(tsdn, &dss_mtx); -} + cassert(have_dss); -void -extent_dss_postfork_parent(tsdn_t *tsdn) -{ + if ((uintptr_t)addr_a < (uintptr_t)dss_base && (uintptr_t)addr_b < + (uintptr_t)dss_base) + return (true); - if (have_dss) - malloc_mutex_postfork_parent(tsdn, &dss_mtx); + max = atomic_read_p(&dss_max); + return (extent_in_dss_helper(addr_a, max) == + extent_in_dss_helper(addr_b, max)); } void -extent_dss_postfork_child(tsdn_t *tsdn) +extent_dss_boot(void) { - if (have_dss) - malloc_mutex_postfork_child(tsdn, &dss_mtx); + cassert(have_dss); + + dss_base = extent_dss_sbrk(0); + dss_exhausted = (unsigned)(dss_base == (void *)-1); + dss_max = dss_base; } /******************************************************************************/ diff --git a/src/jemalloc.c b/src/jemalloc.c index 0348b8ac..5108d15f 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1030,8 +1030,7 @@ malloc_conf_init(void) for (i = 0; i < dss_prec_limit; i++) { if (strncmp(dss_prec_names[i], v, vlen) == 0) { - if (extent_dss_prec_set(NULL, - i)) { + if (extent_dss_prec_set(i)) { malloc_conf_error( "Error setting dss", k, klen, v, vlen); @@ -2631,7 +2630,6 @@ _malloc_prefork(void) } } base_prefork(tsd_tsdn(tsd)); - extent_prefork(tsd_tsdn(tsd)); for (i = 0; i < narenas; i++) { if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) arena_prefork3(tsd_tsdn(tsd), arena); @@ -2660,7 +2658,6 @@ _malloc_postfork(void) witness_postfork_parent(tsd); /* Release all mutexes, now that fork() has completed. */ - extent_postfork_parent(tsd_tsdn(tsd)); base_postfork_parent(tsd_tsdn(tsd)); for (i = 0, narenas = narenas_total_get(); i < narenas; i++) { arena_t *arena; @@ -2685,7 +2682,6 @@ jemalloc_postfork_child(void) witness_postfork_child(tsd); /* Release all mutexes, now that fork() has completed. */ - extent_postfork_child(tsd_tsdn(tsd)); base_postfork_child(tsd_tsdn(tsd)); for (i = 0, narenas = narenas_total_get(); i < narenas; i++) { arena_t *arena; diff --git a/src/large.c b/src/large.c index 34b3bdb5..23af1830 100644 --- a/src/large.c +++ b/src/large.c @@ -81,7 +81,7 @@ large_dalloc_junk_t *large_dalloc_junk = JEMALLOC_N(n_large_dalloc_junk); #define large_dalloc_maybe_junk JEMALLOC_N(n_large_dalloc_maybe_junk) #endif void -large_dalloc_maybe_junk(tsdn_t *tsdn, void *ptr, size_t usize) +large_dalloc_maybe_junk(void *ptr, size_t usize) { if (config_fill && have_dss && unlikely(opt_junk_free)) { @@ -89,7 +89,7 @@ large_dalloc_maybe_junk(tsdn_t *tsdn, void *ptr, size_t usize) * Only bother junk filling if the extent isn't about to be * unmapped. */ - if (!config_munmap || (have_dss && extent_in_dss(tsdn, ptr))) + if (!config_munmap || (have_dss && extent_in_dss(ptr))) large_dalloc_junk(ptr, usize); } } @@ -119,7 +119,7 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) return (true); if (config_fill && unlikely(opt_junk_free)) { - large_dalloc_maybe_junk(tsdn, extent_addr_get(trail), + large_dalloc_maybe_junk(extent_addr_get(trail), extent_usize_get(trail)); } @@ -296,7 +296,7 @@ large_dalloc_impl(tsdn_t *tsdn, extent_t *extent, bool junked_locked) ql_remove(&arena->large, extent, ql_link); malloc_mutex_unlock(tsdn, &arena->large_mtx); if (!junked_locked) { - large_dalloc_maybe_junk(tsdn, extent_addr_get(extent), + large_dalloc_maybe_junk(extent_addr_get(extent), extent_usize_get(extent)); } arena_extent_dalloc_large(tsdn, arena, extent, junked_locked); diff --git a/test/unit/junk.c b/test/unit/junk.c index fe453b6c..680f0d21 100644 --- a/test/unit/junk.c +++ b/test/unit/junk.c @@ -53,10 +53,10 @@ large_dalloc_junk_intercept(void *ptr, size_t usize) } static void -large_dalloc_maybe_junk_intercept(tsdn_t *tsdn, void *ptr, size_t usize) +large_dalloc_maybe_junk_intercept(void *ptr, size_t usize) { - large_dalloc_maybe_junk_orig(tsdn, ptr, usize); + large_dalloc_maybe_junk_orig(ptr, usize); if (ptr == watch_for_junking) saw_junking = true; } -- GitLab From b54d160dc4507eab5fb64e2e293019c5d3afd18c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 20 Oct 2016 23:59:12 -0700 Subject: [PATCH 126/544] Do not (recursively) allocate within tsd_fetch(). Refactor tsd so that tsdn_fetch() does not trigger allocation, since allocation could cause infinite recursion. This resolves #458. --- include/jemalloc/internal/ckh.h | 8 +- .../jemalloc/internal/jemalloc_internal.h.in | 10 +-- include/jemalloc/internal/private_symbols.txt | 2 + include/jemalloc/internal/prof.h | 8 +- include/jemalloc/internal/tcache.h | 2 +- include/jemalloc/internal/tsd.h | 74 +++++++++++---- src/ckh.c | 49 +++++----- src/ctl.c | 4 +- src/jemalloc.c | 2 +- src/prof.c | 89 +++++++++---------- src/tcache.c | 8 +- test/unit/ckh.c | 42 ++++----- test/unit/tsd.c | 6 +- 13 files changed, 172 insertions(+), 132 deletions(-) diff --git a/include/jemalloc/internal/ckh.h b/include/jemalloc/internal/ckh.h index 46e151cd..f75ad90b 100644 --- a/include/jemalloc/internal/ckh.h +++ b/include/jemalloc/internal/ckh.h @@ -64,13 +64,13 @@ struct ckh_s { /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS -bool ckh_new(tsdn_t *tsdn, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, +bool ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_keycomp_t *keycomp); -void ckh_delete(tsdn_t *tsdn, ckh_t *ckh); +void ckh_delete(tsd_t *tsd, ckh_t *ckh); size_t ckh_count(ckh_t *ckh); bool ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data); -bool ckh_insert(tsdn_t *tsdn, ckh_t *ckh, const void *key, const void *data); -bool ckh_remove(tsdn_t *tsdn, ckh_t *ckh, const void *searchkey, void **key, +bool ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data); +bool ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key, void **data); bool ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data); void ckh_string_hash(const void *key, size_t r_hash[2]); diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 1d02c20e..fac0ea39 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -535,7 +535,7 @@ size_t s2u(size_t size); size_t sa2u(size_t size, size_t alignment); arena_t *arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal); arena_t *arena_choose(tsd_t *tsd, arena_t *arena); -arena_t *arena_ichoose(tsdn_t *tsdn, arena_t *arena); +arena_t *arena_ichoose(tsd_t *tsd, arena_t *arena); arena_tdata_t *arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing); arena_t *arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing); @@ -862,14 +862,10 @@ arena_choose(tsd_t *tsd, arena_t *arena) } JEMALLOC_INLINE arena_t * -arena_ichoose(tsdn_t *tsdn, arena_t *arena) +arena_ichoose(tsd_t *tsd, arena_t *arena) { - assert(!tsdn_null(tsdn) || arena != NULL); - - if (!tsdn_null(tsdn)) - return (arena_choose_impl(tsdn_tsd(tsdn), NULL, true)); - return (arena); + return (arena_choose_impl(tsd, arena, true)); } JEMALLOC_INLINE arena_tdata_t * diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 8d573b76..1bf79ca8 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -471,7 +471,9 @@ tsd_booted_get tsd_cleanup tsd_cleanup_wrapper tsd_fetch +tsd_fetch_impl tsd_get +tsd_get_allocates tsd_iarena_get tsd_iarena_set tsd_iarenap_get diff --git a/include/jemalloc/internal/prof.h b/include/jemalloc/internal/prof.h index 0fdee08c..2d1791b9 100644 --- a/include/jemalloc/internal/prof.h +++ b/include/jemalloc/internal/prof.h @@ -299,9 +299,9 @@ extern prof_dump_header_t *prof_dump_header; void prof_idump(tsdn_t *tsdn); bool prof_mdump(tsd_t *tsd, const char *filename); void prof_gdump(tsdn_t *tsdn); -prof_tdata_t *prof_tdata_init(tsdn_t *tsdn); +prof_tdata_t *prof_tdata_init(tsd_t *tsd); prof_tdata_t *prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata); -void prof_reset(tsdn_t *tsdn, size_t lg_sample); +void prof_reset(tsd_t *tsd, size_t lg_sample); void prof_tdata_cleanup(tsd_t *tsd); bool prof_active_get(tsdn_t *tsdn); bool prof_active_set(tsdn_t *tsdn, bool active); @@ -315,7 +315,7 @@ bool prof_gdump_get(tsdn_t *tsdn); bool prof_gdump_set(tsdn_t *tsdn, bool active); void prof_boot0(void); void prof_boot1(void); -bool prof_boot2(tsdn_t *tsdn); +bool prof_boot2(tsd_t *tsd); void prof_prefork0(tsdn_t *tsdn); void prof_prefork1(tsdn_t *tsdn); void prof_postfork_parent(tsdn_t *tsdn); @@ -387,7 +387,7 @@ prof_tdata_get(tsd_t *tsd, bool create) if (create) { if (unlikely(tdata == NULL)) { if (tsd_nominal(tsd)) { - tdata = prof_tdata_init(tsd_tsdn(tsd)); + tdata = prof_tdata_init(tsd); tsd_prof_tdata_set(tsd, tdata); } } else if (unlikely(tdata->expired)) { diff --git a/include/jemalloc/internal/tcache.h b/include/jemalloc/internal/tcache.h index 933255ce..25a1ad02 100644 --- a/include/jemalloc/internal/tcache.h +++ b/include/jemalloc/internal/tcache.h @@ -144,7 +144,7 @@ tcache_t *tcache_get_hard(tsd_t *tsd); tcache_t *tcache_create(tsdn_t *tsdn, arena_t *arena); void tcache_cleanup(tsd_t *tsd); void tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); -bool tcaches_create(tsdn_t *tsdn, unsigned *r_ind); +bool tcaches_create(tsd_t *tsd, unsigned *r_ind); void tcaches_flush(tsd_t *tsd, unsigned ind); void tcaches_destroy(tsd_t *tsd, unsigned ind); bool tcache_boot(tsdn_t *tsdn); diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h index 5df5f673..b33de703 100644 --- a/include/jemalloc/internal/tsd.h +++ b/include/jemalloc/internal/tsd.h @@ -48,7 +48,7 @@ typedef enum { * * bool example_tsd_boot(void) {...} * bool example_tsd_booted_get(void) {...} - * example_t *example_tsd_get() {...} + * example_t *example_tsd_get(bool init) {...} * void example_tsd_set(example_t *val) {...} * * Note that all of the functions deal in terms of (a_type *) rather than @@ -105,7 +105,7 @@ a_name##tsd_boot(void); \ a_attr bool \ a_name##tsd_booted_get(void); \ a_attr a_type * \ -a_name##tsd_get(void); \ +a_name##tsd_get(bool init); \ a_attr void \ a_name##tsd_set(a_type *val); @@ -213,9 +213,15 @@ a_name##tsd_booted_get(void) \ \ return (a_name##tsd_booted); \ } \ +a_attr bool \ +a_name##tsd_get_allocates(void) \ +{ \ + \ + return (false); \ +} \ /* Get/set. */ \ a_attr a_type * \ -a_name##tsd_get(void) \ +a_name##tsd_get(bool init) \ { \ \ assert(a_name##tsd_booted); \ @@ -265,9 +271,15 @@ a_name##tsd_booted_get(void) \ \ return (a_name##tsd_booted); \ } \ +a_attr bool \ +a_name##tsd_get_allocates(void) \ +{ \ + \ + return (false); \ +} \ /* Get/set. */ \ a_attr a_type * \ -a_name##tsd_get(void) \ +a_name##tsd_get(bool init) \ { \ \ assert(a_name##tsd_booted); \ @@ -327,14 +339,14 @@ a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \ } \ } \ a_attr a_name##tsd_wrapper_t * \ -a_name##tsd_wrapper_get(void) \ +a_name##tsd_wrapper_get(bool init) \ { \ DWORD error = GetLastError(); \ a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ TlsGetValue(a_name##tsd_tsd); \ SetLastError(error); \ \ - if (unlikely(wrapper == NULL)) { \ + if (init && unlikely(wrapper == NULL)) { \ wrapper = (a_name##tsd_wrapper_t *) \ malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ if (wrapper == NULL) { \ @@ -394,14 +406,22 @@ a_name##tsd_booted_get(void) \ \ return (a_name##tsd_booted); \ } \ +a_attr bool \ +a_name##tsd_get_allocates(void) \ +{ \ + \ + return (true); \ +} \ /* Get/set. */ \ a_attr a_type * \ -a_name##tsd_get(void) \ +a_name##tsd_get(bool init) \ { \ a_name##tsd_wrapper_t *wrapper; \ \ assert(a_name##tsd_booted); \ - wrapper = a_name##tsd_wrapper_get(); \ + wrapper = a_name##tsd_wrapper_get(init); \ + if (a_name##tsd_get_allocates() && !init && wrapper == NULL) \ + return (NULL); \ return (&wrapper->val); \ } \ a_attr void \ @@ -410,7 +430,7 @@ a_name##tsd_set(a_type *val) \ a_name##tsd_wrapper_t *wrapper; \ \ assert(a_name##tsd_booted); \ - wrapper = a_name##tsd_wrapper_get(); \ + wrapper = a_name##tsd_wrapper_get(true); \ if (likely(&wrapper->val != val)) \ wrapper->val = *(val); \ if (a_cleanup != malloc_tsd_no_cleanup) \ @@ -455,12 +475,12 @@ a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \ } \ } \ a_attr a_name##tsd_wrapper_t * \ -a_name##tsd_wrapper_get(void) \ +a_name##tsd_wrapper_get(bool init) \ { \ a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ pthread_getspecific(a_name##tsd_tsd); \ \ - if (unlikely(wrapper == NULL)) { \ + if (init && unlikely(wrapper == NULL)) { \ tsd_init_block_t block; \ wrapper = tsd_init_check_recursion( \ &a_name##tsd_init_head, &block); \ @@ -523,14 +543,22 @@ a_name##tsd_booted_get(void) \ \ return (a_name##tsd_booted); \ } \ +a_attr bool \ +a_name##tsd_get_allocates(void) \ +{ \ + \ + return (true); \ +} \ /* Get/set. */ \ a_attr a_type * \ -a_name##tsd_get(void) \ +a_name##tsd_get(bool init) \ { \ a_name##tsd_wrapper_t *wrapper; \ \ assert(a_name##tsd_booted); \ - wrapper = a_name##tsd_wrapper_get(); \ + wrapper = a_name##tsd_wrapper_get(init); \ + if (a_name##tsd_get_allocates() && !init && wrapper == NULL) \ + return (NULL); \ return (&wrapper->val); \ } \ a_attr void \ @@ -539,7 +567,7 @@ a_name##tsd_set(a_type *val) \ a_name##tsd_wrapper_t *wrapper; \ \ assert(a_name##tsd_booted); \ - wrapper = a_name##tsd_wrapper_get(); \ + wrapper = a_name##tsd_wrapper_get(true); \ if (likely(&wrapper->val != val)) \ wrapper->val = *(val); \ if (a_cleanup != malloc_tsd_no_cleanup) \ @@ -645,6 +673,7 @@ void tsd_cleanup(void *arg); #ifndef JEMALLOC_ENABLE_INLINE malloc_tsd_protos(JEMALLOC_ATTR(unused), , tsd_t) +tsd_t *tsd_fetch_impl(bool init); tsd_t *tsd_fetch(void); tsdn_t *tsd_tsdn(tsd_t *tsd); bool tsd_nominal(tsd_t *tsd); @@ -665,9 +694,13 @@ malloc_tsd_externs(, tsd_t) malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, , tsd_t, tsd_initializer, tsd_cleanup) JEMALLOC_ALWAYS_INLINE tsd_t * -tsd_fetch(void) +tsd_fetch_impl(bool init) { - tsd_t *tsd = tsd_get(); + tsd_t *tsd = tsd_get(init); + + if (!init && tsd_get_allocates() && tsd == NULL) + return (NULL); + assert(tsd != NULL); if (unlikely(tsd->state != tsd_state_nominal)) { if (tsd->state == tsd_state_uninitialized) { @@ -684,6 +717,13 @@ tsd_fetch(void) return (tsd); } +JEMALLOC_ALWAYS_INLINE tsd_t * +tsd_fetch(void) +{ + + return (tsd_fetch_impl(true)); +} + JEMALLOC_ALWAYS_INLINE tsdn_t * tsd_tsdn(tsd_t *tsd) { @@ -730,7 +770,7 @@ tsdn_fetch(void) if (!tsd_booted_get()) return (NULL); - return (tsd_tsdn(tsd_fetch())); + return (tsd_tsdn(tsd_fetch_impl(false))); } JEMALLOC_ALWAYS_INLINE bool diff --git a/src/ckh.c b/src/ckh.c index 90a81155..75376017 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -40,8 +40,8 @@ /******************************************************************************/ /* Function prototypes for non-inline static functions. */ -static bool ckh_grow(tsdn_t *tsdn, ckh_t *ckh); -static void ckh_shrink(tsdn_t *tsdn, ckh_t *ckh); +static bool ckh_grow(tsd_t *tsd, ckh_t *ckh); +static void ckh_shrink(tsd_t *tsd, ckh_t *ckh); /******************************************************************************/ @@ -245,7 +245,7 @@ ckh_rebuild(ckh_t *ckh, ckhc_t *aTab) } static bool -ckh_grow(tsdn_t *tsdn, ckh_t *ckh) +ckh_grow(tsd_t *tsd, ckh_t *ckh) { bool ret; ckhc_t *tab, *ttab; @@ -271,8 +271,8 @@ ckh_grow(tsdn_t *tsdn, ckh_t *ckh) ret = true; goto label_return; } - tab = (ckhc_t *)ipallocztm(tsdn, usize, CACHELINE, true, NULL, - true, arena_ichoose(tsdn, NULL)); + tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE, + true, NULL, true, arena_ichoose(tsd, NULL)); if (tab == NULL) { ret = true; goto label_return; @@ -284,14 +284,14 @@ ckh_grow(tsdn_t *tsdn, ckh_t *ckh) ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; if (!ckh_rebuild(ckh, tab)) { - idalloctm(tsdn, iealloc(tsdn, tab), tab, NULL, true, - true); + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tab), + tab, NULL, true, true); break; } /* Rebuilding failed, so back out partially rebuilt table. */ - idalloctm(tsdn, iealloc(tsdn, ckh->tab), ckh->tab, NULL, true, - true); + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), ckh->tab), + ckh->tab, NULL, true, true); ckh->tab = tab; ckh->lg_curbuckets = lg_prevbuckets; } @@ -302,7 +302,7 @@ label_return: } static void -ckh_shrink(tsdn_t *tsdn, ckh_t *ckh) +ckh_shrink(tsd_t *tsd, ckh_t *ckh) { ckhc_t *tab, *ttab; size_t usize; @@ -317,8 +317,8 @@ ckh_shrink(tsdn_t *tsdn, ckh_t *ckh) usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) return; - tab = (ckhc_t *)ipallocztm(tsdn, usize, CACHELINE, true, NULL, true, - arena_ichoose(tsdn, NULL)); + tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE, true, NULL, + true, arena_ichoose(tsd, NULL)); if (tab == NULL) { /* * An OOM error isn't worth propagating, since it doesn't @@ -333,7 +333,8 @@ ckh_shrink(tsdn_t *tsdn, ckh_t *ckh) ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; if (!ckh_rebuild(ckh, tab)) { - idalloctm(tsdn, iealloc(tsdn, tab), tab, NULL, true, true); + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tab), tab, NULL, + true, true); #ifdef CKH_COUNT ckh->nshrinks++; #endif @@ -341,7 +342,8 @@ ckh_shrink(tsdn_t *tsdn, ckh_t *ckh) } /* Rebuilding failed, so back out partially rebuilt table. */ - idalloctm(tsdn, iealloc(tsdn, ckh->tab), ckh->tab, NULL, true, true); + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), ckh->tab), ckh->tab, + NULL, true, true); ckh->tab = tab; ckh->lg_curbuckets = lg_prevbuckets; #ifdef CKH_COUNT @@ -350,7 +352,7 @@ ckh_shrink(tsdn_t *tsdn, ckh_t *ckh) } bool -ckh_new(tsdn_t *tsdn, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, +ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_keycomp_t *keycomp) { bool ret; @@ -394,8 +396,8 @@ ckh_new(tsdn_t *tsdn, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ret = true; goto label_return; } - ckh->tab = (ckhc_t *)ipallocztm(tsdn, usize, CACHELINE, true, NULL, - true, arena_ichoose(tsdn, NULL)); + ckh->tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE, true, + NULL, true, arena_ichoose(tsd, NULL)); if (ckh->tab == NULL) { ret = true; goto label_return; @@ -407,7 +409,7 @@ label_return: } void -ckh_delete(tsdn_t *tsdn, ckh_t *ckh) +ckh_delete(tsd_t *tsd, ckh_t *ckh) { assert(ckh != NULL); @@ -424,7 +426,8 @@ ckh_delete(tsdn_t *tsdn, ckh_t *ckh) (unsigned long long)ckh->nrelocs); #endif - idalloctm(tsdn, iealloc(tsdn, ckh->tab), ckh->tab, NULL, true, true); + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), ckh->tab), ckh->tab, + NULL, true, true); if (config_debug) memset(ckh, JEMALLOC_FREE_JUNK, sizeof(ckh_t)); } @@ -459,7 +462,7 @@ ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data) } bool -ckh_insert(tsdn_t *tsdn, ckh_t *ckh, const void *key, const void *data) +ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data) { bool ret; @@ -471,7 +474,7 @@ ckh_insert(tsdn_t *tsdn, ckh_t *ckh, const void *key, const void *data) #endif while (ckh_try_insert(ckh, &key, &data)) { - if (ckh_grow(tsdn, ckh)) { + if (ckh_grow(tsd, ckh)) { ret = true; goto label_return; } @@ -483,7 +486,7 @@ label_return: } bool -ckh_remove(tsdn_t *tsdn, ckh_t *ckh, const void *searchkey, void **key, +ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key, void **data) { size_t cell; @@ -505,7 +508,7 @@ ckh_remove(tsdn_t *tsdn, ckh_t *ckh, const void *searchkey, void **key, + LG_CKH_BUCKET_CELLS - 2)) && ckh->lg_curbuckets > ckh->lg_minbuckets) { /* Ignore error due to OOM. */ - ckh_shrink(tsdn, ckh); + ckh_shrink(tsd, ckh); } return (false); diff --git a/src/ctl.c b/src/ctl.c index 067b6772..47b4768b 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1326,7 +1326,7 @@ tcache_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); READONLY(); - if (tcaches_create(tsd_tsdn(tsd), &tcache_ind)) { + if (tcaches_create(tsd, &tcache_ind)) { ret = EFAULT; goto label_return; } @@ -1871,7 +1871,7 @@ prof_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, if (lg_sample >= (sizeof(uint64_t) << 3)) lg_sample = (sizeof(uint64_t) << 3) - 1; - prof_reset(tsd_tsdn(tsd), lg_sample); + prof_reset(tsd, lg_sample); ret = 0; label_return: diff --git a/src/jemalloc.c b/src/jemalloc.c index 5108d15f..1f951e2f 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1313,7 +1313,7 @@ malloc_init_hard(void) return (true); malloc_mutex_lock(tsd_tsdn(tsd), &init_lock); - if (config_prof && prof_boot2(tsd_tsdn(tsd))) { + if (config_prof && prof_boot2(tsd)) { malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); return (true); } diff --git a/src/prof.c b/src/prof.c index 5eb9a3d1..4bafb39a 100644 --- a/src/prof.c +++ b/src/prof.c @@ -125,7 +125,7 @@ static bool prof_tctx_should_destroy(tsdn_t *tsdn, prof_tctx_t *tctx); static void prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx); static bool prof_tdata_should_destroy(tsdn_t *tsdn, prof_tdata_t *tdata, bool even_if_attached); -static void prof_tdata_destroy(tsdn_t *tsdn, prof_tdata_t *tdata, +static void prof_tdata_destroy(tsd_t *tsd, prof_tdata_t *tdata, bool even_if_attached); static char *prof_thread_name_alloc(tsdn_t *tsdn, const char *thread_name); @@ -591,7 +591,7 @@ prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self, prof_gctx_t *gctx, assert(gctx->nlimbo != 0); if (tctx_tree_empty(&gctx->tctxs) && gctx->nlimbo == 1) { /* Remove gctx from bt2gctx. */ - if (ckh_remove(tsd_tsdn(tsd), &bt2gctx, &gctx->bt, NULL, NULL)) + if (ckh_remove(tsd, &bt2gctx, &gctx->bt, NULL, NULL)) not_reached(); prof_leave(tsd, tdata_self); /* Destroy gctx. */ @@ -652,7 +652,7 @@ prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) assert(tctx->cnts.accumobjs == 0); assert(tctx->cnts.accumbytes == 0); - ckh_remove(tsd_tsdn(tsd), &tdata->bt2tctx, &gctx->bt, NULL, NULL); + ckh_remove(tsd, &tdata->bt2tctx, &gctx->bt, NULL, NULL); destroy_tdata = prof_tdata_should_destroy(tsd_tsdn(tsd), tdata, false); malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); @@ -705,7 +705,7 @@ prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) malloc_mutex_assert_not_owner(tsd_tsdn(tsd), tctx->tdata->lock); if (destroy_tdata) - prof_tdata_destroy(tsd_tsdn(tsd), tdata, false); + prof_tdata_destroy(tsd, tdata, false); if (destroy_tctx) idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tctx), tctx, @@ -735,7 +735,7 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, return (true); } btkey.p = &gctx.p->bt; - if (ckh_insert(tsd_tsdn(tsd), &bt2gctx, btkey.v, gctx.v)) { + if (ckh_insert(tsd, &bt2gctx, btkey.v, gctx.v)) { /* OOM. */ prof_leave(tsd, tdata); idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), gctx.v), @@ -798,7 +798,7 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) /* Link a prof_tctx_t into gctx for this thread. */ ret.v = iallocztm(tsd_tsdn(tsd), sizeof(prof_tctx_t), size2index(sizeof(prof_tctx_t)), false, NULL, true, - arena_ichoose(tsd_tsdn(tsd), NULL), true); + arena_ichoose(tsd, NULL), true); if (ret.p == NULL) { if (new_gctx) prof_gctx_try_destroy(tsd, tdata, gctx, tdata); @@ -813,8 +813,7 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) ret.p->prepared = true; ret.p->state = prof_tctx_state_initializing; malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock); - error = ckh_insert(tsd_tsdn(tsd), &tdata->bt2tctx, btkey, - ret.v); + error = ckh_insert(tsd, &tdata->bt2tctx, btkey, ret.v); malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); if (error) { if (new_gctx) @@ -1796,7 +1795,7 @@ prof_thr_uid_alloc(tsdn_t *tsdn) } static prof_tdata_t * -prof_tdata_init_impl(tsdn_t *tsdn, uint64_t thr_uid, uint64_t thr_discrim, +prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim, char *thread_name, bool active) { prof_tdata_t *tdata; @@ -1804,7 +1803,7 @@ prof_tdata_init_impl(tsdn_t *tsdn, uint64_t thr_uid, uint64_t thr_discrim, cassert(config_prof); /* Initialize an empty cache for this thread. */ - tdata = (prof_tdata_t *)iallocztm(tsdn, sizeof(prof_tdata_t), + tdata = (prof_tdata_t *)iallocztm(tsd_tsdn(tsd), sizeof(prof_tdata_t), size2index(sizeof(prof_tdata_t)), false, NULL, true, arena_get(TSDN_NULL, 0, true), true); if (tdata == NULL) @@ -1818,9 +1817,10 @@ prof_tdata_init_impl(tsdn_t *tsdn, uint64_t thr_uid, uint64_t thr_discrim, tdata->expired = false; tdata->tctx_uid_next = 0; - if (ckh_new(tsdn, &tdata->bt2tctx, PROF_CKH_MINITEMS, - prof_bt_hash, prof_bt_keycomp)) { - idalloctm(tsdn, iealloc(tsdn, tdata), tdata, NULL, true, true); + if (ckh_new(tsd, &tdata->bt2tctx, PROF_CKH_MINITEMS, prof_bt_hash, + prof_bt_keycomp)) { + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tdata), tdata, + NULL, true, true); return (NULL); } @@ -1834,19 +1834,19 @@ prof_tdata_init_impl(tsdn_t *tsdn, uint64_t thr_uid, uint64_t thr_discrim, tdata->dumping = false; tdata->active = active; - malloc_mutex_lock(tsdn, &tdatas_mtx); + malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx); tdata_tree_insert(&tdatas, tdata); - malloc_mutex_unlock(tsdn, &tdatas_mtx); + malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx); return (tdata); } prof_tdata_t * -prof_tdata_init(tsdn_t *tsdn) +prof_tdata_init(tsd_t *tsd) { - return (prof_tdata_init_impl(tsdn, prof_thr_uid_alloc(tsdn), 0, NULL, - prof_thread_active_init_get(tsdn))); + return (prof_tdata_init_impl(tsd, prof_thr_uid_alloc(tsd_tsdn(tsd)), 0, + NULL, prof_thread_active_init_get(tsd_tsdn(tsd)))); } static bool @@ -1871,33 +1871,32 @@ prof_tdata_should_destroy(tsdn_t *tsdn, prof_tdata_t *tdata, } static void -prof_tdata_destroy_locked(tsdn_t *tsdn, prof_tdata_t *tdata, +prof_tdata_destroy_locked(tsd_t *tsd, prof_tdata_t *tdata, bool even_if_attached) { - malloc_mutex_assert_owner(tsdn, &tdatas_mtx); - - assert(tsdn_null(tsdn) || tsd_prof_tdata_get(tsdn_tsd(tsdn)) != tdata); + malloc_mutex_assert_owner(tsd_tsdn(tsd), &tdatas_mtx); tdata_tree_remove(&tdatas, tdata); assert(prof_tdata_should_destroy_unlocked(tdata, even_if_attached)); if (tdata->thread_name != NULL) { - idalloctm(tsdn, iealloc(tsdn, tdata->thread_name), - tdata->thread_name, NULL, true, true); + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), + tdata->thread_name), tdata->thread_name, NULL, true, true); } - ckh_delete(tsdn, &tdata->bt2tctx); - idalloctm(tsdn, iealloc(tsdn, tdata), tdata, NULL, true, true); + ckh_delete(tsd, &tdata->bt2tctx); + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tdata), tdata, NULL, + true, true); } static void -prof_tdata_destroy(tsdn_t *tsdn, prof_tdata_t *tdata, bool even_if_attached) +prof_tdata_destroy(tsd_t *tsd, prof_tdata_t *tdata, bool even_if_attached) { - malloc_mutex_lock(tsdn, &tdatas_mtx); - prof_tdata_destroy_locked(tsdn, tdata, even_if_attached); - malloc_mutex_unlock(tsdn, &tdatas_mtx); + malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx); + prof_tdata_destroy_locked(tsd, tdata, even_if_attached); + malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx); } static void @@ -1920,7 +1919,7 @@ prof_tdata_detach(tsd_t *tsd, prof_tdata_t *tdata) destroy_tdata = false; malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); if (destroy_tdata) - prof_tdata_destroy(tsd_tsdn(tsd), tdata, true); + prof_tdata_destroy(tsd, tdata, true); } prof_tdata_t * @@ -1933,8 +1932,8 @@ prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata) bool active = tdata->active; prof_tdata_detach(tsd, tdata); - return (prof_tdata_init_impl(tsd_tsdn(tsd), thr_uid, thr_discrim, - thread_name, active)); + return (prof_tdata_init_impl(tsd, thr_uid, thr_discrim, thread_name, + active)); } static bool @@ -1963,30 +1962,30 @@ prof_tdata_reset_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, void *arg) } void -prof_reset(tsdn_t *tsdn, size_t lg_sample) +prof_reset(tsd_t *tsd, size_t lg_sample) { prof_tdata_t *next; assert(lg_sample < (sizeof(uint64_t) << 3)); - malloc_mutex_lock(tsdn, &prof_dump_mtx); - malloc_mutex_lock(tsdn, &tdatas_mtx); + malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_mtx); + malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx); lg_prof_sample = lg_sample; next = NULL; do { prof_tdata_t *to_destroy = tdata_tree_iter(&tdatas, next, - prof_tdata_reset_iter, (void *)tsdn); + prof_tdata_reset_iter, (void *)tsd); if (to_destroy != NULL) { next = tdata_tree_next(&tdatas, to_destroy); - prof_tdata_destroy_locked(tsdn, to_destroy, false); + prof_tdata_destroy_locked(tsd, to_destroy, false); } else next = NULL; } while (next != NULL); - malloc_mutex_unlock(tsdn, &tdatas_mtx); - malloc_mutex_unlock(tsdn, &prof_dump_mtx); + malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx); + malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_mtx); } void @@ -2197,7 +2196,7 @@ prof_boot1(void) } bool -prof_boot2(tsdn_t *tsdn) +prof_boot2(tsd_t *tsd) { cassert(config_prof); @@ -2223,7 +2222,7 @@ prof_boot2(tsdn_t *tsdn) WITNESS_RANK_PROF_THREAD_ACTIVE_INIT)) return (true); - if (ckh_new(tsdn, &bt2gctx, PROF_CKH_MINITEMS, prof_bt_hash, + if (ckh_new(tsd, &bt2gctx, PROF_CKH_MINITEMS, prof_bt_hash, prof_bt_keycomp)) return (true); if (malloc_mutex_init(&bt2gctx_mtx, "prof_bt2gctx", @@ -2254,8 +2253,8 @@ prof_boot2(tsdn_t *tsdn) abort(); } - gctx_locks = (malloc_mutex_t *)base_alloc(tsdn, PROF_NCTX_LOCKS - * sizeof(malloc_mutex_t)); + gctx_locks = (malloc_mutex_t *)base_alloc(tsd_tsdn(tsd), + PROF_NCTX_LOCKS * sizeof(malloc_mutex_t)); if (gctx_locks == NULL) return (true); for (i = 0; i < PROF_NCTX_LOCKS; i++) { @@ -2264,7 +2263,7 @@ prof_boot2(tsdn_t *tsdn) return (true); } - tdata_locks = (malloc_mutex_t *)base_alloc(tsdn, + tdata_locks = (malloc_mutex_t *)base_alloc(tsd_tsdn(tsd), PROF_NTDATA_LOCKS * sizeof(malloc_mutex_t)); if (tdata_locks == NULL) return (true); diff --git a/src/tcache.c b/src/tcache.c index 96e54e1a..98c18a04 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -433,14 +433,14 @@ tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) } bool -tcaches_create(tsdn_t *tsdn, unsigned *r_ind) +tcaches_create(tsd_t *tsd, unsigned *r_ind) { arena_t *arena; tcache_t *tcache; tcaches_t *elm; if (tcaches == NULL) { - tcaches = base_alloc(tsdn, sizeof(tcache_t *) * + tcaches = base_alloc(tsd_tsdn(tsd), sizeof(tcache_t *) * (MALLOCX_TCACHE_MAX+1)); if (tcaches == NULL) return (true); @@ -448,10 +448,10 @@ tcaches_create(tsdn_t *tsdn, unsigned *r_ind) if (tcaches_avail == NULL && tcaches_past > MALLOCX_TCACHE_MAX) return (true); - arena = arena_ichoose(tsdn, NULL); + arena = arena_ichoose(tsd, NULL); if (unlikely(arena == NULL)) return (true); - tcache = tcache_create(tsdn, arena); + tcache = tcache_create(tsd_tsdn(tsd), arena); if (tcache == NULL) return (true); diff --git a/test/unit/ckh.c b/test/unit/ckh.c index 961e2acb..2cbc2268 100644 --- a/test/unit/ckh.c +++ b/test/unit/ckh.c @@ -2,24 +2,24 @@ TEST_BEGIN(test_new_delete) { - tsdn_t *tsdn; + tsd_t *tsd; ckh_t ckh; - tsdn = tsdn_fetch(); + tsd = tsd_fetch(); - assert_false(ckh_new(tsdn, &ckh, 2, ckh_string_hash, + assert_false(ckh_new(tsd, &ckh, 2, ckh_string_hash, ckh_string_keycomp), "Unexpected ckh_new() error"); - ckh_delete(tsdn, &ckh); + ckh_delete(tsd, &ckh); - assert_false(ckh_new(tsdn, &ckh, 3, ckh_pointer_hash, + assert_false(ckh_new(tsd, &ckh, 3, ckh_pointer_hash, ckh_pointer_keycomp), "Unexpected ckh_new() error"); - ckh_delete(tsdn, &ckh); + ckh_delete(tsd, &ckh); } TEST_END TEST_BEGIN(test_count_insert_search_remove) { - tsdn_t *tsdn; + tsd_t *tsd; ckh_t ckh; const char *strs[] = { "a string", @@ -30,9 +30,9 @@ TEST_BEGIN(test_count_insert_search_remove) const char *missing = "A string not in the hash table."; size_t i; - tsdn = tsdn_fetch(); + tsd = tsd_fetch(); - assert_false(ckh_new(tsdn, &ckh, 2, ckh_string_hash, + assert_false(ckh_new(tsd, &ckh, 2, ckh_string_hash, ckh_string_keycomp), "Unexpected ckh_new() error"); assert_zu_eq(ckh_count(&ckh), 0, "ckh_count() should return %zu, but it returned %zu", ZU(0), @@ -40,7 +40,7 @@ TEST_BEGIN(test_count_insert_search_remove) /* Insert. */ for (i = 0; i < sizeof(strs)/sizeof(const char *); i++) { - ckh_insert(tsdn, &ckh, strs[i], strs[i]); + ckh_insert(tsd, &ckh, strs[i], strs[i]); assert_zu_eq(ckh_count(&ckh), i+1, "ckh_count() should return %zu, but it returned %zu", i+1, ckh_count(&ckh)); @@ -85,7 +85,7 @@ TEST_BEGIN(test_count_insert_search_remove) vp = (i & 2) ? &v.p : NULL; k.p = NULL; v.p = NULL; - assert_false(ckh_remove(tsdn, &ckh, strs[i], kp, vp), + assert_false(ckh_remove(tsd, &ckh, strs[i], kp, vp), "Unexpected ckh_remove() error"); ks = (i & 1) ? strs[i] : (const char *)NULL; @@ -101,22 +101,22 @@ TEST_BEGIN(test_count_insert_search_remove) ckh_count(&ckh)); } - ckh_delete(tsdn, &ckh); + ckh_delete(tsd, &ckh); } TEST_END TEST_BEGIN(test_insert_iter_remove) { #define NITEMS ZU(1000) - tsdn_t *tsdn; + tsd_t *tsd; ckh_t ckh; void **p[NITEMS]; void *q, *r; size_t i; - tsdn = tsdn_fetch(); + tsd = tsd_fetch(); - assert_false(ckh_new(tsdn, &ckh, 2, ckh_pointer_hash, + assert_false(ckh_new(tsd, &ckh, 2, ckh_pointer_hash, ckh_pointer_keycomp), "Unexpected ckh_new() error"); for (i = 0; i < NITEMS; i++) { @@ -128,7 +128,7 @@ TEST_BEGIN(test_insert_iter_remove) size_t j; for (j = i; j < NITEMS; j++) { - assert_false(ckh_insert(tsdn, &ckh, p[j], p[j]), + assert_false(ckh_insert(tsd, &ckh, p[j], p[j]), "Unexpected ckh_insert() failure"); assert_false(ckh_search(&ckh, p[j], &q, &r), "Unexpected ckh_search() failure"); @@ -143,13 +143,13 @@ TEST_BEGIN(test_insert_iter_remove) for (j = i + 1; j < NITEMS; j++) { assert_false(ckh_search(&ckh, p[j], NULL, NULL), "Unexpected ckh_search() failure"); - assert_false(ckh_remove(tsdn, &ckh, p[j], &q, &r), + assert_false(ckh_remove(tsd, &ckh, p[j], &q, &r), "Unexpected ckh_remove() failure"); assert_ptr_eq(p[j], q, "Key pointer mismatch"); assert_ptr_eq(p[j], r, "Value pointer mismatch"); assert_true(ckh_search(&ckh, p[j], NULL, NULL), "Unexpected ckh_search() success"); - assert_true(ckh_remove(tsdn, &ckh, p[j], &q, &r), + assert_true(ckh_remove(tsd, &ckh, p[j], &q, &r), "Unexpected ckh_remove() success"); } @@ -184,13 +184,13 @@ TEST_BEGIN(test_insert_iter_remove) for (i = 0; i < NITEMS; i++) { assert_false(ckh_search(&ckh, p[i], NULL, NULL), "Unexpected ckh_search() failure"); - assert_false(ckh_remove(tsdn, &ckh, p[i], &q, &r), + assert_false(ckh_remove(tsd, &ckh, p[i], &q, &r), "Unexpected ckh_remove() failure"); assert_ptr_eq(p[i], q, "Key pointer mismatch"); assert_ptr_eq(p[i], r, "Value pointer mismatch"); assert_true(ckh_search(&ckh, p[i], NULL, NULL), "Unexpected ckh_search() success"); - assert_true(ckh_remove(tsdn, &ckh, p[i], &q, &r), + assert_true(ckh_remove(tsd, &ckh, p[i], &q, &r), "Unexpected ckh_remove() success"); dallocx(p[i], 0); } @@ -198,7 +198,7 @@ TEST_BEGIN(test_insert_iter_remove) assert_zu_eq(ckh_count(&ckh), 0, "ckh_count() should return %zu, but it returned %zu", ZU(0), ckh_count(&ckh)); - ckh_delete(tsdn, &ckh); + ckh_delete(tsd, &ckh); #undef NITEMS } TEST_END diff --git a/test/unit/tsd.c b/test/unit/tsd.c index 7dde4b77..4e2622a3 100644 --- a/test/unit/tsd.c +++ b/test/unit/tsd.c @@ -58,18 +58,18 @@ thd_start(void *arg) data_t d = (data_t)(uintptr_t)arg; void *p; - assert_x_eq(*data_tsd_get(), DATA_INIT, + assert_x_eq(*data_tsd_get(true), DATA_INIT, "Initial tsd get should return initialization value"); p = malloc(1); assert_ptr_not_null(p, "Unexpected malloc() failure"); data_tsd_set(&d); - assert_x_eq(*data_tsd_get(), d, + assert_x_eq(*data_tsd_get(true), d, "After tsd set, tsd get should return value that was set"); d = 0; - assert_x_eq(*data_tsd_get(), (data_t)(uintptr_t)arg, + assert_x_eq(*data_tsd_get(true), (data_t)(uintptr_t)arg, "Resetting local data should have no effect on tsd"); free(p); -- GitLab From 7b24c6e5570062495243f1e55131b395adb31e33 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 25 Oct 2016 21:52:36 -0700 Subject: [PATCH 127/544] Use --whole-archive when linking integration tests on MinGW. Prior to this change, the malloc_conf weak symbol provided by the jemalloc dynamic library is always used, even if the application provides a malloc_conf symbol. Use the --whole-archive linker option to allow the weak symbol to be overridden. --- Makefile.in | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 9e063095..d509d551 100644 --- a/Makefile.in +++ b/Makefile.in @@ -119,6 +119,11 @@ DSOS := $(objroot)lib/$(LIBJEMALLOC).$(SOREV) ifneq ($(SOREV),$(SO)) DSOS += $(objroot)lib/$(LIBJEMALLOC).$(SO) endif +ifeq (pecoff, $(ABI)) +LJEMALLOC := -Wl,--whole-archive -L$(objroot)lib -l$(LIBJEMALLOC) -Wl,--no-whole-archive +else +LJEMALLOC := $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) +endif PC := $(objroot)jemalloc.pc MAN3 := $(objroot)doc/jemalloc$(install_suffix).3 DOCS_XML := $(objroot)doc/jemalloc$(install_suffix).xml @@ -130,7 +135,11 @@ C_TESTLIB_SRCS := $(srcroot)test/src/btalloc.c $(srcroot)test/src/btalloc_0.c \ $(srcroot)test/src/mtx.c $(srcroot)test/src/mq.c \ $(srcroot)test/src/SFMT.c $(srcroot)test/src/test.c \ $(srcroot)test/src/thd.c $(srcroot)test/src/timer.c +ifeq (pecoff, $(ABI)) +C_UTIL_INTEGRATION_SRCS := +else C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/util.c +endif TESTS_UNIT := \ $(srcroot)test/unit/a0.c \ $(srcroot)test/unit/arena_reset.c \ @@ -294,7 +303,7 @@ $(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(TESTS_UNIT_LINK_OBJS) $(objroot)test/integration/%$(EXE): $(objroot)test/integration/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) @mkdir -p $(@D) - $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -lpthread,$(LIBS))) -lm $(EXTRA_LDFLAGS) + $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LJEMALLOC) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -lpthread,$(LIBS))) -lm $(EXTRA_LDFLAGS) $(objroot)test/stress/%$(EXE): $(objroot)test/stress/%.$(O) $(C_JET_OBJS) $(C_TESTLIB_STRESS_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) @mkdir -p $(@D) -- GitLab From 583c32c3056bff7606570e7836d33bf8fd18d299 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 27 Oct 2016 15:41:43 -0700 Subject: [PATCH 128/544] Do not force lazy lock on Windows. This reverts 13473c7c66a81a4dc1cf11a97e9c8b1dbb785b64, which was intended to work around bootstrapping issues when linking statically. However, this actually causes problems in various other configurations, so this reversion may force a future fix for the underlying problem, if it still exists. --- configure.ac | 1 - 1 file changed, 1 deletion(-) diff --git a/configure.ac b/configure.ac index 0ec710a9..9ece7860 100644 --- a/configure.ac +++ b/configure.ac @@ -426,7 +426,6 @@ case "${host}" in *-*-mingw* | *-*-cygwin*) abi="pecoff" force_tls="0" - force_lazy_lock="1" maps_coalesce="0" RPATH="" so="dll" -- GitLab From c44fa92db5cccf557d1ced431da6aa5ded58ed16 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 27 Oct 2016 17:10:56 -0700 Subject: [PATCH 129/544] Only use --whole-archive with gcc. Conditionalize use of --whole-archive on the platform plus compiler, rather than on the ABI. This fixes a regression caused by 7b24c6e5570062495243f1e55131b395adb31e33 (Use --whole-archive when linking integration tests on MinGW.). --- Makefile.in | 5 +++-- configure.ac | 3 +++ msvc/ReadMe.txt | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile.in b/Makefile.in index d509d551..eb77d9f2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -51,6 +51,7 @@ enable_code_coverage := @enable_code_coverage@ enable_prof := @enable_prof@ enable_zone_allocator := @enable_zone_allocator@ MALLOC_CONF := @JEMALLOC_CPREFIX@MALLOC_CONF +link_whole_archive := @link_whole_archive@ DSO_LDFLAGS = @DSO_LDFLAGS@ SOREV = @SOREV@ PIC_CFLAGS = @PIC_CFLAGS@ @@ -119,7 +120,7 @@ DSOS := $(objroot)lib/$(LIBJEMALLOC).$(SOREV) ifneq ($(SOREV),$(SO)) DSOS += $(objroot)lib/$(LIBJEMALLOC).$(SO) endif -ifeq (pecoff, $(ABI)) +ifeq (1, $(link_whole_archive)) LJEMALLOC := -Wl,--whole-archive -L$(objroot)lib -l$(LIBJEMALLOC) -Wl,--no-whole-archive else LJEMALLOC := $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) @@ -135,7 +136,7 @@ C_TESTLIB_SRCS := $(srcroot)test/src/btalloc.c $(srcroot)test/src/btalloc_0.c \ $(srcroot)test/src/mtx.c $(srcroot)test/src/mq.c \ $(srcroot)test/src/SFMT.c $(srcroot)test/src/test.c \ $(srcroot)test/src/thd.c $(srcroot)test/src/timer.c -ifeq (pecoff, $(ABI)) +ifeq (1, $(link_whole_archive)) C_UTIL_INTEGRATION_SRCS := else C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/util.c diff --git a/configure.ac b/configure.ac index 9ece7860..f27c61f1 100644 --- a/configure.ac +++ b/configure.ac @@ -313,6 +313,7 @@ o="$ac_objext" a="a" exe="$ac_exeext" libprefix="lib" +link_whole_archive="0" DSO_LDFLAGS='-shared -Wl,-soname,$(@F)' RPATH='-Wl,-rpath,$(1)' SOREV="${so}.${rev}" @@ -442,6 +443,7 @@ case "${host}" in else importlib="${so}" DSO_LDFLAGS="-shared" + link_whole_archive="1" fi a="lib" libprefix="" @@ -479,6 +481,7 @@ AC_SUBST([o]) AC_SUBST([a]) AC_SUBST([exe]) AC_SUBST([libprefix]) +AC_SUBST([link_whole_archive]) AC_SUBST([DSO_LDFLAGS]) AC_SUBST([EXTRA_LDFLAGS]) AC_SUBST([SOREV]) diff --git a/msvc/ReadMe.txt b/msvc/ReadMe.txt index b1c2fc5c..77d567da 100644 --- a/msvc/ReadMe.txt +++ b/msvc/ReadMe.txt @@ -17,7 +17,7 @@ How to build jemalloc for Windows (note: x86/x64 doesn't matter at this point) 5. Generate header files: - sh -c "./autogen.sh" CC=cl --enable-lazy-lock=no + sh -c "CC=cl ./autogen.sh" 6. Now the project can be opened and built in Visual Studio: msvc\jemalloc_vc2015.sln -- GitLab From d76cfec319760c71bf3d30b9960c9e666785c461 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 27 Oct 2016 21:23:48 -0700 Subject: [PATCH 130/544] Only link with libm (-lm) if necessary. This fixes warnings when building with MSVC. --- Makefile.in | 7 ++++--- configure.ac | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Makefile.in b/Makefile.in index eb77d9f2..e00dbebc 100644 --- a/Makefile.in +++ b/Makefile.in @@ -62,6 +62,7 @@ MKLIB = @MKLIB@ AR = @AR@ ARFLAGS = @ARFLAGS@ CC_MM = @CC_MM@ +LM := @LM@ INSTALL = @INSTALL@ ifeq (macho, $(ABI)) @@ -300,15 +301,15 @@ $(STATIC_LIBS): $(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(TESTS_UNIT_LINK_OBJS) $(C_JET_OBJS) $(C_TESTLIB_UNIT_OBJS) @mkdir -p $(@D) - $(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LDFLAGS) $(filter-out -lm,$(LIBS)) -lm $(EXTRA_LDFLAGS) + $(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LDFLAGS) $(filter-out -lm,$(LIBS)) $(LM) $(EXTRA_LDFLAGS) $(objroot)test/integration/%$(EXE): $(objroot)test/integration/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) @mkdir -p $(@D) - $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LJEMALLOC) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -lpthread,$(LIBS))) -lm $(EXTRA_LDFLAGS) + $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LJEMALLOC) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -lpthread,$(LIBS))) $(LM) $(EXTRA_LDFLAGS) $(objroot)test/stress/%$(EXE): $(objroot)test/stress/%.$(O) $(C_JET_OBJS) $(C_TESTLIB_STRESS_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) @mkdir -p $(@D) - $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(LIBS)) -lm $(EXTRA_LDFLAGS) + $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(LIBS)) $(LM) $(EXTRA_LDFLAGS) build_lib_shared: $(DSOS) build_lib_static: $(STATIC_LIBS) diff --git a/configure.ac b/configure.ac index f27c61f1..a9d75111 100644 --- a/configure.ac +++ b/configure.ac @@ -494,6 +494,15 @@ AC_SUBST([ARFLAGS]) AC_SUBST([AROUT]) AC_SUBST([CC_MM]) +dnl Determine whether libm must be linked to use e.g. log(3). +AC_SEARCH_LIBS([log], [m], , [AC_MSG_ERROR([Missing math functions])]) +if test "x$ac_cv_search_log" != "xnone required" ; then + LM="$ac_cv_search_log" +else + LM= +fi +AC_SUBST(LM) + JE_COMPILABLE([__attribute__ syntax], [static __attribute__((unused)) void foo(void){}], [], @@ -940,9 +949,9 @@ fi AC_MSG_CHECKING([configured backtracing method]) AC_MSG_RESULT([$backtrace_method]) if test "x$enable_prof" = "x1" ; then - if test "x$abi" != "xpecoff"; then - dnl Heap profiling uses the log(3) function. - LIBS="$LIBS -lm" + dnl Heap profiling uses the log(3) function. + if test "x$LM" != "x" ; then + LIBS="$LIBS $LM" fi AC_DEFINE([JEMALLOC_PROF], [ ]) -- GitLab From 48d4adfbeb32fcc7f455547d89641cd1fc459361 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 27 Oct 2016 21:26:33 -0700 Subject: [PATCH 131/544] Avoid negation of unsigned numbers. Rather than relying on two's complement negation for alignment mask generation, use bitwise not and addition. This dodges warnings from MSVC, and should be strength-reduced by compiler optimization anyway. --- include/jemalloc/internal/jemalloc_internal.h.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index fac0ea39..0e4ffd91 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -315,7 +315,7 @@ typedef unsigned szind_t; /* Return the nearest aligned address at or below a. */ #define ALIGNMENT_ADDR2BASE(a, alignment) \ - ((void *)((uintptr_t)(a) & (-(alignment)))) + ((void *)((uintptr_t)(a) & ((~(alignment)) + 1))) /* Return the offset between a and the nearest aligned address at or below a. */ #define ALIGNMENT_ADDR2OFFSET(a, alignment) \ @@ -323,7 +323,7 @@ typedef unsigned szind_t; /* Return the smallest alignment multiple that is >= s. */ #define ALIGNMENT_CEILING(s, alignment) \ - (((s) + (alignment - 1)) & (-(alignment))) + (((s) + (alignment - 1)) & ((~(alignment)) + 1)) /* Declare a variable-length array. */ #if __STDC_VERSION__ < 199901L -- GitLab From 17aa187f6b3c5c320653167acf1e85d3d8645e62 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 27 Oct 2016 21:29:00 -0700 Subject: [PATCH 132/544] Add cast to silence (harmless) conversion warning. --- test/unit/tsd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/tsd.c b/test/unit/tsd.c index 4e2622a3..d5f96ac3 100644 --- a/test/unit/tsd.c +++ b/test/unit/tsd.c @@ -79,7 +79,7 @@ thd_start(void *arg) TEST_BEGIN(test_tsd_main_thread) { - thd_start((void *) 0xa5f3e329); + thd_start((void *)(uintptr_t)0xa5f3e329); } TEST_END -- GitLab From 44df4a45cf587db8adee7edff4acfb96bfd3d670 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 27 Oct 2016 21:29:59 -0700 Subject: [PATCH 133/544] Explicitly cast negative constants meant for use as unsigned. --- test/unit/util.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/unit/util.c b/test/unit/util.c index c958dc0f..b1f9abd9 100644 --- a/test/unit/util.c +++ b/test/unit/util.c @@ -75,6 +75,7 @@ TEST_BEGIN(test_malloc_strtoumax) }; #define ERR(e) e, #e #define KUMAX(x) ((uintmax_t)x##ULL) +#define KSMAX(x) ((uintmax_t)(intmax_t)x##LL) struct test_s tests[] = { {"0", "0", -1, ERR(EINVAL), UINTMAX_MAX}, {"0", "0", 1, ERR(EINVAL), UINTMAX_MAX}, @@ -87,13 +88,13 @@ TEST_BEGIN(test_malloc_strtoumax) {"42", "", 0, ERR(0), KUMAX(42)}, {"+42", "", 0, ERR(0), KUMAX(42)}, - {"-42", "", 0, ERR(0), KUMAX(-42)}, + {"-42", "", 0, ERR(0), KSMAX(-42)}, {"042", "", 0, ERR(0), KUMAX(042)}, {"+042", "", 0, ERR(0), KUMAX(042)}, - {"-042", "", 0, ERR(0), KUMAX(-042)}, + {"-042", "", 0, ERR(0), KSMAX(-042)}, {"0x42", "", 0, ERR(0), KUMAX(0x42)}, {"+0x42", "", 0, ERR(0), KUMAX(0x42)}, - {"-0x42", "", 0, ERR(0), KUMAX(-0x42)}, + {"-0x42", "", 0, ERR(0), KSMAX(-0x42)}, {"0", "", 0, ERR(0), KUMAX(0)}, {"1", "", 0, ERR(0), KUMAX(1)}, @@ -130,6 +131,7 @@ TEST_BEGIN(test_malloc_strtoumax) }; #undef ERR #undef KUMAX +#undef KSMAX unsigned i; for (i = 0; i < sizeof(tests)/sizeof(struct test_s); i++) { -- GitLab From 977103c897225a4ab0380f09adc67b4c43143521 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 27 Oct 2016 21:31:25 -0700 Subject: [PATCH 134/544] Uniformly cast mallctl[bymib]() oldp/newp arguments to (void *). This avoids warnings in some cases, and is otherwise generally good hygiene. --- .../vc2015/test_threads/test_threads.cpp | 6 +- src/stats.c | 44 +++-- src/tcache.c | 4 +- src/util.c | 2 +- test/integration/MALLOCX_ARENA.c | 4 +- test/integration/allocated.c | 17 +- test/integration/extent.c | 27 +-- test/integration/mallocx.c | 4 +- test/integration/overflow.c | 8 +- test/integration/rallocx.c | 4 +- test/integration/thread_arena.c | 10 +- test/integration/thread_tcache_enabled.c | 39 ++-- test/integration/xallocx.c | 8 +- test/unit/arena_reset.c | 8 +- test/unit/decay.c | 48 ++--- test/unit/extent_quantize.c | 18 +- test/unit/mallctl.c | 178 ++++++++++-------- test/unit/prof_accum.c | 5 +- test/unit/prof_active.c | 5 +- test/unit/prof_gdump.c | 13 +- test/unit/prof_idump.c | 5 +- test/unit/prof_reset.c | 13 +- test/unit/prof_thread_name.c | 22 ++- test/unit/size_classes.c | 8 +- test/unit/stats.c | 175 +++++++++-------- 25 files changed, 358 insertions(+), 317 deletions(-) diff --git a/msvc/projects/vc2015/test_threads/test_threads.cpp b/msvc/projects/vc2015/test_threads/test_threads.cpp index c8cb7d66..a3d1a792 100644 --- a/msvc/projects/vc2015/test_threads/test_threads.cpp +++ b/msvc/projects/vc2015/test_threads/test_threads.cpp @@ -21,7 +21,7 @@ int test_threads() je_malloc_conf = "narenas:3"; int narenas = 0; size_t sz = sizeof(narenas); - je_mallctl("opt.narenas", &narenas, &sz, NULL, 0); + je_mallctl("opt.narenas", (void *)&narenas, &sz, NULL, 0); if (narenas != 3) { printf("Error: unexpected number of arenas: %d\n", narenas); return 1; @@ -33,7 +33,7 @@ int test_threads() je_malloc_stats_print(NULL, NULL, NULL); size_t allocated1; size_t sz1 = sizeof(allocated1); - je_mallctl("stats.active", &allocated1, &sz1, NULL, 0); + je_mallctl("stats.active", (void *)&allocated1, &sz1, NULL, 0); printf("\nPress Enter to start threads...\n"); getchar(); printf("Starting %d threads x %d x %d iterations...\n", numThreads, numIter1, numIter2); @@ -78,7 +78,7 @@ int test_threads() } je_malloc_stats_print(NULL, NULL, NULL); size_t allocated2; - je_mallctl("stats.active", &allocated2, &sz1, NULL, 0); + je_mallctl("stats.active", (void *)&allocated2, &sz1, NULL, 0); size_t leaked = allocated2 - allocated1; printf("\nDone. Leaked: %zd bytes\n", leaked); bool failed = leaked > 65536; // in case C++ runtime allocated something (e.g. iostream locale or facet) diff --git a/src/stats.c b/src/stats.c index ca716d5e..689299fa 100644 --- a/src/stats.c +++ b/src/stats.c @@ -3,7 +3,7 @@ #define CTL_GET(n, v, t) do { \ size_t sz = sizeof(t); \ - xmallctl(n, v, &sz, NULL, 0); \ + xmallctl(n, (void *)v, &sz, NULL, 0); \ } while (0) #define CTL_M2_GET(n, i, v, t) do { \ @@ -12,7 +12,7 @@ size_t sz = sizeof(t); \ xmallctlnametomib(n, mib, &miblen); \ mib[2] = (i); \ - xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \ + xmallctlbymib(mib, miblen, (void *)v, &sz, NULL, 0); \ } while (0) #define CTL_M2_M4_GET(n, i, j, v, t) do { \ @@ -22,7 +22,7 @@ xmallctlnametomib(n, mib, &miblen); \ mib[2] = (i); \ mib[4] = (j); \ - xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \ + xmallctlbymib(mib, miblen, (void *)v, &sz, NULL, 0); \ } while (0) /******************************************************************************/ @@ -368,45 +368,51 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, "config.malloc_conf: \"%s\"\n", config_malloc_conf); #define OPT_WRITE_BOOL(n) \ - if (je_mallctl("opt."#n, &bv, &bsz, NULL, 0) == 0) { \ + if (je_mallctl("opt."#n, (void *)&bv, &bsz, NULL, 0) == \ + 0) { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %s\n", bv ? "true" : "false"); \ } #define OPT_WRITE_BOOL_MUTABLE(n, m) { \ bool bv2; \ - if (je_mallctl("opt."#n, &bv, &bsz, NULL, 0) == 0 && \ - je_mallctl(#m, &bv2, &bsz, NULL, 0) == 0) { \ + if (je_mallctl("opt."#n, (void *)&bv, &bsz, NULL, 0) == \ + 0 && je_mallctl(#m, &bv2, &bsz, NULL, 0) == 0) { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %s ("#m": %s)\n", bv ? "true" \ : "false", bv2 ? "true" : "false"); \ } \ } #define OPT_WRITE_UNSIGNED(n) \ - if (je_mallctl("opt."#n, &uv, &usz, NULL, 0) == 0) { \ + if (je_mallctl("opt."#n, (void *)&uv, &usz, NULL, 0) == \ + 0) { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %u\n", uv); \ } #define OPT_WRITE_SIZE_T(n) \ - if (je_mallctl("opt."#n, &sv, &ssz, NULL, 0) == 0) { \ + if (je_mallctl("opt."#n, (void *)&sv, &ssz, NULL, 0) == \ + 0) { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %zu\n", sv); \ } #define OPT_WRITE_SSIZE_T(n) \ - if (je_mallctl("opt."#n, &ssv, &sssz, NULL, 0) == 0) { \ + if (je_mallctl("opt."#n, (void *)&ssv, &sssz, NULL, 0) \ + == 0) { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %zd\n", ssv); \ } #define OPT_WRITE_SSIZE_T_MUTABLE(n, m) { \ ssize_t ssv2; \ - if (je_mallctl("opt."#n, &ssv, &sssz, NULL, 0) == 0 && \ - je_mallctl(#m, &ssv2, &sssz, NULL, 0) == 0) { \ + if (je_mallctl("opt."#n, (void *)&ssv, &sssz, NULL, 0) \ + == 0 && je_mallctl(#m, &ssv2, &sssz, NULL, 0) == \ + 0) { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %zd ("#m": %zd)\n", \ ssv, ssv2); \ } \ } #define OPT_WRITE_CHAR_P(n) \ - if (je_mallctl("opt."#n, &cpv, &cpsz, NULL, 0) == 0) { \ + if (je_mallctl("opt."#n, (void *)&cpv, &cpsz, NULL, 0) \ + == 0) { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": \"%s\"\n", cpv); \ } @@ -462,11 +468,13 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "Unused dirty page decay time: %zd%s\n", ssv, (ssv < 0) ? " (no decay)" : ""); - if (je_mallctl("arenas.tcache_max", &sv, &ssz, NULL, 0) == 0) { + if (je_mallctl("arenas.tcache_max", (void *)&sv, &ssz, NULL, 0) + == 0) { malloc_cprintf(write_cb, cbopaque, "Maximum thread-cached size class: %zu\n", sv); } - if (je_mallctl("opt.prof", &bv, &bsz, NULL, 0) == 0 && bv) { + if (je_mallctl("opt.prof", (void *)&bv, &bsz, NULL, 0) == 0 && + bv) { CTL_GET("prof.lg_sample", &sv, size_t); malloc_cprintf(write_cb, cbopaque, "Average profile sample interval: %"FMTu64 @@ -509,8 +517,8 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, unsigned i, ninitialized; isz = sizeof(bool) * narenas; - xmallctl("arenas.initialized", initialized, - &isz, NULL, 0); + xmallctl("arenas.initialized", + (void *)initialized, &isz, NULL, 0); for (i = ninitialized = 0; i < narenas; i++) { if (initialized[i]) ninitialized++; @@ -538,8 +546,8 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, unsigned i; isz = sizeof(bool) * narenas; - xmallctl("arenas.initialized", initialized, - &isz, NULL, 0); + xmallctl("arenas.initialized", + (void *)initialized, &isz, NULL, 0); for (i = 0; i < narenas; i++) { if (initialized[i]) { diff --git a/src/tcache.c b/src/tcache.c index 98c18a04..7f5b291c 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -502,10 +502,10 @@ tcache_boot(tsdn_t *tsdn) unsigned i; /* If necessary, clamp opt_lg_tcache_max. */ - if (opt_lg_tcache_max < 0 || (1U << opt_lg_tcache_max) < SMALL_MAXCLASS) + if (opt_lg_tcache_max < 0 || (ZU(1) << opt_lg_tcache_max) < SMALL_MAXCLASS) tcache_maxclass = SMALL_MAXCLASS; else - tcache_maxclass = (1U << opt_lg_tcache_max); + tcache_maxclass = (ZU(1) << opt_lg_tcache_max); nhbins = size2index(tcache_maxclass) + 1; diff --git a/src/util.c b/src/util.c index a1c4a2a4..881a7fd1 100644 --- a/src/util.c +++ b/src/util.c @@ -200,7 +200,7 @@ malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base) p++; } if (neg) - ret = -ret; + ret = (uintmax_t)(-((intmax_t)ret)); if (p == ns) { /* No conversion performed. */ diff --git a/test/integration/MALLOCX_ARENA.c b/test/integration/MALLOCX_ARENA.c index 30c203ae..910a096f 100644 --- a/test/integration/MALLOCX_ARENA.c +++ b/test/integration/MALLOCX_ARENA.c @@ -19,8 +19,8 @@ thd_start(void *arg) size_t sz; sz = sizeof(arena_ind); - assert_d_eq(mallctl("arenas.extend", &arena_ind, &sz, NULL, 0), 0, - "Error in arenas.extend"); + assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, NULL, 0), + 0, "Error in arenas.extend"); if (thread_ind % 4 != 3) { size_t mib[3]; diff --git a/test/integration/allocated.c b/test/integration/allocated.c index 3630e80c..6ce145b3 100644 --- a/test/integration/allocated.c +++ b/test/integration/allocated.c @@ -18,14 +18,14 @@ thd_start(void *arg) size_t sz, usize; sz = sizeof(a0); - if ((err = mallctl("thread.allocated", &a0, &sz, NULL, 0))) { + if ((err = mallctl("thread.allocated", (void *)&a0, &sz, NULL, 0))) { if (err == ENOENT) goto label_ENOENT; test_fail("%s(): Error in mallctl(): %s", __func__, strerror(err)); } sz = sizeof(ap0); - if ((err = mallctl("thread.allocatedp", &ap0, &sz, NULL, 0))) { + if ((err = mallctl("thread.allocatedp", (void *)&ap0, &sz, NULL, 0))) { if (err == ENOENT) goto label_ENOENT; test_fail("%s(): Error in mallctl(): %s", __func__, @@ -36,14 +36,15 @@ thd_start(void *arg) "storage"); sz = sizeof(d0); - if ((err = mallctl("thread.deallocated", &d0, &sz, NULL, 0))) { + if ((err = mallctl("thread.deallocated", (void *)&d0, &sz, NULL, 0))) { if (err == ENOENT) goto label_ENOENT; test_fail("%s(): Error in mallctl(): %s", __func__, strerror(err)); } sz = sizeof(dp0); - if ((err = mallctl("thread.deallocatedp", &dp0, &sz, NULL, 0))) { + if ((err = mallctl("thread.deallocatedp", (void *)&dp0, &sz, NULL, + 0))) { if (err == ENOENT) goto label_ENOENT; test_fail("%s(): Error in mallctl(): %s", __func__, @@ -57,9 +58,9 @@ thd_start(void *arg) assert_ptr_not_null(p, "Unexpected malloc() error"); sz = sizeof(a1); - mallctl("thread.allocated", &a1, &sz, NULL, 0); + mallctl("thread.allocated", (void *)&a1, &sz, NULL, 0); sz = sizeof(ap1); - mallctl("thread.allocatedp", &ap1, &sz, NULL, 0); + mallctl("thread.allocatedp", (void *)&ap1, &sz, NULL, 0); assert_u64_eq(*ap1, a1, "Dereferenced \"thread.allocatedp\" value should equal " "\"thread.allocated\" value"); @@ -74,9 +75,9 @@ thd_start(void *arg) free(p); sz = sizeof(d1); - mallctl("thread.deallocated", &d1, &sz, NULL, 0); + mallctl("thread.deallocated", (void *)&d1, &sz, NULL, 0); sz = sizeof(dp1); - mallctl("thread.deallocatedp", &dp1, &sz, NULL, 0); + mallctl("thread.deallocatedp", (void *)&dp1, &sz, NULL, 0); assert_u64_eq(*dp1, d1, "Dereferenced \"thread.deallocatedp\" value should equal " "\"thread.deallocated\" value"); diff --git a/test/integration/extent.c b/test/integration/extent.c index 8acdad82..2af20ce2 100644 --- a/test/integration/extent.c +++ b/test/integration/extent.c @@ -194,8 +194,8 @@ TEST_BEGIN(test_extent) bool xallocx_success_a, xallocx_success_b, xallocx_success_c; sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.extend", &arena_ind, &sz, NULL, 0), 0, - "Unexpected mallctl() failure"); + assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, NULL, 0), + 0, "Unexpected mallctl() failure"); flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; /* Install custom extent hooks. */ @@ -205,8 +205,9 @@ TEST_BEGIN(test_extent) hooks_mib[1] = (size_t)arena_ind; old_size = sizeof(extent_hooks_t *); new_size = sizeof(extent_hooks_t *); - assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, &old_hooks, &old_size, - &new_hooks, new_size), 0, "Unexpected extent_hooks error"); + assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks, + &old_size, (void *)&new_hooks, new_size), 0, + "Unexpected extent_hooks error"); orig_hooks = old_hooks; assert_ptr_ne(old_hooks->alloc, extent_alloc, "Unexpected alloc error"); assert_ptr_ne(old_hooks->dalloc, extent_dalloc, @@ -221,12 +222,12 @@ TEST_BEGIN(test_extent) /* Get large size classes. */ sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.lextent.0.size", &large0, &sz, NULL, 0), 0, - "Unexpected arenas.lextent.0.size failure"); - assert_d_eq(mallctl("arenas.lextent.1.size", &large1, &sz, NULL, 0), 0, - "Unexpected arenas.lextent.1.size failure"); - assert_d_eq(mallctl("arenas.lextent.2.size", &large2, &sz, NULL, 0), 0, - "Unexpected arenas.lextent.2.size failure"); + assert_d_eq(mallctl("arenas.lextent.0.size", (void *)&large0, &sz, NULL, + 0), 0, "Unexpected arenas.lextent.0.size failure"); + assert_d_eq(mallctl("arenas.lextent.1.size", (void *)&large1, &sz, NULL, + 0), 0, "Unexpected arenas.lextent.1.size failure"); + assert_d_eq(mallctl("arenas.lextent.2.size", (void *)&large2, &sz, NULL, + 0), 0, "Unexpected arenas.lextent.2.size failure"); /* Test dalloc/decommit/purge cascade. */ purge_miblen = sizeof(purge_mib)/sizeof(size_t); @@ -287,9 +288,9 @@ TEST_BEGIN(test_extent) /* Restore extent hooks. */ assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, NULL, NULL, - &old_hooks, new_size), 0, "Unexpected extent_hooks error"); - assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, &old_hooks, &old_size, - NULL, 0), 0, "Unexpected extent_hooks error"); + (void *)&old_hooks, new_size), 0, "Unexpected extent_hooks error"); + assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks, + &old_size, NULL, 0), 0, "Unexpected extent_hooks error"); assert_ptr_eq(old_hooks, orig_hooks, "Unexpected hooks error"); assert_ptr_eq(old_hooks->alloc, orig_hooks->alloc, "Unexpected alloc error"); diff --git a/test/integration/mallocx.c b/test/integration/mallocx.c index 9d623eb7..4fd290c0 100644 --- a/test/integration/mallocx.c +++ b/test/integration/mallocx.c @@ -11,7 +11,7 @@ get_nsizes_impl(const char *cmd) size_t z; z = sizeof(unsigned); - assert_d_eq(mallctl(cmd, &ret, &z, NULL, 0), 0, + assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctl(\"%s\", ...) failure", cmd); return (ret); @@ -37,7 +37,7 @@ get_size_impl(const char *cmd, size_t ind) 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd); mib[2] = ind; z = sizeof(size_t); - assert_d_eq(mallctlbymib(mib, miblen, &ret, &z, NULL, 0), + assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); return (ret); diff --git a/test/integration/overflow.c b/test/integration/overflow.c index 8dea1c95..3e1e15f9 100644 --- a/test/integration/overflow.c +++ b/test/integration/overflow.c @@ -8,8 +8,8 @@ TEST_BEGIN(test_overflow) void *p; sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.nlextents", &nlextents, &sz, NULL, 0), 0, - "Unexpected mallctl() error"); + assert_d_eq(mallctl("arenas.nlextents", (void *)&nlextents, &sz, NULL, + 0), 0, "Unexpected mallctl() error"); miblen = sizeof(mib) / sizeof(size_t); assert_d_eq(mallctlnametomib("arenas.lextent.0.size", mib, &miblen), 0, @@ -17,8 +17,8 @@ TEST_BEGIN(test_overflow) mib[2] = nlextents - 1; sz = sizeof(size_t); - assert_d_eq(mallctlbymib(mib, miblen, &max_size_class, &sz, NULL, 0), 0, - "Unexpected mallctlbymib() error"); + assert_d_eq(mallctlbymib(mib, miblen, (void *)&max_size_class, &sz, + NULL, 0), 0, "Unexpected mallctlbymib() error"); assert_ptr_null(malloc(max_size_class + 1), "Expected OOM due to over-sized allocation request"); diff --git a/test/integration/rallocx.c b/test/integration/rallocx.c index 030fb479..dd89e8cb 100644 --- a/test/integration/rallocx.c +++ b/test/integration/rallocx.c @@ -7,7 +7,7 @@ get_nsizes_impl(const char *cmd) size_t z; z = sizeof(unsigned); - assert_d_eq(mallctl(cmd, &ret, &z, NULL, 0), 0, + assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctl(\"%s\", ...) failure", cmd); return (ret); @@ -33,7 +33,7 @@ get_size_impl(const char *cmd, size_t ind) 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd); mib[2] = ind; z = sizeof(size_t); - assert_d_eq(mallctlbymib(mib, miblen, &ret, &z, NULL, 0), + assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); return (ret); diff --git a/test/integration/thread_arena.c b/test/integration/thread_arena.c index 67be5351..7a35a635 100644 --- a/test/integration/thread_arena.c +++ b/test/integration/thread_arena.c @@ -16,8 +16,8 @@ thd_start(void *arg) free(p); size = sizeof(arena_ind); - if ((err = mallctl("thread.arena", &arena_ind, &size, &main_arena_ind, - sizeof(main_arena_ind)))) { + if ((err = mallctl("thread.arena", (void *)&arena_ind, &size, + (void *)&main_arena_ind, sizeof(main_arena_ind)))) { char buf[BUFERROR_BUF]; buferror(err, buf, sizeof(buf)); @@ -25,7 +25,8 @@ thd_start(void *arg) } size = sizeof(arena_ind); - if ((err = mallctl("thread.arena", &arena_ind, &size, NULL, 0))) { + if ((err = mallctl("thread.arena", (void *)&arena_ind, &size, NULL, + 0))) { char buf[BUFERROR_BUF]; buferror(err, buf, sizeof(buf)); @@ -50,7 +51,8 @@ TEST_BEGIN(test_thread_arena) assert_ptr_not_null(p, "Error in malloc()"); size = sizeof(arena_ind); - if ((err = mallctl("thread.arena", &arena_ind, &size, NULL, 0))) { + if ((err = mallctl("thread.arena", (void *)&arena_ind, &size, NULL, + 0))) { char buf[BUFERROR_BUF]; buferror(err, buf, sizeof(buf)); diff --git a/test/integration/thread_tcache_enabled.c b/test/integration/thread_tcache_enabled.c index f4e89c68..2c2825e1 100644 --- a/test/integration/thread_tcache_enabled.c +++ b/test/integration/thread_tcache_enabled.c @@ -16,7 +16,8 @@ thd_start(void *arg) bool e0, e1; sz = sizeof(bool); - if ((err = mallctl("thread.tcache.enabled", &e0, &sz, NULL, 0))) { + if ((err = mallctl("thread.tcache.enabled", (void *)&e0, &sz, NULL, + 0))) { if (err == ENOENT) { assert_false(config_tcache, "ENOENT should only be returned if tcache is " @@ -27,53 +28,53 @@ thd_start(void *arg) if (e0) { e1 = false; - assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), - 0, "Unexpected mallctl() error"); + assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz, + (void *)&e1, sz), 0, "Unexpected mallctl() error"); assert_true(e0, "tcache should be enabled"); } e1 = true; - assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, - "Unexpected mallctl() error"); + assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz, + (void *)&e1, sz), 0, "Unexpected mallctl() error"); assert_false(e0, "tcache should be disabled"); e1 = true; - assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, - "Unexpected mallctl() error"); + assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz, + (void *)&e1, sz), 0, "Unexpected mallctl() error"); assert_true(e0, "tcache should be enabled"); e1 = false; - assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, - "Unexpected mallctl() error"); + assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz, + (void *)&e1, sz), 0, "Unexpected mallctl() error"); assert_true(e0, "tcache should be enabled"); e1 = false; - assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, - "Unexpected mallctl() error"); + assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz, + (void *)&e1, sz), 0, "Unexpected mallctl() error"); assert_false(e0, "tcache should be disabled"); free(malloc(1)); e1 = true; - assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, - "Unexpected mallctl() error"); + assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz, + (void *)&e1, sz), 0, "Unexpected mallctl() error"); assert_false(e0, "tcache should be disabled"); free(malloc(1)); e1 = true; - assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, - "Unexpected mallctl() error"); + assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz, + (void *)&e1, sz), 0, "Unexpected mallctl() error"); assert_true(e0, "tcache should be enabled"); free(malloc(1)); e1 = false; - assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, - "Unexpected mallctl() error"); + assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz, + (void *)&e1, sz), 0, "Unexpected mallctl() error"); assert_true(e0, "tcache should be enabled"); free(malloc(1)); e1 = false; - assert_d_eq(mallctl("thread.tcache.enabled", &e0, &sz, &e1, sz), 0, - "Unexpected mallctl() error"); + assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz, + (void *)&e1, sz), 0, "Unexpected mallctl() error"); assert_false(e0, "tcache should be disabled"); free(malloc(1)); diff --git a/test/integration/xallocx.c b/test/integration/xallocx.c index 4dcf08da..f6083728 100644 --- a/test/integration/xallocx.c +++ b/test/integration/xallocx.c @@ -16,8 +16,8 @@ arena_ind(void) if (ind == 0) { size_t sz = sizeof(ind); - assert_d_eq(mallctl("arenas.extend", &ind, &sz, NULL, 0), 0, - "Unexpected mallctl failure creating arena"); + assert_d_eq(mallctl("arenas.extend", (void *)&ind, &sz, NULL, + 0), 0, "Unexpected mallctl failure creating arena"); } return (ind); @@ -78,7 +78,7 @@ get_nsizes_impl(const char *cmd) size_t z; z = sizeof(unsigned); - assert_d_eq(mallctl(cmd, &ret, &z, NULL, 0), 0, + assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctl(\"%s\", ...) failure", cmd); return (ret); @@ -111,7 +111,7 @@ get_size_impl(const char *cmd, size_t ind) 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd); mib[2] = ind; z = sizeof(size_t); - assert_d_eq(mallctlbymib(mib, miblen, &ret, &z, NULL, 0), + assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); return (ret); diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 61caf3c5..6c944b2e 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -11,7 +11,7 @@ get_nsizes_impl(const char *cmd) size_t z; z = sizeof(unsigned); - assert_d_eq(mallctl(cmd, &ret, &z, NULL, 0), 0, + assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctl(\"%s\", ...) failure", cmd); return (ret); @@ -44,7 +44,7 @@ get_size_impl(const char *cmd, size_t ind) 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd); mib[2] = ind; z = sizeof(size_t); - assert_d_eq(mallctlbymib(mib, miblen, &ret, &z, NULL, 0), + assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); return (ret); @@ -90,8 +90,8 @@ TEST_BEGIN(test_arena_reset) tsdn_t *tsdn; sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.extend", &arena_ind, &sz, NULL, 0), 0, - "Unexpected mallctl() failure"); + assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, NULL, 0), + 0, "Unexpected mallctl() failure"); flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; diff --git a/test/unit/decay.c b/test/unit/decay.c index 058a58cb..7efecf0f 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -38,8 +38,8 @@ TEST_BEGIN(test_decay_ticks) "Unexpected failure getting decay ticker"); sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.lextent.0.size", &large0, &sz, NULL, 0), 0, - "Unexpected mallctl failure"); + assert_d_eq(mallctl("arenas.lextent.0.size", (void *)&large0, &sz, NULL, + 0), 0, "Unexpected mallctl failure"); /* * Test the standard APIs using a large size class, since we can't @@ -170,8 +170,8 @@ TEST_BEGIN(test_decay_ticks) tcache_sizes[1] = 1; sz = sizeof(unsigned); - assert_d_eq(mallctl("tcache.create", &tcache_ind, &sz, NULL, 0), - 0, "Unexpected mallctl failure"); + assert_d_eq(mallctl("tcache.create", (void *)&tcache_ind, &sz, + NULL, 0), 0, "Unexpected mallctl failure"); for (i = 0; i < sizeof(tcache_sizes) / sizeof(size_t); i++) { sz = tcache_sizes[i]; @@ -188,7 +188,7 @@ TEST_BEGIN(test_decay_ticks) dallocx(p, MALLOCX_TCACHE(tcache_ind)); tick0 = ticker_read(decay_ticker); assert_d_eq(mallctl("tcache.flush", NULL, NULL, - &tcache_ind, sizeof(unsigned)), 0, + (void *)&tcache_ind, sizeof(unsigned)), 0, "Unexpected mallctl failure"); tick1 = ticker_read(decay_ticker); assert_u32_ne(tick1, tick0, @@ -221,8 +221,8 @@ TEST_BEGIN(test_decay_ticker) size_t tcache_max; sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.tcache_max", &tcache_max, &sz, NULL, - 0), 0, "Unexpected mallctl failure"); + assert_d_eq(mallctl("arenas.tcache_max", (void *)&tcache_max, + &sz, NULL, 0), 0, "Unexpected mallctl failure"); large = nallocx(tcache_max + 1, flags); } else { sz = sizeof(size_t); @@ -232,11 +232,11 @@ TEST_BEGIN(test_decay_ticker) assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl failure"); - assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(uint64_t)), 0, - "Unexpected mallctl failure"); + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, + sizeof(uint64_t)), 0, "Unexpected mallctl failure"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.npurge", &npurge0, &sz, NULL, 0), - config_stats ? 0 : ENOENT, "Unexpected mallctl result"); + assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge0, &sz, + NULL, 0), config_stats ? 0 : ENOENT, "Unexpected mallctl result"); for (i = 0; i < NPS; i++) { ps[i] = mallocx(large, flags); @@ -276,11 +276,11 @@ TEST_BEGIN(test_decay_ticker) assert_ptr_not_null(p, "Unexpected mallocx() failure"); dallocx(p, flags); } - assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(uint64_t)), 0, "Unexpected mallctl failure"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.npurge", &npurge1, &sz, - NULL, 0), config_stats ? 0 : ENOENT, + assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge1, + &sz, NULL, 0), config_stats ? 0 : ENOENT, "Unexpected mallctl result"); nstime_update(&time); @@ -304,16 +304,16 @@ TEST_BEGIN(test_decay_nonmonotonic) unsigned i, nupdates0; sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.lextent.0.size", &large0, &sz, NULL, 0), 0, - "Unexpected mallctl failure"); + assert_d_eq(mallctl("arenas.lextent.0.size", (void *)&large0, &sz, NULL, + 0), 0, "Unexpected mallctl failure"); assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl failure"); - assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(uint64_t)), 0, - "Unexpected mallctl failure"); + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, + sizeof(uint64_t)), 0, "Unexpected mallctl failure"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.npurge", &npurge0, &sz, NULL, 0), - config_stats ? 0 : ENOENT, "Unexpected mallctl result"); + assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge0, &sz, + NULL, 0), config_stats ? 0 : ENOENT, "Unexpected mallctl result"); nupdates_mock = 0; nstime_init(&time_mock, 0); @@ -339,11 +339,11 @@ TEST_BEGIN(test_decay_nonmonotonic) "Expected nstime_update() to be called"); } - assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(uint64_t)), 0, - "Unexpected mallctl failure"); + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, + sizeof(uint64_t)), 0, "Unexpected mallctl failure"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.npurge", &npurge1, &sz, NULL, 0), - config_stats ? 0 : ENOENT, "Unexpected mallctl result"); + assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge1, &sz, + NULL, 0), config_stats ? 0 : ENOENT, "Unexpected mallctl result"); if (config_stats) assert_u64_eq(npurge0, npurge1, "Unexpected purging occurred"); diff --git a/test/unit/extent_quantize.c b/test/unit/extent_quantize.c index d8928da0..43fa3604 100644 --- a/test/unit/extent_quantize.c +++ b/test/unit/extent_quantize.c @@ -13,7 +13,7 @@ TEST_BEGIN(test_small_extent_size) */ sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.nbins", &nbins, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arenas.nbins", (void *)&nbins, &sz, NULL, 0), 0, "Unexpected mallctl failure"); assert_d_eq(mallctlnametomib("arenas.bin.0.slab_size", mib, &miblen), 0, @@ -21,8 +21,8 @@ TEST_BEGIN(test_small_extent_size) for (i = 0; i < nbins; i++) { mib[2] = i; sz = sizeof(size_t); - assert_d_eq(mallctlbymib(mib, miblen, &extent_size, &sz, NULL, - 0), 0, "Unexpected mallctlbymib failure"); + assert_d_eq(mallctlbymib(mib, miblen, (void *)&extent_size, &sz, + NULL, 0), 0, "Unexpected mallctlbymib failure"); assert_zu_eq(extent_size, extent_size_quantize_floor(extent_size), "Small extent quantization should be a no-op " @@ -49,12 +49,12 @@ TEST_BEGIN(test_large_extent_size) */ sz = sizeof(bool); - assert_d_eq(mallctl("config.cache_oblivious", &cache_oblivious, &sz, - NULL, 0), 0, "Unexpected mallctl failure"); + assert_d_eq(mallctl("config.cache_oblivious", (void *)&cache_oblivious, + &sz, NULL, 0), 0, "Unexpected mallctl failure"); sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.nlextents", &nlextents, &sz, NULL, 0), 0, - "Unexpected mallctl failure"); + assert_d_eq(mallctl("arenas.nlextents", (void *)&nlextents, &sz, NULL, + 0), 0, "Unexpected mallctl failure"); assert_d_eq(mallctlnametomib("arenas.lextent.0.size", mib, &miblen), 0, "Unexpected mallctlnametomib failure"); @@ -63,8 +63,8 @@ TEST_BEGIN(test_large_extent_size) mib[2] = i; sz = sizeof(size_t); - assert_d_eq(mallctlbymib(mib, miblen, &lextent_size, &sz, NULL, - 0), 0, "Unexpected mallctlbymib failure"); + assert_d_eq(mallctlbymib(mib, miblen, (void *)&lextent_size, + &sz, NULL, 0), 0, "Unexpected mallctlbymib failure"); extent_size = cache_oblivious ? lextent_size + PAGE : lextent_size; floor = extent_size_quantize_floor(extent_size); diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 0e979a11..5073c7b1 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -12,16 +12,18 @@ TEST_BEGIN(test_mallctl_errors) EPERM, "mallctl() should return EPERM on attempt to write " "read-only value"); - assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)-1), - EINVAL, "mallctl() should return EINVAL for input size mismatch"); - assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)+1), - EINVAL, "mallctl() should return EINVAL for input size mismatch"); + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, + sizeof(epoch)-1), EINVAL, + "mallctl() should return EINVAL for input size mismatch"); + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, + sizeof(epoch)+1), EINVAL, + "mallctl() should return EINVAL for input size mismatch"); sz = sizeof(epoch)-1; - assert_d_eq(mallctl("epoch", &epoch, &sz, NULL, 0), EINVAL, + assert_d_eq(mallctl("epoch", (void *)&epoch, &sz, NULL, 0), EINVAL, "mallctl() should return EINVAL for output size mismatch"); sz = sizeof(epoch)+1; - assert_d_eq(mallctl("epoch", &epoch, &sz, NULL, 0), EINVAL, + assert_d_eq(mallctl("epoch", (void *)&epoch, &sz, NULL, 0), EINVAL, "mallctl() should return EINVAL for output size mismatch"); } TEST_END @@ -56,18 +58,20 @@ TEST_BEGIN(test_mallctlbymib_errors) assert_d_eq(mallctlnametomib("epoch", mib, &miblen), 0, "Unexpected mallctlnametomib() failure"); - assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &epoch, + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&epoch, sizeof(epoch)-1), EINVAL, "mallctlbymib() should return EINVAL for input size mismatch"); - assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &epoch, + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&epoch, sizeof(epoch)+1), EINVAL, "mallctlbymib() should return EINVAL for input size mismatch"); sz = sizeof(epoch)-1; - assert_d_eq(mallctlbymib(mib, miblen, &epoch, &sz, NULL, 0), EINVAL, + assert_d_eq(mallctlbymib(mib, miblen, (void *)&epoch, &sz, NULL, 0), + EINVAL, "mallctlbymib() should return EINVAL for output size mismatch"); sz = sizeof(epoch)+1; - assert_d_eq(mallctlbymib(mib, miblen, &epoch, &sz, NULL, 0), EINVAL, + assert_d_eq(mallctlbymib(mib, miblen, (void *)&epoch, &sz, NULL, 0), + EINVAL, "mallctlbymib() should return EINVAL for output size mismatch"); } TEST_END @@ -83,18 +87,19 @@ TEST_BEGIN(test_mallctl_read_write) assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size"); /* Read. */ - assert_d_eq(mallctl("epoch", &old_epoch, &sz, NULL, 0), 0, + assert_d_eq(mallctl("epoch", (void *)&old_epoch, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size"); /* Write. */ - assert_d_eq(mallctl("epoch", NULL, NULL, &new_epoch, sizeof(new_epoch)), - 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&new_epoch, + sizeof(new_epoch)), 0, "Unexpected mallctl() failure"); assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size"); /* Read+write. */ - assert_d_eq(mallctl("epoch", &old_epoch, &sz, &new_epoch, - sizeof(new_epoch)), 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("epoch", (void *)&old_epoch, &sz, + (void *)&new_epoch, sizeof(new_epoch)), 0, + "Unexpected mallctl() failure"); assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size"); } TEST_END @@ -120,8 +125,8 @@ TEST_BEGIN(test_mallctl_config) #define TEST_MALLCTL_CONFIG(config, t) do { \ t oldval; \ size_t sz = sizeof(oldval); \ - assert_d_eq(mallctl("config."#config, &oldval, &sz, NULL, 0), \ - 0, "Unexpected mallctl() failure"); \ + assert_d_eq(mallctl("config."#config, (void *)&oldval, &sz, \ + NULL, 0), 0, "Unexpected mallctl() failure"); \ assert_b_eq(oldval, config_##config, "Incorrect config value"); \ assert_zu_eq(sz, sizeof(oldval), "Unexpected output size"); \ } while (0) @@ -153,7 +158,8 @@ TEST_BEGIN(test_mallctl_opt) t oldval; \ size_t sz = sizeof(oldval); \ int expected = config_##config ? 0 : ENOENT; \ - int result = mallctl("opt."#opt, &oldval, &sz, NULL, 0); \ + int result = mallctl("opt."#opt, (void *)&oldval, &sz, NULL, \ + 0); \ assert_d_eq(result, expected, \ "Unexpected mallctl() result for opt."#opt); \ assert_zu_eq(sz, sizeof(oldval), "Unexpected output size"); \ @@ -191,7 +197,7 @@ TEST_BEGIN(test_manpage_example) size_t len, miblen; len = sizeof(nbins); - assert_d_eq(mallctl("arenas.nbins", &nbins, &len, NULL, 0), 0, + assert_d_eq(mallctl("arenas.nbins", (void *)&nbins, &len, NULL, 0), 0, "Unexpected mallctl() failure"); miblen = 4; @@ -202,8 +208,8 @@ TEST_BEGIN(test_manpage_example) mib[2] = i; len = sizeof(bin_size); - assert_d_eq(mallctlbymib(mib, miblen, &bin_size, &len, NULL, 0), - 0, "Unexpected mallctlbymib() failure"); + assert_d_eq(mallctlbymib(mib, miblen, (void *)&bin_size, &len, + NULL, 0), 0, "Unexpected mallctlbymib() failure"); /* Do something with bin_size... */ } } @@ -252,25 +258,25 @@ TEST_BEGIN(test_tcache) /* Create tcaches. */ for (i = 0; i < NTCACHES; i++) { sz = sizeof(unsigned); - assert_d_eq(mallctl("tcache.create", &tis[i], &sz, NULL, 0), 0, - "Unexpected mallctl() failure, i=%u", i); + assert_d_eq(mallctl("tcache.create", (void *)&tis[i], &sz, NULL, + 0), 0, "Unexpected mallctl() failure, i=%u", i); } /* Exercise tcache ID recycling. */ for (i = 0; i < NTCACHES; i++) { - assert_d_eq(mallctl("tcache.destroy", NULL, NULL, &tis[i], - sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u", - i); + assert_d_eq(mallctl("tcache.destroy", NULL, NULL, + (void *)&tis[i], sizeof(unsigned)), 0, + "Unexpected mallctl() failure, i=%u", i); } for (i = 0; i < NTCACHES; i++) { sz = sizeof(unsigned); - assert_d_eq(mallctl("tcache.create", &tis[i], &sz, NULL, 0), 0, - "Unexpected mallctl() failure, i=%u", i); + assert_d_eq(mallctl("tcache.create", (void *)&tis[i], &sz, NULL, + 0), 0, "Unexpected mallctl() failure, i=%u", i); } /* Flush empty tcaches. */ for (i = 0; i < NTCACHES; i++) { - assert_d_eq(mallctl("tcache.flush", NULL, NULL, &tis[i], + assert_d_eq(mallctl("tcache.flush", NULL, NULL, (void *)&tis[i], sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u", i); } @@ -315,16 +321,16 @@ TEST_BEGIN(test_tcache) /* Flush some non-empty tcaches. */ for (i = 0; i < NTCACHES/2; i++) { - assert_d_eq(mallctl("tcache.flush", NULL, NULL, &tis[i], + assert_d_eq(mallctl("tcache.flush", NULL, NULL, (void *)&tis[i], sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u", i); } /* Destroy tcaches. */ for (i = 0; i < NTCACHES; i++) { - assert_d_eq(mallctl("tcache.destroy", NULL, NULL, &tis[i], - sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u", - i); + assert_d_eq(mallctl("tcache.destroy", NULL, NULL, + (void *)&tis[i], sizeof(unsigned)), 0, + "Unexpected mallctl() failure, i=%u", i); } } TEST_END @@ -334,15 +340,17 @@ TEST_BEGIN(test_thread_arena) unsigned arena_old, arena_new, narenas; size_t sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0, - "Unexpected mallctl() failure"); + assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0), + 0, "Unexpected mallctl() failure"); assert_u_eq(narenas, opt_narenas, "Number of arenas incorrect"); arena_new = narenas - 1; - assert_d_eq(mallctl("thread.arena", &arena_old, &sz, &arena_new, - sizeof(unsigned)), 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("thread.arena", (void *)&arena_old, &sz, + (void *)&arena_new, sizeof(unsigned)), 0, + "Unexpected mallctl() failure"); arena_new = 0; - assert_d_eq(mallctl("thread.arena", &arena_old, &sz, &arena_new, - sizeof(unsigned)), 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("thread.arena", (void *)&arena_old, &sz, + (void *)&arena_new, sizeof(unsigned)), 0, + "Unexpected mallctl() failure"); } TEST_END @@ -351,25 +359,25 @@ TEST_BEGIN(test_arena_i_decay_time) ssize_t decay_time, orig_decay_time, prev_decay_time; size_t sz = sizeof(ssize_t); - assert_d_eq(mallctl("arena.0.decay_time", &orig_decay_time, &sz, + assert_d_eq(mallctl("arena.0.decay_time", (void *)&orig_decay_time, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); decay_time = -2; assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL, - &decay_time, sizeof(ssize_t)), EFAULT, + (void *)&decay_time, sizeof(ssize_t)), EFAULT, "Unexpected mallctl() success"); decay_time = 0x7fffffff; assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL, - &decay_time, sizeof(ssize_t)), 0, + (void *)&decay_time, sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); for (prev_decay_time = decay_time, decay_time = -1; decay_time < 20; prev_decay_time = decay_time, decay_time++) { ssize_t old_decay_time; - assert_d_eq(mallctl("arena.0.decay_time", &old_decay_time, - &sz, &decay_time, sizeof(ssize_t)), 0, + assert_d_eq(mallctl("arena.0.decay_time", (void *)&old_decay_time, + &sz, (void *)&decay_time, sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); assert_zd_eq(old_decay_time, prev_decay_time, "Unexpected old arena.0.decay_time"); @@ -387,8 +395,8 @@ TEST_BEGIN(test_arena_i_purge) assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl() failure"); - assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0, - "Unexpected mallctl() failure"); + assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0), + 0, "Unexpected mallctl() failure"); assert_d_eq(mallctlnametomib("arena.0.purge", mib, &miblen), 0, "Unexpected mallctlnametomib() failure"); mib[1] = narenas; @@ -407,8 +415,8 @@ TEST_BEGIN(test_arena_i_decay) assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0, "Unexpected mallctl() failure"); - assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0, - "Unexpected mallctl() failure"); + assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0), + 0, "Unexpected mallctl() failure"); assert_d_eq(mallctlnametomib("arena.0.decay", mib, &miblen), 0, "Unexpected mallctlnametomib() failure"); mib[1] = narenas; @@ -429,31 +437,35 @@ TEST_BEGIN(test_arena_i_dss) "Unexpected mallctlnametomib() error"); dss_prec_new = "disabled"; - assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, &dss_prec_new, - sizeof(dss_prec_new)), 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, + (void *)&dss_prec_new, sizeof(dss_prec_new)), 0, + "Unexpected mallctl() failure"); assert_str_ne(dss_prec_old, "primary", "Unexpected default for dss precedence"); - assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_new, &sz, &dss_prec_old, - sizeof(dss_prec_old)), 0, "Unexpected mallctl() failure"); - - assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, NULL, 0), 0, + assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_new, &sz, + (void *)&dss_prec_old, sizeof(dss_prec_old)), 0, "Unexpected mallctl() failure"); + + assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, NULL, + 0), 0, "Unexpected mallctl() failure"); assert_str_ne(dss_prec_old, "primary", "Unexpected value for dss precedence"); mib[1] = narenas_total_get(); dss_prec_new = "disabled"; - assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, &dss_prec_new, - sizeof(dss_prec_new)), 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, + (void *)&dss_prec_new, sizeof(dss_prec_new)), 0, + "Unexpected mallctl() failure"); assert_str_ne(dss_prec_old, "primary", "Unexpected default for dss precedence"); - assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_new, &sz, &dss_prec_old, - sizeof(dss_prec_new)), 0, "Unexpected mallctl() failure"); - - assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, NULL, 0), 0, + assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_new, &sz, + (void *)&dss_prec_old, sizeof(dss_prec_new)), 0, "Unexpected mallctl() failure"); + + assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, NULL, + 0), 0, "Unexpected mallctl() failure"); assert_str_ne(dss_prec_old, "primary", "Unexpected value for dss precedence"); } @@ -464,14 +476,14 @@ TEST_BEGIN(test_arenas_initialized) unsigned narenas; size_t sz = sizeof(narenas); - assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0, - "Unexpected mallctl() failure"); + assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0), + 0, "Unexpected mallctl() failure"); { VARIABLE_ARRAY(bool, initialized, narenas); sz = narenas * sizeof(bool); - assert_d_eq(mallctl("arenas.initialized", initialized, &sz, - NULL, 0), 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("arenas.initialized", (void *)initialized, + &sz, NULL, 0), 0, "Unexpected mallctl() failure"); } } TEST_END @@ -481,26 +493,26 @@ TEST_BEGIN(test_arenas_decay_time) ssize_t decay_time, orig_decay_time, prev_decay_time; size_t sz = sizeof(ssize_t); - assert_d_eq(mallctl("arenas.decay_time", &orig_decay_time, &sz, + assert_d_eq(mallctl("arenas.decay_time", (void *)&orig_decay_time, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); decay_time = -2; assert_d_eq(mallctl("arenas.decay_time", NULL, NULL, - &decay_time, sizeof(ssize_t)), EFAULT, + (void *)&decay_time, sizeof(ssize_t)), EFAULT, "Unexpected mallctl() success"); decay_time = 0x7fffffff; assert_d_eq(mallctl("arenas.decay_time", NULL, NULL, - &decay_time, sizeof(ssize_t)), 0, + (void *)&decay_time, sizeof(ssize_t)), 0, "Expected mallctl() failure"); for (prev_decay_time = decay_time, decay_time = -1; decay_time < 20; prev_decay_time = decay_time, decay_time++) { ssize_t old_decay_time; - assert_d_eq(mallctl("arenas.decay_time", &old_decay_time, - &sz, &decay_time, sizeof(ssize_t)), 0, - "Unexpected mallctl() failure"); + assert_d_eq(mallctl("arenas.decay_time", + (void *)&old_decay_time, &sz, (void *)&decay_time, + sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); assert_zd_eq(old_decay_time, prev_decay_time, "Unexpected old arenas.decay_time"); } @@ -513,8 +525,8 @@ TEST_BEGIN(test_arenas_constants) #define TEST_ARENAS_CONSTANT(t, name, expected) do { \ t name; \ size_t sz = sizeof(t); \ - assert_d_eq(mallctl("arenas."#name, &name, &sz, NULL, 0), 0, \ - "Unexpected mallctl() failure"); \ + assert_d_eq(mallctl("arenas."#name, (void *)&name, &sz, NULL, \ + 0), 0, "Unexpected mallctl() failure"); \ assert_zu_eq(name, expected, "Incorrect "#name" size"); \ } while (0) @@ -533,8 +545,8 @@ TEST_BEGIN(test_arenas_bin_constants) #define TEST_ARENAS_BIN_CONSTANT(t, name, expected) do { \ t name; \ size_t sz = sizeof(t); \ - assert_d_eq(mallctl("arenas.bin.0."#name, &name, &sz, NULL, 0), \ - 0, "Unexpected mallctl() failure"); \ + assert_d_eq(mallctl("arenas.bin.0."#name, (void *)&name, &sz, \ + NULL, 0), 0, "Unexpected mallctl() failure"); \ assert_zu_eq(name, expected, "Incorrect "#name" size"); \ } while (0) @@ -553,8 +565,8 @@ TEST_BEGIN(test_arenas_lextent_constants) #define TEST_ARENAS_LEXTENT_CONSTANT(t, name, expected) do { \ t name; \ size_t sz = sizeof(t); \ - assert_d_eq(mallctl("arenas.lextent.0."#name, &name, &sz, NULL, \ - 0), 0, "Unexpected mallctl() failure"); \ + assert_d_eq(mallctl("arenas.lextent.0."#name, (void *)&name, \ + &sz, NULL, 0), 0, "Unexpected mallctl() failure"); \ assert_zu_eq(name, expected, "Incorrect "#name" size"); \ } while (0) @@ -569,12 +581,12 @@ TEST_BEGIN(test_arenas_extend) unsigned narenas_before, arena, narenas_after; size_t sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.narenas", &narenas_before, &sz, NULL, 0), 0, - "Unexpected mallctl() failure"); - assert_d_eq(mallctl("arenas.extend", &arena, &sz, NULL, 0), 0, - "Unexpected mallctl() failure"); - assert_d_eq(mallctl("arenas.narenas", &narenas_after, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arenas.narenas", (void *)&narenas_before, &sz, + NULL, 0), 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("arenas.extend", (void *)&arena, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("arenas.narenas", (void *)&narenas_after, &sz, NULL, + 0), 0, "Unexpected mallctl() failure"); assert_u_eq(narenas_before+1, narenas_after, "Unexpected number of arenas before versus after extension"); @@ -588,8 +600,8 @@ TEST_BEGIN(test_stats_arenas) #define TEST_STATS_ARENAS(t, name) do { \ t name; \ size_t sz = sizeof(t); \ - assert_d_eq(mallctl("stats.arenas.0."#name, &name, &sz, NULL, \ - 0), 0, "Unexpected mallctl() failure"); \ + assert_d_eq(mallctl("stats.arenas.0."#name, (void *)&name, &sz, \ + NULL, 0), 0, "Unexpected mallctl() failure"); \ } while (0) TEST_STATS_ARENAS(unsigned, nthreads); diff --git a/test/unit/prof_accum.c b/test/unit/prof_accum.c index fd229e0f..d941b5bc 100644 --- a/test/unit/prof_accum.c +++ b/test/unit/prof_accum.c @@ -68,8 +68,9 @@ TEST_BEGIN(test_idump) test_skip_if(!config_prof); active = true; - assert_d_eq(mallctl("prof.active", NULL, NULL, &active, sizeof(active)), - 0, "Unexpected mallctl failure while activating profiling"); + assert_d_eq(mallctl("prof.active", NULL, NULL, (void *)&active, + sizeof(active)), 0, + "Unexpected mallctl failure while activating profiling"); prof_dump_open = prof_dump_open_intercept; diff --git a/test/unit/prof_active.c b/test/unit/prof_active.c index 81490957..d00943a4 100644 --- a/test/unit/prof_active.c +++ b/test/unit/prof_active.c @@ -12,7 +12,7 @@ mallctl_bool_get(const char *name, bool expected, const char *func, int line) size_t sz; sz = sizeof(old); - assert_d_eq(mallctl(name, &old, &sz, NULL, 0), 0, + assert_d_eq(mallctl(name, (void *)&old, &sz, NULL, 0), 0, "%s():%d: Unexpected mallctl failure reading %s", func, line, name); assert_b_eq(old, expected, "%s():%d: Unexpected %s value", func, line, name); @@ -26,7 +26,8 @@ mallctl_bool_set(const char *name, bool old_expected, bool val_new, size_t sz; sz = sizeof(old); - assert_d_eq(mallctl(name, &old, &sz, &val_new, sizeof(val_new)), 0, + assert_d_eq(mallctl(name, (void *)&old, &sz, (void *)&val_new, + sizeof(val_new)), 0, "%s():%d: Unexpected mallctl failure reading/writing %s", func, line, name); assert_b_eq(old, old_expected, "%s():%d: Unexpected %s value", func, diff --git a/test/unit/prof_gdump.c b/test/unit/prof_gdump.c index ca93f300..cb99acdf 100644 --- a/test/unit/prof_gdump.c +++ b/test/unit/prof_gdump.c @@ -28,8 +28,9 @@ TEST_BEGIN(test_gdump) test_skip_if(!config_prof); active = true; - assert_d_eq(mallctl("prof.active", NULL, NULL, &active, sizeof(active)), - 0, "Unexpected mallctl failure while activating profiling"); + assert_d_eq(mallctl("prof.active", NULL, NULL, (void *)&active, + sizeof(active)), 0, + "Unexpected mallctl failure while activating profiling"); prof_dump_open = prof_dump_open_intercept; @@ -45,8 +46,8 @@ TEST_BEGIN(test_gdump) gdump = false; sz = sizeof(gdump_old); - assert_d_eq(mallctl("prof.gdump", &gdump_old, &sz, &gdump, - sizeof(gdump)), 0, + assert_d_eq(mallctl("prof.gdump", (void *)&gdump_old, &sz, + (void *)&gdump, sizeof(gdump)), 0, "Unexpected mallctl failure while disabling prof.gdump"); assert(gdump_old); did_prof_dump_open = false; @@ -56,8 +57,8 @@ TEST_BEGIN(test_gdump) gdump = true; sz = sizeof(gdump_old); - assert_d_eq(mallctl("prof.gdump", &gdump_old, &sz, &gdump, - sizeof(gdump)), 0, + assert_d_eq(mallctl("prof.gdump", (void *)&gdump_old, &sz, + (void *)&gdump, sizeof(gdump)), 0, "Unexpected mallctl failure while enabling prof.gdump"); assert(!gdump_old); did_prof_dump_open = false; diff --git a/test/unit/prof_idump.c b/test/unit/prof_idump.c index 2b0639d8..c293350f 100644 --- a/test/unit/prof_idump.c +++ b/test/unit/prof_idump.c @@ -36,8 +36,9 @@ TEST_BEGIN(test_idump) test_skip_if(!config_prof); active = true; - assert_d_eq(mallctl("prof.active", NULL, NULL, &active, sizeof(active)), - 0, "Unexpected mallctl failure while activating profiling"); + assert_d_eq(mallctl("prof.active", NULL, NULL, (void *)&active, + sizeof(active)), 0, + "Unexpected mallctl failure while activating profiling"); prof_dump_open = prof_dump_open_intercept; diff --git a/test/unit/prof_reset.c b/test/unit/prof_reset.c index 5ae45fd2..59d70796 100644 --- a/test/unit/prof_reset.c +++ b/test/unit/prof_reset.c @@ -20,8 +20,8 @@ static void set_prof_active(bool active) { - assert_d_eq(mallctl("prof.active", NULL, NULL, &active, sizeof(active)), - 0, "Unexpected mallctl failure"); + assert_d_eq(mallctl("prof.active", NULL, NULL, (void *)&active, + sizeof(active)), 0, "Unexpected mallctl failure"); } static size_t @@ -30,7 +30,8 @@ get_lg_prof_sample(void) size_t lg_prof_sample; size_t sz = sizeof(size_t); - assert_d_eq(mallctl("prof.lg_sample", &lg_prof_sample, &sz, NULL, 0), 0, + assert_d_eq(mallctl("prof.lg_sample", (void *)&lg_prof_sample, &sz, + NULL, 0), 0, "Unexpected mallctl failure while reading profiling sample rate"); return (lg_prof_sample); } @@ -39,7 +40,7 @@ static void do_prof_reset(size_t lg_prof_sample) { assert_d_eq(mallctl("prof.reset", NULL, NULL, - &lg_prof_sample, sizeof(size_t)), 0, + (void *)&lg_prof_sample, sizeof(size_t)), 0, "Unexpected mallctl failure while resetting profile data"); assert_zu_eq(lg_prof_sample, get_lg_prof_sample(), "Expected profile sample rate change"); @@ -54,8 +55,8 @@ TEST_BEGIN(test_prof_reset_basic) test_skip_if(!config_prof); sz = sizeof(size_t); - assert_d_eq(mallctl("opt.lg_prof_sample", &lg_prof_sample_orig, &sz, - NULL, 0), 0, + assert_d_eq(mallctl("opt.lg_prof_sample", (void *)&lg_prof_sample_orig, + &sz, NULL, 0), 0, "Unexpected mallctl failure while reading profiling sample rate"); assert_zu_eq(lg_prof_sample_orig, 0, "Unexpected profiling sample rate"); diff --git a/test/unit/prof_thread_name.c b/test/unit/prof_thread_name.c index f501158d..9ec54977 100644 --- a/test/unit/prof_thread_name.c +++ b/test/unit/prof_thread_name.c @@ -12,8 +12,9 @@ mallctl_thread_name_get_impl(const char *thread_name_expected, const char *func, size_t sz; sz = sizeof(thread_name_old); - assert_d_eq(mallctl("thread.prof.name", &thread_name_old, &sz, NULL, 0), - 0, "%s():%d: Unexpected mallctl failure reading thread.prof.name", + assert_d_eq(mallctl("thread.prof.name", (void *)&thread_name_old, &sz, + NULL, 0), 0, + "%s():%d: Unexpected mallctl failure reading thread.prof.name", func, line); assert_str_eq(thread_name_old, thread_name_expected, "%s():%d: Unexpected thread.prof.name value", func, line); @@ -26,8 +27,8 @@ mallctl_thread_name_set_impl(const char *thread_name, const char *func, int line) { - assert_d_eq(mallctl("thread.prof.name", NULL, NULL, &thread_name, - sizeof(thread_name)), 0, + assert_d_eq(mallctl("thread.prof.name", NULL, NULL, + (void *)&thread_name, sizeof(thread_name)), 0, "%s():%d: Unexpected mallctl failure reading thread.prof.name", func, line); mallctl_thread_name_get_impl(thread_name, func, line); @@ -46,15 +47,15 @@ TEST_BEGIN(test_prof_thread_name_validation) /* NULL input shouldn't be allowed. */ thread_name = NULL; - assert_d_eq(mallctl("thread.prof.name", NULL, NULL, &thread_name, - sizeof(thread_name)), EFAULT, + assert_d_eq(mallctl("thread.prof.name", NULL, NULL, + (void *)&thread_name, sizeof(thread_name)), EFAULT, "Unexpected mallctl result writing \"%s\" to thread.prof.name", thread_name); /* '\n' shouldn't be allowed. */ thread_name = "hi\nthere"; - assert_d_eq(mallctl("thread.prof.name", NULL, NULL, &thread_name, - sizeof(thread_name)), EFAULT, + assert_d_eq(mallctl("thread.prof.name", NULL, NULL, + (void *)&thread_name, sizeof(thread_name)), EFAULT, "Unexpected mallctl result writing \"%s\" to thread.prof.name", thread_name); @@ -64,8 +65,9 @@ TEST_BEGIN(test_prof_thread_name_validation) size_t sz; sz = sizeof(thread_name_old); - assert_d_eq(mallctl("thread.prof.name", &thread_name_old, &sz, - &thread_name, sizeof(thread_name)), EPERM, + assert_d_eq(mallctl("thread.prof.name", + (void *)&thread_name_old, &sz, (void *)&thread_name, + sizeof(thread_name)), EPERM, "Unexpected mallctl result writing \"%s\" to " "thread.prof.name", thread_name); } diff --git a/test/unit/size_classes.c b/test/unit/size_classes.c index f5a5873d..d4875549 100644 --- a/test/unit/size_classes.c +++ b/test/unit/size_classes.c @@ -8,8 +8,8 @@ get_max_size_class(void) size_t sz, miblen, max_size_class; sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.nlextents", &nlextents, &sz, NULL, 0), 0, - "Unexpected mallctl() error"); + assert_d_eq(mallctl("arenas.nlextents", (void *)&nlextents, &sz, NULL, + 0), 0, "Unexpected mallctl() error"); miblen = sizeof(mib) / sizeof(size_t); assert_d_eq(mallctlnametomib("arenas.lextent.0.size", mib, &miblen), 0, @@ -17,8 +17,8 @@ get_max_size_class(void) mib[2] = nlextents - 1; sz = sizeof(size_t); - assert_d_eq(mallctlbymib(mib, miblen, &max_size_class, &sz, NULL, 0), 0, - "Unexpected mallctlbymib() error"); + assert_d_eq(mallctlbymib(mib, miblen, (void *)&max_size_class, &sz, + NULL, 0), 0, "Unexpected mallctlbymib() error"); return (max_size_class); } diff --git a/test/unit/stats.c b/test/unit/stats.c index ed0d3fe9..a99a88f0 100644 --- a/test/unit/stats.c +++ b/test/unit/stats.c @@ -6,14 +6,14 @@ TEST_BEGIN(test_stats_summary) int expected = config_stats ? 0 : ENOENT; sz = sizeof(size_t); - assert_d_eq(mallctl("stats.allocated", &allocated, &sz, NULL, 0), + assert_d_eq(mallctl("stats.allocated", (void *)&allocated, &sz, NULL, + 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.active", (void *)&active, &sz, NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.active", &active, &sz, NULL, 0), expected, - "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.resident", &resident, &sz, NULL, 0), + assert_d_eq(mallctl("stats.resident", (void *)&resident, &sz, NULL, 0), + expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.mapped", (void *)&mapped, &sz, NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.mapped", &mapped, &sz, NULL, 0), expected, - "Unexpected mallctl() result"); if (config_stats) { assert_zu_le(allocated, active, @@ -38,19 +38,21 @@ TEST_BEGIN(test_stats_large) p = mallocx(SMALL_MAXCLASS+1, 0); assert_ptr_not_null(p, "Unexpected mallocx() failure"); - assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, - "Unexpected mallctl() failure"); + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), + 0, "Unexpected mallctl() failure"); sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.large.allocated", &allocated, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.large.allocated", + (void *)&allocated, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.large.nmalloc", &nmalloc, &sz, NULL, - 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.large.ndalloc", &ndalloc, &sz, NULL, - 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.large.nrequests", &nrequests, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.large.nmalloc", (void *)&nmalloc, + &sz, NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.large.ndalloc", (void *)&ndalloc, + &sz, NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.large.nrequests", + (void *)&nrequests, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); if (config_stats) { assert_zu_gt(allocated, 0, @@ -76,8 +78,8 @@ TEST_BEGIN(test_stats_arenas_summary) uint64_t npurge, nmadvise, purged; arena = 0; - assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)), - 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("thread.arena", NULL, NULL, (void *)&arena, + sizeof(arena)), 0, "Unexpected mallctl() failure"); little = mallocx(SMALL_MAXCLASS, 0); assert_ptr_not_null(little, "Unexpected mallocx() failure"); @@ -92,19 +94,19 @@ TEST_BEGIN(test_stats_arenas_summary) assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl() failure"); - assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, - "Unexpected mallctl() failure"); + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), + 0, "Unexpected mallctl() failure"); sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.mapped", &mapped, &sz, NULL, 0), - expected, "Unexepected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.mapped", (void *)&mapped, &sz, NULL, + 0), expected, "Unexepected mallctl() result"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.npurge", &npurge, &sz, NULL, 0), - expected, "Unexepected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.nmadvise", &nmadvise, &sz, NULL, 0), - expected, "Unexepected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.purged", &purged, &sz, NULL, 0), - expected, "Unexepected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge, &sz, NULL, + 0), expected, "Unexepected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.nmadvise", (void *)&nmadvise, &sz, + NULL, 0), expected, "Unexepected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.purged", (void *)&purged, &sz, NULL, + 0), expected, "Unexepected mallctl() result"); if (config_stats) { assert_u64_gt(npurge, 0, @@ -142,8 +144,8 @@ TEST_BEGIN(test_stats_arenas_small) no_lazy_lock(); /* Lazy locking would dodge tcache testing. */ arena = 0; - assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)), - 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("thread.arena", NULL, NULL, (void *)&arena, + sizeof(arena)), 0, "Unexpected mallctl() failure"); p = mallocx(SMALL_MAXCLASS, 0); assert_ptr_not_null(p, "Unexpected mallocx() failure"); @@ -151,19 +153,21 @@ TEST_BEGIN(test_stats_arenas_small) assert_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), config_tcache ? 0 : ENOENT, "Unexpected mallctl() result"); - assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, - "Unexpected mallctl() failure"); + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), + 0, "Unexpected mallctl() failure"); sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.small.allocated", &allocated, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.small.allocated", + (void *)&allocated, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.small.nmalloc", &nmalloc, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.small.ndalloc", &ndalloc, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.small.nrequests", &nrequests, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.small.nmalloc", (void *)&nmalloc, + &sz, NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.small.ndalloc", (void *)&ndalloc, + &sz, NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.small.nrequests", + (void *)&nrequests, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); if (config_stats) { assert_zu_gt(allocated, 0, @@ -189,23 +193,24 @@ TEST_BEGIN(test_stats_arenas_large) int expected = config_stats ? 0 : ENOENT; arena = 0; - assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)), - 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("thread.arena", NULL, NULL, (void *)&arena, + sizeof(arena)), 0, "Unexpected mallctl() failure"); p = mallocx((1U << LG_LARGE_MINCLASS), 0); assert_ptr_not_null(p, "Unexpected mallocx() failure"); - assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, - "Unexpected mallctl() failure"); + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), + 0, "Unexpected mallctl() failure"); sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.large.allocated", &allocated, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.large.allocated", + (void *)&allocated, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.large.nmalloc", &nmalloc, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.large.ndalloc", &ndalloc, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.large.nmalloc", (void *)&nmalloc, + &sz, NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.large.ndalloc", (void *)&ndalloc, + &sz, NULL, 0), expected, "Unexpected mallctl() result"); if (config_stats) { assert_zu_gt(allocated, 0, @@ -230,8 +235,8 @@ TEST_BEGIN(test_stats_arenas_bins) int expected = config_stats ? 0 : ENOENT; arena = 0; - assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)), - 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("thread.arena", NULL, NULL, (void *)&arena, + sizeof(arena)), 0, "Unexpected mallctl() failure"); p = mallocx(arena_bin_info[0].reg_size, 0); assert_ptr_not_null(p, "Unexpected mallocx() failure"); @@ -239,35 +244,36 @@ TEST_BEGIN(test_stats_arenas_bins) assert_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), config_tcache ? 0 : ENOENT, "Unexpected mallctl() result"); - assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, - "Unexpected mallctl() failure"); + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), + 0, "Unexpected mallctl() failure"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.bins.0.nmalloc", &nmalloc, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.bins.0.ndalloc", &ndalloc, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.bins.0.nrequests", &nrequests, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.bins.0.nmalloc", (void *)&nmalloc, + &sz, NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.bins.0.ndalloc", (void *)&ndalloc, + &sz, NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.bins.0.nrequests", + (void *)&nrequests, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.bins.0.curregs", &curregs, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.bins.0.curregs", (void *)&curregs, + &sz, NULL, 0), expected, "Unexpected mallctl() result"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.bins.0.nfills", &nfills, &sz, - NULL, 0), config_tcache ? expected : ENOENT, + assert_d_eq(mallctl("stats.arenas.0.bins.0.nfills", (void *)&nfills, + &sz, NULL, 0), config_tcache ? expected : ENOENT, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.bins.0.nflushes", &nflushes, &sz, - NULL, 0), config_tcache ? expected : ENOENT, + assert_d_eq(mallctl("stats.arenas.0.bins.0.nflushes", (void *)&nflushes, + &sz, NULL, 0), config_tcache ? expected : ENOENT, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.bins.0.nslabs", &nslabs, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.bins.0.nreslabs", &nreslabs, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.bins.0.nslabs", (void *)&nslabs, + &sz, NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.bins.0.nreslabs", (void *)&nreslabs, + &sz, NULL, 0), expected, "Unexpected mallctl() result"); sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.bins.0.curslabs", &curslabs, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.bins.0.curslabs", (void *)&curslabs, + &sz, NULL, 0), expected, "Unexpected mallctl() result"); if (config_stats) { assert_u64_gt(nmalloc, 0, @@ -303,27 +309,30 @@ TEST_BEGIN(test_stats_arenas_lextents) int expected = config_stats ? 0 : ENOENT; arena = 0; - assert_d_eq(mallctl("thread.arena", NULL, NULL, &arena, sizeof(arena)), - 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("thread.arena", NULL, NULL, (void *)&arena, + sizeof(arena)), 0, "Unexpected mallctl() failure"); sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.lextent.0.size", &hsize, &sz, NULL, 0), 0, - "Unexpected mallctl() failure"); + assert_d_eq(mallctl("arenas.lextent.0.size", (void *)&hsize, &sz, NULL, + 0), 0, "Unexpected mallctl() failure"); p = mallocx(hsize, 0); assert_ptr_not_null(p, "Unexpected mallocx() failure"); - assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)), 0, - "Unexpected mallctl() failure"); + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), + 0, "Unexpected mallctl() failure"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.lextents.0.nmalloc", &nmalloc, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.lextents.0.ndalloc", &ndalloc, &sz, - NULL, 0), expected, "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.lextents.0.nmalloc", + (void *)&nmalloc, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.lextents.0.ndalloc", + (void *)&ndalloc, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); sz = sizeof(size_t); assert_d_eq(mallctl("stats.arenas.0.lextents.0.curlextents", - &curlextents, &sz, NULL, 0), expected, "Unexpected mallctl() result"); + (void *)&curlextents, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); if (config_stats) { assert_u64_gt(nmalloc, 0, -- GitLab From 68e14c988460907c4b135feb3eb5fccd28953feb Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 28 Oct 2016 00:16:55 -0700 Subject: [PATCH 135/544] Fix over-sized allocation of rtree leaf nodes. Use the correct level metadata when allocating child nodes so that leaf nodes don't end up over-sized (2^16 elements vs 2^4 elements). --- src/rtree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rtree.c b/src/rtree.c index d4a705ae..0a42a982 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -171,7 +171,7 @@ rtree_child_read_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level) { - return (rtree_node_init(tsdn, rtree, level, &elm->child)); + return (rtree_node_init(tsdn, rtree, level+1, &elm->child)); } static int -- GitLab From 963289df13115001f85b028744dd5f4070b9dc05 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 28 Oct 2016 10:44:39 -0700 Subject: [PATCH 136/544] Periodically purge in memory-intensive integration tests. This resolves #393. --- test/integration/aligned_alloc.c | 13 ++++++++++--- test/integration/mallocx.c | 7 +++++++ test/integration/posix_memalign.c | 13 ++++++++++--- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/test/integration/aligned_alloc.c b/test/integration/aligned_alloc.c index ec2f5a7b..3f1c67ab 100644 --- a/test/integration/aligned_alloc.c +++ b/test/integration/aligned_alloc.c @@ -1,8 +1,6 @@ #include "test/jemalloc_test.h" -/* #define MAXALIGN ((size_t)UINT64_C(0x80000000000)) */ -#define MAXALIGN ((size_t)0x2000000LU) -#define NITER 4 +#define MAXALIGN (((size_t)1) << 25) TEST_BEGIN(test_alignment_errors) { @@ -73,6 +71,7 @@ TEST_END TEST_BEGIN(test_alignment_and_size) { +#define NITER 4 size_t alignment, size, total; unsigned i; void *ps[NITER]; @@ -109,7 +108,15 @@ TEST_BEGIN(test_alignment_and_size) } } } + /* + * On systems which can't merge extents, this test generates a + * lot of dirty memory very quickly. Purge between cycles to + * avoid potential OOM on e.g. 32-bit Windows. + */ + assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, + "Unexpected mallctl error"); } +#undef NITER } TEST_END diff --git a/test/integration/mallocx.c b/test/integration/mallocx.c index 4fd290c0..175be8e1 100644 --- a/test/integration/mallocx.c +++ b/test/integration/mallocx.c @@ -196,6 +196,13 @@ TEST_BEGIN(test_alignment_and_size) } } } + /* + * On systems which can't merge extents, this test generates a + * lot of dirty memory very quickly. Purge between cycles to + * avoid potential OOM on e.g. 32-bit Windows. + */ + assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, + "Unexpected mallctl error"); } #undef MAXALIGN #undef NITER diff --git a/test/integration/posix_memalign.c b/test/integration/posix_memalign.c index d5e39b63..a64886d6 100644 --- a/test/integration/posix_memalign.c +++ b/test/integration/posix_memalign.c @@ -1,8 +1,6 @@ #include "test/jemalloc_test.h" -/* #define MAXALIGN ((size_t)UINT64_C(0x80000000000)) */ -#define MAXALIGN ((size_t)0x2000000LU) -#define NITER 4 +#define MAXALIGN (((size_t)1) << 25) TEST_BEGIN(test_alignment_errors) { @@ -65,6 +63,7 @@ TEST_END TEST_BEGIN(test_alignment_and_size) { +#define NITER 4 size_t alignment, size, total; unsigned i; int err; @@ -103,7 +102,15 @@ TEST_BEGIN(test_alignment_and_size) } } } + /* + * On systems which can't merge extents, this test generates a + * lot of dirty memory very quickly. Purge between cycles to + * avoid potential OOM on e.g. 32-bit Windows. + */ + assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, + "Unexpected mallctl error"); } +#undef NITER } TEST_END -- GitLab From 970d29325770a5006dc227f30481024c8661df51 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 28 Oct 2016 11:00:36 -0700 Subject: [PATCH 137/544] Periodically purge in memory-intensive integration tests. This resolves #393. --- test/integration/mallocx.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/integration/mallocx.c b/test/integration/mallocx.c index 175be8e1..3b8097ed 100644 --- a/test/integration/mallocx.c +++ b/test/integration/mallocx.c @@ -139,6 +139,13 @@ TEST_BEGIN(test_basic) rsz = sallocx(p, 0); assert_zu_eq(nsz, rsz, "nallocx()/sallocx() rsize mismatch"); dallocx(p, 0); + /* + * On systems which can't merge extents, this test generates a + * lot of dirty memory very quickly. Purge between cycles to + * avoid potential OOM on e.g. 32-bit Windows. + */ + assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, + "Unexpected mallctl error"); } #undef MAXSZ } -- GitLab From bde815dc40c636523382912ecba443cc50b0eccd Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 28 Oct 2016 11:23:24 -0700 Subject: [PATCH 138/544] Reduce memory requirements for regression tests. This is intended to drop memory usage to a level that AppVeyor test instances can handle. This resolves #393. --- test/integration/aligned_alloc.c | 23 ++++++++++------ test/integration/mallocx.c | 44 ++++++++++++++++++------------- test/integration/posix_memalign.c | 23 ++++++++++------ 3 files changed, 55 insertions(+), 35 deletions(-) diff --git a/test/integration/aligned_alloc.c b/test/integration/aligned_alloc.c index 3f1c67ab..36fb6997 100644 --- a/test/integration/aligned_alloc.c +++ b/test/integration/aligned_alloc.c @@ -1,6 +1,19 @@ #include "test/jemalloc_test.h" -#define MAXALIGN (((size_t)1) << 25) +#define MAXALIGN (((size_t)1) << 23) + +/* + * On systems which can't merge extents, tests that call this function generate + * a lot of dirty memory very quickly. Purging between cycles mitigates + * potential OOM on e.g. 32-bit Windows. + */ +static void +purge(void) +{ + + assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, + "Unexpected mallctl error"); +} TEST_BEGIN(test_alignment_errors) { @@ -108,13 +121,7 @@ TEST_BEGIN(test_alignment_and_size) } } } - /* - * On systems which can't merge extents, this test generates a - * lot of dirty memory very quickly. Purge between cycles to - * avoid potential OOM on e.g. 32-bit Windows. - */ - assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, - "Unexpected mallctl error"); + purge(); } #undef NITER } diff --git a/test/integration/mallocx.c b/test/integration/mallocx.c index 3b8097ed..2298f729 100644 --- a/test/integration/mallocx.c +++ b/test/integration/mallocx.c @@ -50,6 +50,19 @@ get_large_size(size_t ind) return (get_size_impl("arenas.lextent.0.size", ind)); } +/* + * On systems which can't merge extents, tests that call this function generate + * a lot of dirty memory very quickly. Purging between cycles mitigates + * potential OOM on e.g. 32-bit Windows. + */ +static void +purge(void) +{ + + assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, + "Unexpected mallctl error"); +} + TEST_BEGIN(test_overflow) { size_t largemax; @@ -96,6 +109,7 @@ TEST_BEGIN(test_oom) if (ptrs[i] != NULL) dallocx(ptrs[i], 0); } + purge(); #if LG_SIZEOF_PTR == 3 assert_ptr_null(mallocx(0x8000000000000000ULL, @@ -113,7 +127,7 @@ TEST_END TEST_BEGIN(test_basic) { -#define MAXSZ (((size_t)1) << 26) +#define MAXSZ (((size_t)1) << 23) size_t sz; for (sz = 1; sz < MAXSZ; sz = nallocx(sz, 0) + 1) { @@ -122,30 +136,28 @@ TEST_BEGIN(test_basic) nsz = nallocx(sz, 0); assert_zu_ne(nsz, 0, "Unexpected nallocx() error"); p = mallocx(sz, 0); - assert_ptr_not_null(p, "Unexpected mallocx() error"); + assert_ptr_not_null(p, + "Unexpected mallocx(size=%zx, flags=0) error", sz); rsz = sallocx(p, 0); assert_zu_ge(rsz, sz, "Real size smaller than expected"); assert_zu_eq(nsz, rsz, "nallocx()/sallocx() size mismatch"); dallocx(p, 0); p = mallocx(sz, 0); - assert_ptr_not_null(p, "Unexpected mallocx() error"); + assert_ptr_not_null(p, + "Unexpected mallocx(size=%zx, flags=0) error", sz); dallocx(p, 0); nsz = nallocx(sz, MALLOCX_ZERO); assert_zu_ne(nsz, 0, "Unexpected nallocx() error"); p = mallocx(sz, MALLOCX_ZERO); - assert_ptr_not_null(p, "Unexpected mallocx() error"); + assert_ptr_not_null(p, + "Unexpected mallocx(size=%zx, flags=MALLOCX_ZERO) error", + nsz); rsz = sallocx(p, 0); assert_zu_eq(nsz, rsz, "nallocx()/sallocx() rsize mismatch"); dallocx(p, 0); - /* - * On systems which can't merge extents, this test generates a - * lot of dirty memory very quickly. Purge between cycles to - * avoid potential OOM on e.g. 32-bit Windows. - */ - assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, - "Unexpected mallctl error"); + purge(); } #undef MAXSZ } @@ -153,7 +165,7 @@ TEST_END TEST_BEGIN(test_alignment_and_size) { -#define MAXALIGN (((size_t)1) << 25) +#define MAXALIGN (((size_t)1) << 23) #define NITER 4 size_t nsz, rsz, sz, alignment, total; unsigned i; @@ -203,13 +215,7 @@ TEST_BEGIN(test_alignment_and_size) } } } - /* - * On systems which can't merge extents, this test generates a - * lot of dirty memory very quickly. Purge between cycles to - * avoid potential OOM on e.g. 32-bit Windows. - */ - assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, - "Unexpected mallctl error"); + purge(); } #undef MAXALIGN #undef NITER diff --git a/test/integration/posix_memalign.c b/test/integration/posix_memalign.c index a64886d6..9f3156ac 100644 --- a/test/integration/posix_memalign.c +++ b/test/integration/posix_memalign.c @@ -1,6 +1,19 @@ #include "test/jemalloc_test.h" -#define MAXALIGN (((size_t)1) << 25) +#define MAXALIGN (((size_t)1) << 23) + +/* + * On systems which can't merge extents, tests that call this function generate + * a lot of dirty memory very quickly. Purging between cycles mitigates + * potential OOM on e.g. 32-bit Windows. + */ +static void +purge(void) +{ + + assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, + "Unexpected mallctl error"); +} TEST_BEGIN(test_alignment_errors) { @@ -102,13 +115,7 @@ TEST_BEGIN(test_alignment_and_size) } } } - /* - * On systems which can't merge extents, this test generates a - * lot of dirty memory very quickly. Purge between cycles to - * avoid potential OOM on e.g. 32-bit Windows. - */ - assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, - "Unexpected mallctl error"); + purge(); } #undef NITER } -- GitLab From 830938840865fe236ae2bdc0abdb0d5778146859 Mon Sep 17 00:00:00 2001 From: Dave Watson Date: Fri, 28 Oct 2016 13:51:52 -0700 Subject: [PATCH 139/544] Support static linking of jemalloc with glibc glibc defines its malloc implementation with several weak and strong symbols: strong_alias (__libc_calloc, __calloc) weak_alias (__libc_calloc, calloc) strong_alias (__libc_free, __cfree) weak_alias (__libc_free, cfree) strong_alias (__libc_free, __free) strong_alias (__libc_free, free) strong_alias (__libc_malloc, __malloc) strong_alias (__libc_malloc, malloc) The issue is not with the weak symbols, but that other parts of glibc depend on __libc_malloc explicitly. Defining them in terms of jemalloc API's allows the linker to drop glibc's malloc.o completely from the link, and static linking no longer results in symbol collisions. Another wrinkle: jemalloc during initialization calls sysconf to get the number of CPU's. GLIBC allocates for the first time before setting up isspace (and other related) tables, which are used by sysconf. Instead, use the pthread API to get the number of CPUs with GLIBC, which seems to work. This resolves #442. --- .../internal/jemalloc_internal_decls.h | 3 ++ src/jemalloc.c | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/jemalloc/internal/jemalloc_internal_decls.h b/include/jemalloc/internal/jemalloc_internal_decls.h index 910b2fc6..1d7f2075 100644 --- a/include/jemalloc/internal/jemalloc_internal_decls.h +++ b/include/jemalloc/internal/jemalloc_internal_decls.h @@ -17,6 +17,9 @@ # include # endif # include +# ifdef JEMALLOC_GLIBC_MALLOC_HOOK +# include +# endif # include # include # include diff --git a/src/jemalloc.c b/src/jemalloc.c index 1f951e2f..816cc73c 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -749,6 +749,18 @@ malloc_ncpus(void) SYSTEM_INFO si; GetSystemInfo(&si); result = si.dwNumberOfProcessors; +#elif defined(JEMALLOC_GLIBC_MALLOC_HOOK) + /* + * glibc's sysconf() uses isspace(). glibc allocates for the first time + * *before* setting up the isspace tables. Therefore we need a + * different method to get the number of CPUs. + */ + { + cpu_set_t set; + + pthread_getaffinity_np(pthread_self(), sizeof(set), &set); + result = CPU_COUNT(&set); + } #else result = sysconf(_SC_NPROCESSORS_ONLN); #endif @@ -1882,6 +1894,25 @@ JEMALLOC_EXPORT void *(*__realloc_hook)(void *ptr, size_t size) = je_realloc; JEMALLOC_EXPORT void *(*__memalign_hook)(size_t alignment, size_t size) = je_memalign; # endif + +/* + * To enable static linking with glibc, the libc specific malloc interface must + * be implemented also, so none of glibc's malloc.o functions are added to the + * link. + */ +#define ALIAS(je_fn) __attribute__((alias (#je_fn), used)) +/* To force macro expansion of je_ prefix before stringification. */ +#define PREALIAS(je_fn) ALIAS(je_fn) +void *__libc_malloc(size_t size) PREALIAS(je_malloc); +void __libc_free(void* ptr) PREALIAS(je_free); +void *__libc_realloc(void* ptr, size_t size) PREALIAS(je_realloc); +void *__libc_calloc(size_t n, size_t size) PREALIAS(je_calloc); +void *__libc_memalign(size_t align, size_t s) PREALIAS(je_memalign); +void *__libc_valloc(size_t size) PREALIAS(je_valloc); +int __posix_memalign(void** r, size_t a, size_t s) + PREALIAS(je_posix_memalign); +#undef PREALIAS +#undef ALIAS #endif /* -- GitLab From 6ec2d8e279136f97b43078c7267f923a7cb0e571 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 28 Oct 2016 23:03:25 -0700 Subject: [PATCH 140/544] Do not mark malloc_conf as weak for unit tests. This is generally correct (no need for weak symbols since no jemalloc library is involved in the link phase), and avoids linking problems (apparently unininitialized non-NULL malloc_conf) when using cygwin with gcc. --- src/jemalloc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index 816cc73c..7484dd22 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -5,7 +5,11 @@ /* Data. */ /* Runtime configuration options. */ -const char *je_malloc_conf JEMALLOC_ATTR(weak); +const char *je_malloc_conf +#ifndef JEMALLOC_JET + JEMALLOC_ATTR(weak) +#endif + ; bool opt_abort = #ifdef JEMALLOC_DEBUG true -- GitLab From 1dcd0aa07fa16d2f70494baf997ac85b41de2ef1 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 28 Oct 2016 23:59:42 -0700 Subject: [PATCH 141/544] Do not mark malloc_conf as weak on Windows. This works around malloc_conf not being properly initialized by at least the cygwin toolchain. Prior build system changes to use -Wl,--[no-]whole-archive may be necessary for malloc_conf resolution to work properly as a non-weak symbol (not tested). --- src/jemalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index 7484dd22..3e0605ec 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -6,7 +6,7 @@ /* Runtime configuration options. */ const char *je_malloc_conf -#ifndef JEMALLOC_JET +#ifndef _WIN32 JEMALLOC_ATTR(weak) #endif ; -- GitLab From af0e28fd942d6f3b6198aebdeea6043b3542d096 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 29 Oct 2016 22:14:55 -0700 Subject: [PATCH 142/544] Fix EXTRA_CFLAGS to not affect configuration. --- Makefile.in | 3 ++- configure.ac | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Makefile.in b/Makefile.in index e00dbebc..e4aaaf21 100644 --- a/Makefile.in +++ b/Makefile.in @@ -24,7 +24,8 @@ abs_objroot := @abs_objroot@ # Build parameters. CPPFLAGS := @CPPFLAGS@ -I$(srcroot)include -I$(objroot)include -CFLAGS := @CFLAGS@ +EXTRA_CFLAGS := @EXTRA_CFLAGS@ +CFLAGS := @CFLAGS@ $(EXTRA_CFLAGS) LDFLAGS := @LDFLAGS@ EXTRA_LDFLAGS := @EXTRA_LDFLAGS@ LIBS := @LIBS@ diff --git a/configure.ac b/configure.ac index a9d75111..2dff55b2 100644 --- a/configure.ac +++ b/configure.ac @@ -203,10 +203,7 @@ if test "x$CFLAGS" = "x" ; then fi fi fi -dnl Append EXTRA_CFLAGS to CFLAGS, if defined. -if test "x$EXTRA_CFLAGS" != "x" ; then - JE_CFLAGS_APPEND([$EXTRA_CFLAGS]) -fi +AC_SUBST([EXTRA_CFLAGS]) AC_PROG_CPP AC_C_BIGENDIAN([ac_cv_big_endian=1], [ac_cv_big_endian=0]) @@ -1853,6 +1850,7 @@ AC_MSG_RESULT([]) AC_MSG_RESULT([CONFIG : ${CONFIG}]) AC_MSG_RESULT([CC : ${CC}]) AC_MSG_RESULT([CFLAGS : ${CFLAGS}]) +AC_MSG_RESULT([EXTRA_CFLAGS : ${EXTRA_CFLAGS}]) AC_MSG_RESULT([CPPFLAGS : ${CPPFLAGS}]) AC_MSG_RESULT([LDFLAGS : ${LDFLAGS}]) AC_MSG_RESULT([EXTRA_LDFLAGS : ${EXTRA_LDFLAGS}]) -- GitLab From d87037a62c651f96ac4fb5a8c9db668697ee96e0 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 29 Oct 2016 22:41:04 -0700 Subject: [PATCH 143/544] Use syscall(2) rather than {open,read,close}(2) during boot. Some applications wrap various system calls, and if they call the allocator in their wrappers, unexpected reentry can result. This is not a general solution (many other syscalls are spread throughout the code), but this resolves a bootstrapping issue that is apparently common. This resolves #443. --- src/pages.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/pages.c b/src/pages.c index 05b0d690..84e22160 100644 --- a/src/pages.c +++ b/src/pages.c @@ -207,6 +207,11 @@ os_overcommits_sysctl(void) #endif #ifdef JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY +/* + * Use syscall(2) rather than {open,read,close}(2) when possible to avoid + * reentry during bootstrapping if another library has interposed system call + * wrappers. + */ static bool os_overcommits_proc(void) { @@ -214,12 +219,26 @@ os_overcommits_proc(void) char buf[1]; ssize_t nread; +#ifdef SYS_open + fd = (int)syscall(SYS_open, "/proc/sys/vm/overcommit_memory", O_RDONLY); +#else fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY); +#endif if (fd == -1) return (false); /* Error. */ +#ifdef SYS_read + nread = (ssize_t)syscall(SYS_read, fd, &buf, sizeof(buf)); +#else nread = read(fd, &buf, sizeof(buf)); +#endif + +#ifdef SYS_close + syscall(SYS_close, fd); +#else close(fd); +#endif + if (nread < 1) return (false); /* Error. */ /* -- GitLab From 6c80321aed4b620acba4ced1a7a5871377cbc396 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 29 Oct 2016 22:55:08 -0700 Subject: [PATCH 144/544] Use CLOCK_MONOTONIC_COARSE rather than COARSE_MONOTONIC_RAW. The raw clock variant is slow (even relative to plain CLOCK_MONOTONIC), whereas the coarse clock variant is faster than CLOCK_MONOTONIC, but still has resolution (~1ms) that is adequate for our purposes. This resolves #479. --- configure.ac | 12 ++++++------ .../jemalloc/internal/jemalloc_internal_defs.h.in | 4 ++-- src/nstime.c | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/configure.ac b/configure.ac index 2dff55b2..b2616b9a 100644 --- a/configure.ac +++ b/configure.ac @@ -1312,16 +1312,16 @@ if test "x$je_cv_cray_prgenv_wrapper" = "xyes" ; then fi fi -dnl check for CLOCK_MONOTONIC_RAW (Linux-specific). -JE_COMPILABLE([clock_gettime(CLOCK_MONOTONIC_RAW, ...)], [ +dnl check for CLOCK_MONOTONIC_COARSE (Linux-specific). +JE_COMPILABLE([clock_gettime(CLOCK_MONOTONIC_COARSE, ...)], [ #include ], [ struct timespec ts; - clock_gettime(CLOCK_MONOTONIC_RAW, &ts); -], [je_cv_clock_monotonic_raw]) -if test "x${je_cv_clock_monotonic_raw}" = "xyes" ; then - AC_DEFINE([JEMALLOC_HAVE_CLOCK_MONOTONIC_RAW]) + clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); +], [je_cv_clock_monotonic_coarse]) +if test "x${je_cv_clock_monotonic_coarse}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE]) fi dnl check for CLOCK_MONOTONIC. diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 70b32871..0ba960ba 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -77,9 +77,9 @@ #undef JEMALLOC_HAVE_ISSETUGID /* - * Defined if clock_gettime(CLOCK_MONOTONIC_RAW, ...) is available. + * Defined if clock_gettime(CLOCK_MONOTONIC_COARSE, ...) is available. */ -#undef JEMALLOC_HAVE_CLOCK_MONOTONIC_RAW +#undef JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE /* * Defined if clock_gettime(CLOCK_MONOTONIC, ...) is available. diff --git a/src/nstime.c b/src/nstime.c index c420c88d..0948e29f 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -110,14 +110,14 @@ nstime_get(nstime_t *time) nstime_init(time, ticks_100ns * 100); } -#elif JEMALLOC_HAVE_CLOCK_MONOTONIC_RAW +#elif JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE # define NSTIME_MONOTONIC true static void nstime_get(nstime_t *time) { struct timespec ts; - clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); nstime_init2(time, ts.tv_sec, ts.tv_nsec); } #elif JEMALLOC_HAVE_CLOCK_MONOTONIC -- GitLab From 6a834d94bb863d1abd0175a07e98f4b9797fa435 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 31 Oct 2016 11:45:41 -0700 Subject: [PATCH 145/544] Refactor witness_unlock() to fix undefined test behavior. This resolves #396. --- include/jemalloc/internal/private_symbols.txt | 1 + include/jemalloc/internal/witness.h | 39 +++++++++++++------ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 1bf79ca8..315d2872 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -530,6 +530,7 @@ witness_lock witness_lock_error witness_lockless_error witness_not_owner_error +witness_owner witness_owner_error witness_postfork_child witness_postfork_parent diff --git a/include/jemalloc/internal/witness.h b/include/jemalloc/internal/witness.h index 9a2a6760..3bc5ebe8 100644 --- a/include/jemalloc/internal/witness.h +++ b/include/jemalloc/internal/witness.h @@ -112,6 +112,7 @@ void witness_postfork_child(tsd_t *tsd); #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE +bool witness_owner(tsd_t *tsd, const witness_t *witness); void witness_assert_owner(tsdn_t *tsdn, const witness_t *witness); void witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness); void witness_assert_lockless(tsdn_t *tsdn); @@ -120,12 +121,25 @@ void witness_unlock(tsdn_t *tsdn, witness_t *witness); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) +JEMALLOC_INLINE bool +witness_owner(tsd_t *tsd, const witness_t *witness) +{ + witness_list_t *witnesses; + witness_t *w; + + witnesses = tsd_witnessesp_get(tsd); + ql_foreach(w, witnesses, link) { + if (w == witness) + return (true); + } + + return (false); +} + JEMALLOC_INLINE void witness_assert_owner(tsdn_t *tsdn, const witness_t *witness) { tsd_t *tsd; - witness_list_t *witnesses; - witness_t *w; if (!config_debug) return; @@ -136,11 +150,8 @@ witness_assert_owner(tsdn_t *tsdn, const witness_t *witness) if (witness->rank == WITNESS_RANK_OMIT) return; - witnesses = tsd_witnessesp_get(tsd); - ql_foreach(w, witnesses, link) { - if (w == witness) - return; - } + if (witness_owner(tsd, witness)) + return; witness_owner_error(witness); } @@ -243,10 +254,16 @@ witness_unlock(tsdn_t *tsdn, witness_t *witness) if (witness->rank == WITNESS_RANK_OMIT) return; - witness_assert_owner(tsdn, witness); - - witnesses = tsd_witnessesp_get(tsd); - ql_remove(witnesses, witness, link); + /* + * Check whether owner before removal, rather than relying on + * witness_assert_owner() to abort, so that unit tests can test this + * function's failure mode without causing undefined behavior. + */ + if (witness_owner(tsd, witness)) { + witnesses = tsd_witnessesp_get(tsd); + ql_remove(witnesses, witness, link); + } else + witness_assert_owner(tsdn, witness); } #endif -- GitLab From 90b60eeae4f557fae99158f9899bd7b01a9ac662 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 31 Oct 2016 15:28:22 -0700 Subject: [PATCH 146/544] Add an assertion in witness_owner(). --- include/jemalloc/internal/witness.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/jemalloc/internal/witness.h b/include/jemalloc/internal/witness.h index 3bc5ebe8..26024ac2 100644 --- a/include/jemalloc/internal/witness.h +++ b/include/jemalloc/internal/witness.h @@ -121,12 +121,15 @@ void witness_unlock(tsdn_t *tsdn, witness_t *witness); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) +/* Helper, not intended for direct use. */ JEMALLOC_INLINE bool witness_owner(tsd_t *tsd, const witness_t *witness) { witness_list_t *witnesses; witness_t *w; + cassert(config_debug); + witnesses = tsd_witnessesp_get(tsd); ql_foreach(w, witnesses, link) { if (w == witness) -- GitLab From b93f63b3ebab068efdcfa2ea3e19055bfc2e7f82 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 31 Oct 2016 16:32:33 -0700 Subject: [PATCH 147/544] Fix extent_rtree acquire() to release element on error. This resolves #480. --- src/extent.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/extent.c b/src/extent.c index e4ceb8fd..809777a1 100644 --- a/src/extent.c +++ b/src/extent.c @@ -229,8 +229,10 @@ extent_rtree_acquire(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, *r_elm_b = rtree_elm_acquire(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_last_get(extent), dependent, init_missing); - if (!dependent && *r_elm_b == NULL) + if (!dependent && *r_elm_b == NULL) { + rtree_elm_release(tsdn, &extents_rtree, *r_elm_a); return (true); + } assert(*r_elm_b != NULL); } else *r_elm_b = NULL; -- GitLab From 0ba5b9b6189e16a983d8922d8c5cb6ab421906e8 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 31 Oct 2016 22:30:49 -0700 Subject: [PATCH 148/544] Add "J" (JSON) support to malloc_stats_print(). This resolves #474. --- doc/jemalloc.xml.in | 44 +- src/stats.c | 1029 ++++++++++++++++++++++++++++++------------- 2 files changed, 738 insertions(+), 335 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 5ba44d23..22b3d803 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -410,28 +410,28 @@ for (i = 0; i < nbins; i++) { /* Do something with bin_size... */ }]]> - The malloc_stats_print() function - writes human-readable summary statistics via the - write_cb callback function pointer and - cbopaque data passed to - write_cb, or - malloc_message() if - write_cb is NULL. This - function can be called repeatedly. General information that never changes - during execution can be omitted by specifying "g" as a character within - the opts string. Note that - malloc_message() uses the - mallctl*() functions internally, so - inconsistent statistics can be reported if multiple threads use these - functions simultaneously. If is specified - during configuration, “m” and “a” can be specified - to omit merged arena and per arena statistics, respectively; - “b” and “l” can be specified to omit per size - class statistics for bins and large objects, respectively. Unrecognized - characters are silently ignored. Note that thread caching may prevent - some statistics from being completely up to date, since extra locking - would be required to merge counters that track thread cache - operations. + The malloc_stats_print() function writes + summary statistics via the write_cb callback + function pointer and cbopaque data passed to + write_cb, or malloc_message() + if write_cb is NULL. The + statistics are presented in human-readable form unless "J" is specified as + a character within the opts string, in which case + the statistics are presented in JSON + format. This function can be called repeatedly. General + information that never changes during execution can be omitted by + specifying "g" as a character within the opts + string. Note that malloc_message() uses the + mallctl*() functions internally, so inconsistent + statistics can be reported if multiple threads use these functions + simultaneously. If is specified during + configuration, “m” and “a” can be specified to + omit merged arena and per arena statistics, respectively; “b” + and “l” can be specified to omit per size class statistics for + bins and large objects, respectively. Unrecognized characters are + silently ignored. Note that thread caching may prevent some statistics + from being completely up to date, since extra locking would be required to + merge counters that track thread cache operations. The malloc_usable_size() function returns the usable size of the allocation pointed to by diff --git a/src/stats.c b/src/stats.c index 689299fa..dbff6c27 100644 --- a/src/stats.c +++ b/src/stats.c @@ -30,84 +30,108 @@ bool opt_stats_print = false; -/******************************************************************************/ -/* Function prototypes for non-inline static functions. */ - -static void stats_arena_bins_print(void (*write_cb)(void *, const char *), - void *cbopaque, unsigned i); -static void stats_arena_lextents_print( - void (*write_cb)(void *, const char *), void *cbopaque, unsigned i); -static void stats_arena_print(void (*write_cb)(void *, const char *), - void *cbopaque, unsigned i, bool bins, bool large); - /******************************************************************************/ static void stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, - unsigned i) + bool json, bool large, unsigned i) { size_t page; - bool config_tcache, in_gap; + bool config_tcache, in_gap, in_gap_prev; unsigned nbins, j; CTL_GET("arenas.page", &page, size_t); - CTL_GET("config.tcache", &config_tcache, bool); - if (config_tcache) { + CTL_GET("arenas.nbins", &nbins, unsigned); + if (json) { malloc_cprintf(write_cb, cbopaque, - "bins: size ind allocated nmalloc" - " ndalloc nrequests curregs curslabs regs" - " pgs util nfills nflushes newslabs" - " reslabs\n"); + "\t\t\t\t\"bins\": [\n"); } else { - malloc_cprintf(write_cb, cbopaque, - "bins: size ind allocated nmalloc" - " ndalloc nrequests curregs curslabs regs" - " pgs util newslabs reslabs\n"); + CTL_GET("config.tcache", &config_tcache, bool); + if (config_tcache) { + malloc_cprintf(write_cb, cbopaque, + "bins: size ind allocated nmalloc" + " ndalloc nrequests curregs" + " curslabs regs pgs util nfills" + " nflushes newslabs reslabs\n"); + } else { + malloc_cprintf(write_cb, cbopaque, + "bins: size ind allocated nmalloc" + " ndalloc nrequests curregs" + " curslabs regs pgs util newslabs" + " reslabs\n"); + } } - CTL_GET("arenas.nbins", &nbins, unsigned); for (j = 0, in_gap = false; j < nbins; j++) { uint64_t nslabs; + size_t reg_size, slab_size, curregs; + size_t curslabs; + uint32_t nregs; + uint64_t nmalloc, ndalloc, nrequests, nfills, nflushes; + uint64_t nreslabs; CTL_M2_M4_GET("stats.arenas.0.bins.0.nslabs", i, j, &nslabs, uint64_t); + in_gap_prev = in_gap; if (nslabs == 0) in_gap = true; - else { - size_t reg_size, slab_size, curregs, availregs, milli; - size_t curslabs; - uint32_t nregs; - uint64_t nmalloc, ndalloc, nrequests, nfills, nflushes; - uint64_t reslabs; - char util[6]; /* "x.yyy". */ - if (in_gap) { - malloc_cprintf(write_cb, cbopaque, - " ---\n"); - in_gap = false; - } - CTL_M2_GET("arenas.bin.0.size", j, ®_size, size_t); - CTL_M2_GET("arenas.bin.0.nregs", j, &nregs, uint32_t); - CTL_M2_GET("arenas.bin.0.slab_size", j, &slab_size, - size_t); - CTL_M2_M4_GET("stats.arenas.0.bins.0.nmalloc", i, j, - &nmalloc, uint64_t); - CTL_M2_M4_GET("stats.arenas.0.bins.0.ndalloc", i, j, - &ndalloc, uint64_t); - CTL_M2_M4_GET("stats.arenas.0.bins.0.curregs", i, j, - &curregs, size_t); - CTL_M2_M4_GET("stats.arenas.0.bins.0.nrequests", i, j, - &nrequests, uint64_t); + if (!json && in_gap_prev && !in_gap) { + malloc_cprintf(write_cb, cbopaque, + " ---\n"); + } + + CTL_M2_GET("arenas.bin.0.size", j, ®_size, size_t); + CTL_M2_GET("arenas.bin.0.nregs", j, &nregs, uint32_t); + CTL_M2_GET("arenas.bin.0.slab_size", j, &slab_size, size_t); + + CTL_M2_M4_GET("stats.arenas.0.bins.0.nmalloc", i, j, &nmalloc, + uint64_t); + CTL_M2_M4_GET("stats.arenas.0.bins.0.ndalloc", i, j, &ndalloc, + uint64_t); + CTL_M2_M4_GET("stats.arenas.0.bins.0.curregs", i, j, &curregs, + size_t); + CTL_M2_M4_GET("stats.arenas.0.bins.0.nrequests", i, j, + &nrequests, uint64_t); + if (config_tcache) { + CTL_M2_M4_GET("stats.arenas.0.bins.0.nfills", i, j, + &nfills, uint64_t); + CTL_M2_M4_GET("stats.arenas.0.bins.0.nflushes", i, j, + &nflushes, uint64_t); + } + CTL_M2_M4_GET("stats.arenas.0.bins.0.nreslabs", i, j, &nreslabs, + uint64_t); + CTL_M2_M4_GET("stats.arenas.0.bins.0.curslabs", i, j, &curslabs, + size_t); + + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t{\n" + "\t\t\t\t\t\t\"nmalloc\": %"FMTu64",\n" + "\t\t\t\t\t\t\"ndalloc\": %"FMTu64",\n" + "\t\t\t\t\t\t\"curregs\": %zu,\n" + "\t\t\t\t\t\t\"nrequests\": %"FMTu64",\n", + nmalloc, + ndalloc, + curregs, + nrequests); if (config_tcache) { - CTL_M2_M4_GET("stats.arenas.0.bins.0.nfills", i, - j, &nfills, uint64_t); - CTL_M2_M4_GET("stats.arenas.0.bins.0.nflushes", - i, j, &nflushes, uint64_t); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\t\"nfills\": %"FMTu64",\n" + "\t\t\t\t\t\t\"nflushes\": %"FMTu64",\n", + nfills, + nflushes); } - CTL_M2_M4_GET("stats.arenas.0.bins.0.nreslabs", i, j, - &reslabs, uint64_t); - CTL_M2_M4_GET("stats.arenas.0.bins.0.curslabs", i, j, - &curslabs, size_t); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\t\"nreslabs\": %"FMTu64",\n" + "\t\t\t\t\t\t\"curslabs\": %zu\n" + "\t\t\t\t\t}%s\n", + nreslabs, + curslabs, + (j + 1 < nbins) ? "," : ""); + } else if (!in_gap) { + size_t availregs, milli; + char util[6]; /* "x.yyy". */ availregs = nregs * curslabs; milli = (availregs != 0) ? (1000 * curregs) / availregs @@ -134,7 +158,7 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, reg_size, j, curregs * reg_size, nmalloc, ndalloc, nrequests, curregs, curslabs, nregs, slab_size / page, util, nfills, - nflushes, nslabs, reslabs); + nflushes, nslabs, nreslabs); } else { malloc_cprintf(write_cb, cbopaque, "%20zu %3u %12zu %12"FMTu64 @@ -144,28 +168,38 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, reg_size, j, curregs * reg_size, nmalloc, ndalloc, nrequests, curregs, curslabs, nregs, slab_size / page, util, nslabs, - reslabs); + nreslabs); } } } - if (in_gap) { + if (json) { malloc_cprintf(write_cb, cbopaque, - " ---\n"); + "\t\t\t\t]%s\n", large ? "," : ""); + } else { + if (in_gap) { + malloc_cprintf(write_cb, cbopaque, + " ---\n"); + } } } static void stats_arena_lextents_print(void (*write_cb)(void *, const char *), - void *cbopaque, unsigned i) + void *cbopaque, bool json, unsigned i) { unsigned nbins, nlextents, j; - bool in_gap; + bool in_gap, in_gap_prev; - malloc_cprintf(write_cb, cbopaque, - "large: size ind allocated nmalloc ndalloc" - " nrequests curlextents\n"); CTL_GET("arenas.nbins", &nbins, unsigned); CTL_GET("arenas.nlextents", &nlextents, unsigned); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"lextents\": [\n"); + } else { + malloc_cprintf(write_cb, cbopaque, + "large: size ind allocated nmalloc" + " ndalloc nrequests curlextents\n"); + } for (j = 0, in_gap = false; j < nlextents; j++) { uint64_t nmalloc, ndalloc, nrequests; size_t lextent_size, curlextents; @@ -176,18 +210,26 @@ stats_arena_lextents_print(void (*write_cb)(void *, const char *), &ndalloc, uint64_t); CTL_M2_M4_GET("stats.arenas.0.lextents.0.nrequests", i, j, &nrequests, uint64_t); + in_gap_prev = in_gap; if (nrequests == 0) in_gap = true; - else { - CTL_M2_GET("arenas.lextent.0.size", j, &lextent_size, - size_t); - CTL_M2_M4_GET("stats.arenas.0.lextents.0.curlextents", - i, j, &curlextents, size_t); - if (in_gap) { - malloc_cprintf(write_cb, cbopaque, - " ---\n"); - in_gap = false; - } + + if (!json && in_gap_prev && !in_gap) { + malloc_cprintf(write_cb, cbopaque, + " ---\n"); + } + + CTL_M2_GET("arenas.lextent.0.size", j, &lextent_size, size_t); + CTL_M2_M4_GET("stats.arenas.0.lextents.0.curlextents", i, j, + &curlextents, size_t); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t{\n" + "\t\t\t\t\t\t\"curlextents\": %zu\n" + "\t\t\t\t\t}%s\n", + curlextents, + (j + 1 < nlextents) ? "," : ""); + } else if (!in_gap) { malloc_cprintf(write_cb, cbopaque, "%20zu %3u %12zu %12"FMTu64" %12"FMTu64 " %12"FMTu64" %12zu\n", @@ -196,15 +238,20 @@ stats_arena_lextents_print(void (*write_cb)(void *, const char *), nrequests, curlextents); } } - if (in_gap) { + if (json) { malloc_cprintf(write_cb, cbopaque, - " ---\n"); + "\t\t\t\t]\n"); + } else { + if (in_gap) { + malloc_cprintf(write_cb, cbopaque, + " ---\n"); + } } } static void stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, - unsigned i, bool bins, bool large) + bool json, unsigned i, bool bins, bool large) { unsigned nthreads; const char *dss; @@ -219,229 +266,362 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, CTL_GET("arenas.page", &page, size_t); CTL_M2_GET("stats.arenas.0.nthreads", i, &nthreads, unsigned); - malloc_cprintf(write_cb, cbopaque, - "assigned threads: %u\n", nthreads); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"nthreads\": %u,\n", nthreads); + } else { + malloc_cprintf(write_cb, cbopaque, + "assigned threads: %u\n", nthreads); + } + CTL_M2_GET("stats.arenas.0.dss", i, &dss, const char *); - malloc_cprintf(write_cb, cbopaque, "dss allocation precedence: %s\n", - dss); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"dss\": \"%s\",\n", dss); + } else { + malloc_cprintf(write_cb, cbopaque, + "dss allocation precedence: %s\n", dss); + } + CTL_M2_GET("stats.arenas.0.decay_time", i, &decay_time, ssize_t); - if (decay_time >= 0) { - malloc_cprintf(write_cb, cbopaque, "decay time: %zd\n", - decay_time); - } else - malloc_cprintf(write_cb, cbopaque, "decay time: N/A\n"); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"decay_time\": %zd,\n", decay_time); + } else { + if (decay_time >= 0) { + malloc_cprintf(write_cb, cbopaque, "decay time: %zd\n", + decay_time); + } else + malloc_cprintf(write_cb, cbopaque, "decay time: N/A\n"); + } + CTL_M2_GET("stats.arenas.0.pactive", i, &pactive, size_t); CTL_M2_GET("stats.arenas.0.pdirty", i, &pdirty, size_t); CTL_M2_GET("stats.arenas.0.npurge", i, &npurge, uint64_t); CTL_M2_GET("stats.arenas.0.nmadvise", i, &nmadvise, uint64_t); CTL_M2_GET("stats.arenas.0.purged", i, &purged, uint64_t); - malloc_cprintf(write_cb, cbopaque, - "purging: dirty: %zu, sweeps: %"FMTu64", madvises: %"FMTu64", " - "purged: %"FMTu64"\n", pdirty, npurge, nmadvise, purged); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"pactive\": %zu,\n", pactive); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"pdirty\": %zu,\n", pdirty); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"npurge\": %"FMTu64",\n", npurge); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"nmadvise\": %"FMTu64",\n", nmadvise); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"purged\": %"FMTu64",\n", purged); + } else { + malloc_cprintf(write_cb, cbopaque, + "purging: dirty: %zu, sweeps: %"FMTu64", madvises: %"FMTu64 + ", ""purged: %"FMTu64"\n", pdirty, npurge, nmadvise, + purged); + } - malloc_cprintf(write_cb, cbopaque, - " allocated nmalloc ndalloc" - " nrequests\n"); CTL_M2_GET("stats.arenas.0.small.allocated", i, &small_allocated, size_t); CTL_M2_GET("stats.arenas.0.small.nmalloc", i, &small_nmalloc, uint64_t); CTL_M2_GET("stats.arenas.0.small.ndalloc", i, &small_ndalloc, uint64_t); CTL_M2_GET("stats.arenas.0.small.nrequests", i, &small_nrequests, uint64_t); - malloc_cprintf(write_cb, cbopaque, - "small: %12zu %12"FMTu64" %12"FMTu64 - " %12"FMTu64"\n", - small_allocated, small_nmalloc, small_ndalloc, small_nrequests); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"small\": {\n"); + + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\"allocated\": %zu,\n", small_allocated); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\"nmalloc\": %"FMTu64",\n", small_nmalloc); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\"ndalloc\": %"FMTu64",\n", small_ndalloc); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\"nrequests\": %"FMTu64"\n", small_nrequests); + + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t},\n"); + } else { + malloc_cprintf(write_cb, cbopaque, + " allocated nmalloc" + " ndalloc nrequests\n"); + malloc_cprintf(write_cb, cbopaque, + "small: %12zu %12"FMTu64" %12"FMTu64 + " %12"FMTu64"\n", + small_allocated, small_nmalloc, small_ndalloc, + small_nrequests); + } + CTL_M2_GET("stats.arenas.0.large.allocated", i, &large_allocated, size_t); CTL_M2_GET("stats.arenas.0.large.nmalloc", i, &large_nmalloc, uint64_t); CTL_M2_GET("stats.arenas.0.large.ndalloc", i, &large_ndalloc, uint64_t); CTL_M2_GET("stats.arenas.0.large.nrequests", i, &large_nrequests, uint64_t); - malloc_cprintf(write_cb, cbopaque, - "large: %12zu %12"FMTu64" %12"FMTu64 - " %12"FMTu64"\n", - large_allocated, large_nmalloc, large_ndalloc, large_nrequests); - malloc_cprintf(write_cb, cbopaque, - "total: %12zu %12"FMTu64" %12"FMTu64 - " %12"FMTu64"\n", - small_allocated + large_allocated, small_nmalloc + large_nmalloc, - small_ndalloc + large_ndalloc, small_nrequests + large_nrequests); - malloc_cprintf(write_cb, cbopaque, - "active: %12zu\n", pactive * page); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"large\": {\n"); + + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\"allocated\": %zu,\n", large_allocated); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\"nmalloc\": %"FMTu64",\n", large_nmalloc); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\"ndalloc\": %"FMTu64",\n", large_ndalloc); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\"nrequests\": %"FMTu64"\n", large_nrequests); + + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t},\n"); + } else { + malloc_cprintf(write_cb, cbopaque, + "large: %12zu %12"FMTu64" %12"FMTu64 + " %12"FMTu64"\n", + large_allocated, large_nmalloc, large_ndalloc, + large_nrequests); + malloc_cprintf(write_cb, cbopaque, + "total: %12zu %12"FMTu64" %12"FMTu64 + " %12"FMTu64"\n", + small_allocated + large_allocated, small_nmalloc + + large_nmalloc, small_ndalloc + large_ndalloc, + small_nrequests + large_nrequests); + } + if (!json) { + malloc_cprintf(write_cb, cbopaque, + "active: %12zu\n", pactive * page); + } + CTL_M2_GET("stats.arenas.0.mapped", i, &mapped, size_t); - malloc_cprintf(write_cb, cbopaque, - "mapped: %12zu\n", mapped); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"mapped\": %zu,\n", mapped); + } else { + malloc_cprintf(write_cb, cbopaque, + "mapped: %12zu\n", mapped); + } + CTL_M2_GET("stats.arenas.0.retained", i, &retained, size_t); - malloc_cprintf(write_cb, cbopaque, - "retained: %12zu\n", retained); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"retained\": %zu,\n", retained); + } else { + malloc_cprintf(write_cb, cbopaque, + "retained: %12zu\n", retained); + } + CTL_M2_GET("stats.arenas.0.metadata", i, &metadata, size_t); - malloc_cprintf(write_cb, cbopaque, "metadata: %12zu\n", - metadata); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"metatata\": %zu%s\n", metadata, (bins || large) ? + "," : ""); + } else { + malloc_cprintf(write_cb, cbopaque, + "metadata: %12zu\n", metadata); + } if (bins) - stats_arena_bins_print(write_cb, cbopaque, i); + stats_arena_bins_print(write_cb, cbopaque, json, large, i); if (large) - stats_arena_lextents_print(write_cb, cbopaque, i); + stats_arena_lextents_print(write_cb, cbopaque, json, i); } -void -stats_print(void (*write_cb)(void *, const char *), void *cbopaque, - const char *opts) +static void +stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, + bool json, bool merged, bool unmerged) { - int err; - uint64_t epoch; - size_t u64sz; - bool general = true; - bool merged = true; - bool unmerged = true; - bool bins = true; - bool large = true; + const char *cpv; + bool bv; + unsigned uv; + uint32_t u32v; + uint64_t u64v; + ssize_t ssv; + size_t sv, bsz, usz, ssz, sssz, cpsz; + + bsz = sizeof(bool); + usz = sizeof(unsigned); + ssz = sizeof(size_t); + sssz = sizeof(ssize_t); + cpsz = sizeof(const char *); + + CTL_GET("version", &cpv, const char *); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\"version\": \"%s\",\n", cpv); + } else + malloc_cprintf(write_cb, cbopaque, "Version: %s\n", cpv); - /* - * Refresh stats, in case mallctl() was called by the application. - * - * Check for OOM here, since refreshing the ctl cache can trigger - * allocation. In practice, none of the subsequent mallctl()-related - * calls in this function will cause OOM if this one succeeds. - * */ - epoch = 1; - u64sz = sizeof(uint64_t); - err = je_mallctl("epoch", &epoch, &u64sz, &epoch, sizeof(uint64_t)); - if (err != 0) { - if (err == EAGAIN) { - malloc_write(": Memory allocation failure in " - "mallctl(\"epoch\", ...)\n"); - return; - } - malloc_write(": Failure in mallctl(\"epoch\", " - "...)\n"); - abort(); + /* config. */ +#define CONFIG_WRITE_BOOL_JSON(n, c) \ + if (json) { \ + CTL_GET("config."#n, &bv, bool); \ + malloc_cprintf(write_cb, cbopaque, \ + "\t\t\t\""#n"\": %s%s\n", bv ? "true" : "false", \ + (c)); \ } - if (opts != NULL) { - unsigned i; - - for (i = 0; opts[i] != '\0'; i++) { - switch (opts[i]) { - case 'g': - general = false; - break; - case 'm': - merged = false; - break; - case 'a': - unmerged = false; - break; - case 'b': - bins = false; - break; - case 'l': - large = false; - break; - default:; - } - } + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\"config\": {\n"); } - malloc_cprintf(write_cb, cbopaque, - "___ Begin jemalloc statistics ___\n"); - if (general) { - const char *cpv; - bool bv; - unsigned uv; - ssize_t ssv; - size_t sv, bsz, usz, ssz, sssz, cpsz; - - bsz = sizeof(bool); - usz = sizeof(unsigned); - ssz = sizeof(size_t); - sssz = sizeof(ssize_t); - cpsz = sizeof(const char *); + CONFIG_WRITE_BOOL_JSON(cache_oblivious, ",") - CTL_GET("version", &cpv, const char *); - malloc_cprintf(write_cb, cbopaque, "Version: %s\n", cpv); - CTL_GET("config.debug", &bv, bool); + CTL_GET("config.debug", &bv, bool); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"debug\": %s,\n", bv ? "true" : "false"); + } else { malloc_cprintf(write_cb, cbopaque, "Assertions %s\n", bv ? "enabled" : "disabled"); + } + + CONFIG_WRITE_BOOL_JSON(fill, ",") + CONFIG_WRITE_BOOL_JSON(lazy_lock, ",") + + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"malloc_conf\": \"%s\",\n", + config_malloc_conf); + } else { malloc_cprintf(write_cb, cbopaque, "config.malloc_conf: \"%s\"\n", config_malloc_conf); + } + + CONFIG_WRITE_BOOL_JSON(munmap, ",") + CONFIG_WRITE_BOOL_JSON(prof, ",") + CONFIG_WRITE_BOOL_JSON(prof_libgcc, ",") + CONFIG_WRITE_BOOL_JSON(prof_libunwind, ",") + CONFIG_WRITE_BOOL_JSON(stats, ",") + CONFIG_WRITE_BOOL_JSON(tcache, ",") + CONFIG_WRITE_BOOL_JSON(tls, ",") + CONFIG_WRITE_BOOL_JSON(utrace, ",") + CONFIG_WRITE_BOOL_JSON(xmalloc, "") + + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t},\n"); + } +#undef CONFIG_WRITE_BOOL_JSON -#define OPT_WRITE_BOOL(n) \ - if (je_mallctl("opt."#n, (void *)&bv, &bsz, NULL, 0) == \ - 0) { \ + /* opt. */ +#define OPT_WRITE_BOOL(n, c) \ + if (je_mallctl("opt."#n, (void *)&bv, &bsz, NULL, 0) == 0) { \ + if (json) { \ + malloc_cprintf(write_cb, cbopaque, \ + "\t\t\t\""#n"\": %s%s\n", bv ? "true" : \ + "false", (c)); \ + } else { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %s\n", bv ? "true" : "false"); \ - } -#define OPT_WRITE_BOOL_MUTABLE(n, m) { \ - bool bv2; \ - if (je_mallctl("opt."#n, (void *)&bv, &bsz, NULL, 0) == \ - 0 && je_mallctl(#m, &bv2, &bsz, NULL, 0) == 0) { \ + } \ + } +#define OPT_WRITE_BOOL_MUTABLE(n, m, c) { \ + bool bv2; \ + if (je_mallctl("opt."#n, (void *)&bv, &bsz, NULL, 0) == 0 && \ + je_mallctl(#m, &bv2, &bsz, NULL, 0) == 0) { \ + if (json) { \ + malloc_cprintf(write_cb, cbopaque, \ + "\t\t\t\""#n"\": %s%s\n", bv ? "true" : \ + "false", (c)); \ + } else { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %s ("#m": %s)\n", bv ? "true" \ : "false", bv2 ? "true" : "false"); \ } \ + } \ } -#define OPT_WRITE_UNSIGNED(n) \ - if (je_mallctl("opt."#n, (void *)&uv, &usz, NULL, 0) == \ - 0) { \ +#define OPT_WRITE_UNSIGNED(n, c) \ + if (je_mallctl("opt."#n, (void *)&uv, &usz, NULL, 0) == 0) { \ + if (json) { \ + malloc_cprintf(write_cb, cbopaque, \ + "\t\t\t\""#n"\": %u%s\n", uv, (c)); \ + } else { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %u\n", uv); \ - } + } \ + } #define OPT_WRITE_SIZE_T(n) \ - if (je_mallctl("opt."#n, (void *)&sv, &ssz, NULL, 0) == \ - 0) { \ + if (je_mallctl("opt."#n, (void *)&sv, &ssz, NULL, 0) == 0) { \ + if (json) { \ + malloc_cprintf(write_cb, cbopaque, \ + "\t\t\t\""#n"\": %zu%s\n", sv, (c)); \ + } else { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %zu\n", sv); \ - } -#define OPT_WRITE_SSIZE_T(n) \ - if (je_mallctl("opt."#n, (void *)&ssv, &sssz, NULL, 0) \ - == 0) { \ + } \ + } +#define OPT_WRITE_SSIZE_T(n, c) \ + if (je_mallctl("opt."#n, (void *)&ssv, &sssz, NULL, 0) == 0) { \ + if (json) { \ + malloc_cprintf(write_cb, cbopaque, \ + "\t\t\t\""#n"\": %zd%s\n", ssv, (c)); \ + } else { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %zd\n", ssv); \ - } -#define OPT_WRITE_SSIZE_T_MUTABLE(n, m) { \ - ssize_t ssv2; \ - if (je_mallctl("opt."#n, (void *)&ssv, &sssz, NULL, 0) \ - == 0 && je_mallctl(#m, &ssv2, &sssz, NULL, 0) == \ - 0) { \ + } \ + } +#define OPT_WRITE_SSIZE_T_MUTABLE(n, m, c) { \ + ssize_t ssv2; \ + if (je_mallctl("opt."#n, (void *)&ssv, &sssz, NULL, 0) == 0 && \ + je_mallctl(#m, &ssv2, &sssz, NULL, 0) == 0) { \ + if (json) { \ + malloc_cprintf(write_cb, cbopaque, \ + "\t\t\t\""#n"\": %zd%s\n", ssv, (c)); \ + } else { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": %zd ("#m": %zd)\n", \ ssv, ssv2); \ } \ + } \ } -#define OPT_WRITE_CHAR_P(n) \ - if (je_mallctl("opt."#n, (void *)&cpv, &cpsz, NULL, 0) \ - == 0) { \ +#define OPT_WRITE_CHAR_P(n, c) \ + if (je_mallctl("opt."#n, (void *)&cpv, &cpsz, NULL, 0) == 0) { \ + if (json) { \ + malloc_cprintf(write_cb, cbopaque, \ + "\t\t\t\""#n"\": \"%s\"%s\n", cpv, (c)); \ + } else { \ malloc_cprintf(write_cb, cbopaque, \ " opt."#n": \"%s\"\n", cpv); \ - } + } \ + } + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\"opt\": {\n"); + } else { malloc_cprintf(write_cb, cbopaque, "Run-time option settings:\n"); - OPT_WRITE_BOOL(abort) - OPT_WRITE_CHAR_P(dss) - OPT_WRITE_UNSIGNED(narenas) - OPT_WRITE_CHAR_P(purge) - OPT_WRITE_SSIZE_T_MUTABLE(decay_time, arenas.decay_time) - OPT_WRITE_BOOL(stats_print) - OPT_WRITE_CHAR_P(junk) - OPT_WRITE_BOOL(zero) - OPT_WRITE_BOOL(utrace) - OPT_WRITE_BOOL(xmalloc) - OPT_WRITE_BOOL(tcache) - OPT_WRITE_SSIZE_T(lg_tcache_max) - OPT_WRITE_BOOL(prof) - OPT_WRITE_CHAR_P(prof_prefix) - OPT_WRITE_BOOL_MUTABLE(prof_active, prof.active) - OPT_WRITE_BOOL_MUTABLE(prof_thread_active_init, - prof.thread_active_init) - OPT_WRITE_SSIZE_T(lg_prof_sample) - OPT_WRITE_BOOL(prof_accum) - OPT_WRITE_SSIZE_T(lg_prof_interval) - OPT_WRITE_BOOL(prof_gdump) - OPT_WRITE_BOOL(prof_final) - OPT_WRITE_BOOL(prof_leak) + } + OPT_WRITE_BOOL(abort, ",") + OPT_WRITE_CHAR_P(dss, ",") + OPT_WRITE_UNSIGNED(narenas, ",") + OPT_WRITE_CHAR_P(purge, ",") + OPT_WRITE_SSIZE_T_MUTABLE(decay_time, arenas.decay_time, ",") + OPT_WRITE_CHAR_P(junk, ",") + OPT_WRITE_BOOL(zero, ",") + OPT_WRITE_BOOL(utrace, ",") + OPT_WRITE_BOOL(xmalloc, ",") + OPT_WRITE_BOOL(tcache, ",") + OPT_WRITE_SSIZE_T(lg_tcache_max, ",") + OPT_WRITE_BOOL(prof, ",") + OPT_WRITE_CHAR_P(prof_prefix, ",") + OPT_WRITE_BOOL_MUTABLE(prof_active, prof.active, ",") + OPT_WRITE_BOOL_MUTABLE(prof_thread_active_init, prof.thread_active_init, + ",") + OPT_WRITE_SSIZE_T_MUTABLE(lg_prof_sample, prof.lg_sample, ",") + OPT_WRITE_BOOL(prof_accum, ",") + OPT_WRITE_SSIZE_T(lg_prof_interval, ",") + OPT_WRITE_BOOL(prof_gdump, ",") + OPT_WRITE_BOOL(prof_final, ",") + OPT_WRITE_BOOL(prof_leak, ",") + /* + * stats_print is always emitted, so as long as stats_print comes last + * it's safe to unconditionally omit the comma here (rather than having + * to conditionally omit it elsewhere depending on configuration). + */ + OPT_WRITE_BOOL(stats_print, "") + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t},\n"); + } #undef OPT_WRITE_BOOL #undef OPT_WRITE_BOOL_MUTABLE @@ -449,117 +629,340 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, #undef OPT_WRITE_SSIZE_T #undef OPT_WRITE_CHAR_P - malloc_cprintf(write_cb, cbopaque, "CPUs: %u\n", ncpus); + /* arenas. */ + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\"arenas\": {\n"); + } - CTL_GET("arenas.narenas", &uv, unsigned); + CTL_GET("arenas.narenas", &uv, unsigned); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"narenas\": %u,\n", uv); + } else malloc_cprintf(write_cb, cbopaque, "Arenas: %u\n", uv); - malloc_cprintf(write_cb, cbopaque, "Pointer size: %zu\n", - sizeof(void *)); + CTL_GET("arenas.decay_time", &ssv, ssize_t); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"decay_time\": %zd,\n", ssv); + } else { + malloc_cprintf(write_cb, cbopaque, + "Unused dirty page decay time: %zd%s\n", ssv, (ssv < 0) ? + " (no decay)" : ""); + } - CTL_GET("arenas.quantum", &sv, size_t); - malloc_cprintf(write_cb, cbopaque, "Quantum size: %zu\n", - sv); + CTL_GET("arenas.quantum", &sv, size_t); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"quantum\": %zu,\n", sv); + } else + malloc_cprintf(write_cb, cbopaque, "Quantum size: %zu\n", sv); - CTL_GET("arenas.page", &sv, size_t); + CTL_GET("arenas.page", &sv, size_t); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"page\": %zu,\n", sv); + } else malloc_cprintf(write_cb, cbopaque, "Page size: %zu\n", sv); - CTL_GET("arenas.decay_time", &ssv, ssize_t); - malloc_cprintf(write_cb, cbopaque, - "Unused dirty page decay time: %zd%s\n", ssv, (ssv < 0) ? - " (no decay)" : ""); - if (je_mallctl("arenas.tcache_max", (void *)&sv, &ssz, NULL, 0) - == 0) { + if (je_mallctl("arenas.tcache_max", (void *)&sv, &ssz, NULL, 0) == 0) { + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"tcache_max\": %zu,\n", sv); + } else { malloc_cprintf(write_cb, cbopaque, "Maximum thread-cached size class: %zu\n", sv); } - if (je_mallctl("opt.prof", (void *)&bv, &bsz, NULL, 0) == 0 && - bv) { - CTL_GET("prof.lg_sample", &sv, size_t); + } + + if (json) { + unsigned nbins, nlextents, i; + + CTL_GET("arenas.nbins", &nbins, unsigned); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"nbins\": %u,\n", nbins); + + CTL_GET("arenas.nhbins", &uv, unsigned); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"nhbins\": %u,\n", uv); + + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"bin\": [\n"); + for (i = 0; i < nbins; i++) { malloc_cprintf(write_cb, cbopaque, - "Average profile sample interval: %"FMTu64 - " (2^%zu)\n", (((uint64_t)1U) << sv), sv); + "\t\t\t\t{\n"); - CTL_GET("opt.lg_prof_interval", &ssv, ssize_t); - if (ssv >= 0) { - malloc_cprintf(write_cb, cbopaque, - "Average profile dump interval: %"FMTu64 - " (2^%zd)\n", - (((uint64_t)1U) << ssv), ssv); - } else { - malloc_cprintf(write_cb, cbopaque, - "Average profile dump interval: N/A\n"); - } + CTL_M2_GET("arenas.bin.0.size", i, &sv, size_t); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\"size\": %zu,\n", sv); + + CTL_M2_GET("arenas.bin.0.nregs", i, &u32v, uint32_t); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\"nregs\": %"FMTu32",\n", u32v); + + CTL_M2_GET("arenas.bin.0.slab_size", i, &sv, size_t); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\"slab_size\": %zu\n", sv); + + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t}%s\n", (i + 1 < nbins) ? "," : ""); + } + malloc_cprintf(write_cb, cbopaque, + "\t\t\t],\n"); + + CTL_GET("arenas.nlextents", &nlextents, unsigned); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"nlextents\": %u,\n", nlextents); + + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"lextent\": [\n"); + for (i = 0; i < nlextents; i++) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t{\n"); + + CTL_M2_GET("arenas.lextent.0.size", i, &sv, size_t); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\"size\": %zu\n", sv); + + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t}%s\n", (i + 1 < nlextents) ? "," : ""); } + malloc_cprintf(write_cb, cbopaque, + "\t\t\t]\n"); + + malloc_cprintf(write_cb, cbopaque, + "\t\t},\n"); } - if (config_stats) { - size_t allocated, active, metadata, resident, mapped, retained; + /* prof. */ + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\"prof\": {\n"); - CTL_GET("stats.allocated", &allocated, size_t); - CTL_GET("stats.active", &active, size_t); - CTL_GET("stats.metadata", &metadata, size_t); - CTL_GET("stats.resident", &resident, size_t); - CTL_GET("stats.mapped", &mapped, size_t); - CTL_GET("stats.retained", &retained, size_t); + CTL_GET("prof.thread_active_init", &bv, bool); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"thread_active_init\": %s,\n", bv ? "true" : + "false"); + + CTL_GET("prof.active", &bv, bool); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"active\": %s,\n", bv ? "true" : "false"); + + CTL_GET("prof.gdump", &bv, bool); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"gdump\": %s,\n", bv ? "true" : "false"); + + CTL_GET("prof.interval", &u64v, uint64_t); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"interval\": %"FMTu64",\n", u64v); + + CTL_GET("prof.lg_sample", &ssv, ssize_t); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"lg_sample\": %zd\n", ssv); + + malloc_cprintf(write_cb, cbopaque, + "\t\t}%s\n", (config_stats || merged || unmerged) ? "," : + ""); + } +} + +static void +stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, + bool json, bool merged, bool unmerged, bool bins, bool large) +{ + size_t allocated, active, metadata, resident, mapped, retained; + + CTL_GET("stats.allocated", &allocated, size_t); + CTL_GET("stats.active", &active, size_t); + CTL_GET("stats.metadata", &metadata, size_t); + CTL_GET("stats.resident", &resident, size_t); + CTL_GET("stats.mapped", &mapped, size_t); + CTL_GET("stats.retained", &retained, size_t); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\"stats\": {\n"); + + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"allocated\": %zu,\n", allocated); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"active\": %zu,\n", active); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"metadata\": %zu,\n", metadata); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"resident\": %zu,\n", resident); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"mapped\": %zu,\n", mapped); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"retained\": %zu\n", retained); + + malloc_cprintf(write_cb, cbopaque, + "\t\t}%s\n", (merged || unmerged) ? "," : ""); + } else { malloc_cprintf(write_cb, cbopaque, "Allocated: %zu, active: %zu, metadata: %zu," " resident: %zu, mapped: %zu, retained: %zu\n", allocated, active, metadata, resident, mapped, retained); + } - if (merged) { - unsigned narenas; - - CTL_GET("arenas.narenas", &narenas, unsigned); - { - VARIABLE_ARRAY(bool, initialized, narenas); - size_t isz; - unsigned i, ninitialized; - - isz = sizeof(bool) * narenas; - xmallctl("arenas.initialized", - (void *)initialized, &isz, NULL, 0); - for (i = ninitialized = 0; i < narenas; i++) { - if (initialized[i]) - ninitialized++; - } + if (merged || unmerged) { + unsigned narenas; + + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\"stats.arenas\": {\n"); + } - if (ninitialized > 1 || !unmerged) { - /* Print merged arena stats. */ + CTL_GET("arenas.narenas", &narenas, unsigned); + { + VARIABLE_ARRAY(bool, initialized, narenas); + size_t isz; + unsigned i, j, ninitialized; + + isz = sizeof(bool) * narenas; + xmallctl("arenas.initialized", (void *)initialized, + &isz, NULL, 0); + for (i = ninitialized = 0; i < narenas; i++) { + if (initialized[i]) + ninitialized++; + } + + /* Merged stats. */ + if (merged && (ninitialized > 1 || !unmerged)) { + /* Print merged arena stats. */ + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"merged\": {\n"); + } else { malloc_cprintf(write_cb, cbopaque, "\nMerged arenas stats:\n"); + } + stats_arena_print(write_cb, cbopaque, json, + narenas, bins, large); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t}%s\n", (ninitialized > 1) ? + "," : ""); + } + } + + /* Unmerged stats. */ + for (i = j = 0; i < narenas; i++) { + if (initialized[i]) { + if (json) { + j++; + malloc_cprintf(write_cb, + cbopaque, + "\t\t\t\"%u\": {\n", i); + } else { + malloc_cprintf(write_cb, + cbopaque, "\narenas[%u]:\n", + i); + } stats_arena_print(write_cb, cbopaque, - narenas, bins, large); + json, i, bins, large); + if (json) { + malloc_cprintf(write_cb, + cbopaque, + "\t\t\t}%s\n", (j < + ninitialized) ? "," : ""); + } } } } - if (unmerged) { - unsigned narenas; + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t}\n"); + } + } +} - /* Print stats for each arena. */ +void +stats_print(void (*write_cb)(void *, const char *), void *cbopaque, + const char *opts) +{ + int err; + uint64_t epoch; + size_t u64sz; + bool json = false; + bool general = true; + bool merged = true; + bool unmerged = true; + bool bins = true; + bool large = true; - CTL_GET("arenas.narenas", &narenas, unsigned); - { - VARIABLE_ARRAY(bool, initialized, narenas); - size_t isz; - unsigned i; + /* + * Refresh stats, in case mallctl() was called by the application. + * + * Check for OOM here, since refreshing the ctl cache can trigger + * allocation. In practice, none of the subsequent mallctl()-related + * calls in this function will cause OOM if this one succeeds. + * */ + epoch = 1; + u64sz = sizeof(uint64_t); + err = je_mallctl("epoch", &epoch, &u64sz, &epoch, sizeof(uint64_t)); + if (err != 0) { + if (err == EAGAIN) { + malloc_write(": Memory allocation failure in " + "mallctl(\"epoch\", ...)\n"); + return; + } + malloc_write(": Failure in mallctl(\"epoch\", " + "...)\n"); + abort(); + } - isz = sizeof(bool) * narenas; - xmallctl("arenas.initialized", - (void *)initialized, &isz, NULL, 0); + if (opts != NULL) { + unsigned i; - for (i = 0; i < narenas; i++) { - if (initialized[i]) { - malloc_cprintf(write_cb, - cbopaque, - "\narenas[%u]:\n", i); - stats_arena_print(write_cb, - cbopaque, i, bins, large); - } - } + for (i = 0; opts[i] != '\0'; i++) { + switch (opts[i]) { + case 'J': + json = true; + break; + case 'g': + general = false; + break; + case 'm': + merged = false; + break; + case 'a': + unmerged = false; + break; + case 'b': + bins = false; + break; + case 'l': + large = false; + break; + default:; } } } - malloc_cprintf(write_cb, cbopaque, "--- End jemalloc statistics ---\n"); + + if (json) { + malloc_cprintf(write_cb, cbopaque, + "{\n" + "\t\"jemalloc\": {\n"); + } else { + malloc_cprintf(write_cb, cbopaque, + "___ Begin jemalloc statistics ___\n"); + } + + if (general) + stats_general_print(write_cb, cbopaque, json, merged, unmerged); + if (config_stats) { + stats_print_helper(write_cb, cbopaque, json, merged, unmerged, + bins, large); + } + + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t}\n" + "}\n"); + } else { + malloc_cprintf(write_cb, cbopaque, + "--- End jemalloc statistics ---\n"); + } } -- GitLab From 2a2d1b6e86bcad3b0025b6b62689e9d0e666e155 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 1 Nov 2016 13:25:42 -0700 Subject: [PATCH 149/544] Use ... rather than “...” or "..." in XML. --- doc/jemalloc.xml.in | 62 +++++++++++++++++++++++---------------------- doc/stylesheet.xsl | 2 +- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 22b3d803..747cc071 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -375,7 +375,7 @@ The mallctlnametomib() function provides a way to avoid repeated name lookups for applications that repeatedly query the same portion of the namespace, by translating a name - to a “Management Information Base” (MIB) that can be passed + to a Management Information Base (MIB) that can be passed repeatedly to mallctlbymib(). Upon successful return from mallctlnametomib(), mibp contains an array of @@ -415,20 +415,21 @@ for (i = 0; i < nbins; i++) { function pointer and cbopaque data passed to write_cb, or malloc_message() if write_cb is NULL. The - statistics are presented in human-readable form unless "J" is specified as - a character within the opts string, in which case - the statistics are presented in JSON - format. This function can be called repeatedly. General - information that never changes during execution can be omitted by - specifying "g" as a character within the opts - string. Note that malloc_message() uses the + statistics are presented in human-readable form unless J is + specified as a character within the opts string, in + which case the statistics are presented in JSON format. This function can be + called repeatedly. General information that never changes during + execution can be omitted by specifying g as a character + within the opts string. Note that + malloc_message() uses the mallctl*() functions internally, so inconsistent statistics can be reported if multiple threads use these functions simultaneously. If is specified during - configuration, “m” and “a” can be specified to - omit merged arena and per arena statistics, respectively; “b” - and “l” can be specified to omit per size class statistics for - bins and large objects, respectively. Unrecognized characters are + configuration, m and a can be specified to + omit merged arena and per arena statistics, respectively; b + and l can be specified to omit per size class statistics + for bins and large objects, respectively. Unrecognized characters are silently ignored. Note that thread caching may prevent some statistics from being completely up to date, since extra locking would be required to merge counters that track thread cache operations. @@ -454,7 +455,7 @@ for (i = 0; i < nbins; i++) { The string specified via , the string pointed to by the global variable malloc_conf, the - “name” of the file referenced by the symbolic link named + name of the file referenced by the symbolic link named /etc/malloc.conf, and the value of the environment variable MALLOC_CONF, will be interpreted, in that order, from left to right as options. Note that @@ -891,12 +892,12 @@ for (i = 0; i < nbins; i++) { settings are supported if sbrk 2 is supported by the operating - system: “disabled”, “primary”, and - “secondary”; otherwise only “disabled” is - supported. The default is “secondary” if + system: disabled, primary, and + secondary; otherwise only disabled is + supported. The default is secondary if sbrk 2 is supported by the operating - system; “disabled” otherwise. + system; disabled otherwise. @@ -963,15 +964,16 @@ for (i = 0; i < nbins; i++) { r- [] - Junk filling. If set to "alloc", each byte of - uninitialized allocated memory will be initialized to - 0xa5. If set to "free", all deallocated memory will - be initialized to 0x5a. If set to "true", both - allocated and deallocated memory will be initialized, and if set to - "false", junk filling be disabled entirely. This is intended for - debugging and will impact performance negatively. This option is - "false" by default unless is specified - during configuration, in which case it is "true" by + Junk filling. If set to alloc, each byte + of uninitialized allocated memory will be initialized to + 0xa5. If set to free, all deallocated + memory will be initialized to 0x5a. If set to + true, both allocated and deallocated memory will be + initialized, and if set to false, junk filling be + disabled entirely. This is intended for debugging and will impact + performance negatively. This option is false by default + unless is specified during + configuration, in which case it is true by default. @@ -2445,7 +2447,7 @@ MAPPED_LIBRARIES: of run-time assertions that catch application errors such as double-free, write-after-free, etc. - Programs often accidentally depend on “uninitialized” + Programs often accidentally depend on uninitialized memory actually being filled with zero bytes. Junk filling (see the opt.junk option) tends to expose such bugs in the form of obviously incorrect @@ -2480,7 +2482,7 @@ MAPPED_LIBRARIES: this function is likely to result in a crash or deadlock. All messages are prefixed by - “<jemalloc>: ”. + <jemalloc>: . RETURN VALUES @@ -2666,9 +2668,9 @@ malloc_conf = "narenas:1";]]> calloc(), realloc(), and free() functions conform to ISO/IEC - 9899:1990 (“ISO C90”). + 9899:1990 (ISO C90). The posix_memalign() function conforms - to IEEE Std 1003.1-2001 (“POSIX.1”). + to IEEE Std 1003.1-2001 (POSIX.1). diff --git a/doc/stylesheet.xsl b/doc/stylesheet.xsl index bc8bc2a9..619365d8 100644 --- a/doc/stylesheet.xsl +++ b/doc/stylesheet.xsl @@ -5,6 +5,6 @@ - "" + -- GitLab From 7b0a8b74f048c397ff2276c9d2f5311fce70bd89 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 1 Nov 2016 15:26:35 -0700 Subject: [PATCH 150/544] malloc_stats_print() fixes/cleanups. Fix and clean up various malloc_stats_print() issues caused by 0ba5b9b6189e16a983d8922d8c5cb6ab421906e8 (Add "J" (JSON) support to malloc_stats_print().). --- src/stats.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/stats.c b/src/stats.c index dbff6c27..44f8c528 100644 --- a/src/stats.c +++ b/src/stats.c @@ -73,8 +73,7 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, CTL_M2_M4_GET("stats.arenas.0.bins.0.nslabs", i, j, &nslabs, uint64_t); in_gap_prev = in_gap; - if (nslabs == 0) - in_gap = true; + in_gap = (nslabs == 0); if (!json && in_gap_prev && !in_gap) { malloc_cprintf(write_cb, cbopaque, @@ -211,8 +210,7 @@ stats_arena_lextents_print(void (*write_cb)(void *, const char *), CTL_M2_M4_GET("stats.arenas.0.lextents.0.nrequests", i, j, &nrequests, uint64_t); in_gap_prev = in_gap; - if (nrequests == 0) - in_gap = true; + in_gap = (nrequests == 0); if (!json && in_gap_prev && !in_gap) { malloc_cprintf(write_cb, cbopaque, @@ -314,8 +312,7 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, } else { malloc_cprintf(write_cb, cbopaque, "purging: dirty: %zu, sweeps: %"FMTu64", madvises: %"FMTu64 - ", ""purged: %"FMTu64"\n", pdirty, npurge, nmadvise, - purged); + ", purged: %"FMTu64"\n", pdirty, npurge, nmadvise, purged); } CTL_M2_GET("stats.arenas.0.small.allocated", i, &small_allocated, @@ -538,16 +535,6 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, " opt."#n": %u\n", uv); \ } \ } -#define OPT_WRITE_SIZE_T(n) \ - if (je_mallctl("opt."#n, (void *)&sv, &ssz, NULL, 0) == 0) { \ - if (json) { \ - malloc_cprintf(write_cb, cbopaque, \ - "\t\t\t\""#n"\": %zu%s\n", sv, (c)); \ - } else { \ - malloc_cprintf(write_cb, cbopaque, \ - " opt."#n": %zu\n", sv); \ - } \ - } #define OPT_WRITE_SSIZE_T(n, c) \ if (je_mallctl("opt."#n, (void *)&ssv, &sssz, NULL, 0) == 0) { \ if (json) { \ @@ -593,7 +580,6 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, OPT_WRITE_BOOL(abort, ",") OPT_WRITE_CHAR_P(dss, ",") OPT_WRITE_UNSIGNED(narenas, ",") - OPT_WRITE_CHAR_P(purge, ",") OPT_WRITE_SSIZE_T_MUTABLE(decay_time, arenas.decay_time, ",") OPT_WRITE_CHAR_P(junk, ",") OPT_WRITE_BOOL(zero, ",") @@ -625,7 +611,6 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, #undef OPT_WRITE_BOOL #undef OPT_WRITE_BOOL_MUTABLE -#undef OPT_WRITE_SIZE_T #undef OPT_WRITE_SSIZE_T #undef OPT_WRITE_CHAR_P -- GitLab From eee1ca655e348b0602c96b702332c28d53869fff Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 2 Nov 2016 08:54:07 -0700 Subject: [PATCH 151/544] Force no lazy-lock on Windows. Monitoring thread creation is unimplemented for Windows, which means lazy-lock cannot function correctly. This resolves #310. --- configure.ac | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index b2616b9a..0d10143c 100644 --- a/configure.ac +++ b/configure.ac @@ -1404,9 +1404,17 @@ fi ], [enable_lazy_lock=""] ) -if test "x$enable_lazy_lock" = "x" -a "x${force_lazy_lock}" = "x1" ; then - AC_MSG_RESULT([Forcing lazy-lock to avoid allocator/threading bootstrap issues]) - enable_lazy_lock="1" +if test "x${enable_lazy_lock}" = "x" ; then + if test "x${force_lazy_lock}" = "x1" ; then + AC_MSG_RESULT([Forcing lazy-lock to avoid allocator/threading bootstrap issues]) + enable_lazy_lock="1" + else + enable_lazy_lock="0" + fi +fi +if test "x${enable_lazy_lock}" = "x1" -a "x${abi}" = "xpecoff" ; then + AC_MSG_RESULT([Forcing no lazy-lock because thread creation monitoring is unimplemented]) + enable_lazy_lock="0" fi if test "x$enable_lazy_lock" = "x1" ; then if test "x$abi" != "xpecoff" ; then @@ -1417,8 +1425,6 @@ if test "x$enable_lazy_lock" = "x1" ; then ]) fi AC_DEFINE([JEMALLOC_LAZY_LOCK], [ ]) -else - enable_lazy_lock="0" fi AC_SUBST([enable_lazy_lock]) -- GitLab From b54072dfeece6d25aa7c6b1a503ae350bfe6e1a0 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 2 Nov 2016 18:05:19 -0700 Subject: [PATCH 152/544] Call _exit(2) rather than exit(3) in forked child. _exit(2) is async-signal-safe, whereas exit(3) is not. --- test/unit/fork.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/fork.c b/test/unit/fork.c index 46c815ef..c530797c 100644 --- a/test/unit/fork.c +++ b/test/unit/fork.c @@ -26,7 +26,7 @@ TEST_BEGIN(test_fork) test_fail("Unexpected fork() failure"); } else if (pid == 0) { /* Child. */ - exit(0); + _exit(0); } else { int status; -- GitLab From d9f7b2a4307f7ff9f7a139b33d366d44e8a8b83d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 2 Nov 2016 18:06:40 -0700 Subject: [PATCH 153/544] Fix/refactor zone allocator integration code. Fix zone_force_unlock() to reinitialize, rather than unlocking mutexes, since OS X 10.12 cannot tolerate a child unlocking mutexes that were locked by its parent. Refactor; this was a side effect of experimenting with zone {de,re}registration during fork(2). --- include/jemalloc/internal/private_symbols.txt | 2 +- src/zone.c | 191 ++++++++++-------- 2 files changed, 108 insertions(+), 85 deletions(-) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 315d2872..29936a87 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -383,7 +383,6 @@ psz2ind psz2ind_clamp psz2ind_impl psz2u -register_zone rtree_child_read rtree_child_read_hard rtree_child_tryread @@ -537,3 +536,4 @@ witness_postfork_parent witness_prefork witness_unlock witnesses_cleanup +zone_register diff --git a/src/zone.c b/src/zone.c index 52d07f30..66ba02b9 100644 --- a/src/zone.c +++ b/src/zone.c @@ -4,7 +4,7 @@ #endif /* - * The malloc_default_purgeable_zone function is only available on >= 10.6. + * The malloc_default_purgeable_zone() function is only available on >= 10.6. * We need to check whether it is present at runtime, thus the weak_import. */ extern malloc_zone_t *malloc_default_purgeable_zone(void) @@ -13,8 +13,9 @@ JEMALLOC_ATTR(weak_import); /******************************************************************************/ /* Data. */ -static malloc_zone_t zone; -static struct malloc_introspection_t zone_introspect; +static malloc_zone_t *default_zone, *purgeable_zone; +static malloc_zone_t jemalloc_zone; +static struct malloc_introspection_t jemalloc_zone_introspect; /******************************************************************************/ /* Function prototypes for non-inline static functions. */ @@ -164,12 +165,68 @@ static void zone_force_unlock(malloc_zone_t *zone) { + /* + * Call jemalloc_postfork_child() rather than + * jemalloc_postfork_parent(), because this function is executed by both + * parent and child. The parent can tolerate having state + * reinitialized, but the child cannot unlock mutexes that were locked + * by the parent. + */ if (isthreaded) - jemalloc_postfork_parent(); + jemalloc_postfork_child(); +} + +static void +zone_init(void) +{ + + jemalloc_zone.size = (void *)zone_size; + jemalloc_zone.malloc = (void *)zone_malloc; + jemalloc_zone.calloc = (void *)zone_calloc; + jemalloc_zone.valloc = (void *)zone_valloc; + jemalloc_zone.free = (void *)zone_free; + jemalloc_zone.realloc = (void *)zone_realloc; + jemalloc_zone.destroy = (void *)zone_destroy; + jemalloc_zone.zone_name = "jemalloc_zone"; + jemalloc_zone.batch_malloc = NULL; + jemalloc_zone.batch_free = NULL; + jemalloc_zone.introspect = &jemalloc_zone_introspect; + jemalloc_zone.version = JEMALLOC_ZONE_VERSION; +#if (JEMALLOC_ZONE_VERSION >= 5) + jemalloc_zone.memalign = zone_memalign; +#endif +#if (JEMALLOC_ZONE_VERSION >= 6) + jemalloc_zone.free_definite_size = zone_free_definite_size; +#endif +#if (JEMALLOC_ZONE_VERSION >= 8) + jemalloc_zone.pressure_relief = NULL; +#endif + + jemalloc_zone_introspect.enumerator = NULL; + jemalloc_zone_introspect.good_size = (void *)zone_good_size; + jemalloc_zone_introspect.check = NULL; + jemalloc_zone_introspect.print = NULL; + jemalloc_zone_introspect.log = NULL; + jemalloc_zone_introspect.force_lock = (void *)zone_force_lock; + jemalloc_zone_introspect.force_unlock = (void *)zone_force_unlock; + jemalloc_zone_introspect.statistics = NULL; +#if (JEMALLOC_ZONE_VERSION >= 6) + jemalloc_zone_introspect.zone_locked = NULL; +#endif +#if (JEMALLOC_ZONE_VERSION >= 7) + jemalloc_zone_introspect.enable_discharge_checking = NULL; + jemalloc_zone_introspect.disable_discharge_checking = NULL; + jemalloc_zone_introspect.discharge = NULL; +# ifdef __BLOCKS__ + jemalloc_zone_introspect.enumerate_discharged_pointers = NULL; +# else + jemalloc_zone_introspect.enumerate_unavailable_without_blocks = NULL; +# endif +#endif } static malloc_zone_t * -get_default_zone(void) +zone_default_get(void) { malloc_zone_t **zones = NULL; unsigned int num_zones = 0; @@ -183,7 +240,7 @@ get_default_zone(void) * zone is the default. So get the list of zones to get the first one, * instead of relying on malloc_default_zone. */ - if (KERN_SUCCESS != malloc_get_all_zones(0, NULL, + if (KERN_SUCCESS != malloc_get_all_zones(0, NULL, (vm_address_t**)&zones, &num_zones)) { /* * Reset the value in case the failure happened after it was @@ -198,82 +255,11 @@ get_default_zone(void) return (malloc_default_zone()); } -JEMALLOC_ATTR(constructor) -void -register_zone(void) +/* As written, this function can only promote jemalloc_zone. */ +static void +zone_promote(void) { - - /* - * If something else replaced the system default zone allocator, don't - * register jemalloc's. - */ - malloc_zone_t *default_zone = get_default_zone(); - malloc_zone_t *purgeable_zone = NULL; - if (!default_zone->zone_name || - strcmp(default_zone->zone_name, "DefaultMallocZone") != 0) { - return; - } - - zone.size = (void *)zone_size; - zone.malloc = (void *)zone_malloc; - zone.calloc = (void *)zone_calloc; - zone.valloc = (void *)zone_valloc; - zone.free = (void *)zone_free; - zone.realloc = (void *)zone_realloc; - zone.destroy = (void *)zone_destroy; - zone.zone_name = "jemalloc_zone"; - zone.batch_malloc = NULL; - zone.batch_free = NULL; - zone.introspect = &zone_introspect; - zone.version = JEMALLOC_ZONE_VERSION; -#if (JEMALLOC_ZONE_VERSION >= 5) - zone.memalign = zone_memalign; -#endif -#if (JEMALLOC_ZONE_VERSION >= 6) - zone.free_definite_size = zone_free_definite_size; -#endif -#if (JEMALLOC_ZONE_VERSION >= 8) - zone.pressure_relief = NULL; -#endif - - zone_introspect.enumerator = NULL; - zone_introspect.good_size = (void *)zone_good_size; - zone_introspect.check = NULL; - zone_introspect.print = NULL; - zone_introspect.log = NULL; - zone_introspect.force_lock = (void *)zone_force_lock; - zone_introspect.force_unlock = (void *)zone_force_unlock; - zone_introspect.statistics = NULL; -#if (JEMALLOC_ZONE_VERSION >= 6) - zone_introspect.zone_locked = NULL; -#endif -#if (JEMALLOC_ZONE_VERSION >= 7) - zone_introspect.enable_discharge_checking = NULL; - zone_introspect.disable_discharge_checking = NULL; - zone_introspect.discharge = NULL; -#ifdef __BLOCKS__ - zone_introspect.enumerate_discharged_pointers = NULL; -#else - zone_introspect.enumerate_unavailable_without_blocks = NULL; -#endif -#endif - - /* - * The default purgeable zone is created lazily by OSX's libc. It uses - * the default zone when it is created for "small" allocations - * (< 15 KiB), but assumes the default zone is a scalable_zone. This - * obviously fails when the default zone is the jemalloc zone, so - * malloc_default_purgeable_zone is called beforehand so that the - * default purgeable zone is created when the default zone is still - * a scalable_zone. As purgeable zones only exist on >= 10.6, we need - * to check for the existence of malloc_default_purgeable_zone() at - * run time. - */ - if (malloc_default_purgeable_zone != NULL) - purgeable_zone = malloc_default_purgeable_zone(); - - /* Register the custom zone. At this point it won't be the default. */ - malloc_zone_register(&zone); + malloc_zone_t *zone; do { /* @@ -286,6 +272,7 @@ register_zone(void) */ malloc_zone_unregister(default_zone); malloc_zone_register(default_zone); + /* * On OSX 10.6, having the default purgeable zone appear before * the default zone makes some things crash because it thinks it @@ -297,11 +284,47 @@ register_zone(void) * above, i.e. the default zone. Registering it again then puts * it at the end, obviously after the default zone. */ - if (purgeable_zone) { + if (purgeable_zone != NULL) { malloc_zone_unregister(purgeable_zone); malloc_zone_register(purgeable_zone); } - default_zone = get_default_zone(); - } while (default_zone != &zone); + zone = zone_default_get(); + } while (zone != &jemalloc_zone); +} + +JEMALLOC_ATTR(constructor) +void +zone_register(void) +{ + + /* + * If something else replaced the system default zone allocator, don't + * register jemalloc's. + */ + default_zone = zone_default_get(); + if (!default_zone->zone_name || strcmp(default_zone->zone_name, + "DefaultMallocZone") != 0) + return; + + /* + * The default purgeable zone is created lazily by OSX's libc. It uses + * the default zone when it is created for "small" allocations + * (< 15 KiB), but assumes the default zone is a scalable_zone. This + * obviously fails when the default zone is the jemalloc zone, so + * malloc_default_purgeable_zone() is called beforehand so that the + * default purgeable zone is created when the default zone is still + * a scalable_zone. As purgeable zones only exist on >= 10.6, we need + * to check for the existence of malloc_default_purgeable_zone() at + * run time. + */ + purgeable_zone = (malloc_default_purgeable_zone == NULL) ? NULL : + malloc_default_purgeable_zone(); + + /* Register the custom zone. At this point it won't be the default. */ + zone_init(); + malloc_zone_register(&jemalloc_zone); + + /* Promote the custom zone to be default. */ + zone_promote(); } -- GitLab From 795f6689dec28f161afbf5964ef1b17288dd384d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 2 Nov 2016 18:09:45 -0700 Subject: [PATCH 154/544] Add os_unfair_lock support. OS X 10.12 deprecated OSSpinLock; os_unfair_lock is the recommended replacement. --- configure.ac | 14 ++++++++++++++ .../jemalloc/internal/jemalloc_internal_decls.h | 3 +++ .../jemalloc/internal/jemalloc_internal_defs.h.in | 5 +++++ include/jemalloc/internal/mutex.h | 9 +++++++++ src/mutex.c | 2 ++ test/include/test/mtx.h | 2 ++ test/src/mtx.c | 7 +++++++ 7 files changed, 42 insertions(+) diff --git a/configure.ac b/configure.ac index 0d10143c..2713cbc2 100644 --- a/configure.ac +++ b/configure.ac @@ -1612,6 +1612,20 @@ if test "x${je_cv_builtin_clz}" = "xyes" ; then AC_DEFINE([JEMALLOC_HAVE_BUILTIN_CLZ], [ ]) fi +dnl ============================================================================ +dnl Check for os_unfair_lock operations as provided on Darwin. + +JE_COMPILABLE([Darwin os_unfair_lock_*()], [ +#include +], [ + os_unfair_lock lock = OS_UNFAIR_LOCK_INIT; + os_unfair_lock_lock(&lock); + os_unfair_lock_unlock(&lock); +], [je_cv_os_unfair_lock]) +if test "x${je_cv_os_unfair_lock}" = "xyes" ; then + AC_DEFINE([JEMALLOC_OS_UNFAIR_LOCK], [ ]) +fi + dnl ============================================================================ dnl Check for spinlock(3) operations as provided on Darwin. diff --git a/include/jemalloc/internal/jemalloc_internal_decls.h b/include/jemalloc/internal/jemalloc_internal_decls.h index 1d7f2075..c907d910 100644 --- a/include/jemalloc/internal/jemalloc_internal_decls.h +++ b/include/jemalloc/internal/jemalloc_internal_decls.h @@ -17,6 +17,9 @@ # include # endif # include +# ifdef JEMALLOC_OS_UNFAIR_LOCK +# include +# endif # ifdef JEMALLOC_GLIBC_MALLOC_HOOK # include # endif diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 0ba960ba..dcbad728 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -60,6 +60,11 @@ */ #undef JEMALLOC_HAVE_MADVISE +/* + * Defined if os_unfair_lock_*() functions are available, as provided by Darwin. + */ +#undef JEMALLOC_OS_UNFAIR_LOCK + /* * Defined if OSSpin*() functions are available, as provided by Darwin, and * documented in the spinlock(3) manual page. diff --git a/include/jemalloc/internal/mutex.h b/include/jemalloc/internal/mutex.h index b4e01ff8..d5b3693c 100644 --- a/include/jemalloc/internal/mutex.h +++ b/include/jemalloc/internal/mutex.h @@ -5,6 +5,9 @@ typedef struct malloc_mutex_s malloc_mutex_t; #ifdef _WIN32 # define MALLOC_MUTEX_INITIALIZER +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) +# define MALLOC_MUTEX_INITIALIZER \ + {OS_UNFAIR_LOCK_INIT, WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} #elif (defined(JEMALLOC_OSSPIN)) # define MALLOC_MUTEX_INITIALIZER \ {0, WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} @@ -38,6 +41,8 @@ struct malloc_mutex_s { # else CRITICAL_SECTION lock; # endif +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) + os_unfair_lock lock; #elif (defined(JEMALLOC_OSSPIN)) OSSpinLock lock; #elif (defined(JEMALLOC_MUTEX_INIT_CB)) @@ -91,6 +96,8 @@ malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) # else EnterCriticalSection(&mutex->lock); # endif +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) + os_unfair_lock_lock(&mutex->lock); #elif (defined(JEMALLOC_OSSPIN)) OSSpinLockLock(&mutex->lock); #else @@ -112,6 +119,8 @@ malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) # else LeaveCriticalSection(&mutex->lock); # endif +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) + os_unfair_lock_unlock(&mutex->lock); #elif (defined(JEMALLOC_OSSPIN)) OSSpinLockUnlock(&mutex->lock); #else diff --git a/src/mutex.c b/src/mutex.c index 119b8e35..b757ba86 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -80,6 +80,8 @@ malloc_mutex_init(malloc_mutex_t *mutex, const char *name, witness_rank_t rank) _CRT_SPINCOUNT)) return (true); # endif +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) + mutex->lock = OS_UNFAIR_LOCK_INIT; #elif (defined(JEMALLOC_OSSPIN)) mutex->lock = 0; #elif (defined(JEMALLOC_MUTEX_INIT_CB)) diff --git a/test/include/test/mtx.h b/test/include/test/mtx.h index bbe822f5..58afbc3d 100644 --- a/test/include/test/mtx.h +++ b/test/include/test/mtx.h @@ -8,6 +8,8 @@ typedef struct { #ifdef _WIN32 CRITICAL_SECTION lock; +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) + os_unfair_lock lock; #elif (defined(JEMALLOC_OSSPIN)) OSSpinLock lock; #else diff --git a/test/src/mtx.c b/test/src/mtx.c index 73bd02f6..8a5dfdd9 100644 --- a/test/src/mtx.c +++ b/test/src/mtx.c @@ -11,6 +11,8 @@ mtx_init(mtx_t *mtx) #ifdef _WIN32 if (!InitializeCriticalSectionAndSpinCount(&mtx->lock, _CRT_SPINCOUNT)) return (true); +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) + mtx->lock = OS_UNFAIR_LOCK_INIT; #elif (defined(JEMALLOC_OSSPIN)) mtx->lock = 0; #else @@ -33,6 +35,7 @@ mtx_fini(mtx_t *mtx) { #ifdef _WIN32 +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) #elif (defined(JEMALLOC_OSSPIN)) #else pthread_mutex_destroy(&mtx->lock); @@ -45,6 +48,8 @@ mtx_lock(mtx_t *mtx) #ifdef _WIN32 EnterCriticalSection(&mtx->lock); +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) + os_unfair_lock_lock(&mtx->lock); #elif (defined(JEMALLOC_OSSPIN)) OSSpinLockLock(&mtx->lock); #else @@ -58,6 +63,8 @@ mtx_unlock(mtx_t *mtx) #ifdef _WIN32 LeaveCriticalSection(&mtx->lock); +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) + os_unfair_lock_unlock(&mtx->lock); #elif (defined(JEMALLOC_OSSPIN)) OSSpinLockUnlock(&mtx->lock); #else -- GitLab From d82f2b3473daef45d92d2a83d11487b22f9db4d3 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 2 Nov 2016 19:18:33 -0700 Subject: [PATCH 155/544] Do not use syscall(2) on OS X 10.12 (deprecated). --- configure.ac | 17 +++++++++++++++++ .../internal/jemalloc_internal_defs.h.in | 3 +++ src/pages.c | 6 +++--- src/util.c | 2 +- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 2713cbc2..6fc44c3e 100644 --- a/configure.ac +++ b/configure.ac @@ -1350,6 +1350,23 @@ if test "x${je_cv_mach_absolute_time}" = "xyes" ; then AC_DEFINE([JEMALLOC_HAVE_MACH_ABSOLUTE_TIME]) fi +dnl Check if syscall(2) is usable. Treat warnings as errors, so that e.g. OS X +dnl 10.12's deprecation warning prevents use. +SAVED_CFLAGS="${CFLAGS}" +JE_CFLAGS_APPEND([-Werror]) +JE_COMPILABLE([syscall(2)], [ +#define _GNU_SOURCE +#include +#include +], [ + syscall(SYS_write, 2, "hello", 5); +], + [je_cv_syscall]) +CFLAGS="${SAVED_CFLAGS}" +if test "x$je_cv_syscall" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_SYSCALL], [ ]) +fi + dnl Check if the GNU-specific secure_getenv function exists. AC_CHECK_FUNC([secure_getenv], [have_secure_getenv="1"], diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index dcbad728..4d2daea8 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -71,6 +71,9 @@ */ #undef JEMALLOC_OSSPIN +/* Defined if syscall(2) is available. */ +#undef JEMALLOC_HAVE_SYSCALL + /* * Defined if secure_getenv(3) is available. */ diff --git a/src/pages.c b/src/pages.c index 84e22160..647952ac 100644 --- a/src/pages.c +++ b/src/pages.c @@ -219,7 +219,7 @@ os_overcommits_proc(void) char buf[1]; ssize_t nread; -#ifdef SYS_open +#if defined(JEMALLOC_HAVE_SYSCALL) && defined(SYS_open) fd = (int)syscall(SYS_open, "/proc/sys/vm/overcommit_memory", O_RDONLY); #else fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY); @@ -227,13 +227,13 @@ os_overcommits_proc(void) if (fd == -1) return (false); /* Error. */ -#ifdef SYS_read +#if defined(JEMALLOC_HAVE_SYSCALL) && defined(SYS_read) nread = (ssize_t)syscall(SYS_read, fd, &buf, sizeof(buf)); #else nread = read(fd, &buf, sizeof(buf)); #endif -#ifdef SYS_close +#if defined(JEMALLOC_HAVE_SYSCALL) && defined(SYS_close) syscall(SYS_close, fd); #else close(fd); diff --git a/src/util.c b/src/util.c index 881a7fd1..5b8175bc 100644 --- a/src/util.c +++ b/src/util.c @@ -49,7 +49,7 @@ static void wrtmessage(void *cbopaque, const char *s) { -#ifdef SYS_write +#if defined(JEMALLOC_HAVE_SYSCALL) && defined(SYS_write) /* * Use syscall(2) rather than write(2) when possible in order to avoid * the possibility of memory allocation within libc. This is necessary -- GitLab From 83ebf2fda5603fe07fcb3ff25c0dd5ad939204d8 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 2 Nov 2016 19:50:44 -0700 Subject: [PATCH 156/544] Fix sycall(2) configure test for Linux. --- configure.ac | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 6fc44c3e..7df6627a 100644 --- a/configure.ac +++ b/configure.ac @@ -379,7 +379,7 @@ case "${host}" in AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) ;; *-*-linux*) - dnl secure_getenv() is exposed by _GNU_SOURCE. + dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" abi="elf" AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) @@ -1355,7 +1355,6 @@ dnl 10.12's deprecation warning prevents use. SAVED_CFLAGS="${CFLAGS}" JE_CFLAGS_APPEND([-Werror]) JE_COMPILABLE([syscall(2)], [ -#define _GNU_SOURCE #include #include ], [ -- GitLab From 712fde79fda767ce1eec7cf1c967feeae90b0c21 Mon Sep 17 00:00:00 2001 From: Dave Watson Date: Wed, 2 Nov 2016 18:22:32 -0700 Subject: [PATCH 157/544] Check for existance of CPU_COUNT macro before using it. This resolves #485. --- src/jemalloc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index 3e0605ec..86030172 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -753,8 +753,10 @@ malloc_ncpus(void) SYSTEM_INFO si; GetSystemInfo(&si); result = si.dwNumberOfProcessors; -#elif defined(JEMALLOC_GLIBC_MALLOC_HOOK) +#elif defined(JEMALLOC_GLIBC_MALLOC_HOOK) && defined(CPU_COUNT) /* + * glibc >= 2.6 has the CPU_COUNT macro. + * * glibc's sysconf() uses isspace(). glibc allocates for the first time * *before* setting up the isspace tables. Therefore we need a * different method to get the number of CPUs. @@ -1899,6 +1901,7 @@ JEMALLOC_EXPORT void *(*__memalign_hook)(size_t alignment, size_t size) = je_memalign; # endif +#ifdef CPU_COUNT /* * To enable static linking with glibc, the libc specific malloc interface must * be implemented also, so none of glibc's malloc.o functions are added to the @@ -1917,6 +1920,9 @@ int __posix_memalign(void** r, size_t a, size_t s) PREALIAS(je_posix_memalign); #undef PREALIAS #undef ALIAS + +#endif + #endif /* -- GitLab From 25f7bbcf28f5c83b11149989b3552d87c1f3c5e9 Mon Sep 17 00:00:00 2001 From: Dave Watson Date: Mon, 31 Oct 2016 16:23:33 -0700 Subject: [PATCH 158/544] Fix long spinning in rtree_node_init rtree_node_init spinlocks the node, allocates, and then sets the node. This is under heavy contention at the top of the tree if many threads start to allocate at the same time. Instead, take a per-rtree sleeping mutex to reduce spinning. Tested both pthreads and osx OSSpinLock, and both reduce spinning adequately Previous benchmark time: ./ttest1 500 100 ~15s New benchmark time: ./ttest1 500 100 .57s --- include/jemalloc/internal/rtree.h | 6 ++---- include/jemalloc/internal/witness.h | 3 ++- src/rtree.c | 23 +++++++++-------------- test/unit/rtree.c | 2 ++ 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/include/jemalloc/internal/rtree.h b/include/jemalloc/internal/rtree.h index fc88dfec..9c6cc22f 100644 --- a/include/jemalloc/internal/rtree.h +++ b/include/jemalloc/internal/rtree.h @@ -23,9 +23,6 @@ typedef struct rtree_s rtree_t; #define RTREE_HEIGHT_MAX \ ((1U << (LG_SIZEOF_PTR+3)) / RTREE_BITS_PER_LEVEL) -/* Used for two-stage lock-free node initialization. */ -#define RTREE_NODE_INITIALIZING ((rtree_elm_t *)0x1) - #define RTREE_CTX_INITIALIZER { \ false, \ 0, \ @@ -139,6 +136,7 @@ struct rtree_s { */ unsigned start_level[RTREE_HEIGHT_MAX + 1]; rtree_level_t levels[RTREE_HEIGHT_MAX]; + malloc_mutex_t init_lock; }; #endif /* JEMALLOC_H_STRUCTS */ @@ -251,7 +249,7 @@ JEMALLOC_ALWAYS_INLINE bool rtree_node_valid(rtree_elm_t *node) { - return ((uintptr_t)node > (uintptr_t)RTREE_NODE_INITIALIZING); + return ((uintptr_t)node != (uintptr_t)0); } JEMALLOC_ALWAYS_INLINE rtree_elm_t * diff --git a/include/jemalloc/internal/witness.h b/include/jemalloc/internal/witness.h index 26024ac2..86ddb64a 100644 --- a/include/jemalloc/internal/witness.h +++ b/include/jemalloc/internal/witness.h @@ -28,7 +28,8 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *, #define WITNESS_RANK_ARENA_EXTENT_CACHE 10 #define WITNESS_RANK_RTREE_ELM 11U -#define WITNESS_RANK_BASE 12U +#define WITNESS_RANK_RTREE 12U +#define WITNESS_RANK_BASE 13U #define WITNESS_RANK_LEAF 0xffffffffU #define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF diff --git a/src/rtree.c b/src/rtree.c index 0a42a982..b6b9ed76 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -59,6 +59,8 @@ rtree_new(rtree_t *rtree, unsigned bits) } rtree->start_level[RTREE_HEIGHT_MAX] = 0; + malloc_mutex_init(&rtree->init_lock, "rtree", WITNESS_RANK_RTREE); + return (false); } @@ -135,25 +137,18 @@ rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level, { rtree_elm_t *node; - if (atomic_cas_p((void **)elmp, NULL, RTREE_NODE_INITIALIZING)) { - spin_t spinner; - - /* - * Another thread is already in the process of initializing. - * Spin-wait until initialization is complete. - */ - spin_init(&spinner); - do { - spin_adaptive(&spinner); - node = atomic_read_p((void **)elmp); - } while (node == RTREE_NODE_INITIALIZING); - } else { + malloc_mutex_lock(tsdn, &rtree->init_lock); + node = atomic_read_p((void**)elmp); + if (node == NULL) { node = rtree_node_alloc(tsdn, rtree, ZU(1) << rtree->levels[level].bits); - if (node == NULL) + if (node == NULL) { + malloc_mutex_unlock(tsdn, &rtree->init_lock); return (NULL); + } atomic_write_p((void **)elmp, node); } + malloc_mutex_unlock(tsdn, &rtree->init_lock); return (node); } diff --git a/test/unit/rtree.c b/test/unit/rtree.c index a05834fa..03f4e269 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -13,8 +13,10 @@ rtree_node_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) if (rtree != test_rtree) return rtree_node_alloc_orig(tsdn, rtree, nelms); + malloc_mutex_unlock(tsdn, &rtree->init_lock); node = (rtree_elm_t *)calloc(nelms, sizeof(rtree_elm_t)); assert_ptr_not_null(node, "Unexpected calloc() failure"); + malloc_mutex_lock(tsdn, &rtree->init_lock); return (node); } -- GitLab From 69f027b8558c30e184921ce22bb187aafcad8a02 Mon Sep 17 00:00:00 2001 From: Samuel Moritz Date: Mon, 25 Jul 2016 19:33:27 +0200 Subject: [PATCH 159/544] Support Debian GNU/kFreeBSD. Treat it exactly like Linux since they both use GNU libc. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7df6627a..d926c8f2 100644 --- a/configure.ac +++ b/configure.ac @@ -378,7 +378,7 @@ case "${host}" in abi="elf" AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) ;; - *-*-linux*) + *-*-linux* | *-*-kfreebsd*) dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" abi="elf" -- GitLab From 04e1328ef143a5b6490f971716d9934719d752bf Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 2 Nov 2016 19:45:01 -0700 Subject: [PATCH 160/544] Update ChangeLog for 4.3.0. --- ChangeLog | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/ChangeLog b/ChangeLog index 532255d1..b43a467e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,43 @@ brevity. Much more detail can be found in the git revision history: https://github.com/jemalloc/jemalloc +* 4.3.0 (November 3, 2016) + + This is the first release that passes the test suite for multiple Windows + configurations, thanks in large part to @glandium setting up continuous + integration via AppVeyor (and Travis CI for Linux and OS X). + + New features: + - Add "J" (JSON) support to malloc_stats_print(). (@jasone) + - Add Cray compiler support. (@ronawho) + + Optimizations: + - Add/use adaptive spinning for bootstrapping and radix tree node + initialization. (@jasone) + + Bug fixes: + - Fix stats.arenas..nthreads accounting. (@interwq) + - Fix and simplify decay-based purging. (@jasone) + - Make DSS (sbrk(2)-related) operations lockless, which resolves potential + deadlocks during thread exit. (@jasone) + - Fix over-sized allocation of radix tree leaf nodes. (@mjp41, @ogaun, + @jasone) + - Fix EXTRA_CFLAGS to not affect configuration. (@jasone) + - Fix a Valgrind integration bug. (@ronawho) + - Disallow 0x5a junk filling when running in Valgrind. (@jasone) + - Fix a file descriptor leak on Linux. This regression was first released in + 4.2.0. (@jasone) + - Fix static linking of jemalloc with glibc. (@djwatson) + - Use syscall(2) rather than {open,read,close}(2) during boot on Linux. This + works around other libraries' system call wrappers performing reentrant + allocation. (@jasone) + - Fix OS X default zone replacement to work with OS X 10.12. (@glandium, + @jasone) + - Fix TSD fetches to avoid (recursive) allocation. This is relevant to + non-TLS and Windows configurations. (@jasone) + - Fix malloc_conf overriding to work on Windows. (@jasone) + - Forcibly disable lazy-lock on Windows (was forcibly *enabled*). (@jasone) + * 4.2.1 (June 8, 2016) Bug fixes: -- GitLab From 4f7d8c2dee624536e30e2fba907e2ce469b2cdf7 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 3 Nov 2016 15:00:02 -0700 Subject: [PATCH 161/544] Update symbol mangling. --- include/jemalloc/internal/private_symbols.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 29936a87..2e2c11d8 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -419,6 +419,8 @@ size2index size2index_compute size2index_lookup size2index_tab +spin_adaptive +spin_init stats_print tcache_alloc_easy tcache_alloc_large -- GitLab From 8dd5ea87cac39d9a90dbe40d13267ec02df0214c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 3 Nov 2016 17:25:54 -0700 Subject: [PATCH 162/544] Fix extent_alloc_cache[_locked]() to support decommitted allocation. Fix extent_alloc_cache[_locked]() to support decommitted allocation, and use this ability in arena_stash_dirty(), so that decommitted extents are not needlessly committed during purging. In practice this does not happen on any currently supported systems, because both extent merging and decommit must be implemented; all supported systems implement one xor the other. --- include/jemalloc/internal/extent.h | 4 ++-- src/arena.c | 11 ++++++----- src/extent.c | 20 +++++++++----------- src/large.c | 4 ++-- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 08d30365..673cac2f 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -101,10 +101,10 @@ ph_proto(, extent_heap_, extent_heap_t, extent_t) extent_t *extent_alloc_cache_locked(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool slab); + size_t alignment, bool *zero, bool *commit, bool slab); extent_t *extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool slab); + size_t alignment, bool *zero, bool *commit, bool slab); extent_t *extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab); diff --git a/src/arena.c b/src/arena.c index ce289594..fd3c5531 100644 --- a/src/arena.c +++ b/src/arena.c @@ -49,11 +49,12 @@ arena_extent_cache_alloc_locked(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool slab) { + bool commit = true; malloc_mutex_assert_owner(tsdn, &arena->lock); return (extent_alloc_cache(tsdn, arena, r_extent_hooks, new_addr, usize, - pad, alignment, zero, slab)); + pad, alignment, zero, &commit, slab)); } extent_t * @@ -681,7 +682,7 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, for (extent = qr_next(&arena->extents_dirty, qr_link); extent != &arena->extents_dirty; extent = next) { size_t npages; - bool zero; + bool zero, commit; UNUSED extent_t *textent; npages = extent_size_get(extent) >> LG_PAGE; @@ -691,9 +692,10 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, next = qr_next(extent, qr_link); /* Allocate. */ zero = false; + commit = false; textent = extent_alloc_cache_locked(tsdn, arena, r_extent_hooks, extent_base_get(extent), extent_size_get(extent), 0, PAGE, - &zero, false); + &zero, &commit, false); assert(textent == extent); assert(zero == extent_zeroed_get(extent)); extent_ring_remove(extent); @@ -943,9 +945,8 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, extent_t *slab; arena_slab_data_t *slab_data; extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; - bool zero; + bool zero = false; - zero = false; slab = arena_extent_cache_alloc_locked(tsdn, arena, &extent_hooks, NULL, bin_info->slab_size, 0, PAGE, &zero, true); if (slab == NULL) { diff --git a/src/extent.c b/src/extent.c index 809777a1..ad78c879 100644 --- a/src/extent.c +++ b/src/extent.c @@ -517,8 +517,9 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_usize_set(extent, usize); } - if (!extent_committed_get(extent) && extent_commit_wrapper(tsdn, arena, - r_extent_hooks, extent, 0, extent_size_get(extent))) { + if (commit && !extent_committed_get(extent) && + extent_commit_wrapper(tsdn, arena, r_extent_hooks, extent, 0, + extent_size_get(extent))) { if (!locked) malloc_mutex_unlock(tsdn, &arena->extents_mtx); extent_record(tsdn, arena, r_extent_hooks, extent_heaps, cache, @@ -590,44 +591,41 @@ extent_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, static extent_t * extent_alloc_cache_impl(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, bool locked, void *new_addr, size_t usize, - size_t pad, size_t alignment, bool *zero, bool slab) + size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) { extent_t *extent; - bool commit; assert(usize + pad != 0); assert(alignment != 0); - commit = true; extent = extent_recycle(tsdn, arena, r_extent_hooks, arena->extents_cached, locked, true, new_addr, usize, pad, - alignment, zero, &commit, slab); + alignment, zero, commit, slab); if (extent == NULL) return (NULL); - assert(commit); return (extent); } extent_t * extent_alloc_cache_locked(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool slab) + size_t alignment, bool *zero, bool *commit, bool slab) { malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); return (extent_alloc_cache_impl(tsdn, arena, r_extent_hooks, true, - new_addr, usize, pad, alignment, zero, slab)); + new_addr, usize, pad, alignment, zero, commit, slab)); } extent_t * extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool slab) + size_t alignment, bool *zero, bool *commit, bool slab) { return (extent_alloc_cache_impl(tsdn, arena, r_extent_hooks, false, - new_addr, usize, pad, alignment, zero, slab)); + new_addr, usize, pad, alignment, zero, commit, slab)); } static void * diff --git a/src/large.c b/src/large.c index 23af1830..1bae9399 100644 --- a/src/large.c +++ b/src/large.c @@ -143,8 +143,8 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, extent_t *trail; if ((trail = arena_extent_cache_alloc(tsdn, arena, &extent_hooks, - extent_past_get(extent), trailsize, CACHELINE, &is_zeroed_trail)) - == NULL) { + extent_past_get(extent), trailsize, CACHELINE, &is_zeroed_trail)) == + NULL) { bool commit = true; if ((trail = extent_alloc_wrapper(tsdn, arena, &extent_hooks, extent_past_get(extent), trailsize, 0, CACHELINE, -- GitLab From ea9961acdbc9f7e2c95a3b55ce0ac1024af5d167 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 3 Nov 2016 21:18:50 -0700 Subject: [PATCH 163/544] Fix psz/pind edge cases. Add an "over-size" extent heap in which to store extents which exceed the maximum size class (plus cache-oblivious padding, if enabled). Remove psz2ind_clamp() and use psz2ind() instead so that trying to allocate the maximum size class can in principle succeed. In practice, this allows assertions to hold so that OOM errors can be successfully generated. --- include/jemalloc/internal/arena.h | 4 +-- .../jemalloc/internal/jemalloc_internal.h.in | 28 ++++------------ include/jemalloc/internal/private_symbols.txt | 2 -- src/arena.c | 2 +- src/extent.c | 21 ++++++------ src/jemalloc.c | 3 +- test/unit/size_classes.c | 32 ++++++++++--------- 7 files changed, 39 insertions(+), 53 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 4e20af48..ce9d8b5e 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -212,8 +212,8 @@ struct arena_s { * Heaps of extents that were previously allocated. These are used when * allocating extents, in an attempt to re-use address space. */ - extent_heap_t extents_cached[NPSIZES]; - extent_heap_t extents_retained[NPSIZES]; + extent_heap_t extents_cached[NPSIZES+1]; + extent_heap_t extents_retained[NPSIZES+1]; /* * Ring sentinel used to track unused dirty memory. Dirty memory is * managed as an LRU of cached extents. diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 0e4ffd91..85b34012 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -434,7 +434,7 @@ extern arena_t **arenas; * pind2sz_tab encodes the same information as could be computed by * pind2sz_compute(). */ -extern size_t const pind2sz_tab[NPSIZES]; +extern size_t const pind2sz_tab[NPSIZES+1]; /* * index2size_tab encodes the same information as could be computed (at * unacceptable cost in some code paths) by index2size_compute(). @@ -516,9 +516,7 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/large.h" #ifndef JEMALLOC_ENABLE_INLINE -pszind_t psz2ind_impl(size_t psz, bool clamp); pszind_t psz2ind(size_t psz); -pszind_t psz2ind_clamp(size_t psz); size_t pind2sz_compute(pszind_t pind); size_t pind2sz_lookup(pszind_t pind); size_t pind2sz(pszind_t pind); @@ -544,11 +542,11 @@ ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) JEMALLOC_ALWAYS_INLINE pszind_t -psz2ind_impl(size_t psz, bool clamp) +psz2ind(size_t psz) { if (unlikely(psz > LARGE_MAXCLASS)) - return (clamp ? NPSIZES-1 : NPSIZES); + return (NPSIZES); { pszind_t x = lg_floor((psz<<1)-1); pszind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_PAGE) ? 0 : x - @@ -567,24 +565,12 @@ psz2ind_impl(size_t psz, bool clamp) } } -JEMALLOC_INLINE pszind_t -psz2ind(size_t psz) -{ - - return (psz2ind_impl(psz, false)); -} - -JEMALLOC_INLINE pszind_t -psz2ind_clamp(size_t psz) -{ - - return (psz2ind_impl(psz, true)); -} - JEMALLOC_INLINE size_t pind2sz_compute(pszind_t pind) { + if (unlikely(pind == NPSIZES)) + return (LARGE_MAXCLASS + PAGE); { size_t grp = pind >> LG_SIZE_CLASS_GROUP; size_t mod = pind & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); @@ -614,7 +600,7 @@ JEMALLOC_INLINE size_t pind2sz(pszind_t pind) { - assert(pind < NPSIZES); + assert(pind < NPSIZES+1); return (pind2sz_lookup(pind)); } @@ -623,7 +609,7 @@ psz2u(size_t psz) { if (unlikely(psz > LARGE_MAXCLASS)) - return (0); + return (LARGE_MAXCLASS + PAGE); { size_t x = lg_floor((psz<<1)-1); size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 2e2c11d8..2949de10 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -380,8 +380,6 @@ prof_thread_active_set prof_thread_name_get prof_thread_name_set psz2ind -psz2ind_clamp -psz2ind_impl psz2u rtree_child_read rtree_child_read_hard diff --git a/src/arena.c b/src/arena.c index fd3c5531..dd8e4d9c 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1696,7 +1696,7 @@ arena_new(tsdn_t *tsdn, unsigned ind) WITNESS_RANK_ARENA_LARGE)) return (NULL); - for (i = 0; i < NPSIZES; i++) { + for (i = 0; i < NPSIZES+1; i++) { extent_heap_new(&arena->extents_cached[i]); extent_heap_new(&arena->extents_retained[i]); } diff --git a/src/extent.c b/src/extent.c index ad78c879..a802ad90 100644 --- a/src/extent.c +++ b/src/extent.c @@ -45,7 +45,7 @@ static size_t highpages; */ static void extent_record(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_heap_t extent_heaps[NPSIZES], + extent_hooks_t **r_extent_hooks, extent_heap_t extent_heaps[NPSIZES+1], bool cache, extent_t *extent); /******************************************************************************/ @@ -190,11 +190,11 @@ extent_ad_comp(const extent_t *a, const extent_t *b) ph_gen(, extent_heap_, extent_heap_t, extent_t, ph_link, extent_ad_comp) static void -extent_heaps_insert(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES], +extent_heaps_insert(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES+1], extent_t *extent) { size_t psz = extent_size_quantize_floor(extent_size_get(extent)); - pszind_t pind = psz2ind_clamp(psz); + pszind_t pind = psz2ind(psz); malloc_mutex_assert_owner(tsdn, &extent_arena_get(extent)->extents_mtx); @@ -202,11 +202,11 @@ extent_heaps_insert(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES], } static void -extent_heaps_remove(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES], +extent_heaps_remove(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES+1], extent_t *extent) { size_t psz = extent_size_quantize_floor(extent_size_get(extent)); - pszind_t pind = psz2ind_clamp(psz); + pszind_t pind = psz2ind(psz); malloc_mutex_assert_owner(tsdn, &extent_arena_get(extent)->extents_mtx); @@ -358,15 +358,14 @@ extent_deregister(tsdn_t *tsdn, extent_t *extent) */ static extent_t * extent_first_best_fit(tsdn_t *tsdn, arena_t *arena, - extent_heap_t extent_heaps[NPSIZES], size_t size) + extent_heap_t extent_heaps[NPSIZES+1], size_t size) { pszind_t pind, i; malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); pind = psz2ind(extent_size_quantize_ceil(size)); - assert(pind < NPSIZES); - for (i = pind; i < NPSIZES; i++) { + for (i = pind; i < NPSIZES+1; i++) { extent_t *extent = extent_heap_first(&extent_heaps[i]); if (extent != NULL) return (extent); @@ -393,7 +392,7 @@ extent_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, static extent_t * extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extent_heap_t extent_heaps[NPSIZES], bool locked, bool cache, + extent_heap_t extent_heaps[NPSIZES+1], bool locked, bool cache, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) { @@ -758,7 +757,7 @@ extent_can_coalesce(const extent_t *a, const extent_t *b) static void extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b, - extent_heap_t extent_heaps[NPSIZES], bool cache) + extent_heap_t extent_heaps[NPSIZES+1], bool cache) { if (!extent_can_coalesce(a, b)) @@ -786,7 +785,7 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, static void extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extent_heap_t extent_heaps[NPSIZES], bool cache, extent_t *extent) + extent_heap_t extent_heaps[NPSIZES+1], bool cache, extent_t *extent) { extent_t *prev, *next; rtree_ctx_t rtree_ctx_fallback; diff --git a/src/jemalloc.c b/src/jemalloc.c index 86030172..dc0add49 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -83,7 +83,7 @@ enum { static uint8_t malloc_slow_flags; JEMALLOC_ALIGNED(CACHELINE) -const size_t pind2sz_tab[NPSIZES] = { +const size_t pind2sz_tab[NPSIZES+1] = { #define PSZ_yes(lg_grp, ndelta, lg_delta) \ (((ZU(1)< Date: Thu, 3 Nov 2016 21:14:59 -0700 Subject: [PATCH 164/544] Fix extent_recycle()'s cache-oblivious padding support. Add padding *after* computing the size class, so that the optimal size class isn't skipped during search for a usable extent. This regression was caused by b46261d58b449cc4c099ed2384451a2499688f0e (Implement cache-oblivious support for huge size classes.). --- src/extent.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/extent.c b/src/extent.c index a802ad90..e190adc4 100644 --- a/src/extent.c +++ b/src/extent.c @@ -427,12 +427,13 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, assert(prev == NULL || extent_past_get(prev) == new_addr); } - size = usize + pad; - alloc_size = (new_addr != NULL) ? size : s2u(size + - PAGE_CEILING(alignment) - PAGE); - /* Beware size_t wrap-around. */ - if (alloc_size < usize) + alloc_size = ((new_addr != NULL) ? usize : s2u(usize + + PAGE_CEILING(alignment) - PAGE)) + pad; + if (alloc_size > LARGE_MAXCLASS + pad || alloc_size < usize) { + /* Too large, possibly wrapped around. */ return (NULL); + } + size = usize + pad; if (!locked) malloc_mutex_lock(tsdn, &arena->extents_mtx); extent_hooks_assure_initialized(arena, r_extent_hooks); -- GitLab From a967fae362f55ee7162fb48776dfac69d4f28d1c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 3 Nov 2016 23:49:21 -0700 Subject: [PATCH 165/544] Fix/simplify extent_recycle() allocation size computations. Do not call s2u() during alloc_size computation, since any necessary ceiling increase is taken care of later by extent_first_best_fit() --> extent_size_quantize_ceil(), and the s2u() call may erroneously cause a higher quantization result. Remove an overly strict overflow check that was added in 4a7852137d8b6598fdb90ea8e1fd3bc8a8b94a3a (Fix extent_recycle()'s cache-oblivious padding support.). --- src/extent.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/extent.c b/src/extent.c index e190adc4..4027e8b7 100644 --- a/src/extent.c +++ b/src/extent.c @@ -405,6 +405,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); assert(new_addr == NULL || !slab); assert(pad == 0 || !slab); + assert(alignment > 0); if (config_debug && new_addr != NULL) { extent_t *prev; @@ -427,13 +428,11 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, assert(prev == NULL || extent_past_get(prev) == new_addr); } - alloc_size = ((new_addr != NULL) ? usize : s2u(usize + - PAGE_CEILING(alignment) - PAGE)) + pad; - if (alloc_size > LARGE_MAXCLASS + pad || alloc_size < usize) { - /* Too large, possibly wrapped around. */ - return (NULL); - } size = usize + pad; + alloc_size = size + PAGE_CEILING(alignment) - PAGE; + /* Beware size_t wrap-around. */ + if (alloc_size < usize) + return (NULL); if (!locked) malloc_mutex_lock(tsdn, &arena->extents_mtx); extent_hooks_assure_initialized(arena, r_extent_hooks); -- GitLab From 076087692750ca6ba43b52c77e03d185002e5371 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 4 Nov 2016 00:02:43 -0700 Subject: [PATCH 166/544] Update ChangeLog for 4.3.0. --- ChangeLog | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index b43a467e..ac2e4d3c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,7 +4,7 @@ brevity. Much more detail can be found in the git revision history: https://github.com/jemalloc/jemalloc -* 4.3.0 (November 3, 2016) +* 4.3.0 (November 4, 2016) This is the first release that passes the test suite for multiple Windows configurations, thanks in large part to @glandium setting up continuous @@ -19,6 +19,9 @@ brevity. Much more detail can be found in the git revision history: initialization. (@jasone) Bug fixes: + - Fix large allocation to search starting in the optimal size class heap, + which can substantially reduce virtual memory churn and fragmentation. This + regression was first released in 4.0.0. (@mjp41, @jasone) - Fix stats.arenas..nthreads accounting. (@interwq) - Fix and simplify decay-based purging. (@jasone) - Make DSS (sbrk(2)-related) operations lockless, which resolves potential @@ -29,13 +32,16 @@ brevity. Much more detail can be found in the git revision history: - Fix a Valgrind integration bug. (@ronawho) - Disallow 0x5a junk filling when running in Valgrind. (@jasone) - Fix a file descriptor leak on Linux. This regression was first released in - 4.2.0. (@jasone) + 4.2.0. (@vsarunas, @jasone) - Fix static linking of jemalloc with glibc. (@djwatson) - Use syscall(2) rather than {open,read,close}(2) during boot on Linux. This works around other libraries' system call wrappers performing reentrant - allocation. (@jasone) + allocation. (@kspinka, @Whissi, @jasone) - Fix OS X default zone replacement to work with OS X 10.12. (@glandium, @jasone) + - Fix cached memory management to avoid needless commit/decommit operations + during purging, which resolves permanent virtual memory map fragmentation + issues on Windows. (@mjp41, @jasone) - Fix TSD fetches to avoid (recursive) allocation. This is relevant to non-TLS and Windows configurations. (@jasone) - Fix malloc_conf overriding to work on Windows. (@jasone) -- GitLab From 6d2a57cfbbd9991ef120b9773e971053deec776a Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 3 Nov 2016 21:57:17 -0700 Subject: [PATCH 167/544] Use -std=gnu11 if available. This supersedes -std=gnu99, and enables C11 atomics. --- configure.ac | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index d926c8f2..6f29ce0a 100644 --- a/configure.ac +++ b/configure.ac @@ -171,9 +171,15 @@ fi if test "x$CFLAGS" = "x" ; then no_CFLAGS="yes" if test "x$GCC" = "xyes" ; then - JE_CFLAGS_APPEND([-std=gnu99]) - if test "x$je_cv_cflags_appended" = "x-std=gnu99" ; then +dnl JE_CFLAGS_APPEND([-std=gnu99]) + JE_CFLAGS_APPEND([-std=gnu11]) + if test "x$je_cv_cflags_appended" = "x-std=gnu11" ; then AC_DEFINE_UNQUOTED([JEMALLOC_HAS_RESTRICT]) + else + JE_CFLAGS_APPEND([-std=gnu99]) + if test "x$je_cv_cflags_appended" = "x-std=gnu99" ; then + AC_DEFINE_UNQUOTED([JEMALLOC_HAS_RESTRICT]) + fi fi JE_CFLAGS_APPEND([-Wall]) JE_CFLAGS_APPEND([-Werror=declaration-after-statement]) -- GitLab From d30b3ea51a6cb3abe88251a0fd769b0438c88a6e Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Fri, 4 Nov 2016 10:27:32 +0000 Subject: [PATCH 168/544] Fixes to Visual Studio Project files --- msvc/projects/vc2015/jemalloc/jemalloc.vcxproj | 2 ++ .../vc2015/jemalloc/jemalloc.vcxproj.filters | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj index e5ecb351..75ea8fba 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj @@ -68,6 +68,7 @@ + @@ -107,6 +108,7 @@ + diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters index 74b45112..a328a6f9 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters @@ -140,6 +140,12 @@ Header Files\internal + + Header Files\internal + + + Header Files\internal + Header Files\internal @@ -155,6 +161,9 @@ Header Files\internal + + Header Files\internal + Header Files\msvc_compat @@ -167,12 +176,6 @@ Header Files\msvc_compat\C99 - - Header Files\internal - - - Header Files\internal - @@ -232,6 +235,9 @@ Source Files + + Source Files + Source Files -- GitLab From e0a9e78374f56bc7a27258ced08d89bfc436d8af Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 4 Nov 2016 15:15:24 -0700 Subject: [PATCH 169/544] Update ChangeLog for 4.3.0. --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index ac2e4d3c..118df96f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,6 +28,8 @@ brevity. Much more detail can be found in the git revision history: deadlocks during thread exit. (@jasone) - Fix over-sized allocation of radix tree leaf nodes. (@mjp41, @ogaun, @jasone) + - Fix over-sized allocation of arena_t (plus associated stats) data + structures. (@jasone, @interwq) - Fix EXTRA_CFLAGS to not affect configuration. (@jasone) - Fix a Valgrind integration bug. (@ronawho) - Disallow 0x5a junk filling when running in Valgrind. (@jasone) -- GitLab From 04b463546e57ecd9ebc334739881a1c69623813a Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 7 Nov 2016 10:52:44 -0800 Subject: [PATCH 170/544] Refactor prng to not use 64-bit atomics on 32-bit platforms. This resolves #495. --- include/jemalloc/internal/arena.h | 2 +- include/jemalloc/internal/extent.h | 4 +- include/jemalloc/internal/private_symbols.txt | 12 +- include/jemalloc/internal/prng.h | 143 ++++++++++-- src/arena.c | 6 +- src/ckh.c | 8 +- src/prof.c | 2 +- test/unit/prng.c | 209 ++++++++++++++++-- 8 files changed, 334 insertions(+), 52 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index ce9d8b5e..dbd334e6 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -182,7 +182,7 @@ struct arena_s { * PRNG state for cache index randomization of large allocation base * pointers. */ - uint64_t offset_state; + size_t offset_state; dss_prec_t dss_prec; diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 673cac2f..531d853c 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -325,8 +325,8 @@ extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment) if (alignment < PAGE) { unsigned lg_range = LG_PAGE - lg_floor(CACHELINE_CEILING(alignment)); - uint64_t r = - prng_lg_range(&extent_arena_get(extent)->offset_state, + size_t r = + prng_lg_range_zu(&extent_arena_get(extent)->offset_state, lg_range, true); uintptr_t random_offset = ((uintptr_t)r) << (LG_PAGE - lg_range); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 2949de10..f178daf7 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -328,9 +328,15 @@ pind2sz_tab pow2_ceil_u32 pow2_ceil_u64 pow2_ceil_zu -prng_lg_range -prng_range -prng_state_next +prng_lg_range_u32 +prng_lg_range_u64 +prng_lg_range_zu +prng_range_u32 +prng_range_u64 +prng_range_zu +prng_state_next_u32 +prng_state_next_u64 +prng_state_next_zu prof_active prof_active_get prof_active_get_unlocked diff --git a/include/jemalloc/internal/prng.h b/include/jemalloc/internal/prng.h index ebe916f8..c2bda19c 100644 --- a/include/jemalloc/internal/prng.h +++ b/include/jemalloc/internal/prng.h @@ -19,8 +19,12 @@ * the next has a cycle of 4, etc. For this reason, we prefer to use the upper * bits. */ -#define PRNG_A UINT64_C(6364136223846793005) -#define PRNG_C UINT64_C(1442695040888963407) + +#define PRNG_A_32 UINT32_C(1103515241) +#define PRNG_C_32 UINT32_C(12347) + +#define PRNG_A_64 UINT64_C(6364136223846793005) +#define PRNG_C_64 UINT64_C(1442695040888963407) #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ @@ -35,45 +39,133 @@ #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE -uint64_t prng_state_next(uint64_t state); -uint64_t prng_lg_range(uint64_t *state, unsigned lg_range, bool atomic); -uint64_t prng_range(uint64_t *state, uint64_t range, bool atomic); +uint32_t prng_state_next_u32(uint32_t state); +uint64_t prng_state_next_u64(uint64_t state); +size_t prng_state_next_zu(size_t state); + +uint32_t prng_lg_range_u32(uint32_t *state, unsigned lg_range, + bool atomic); +uint64_t prng_lg_range_u64(uint64_t *state, unsigned lg_range); +size_t prng_lg_range_zu(size_t *state, unsigned lg_range, bool atomic); + +uint32_t prng_range_u32(uint32_t *state, uint32_t range, bool atomic); +uint64_t prng_range_u64(uint64_t *state, uint64_t range); +size_t prng_range_zu(size_t *state, size_t range, bool atomic); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PRNG_C_)) +JEMALLOC_ALWAYS_INLINE uint32_t +prng_state_next_u32(uint32_t state) +{ + + return ((state * PRNG_A_32) + PRNG_C_32); +} + JEMALLOC_ALWAYS_INLINE uint64_t -prng_state_next(uint64_t state) +prng_state_next_u64(uint64_t state) +{ + + return ((state * PRNG_A_64) + PRNG_C_64); +} + +JEMALLOC_ALWAYS_INLINE size_t +prng_state_next_zu(size_t state) +{ + +#if LG_SIZEOF_PTR == 2 + return ((state * PRNG_A_32) + PRNG_C_32); +#elif LG_SIZEOF_PTR == 3 + return ((state * PRNG_A_64) + PRNG_C_64); +#else +#error Unsupported pointer size +#endif +} + +JEMALLOC_ALWAYS_INLINE uint32_t +prng_lg_range_u32(uint32_t *state, unsigned lg_range, bool atomic) { + uint32_t ret, state1; + + assert(lg_range > 0); + assert(lg_range <= 32); + + if (atomic) { + uint32_t state0; + + do { + state0 = atomic_read_uint32(state); + state1 = prng_state_next_u32(state0); + } while (atomic_cas_uint32(state, state0, state1)); + } else { + state1 = prng_state_next_u32(*state); + *state = state1; + } + ret = state1 >> (32 - lg_range); - return ((state * PRNG_A) + PRNG_C); + return (ret); } +/* 64-bit atomic operations cannot be supported on all relevant platforms. */ JEMALLOC_ALWAYS_INLINE uint64_t -prng_lg_range(uint64_t *state, unsigned lg_range, bool atomic) +prng_lg_range_u64(uint64_t *state, unsigned lg_range) { uint64_t ret, state1; assert(lg_range > 0); assert(lg_range <= 64); + state1 = prng_state_next_u64(*state); + *state = state1; + ret = state1 >> (64 - lg_range); + + return (ret); +} + +JEMALLOC_ALWAYS_INLINE size_t +prng_lg_range_zu(size_t *state, unsigned lg_range, bool atomic) +{ + size_t ret, state1; + + assert(lg_range > 0); + assert(lg_range <= ZU(1) << (3 + LG_SIZEOF_PTR)); + if (atomic) { - uint64_t state0; + size_t state0; do { - state0 = atomic_read_uint64(state); - state1 = prng_state_next(state0); - } while (atomic_cas_uint64(state, state0, state1)); + state0 = atomic_read_z(state); + state1 = prng_state_next_zu(state0); + } while (atomic_cas_z(state, state0, state1)); } else { - state1 = prng_state_next(*state); + state1 = prng_state_next_zu(*state); *state = state1; } - ret = state1 >> (64 - lg_range); + ret = state1 >> ((ZU(1) << (3 + LG_SIZEOF_PTR)) - lg_range); + + return (ret); +} + +JEMALLOC_ALWAYS_INLINE uint32_t +prng_range_u32(uint32_t *state, uint32_t range, bool atomic) +{ + uint32_t ret; + unsigned lg_range; + + assert(range > 1); + + /* Compute the ceiling of lg(range). */ + lg_range = ffs_u32(pow2_ceil_u32(range)) - 1; + + /* Generate a result in [0..range) via repeated trial. */ + do { + ret = prng_lg_range_u32(state, lg_range, atomic); + } while (ret >= range); return (ret); } JEMALLOC_ALWAYS_INLINE uint64_t -prng_range(uint64_t *state, uint64_t range, bool atomic) +prng_range_u64(uint64_t *state, uint64_t range) { uint64_t ret; unsigned lg_range; @@ -85,7 +177,26 @@ prng_range(uint64_t *state, uint64_t range, bool atomic) /* Generate a result in [0..range) via repeated trial. */ do { - ret = prng_lg_range(state, lg_range, atomic); + ret = prng_lg_range_u64(state, lg_range); + } while (ret >= range); + + return (ret); +} + +JEMALLOC_ALWAYS_INLINE size_t +prng_range_zu(size_t *state, size_t range, bool atomic) +{ + size_t ret; + unsigned lg_range; + + assert(range > 1); + + /* Compute the ceiling of lg(range). */ + lg_range = ffs_u64(pow2_ceil_u64(range)) - 1; + + /* Generate a result in [0..range) via repeated trial. */ + do { + ret = prng_lg_range_zu(state, lg_range, atomic); } while (ret >= range); return (ret); diff --git a/src/arena.c b/src/arena.c index dd8e4d9c..4b104a0e 100644 --- a/src/arena.c +++ b/src/arena.c @@ -422,8 +422,8 @@ arena_decay_deadline_init(arena_t *arena) if (arena->decay.time > 0) { nstime_t jitter; - nstime_init(&jitter, prng_range(&arena->decay.jitter_state, - nstime_ns(&arena->decay.interval), false)); + nstime_init(&jitter, prng_range_u64(&arena->decay.jitter_state, + nstime_ns(&arena->decay.interval))); nstime_add(&arena->decay.deadline, &jitter); } } @@ -1680,7 +1680,7 @@ arena_new(tsdn_t *tsdn, unsigned ind) * deterministic seed. */ arena->offset_state = config_debug ? ind : - (uint64_t)(uintptr_t)arena; + (size_t)(uintptr_t)arena; } arena->dss_prec = extent_dss_prec_get(); diff --git a/src/ckh.c b/src/ckh.c index 75376017..6f16565f 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -99,8 +99,8 @@ ckh_try_bucket_insert(ckh_t *ckh, size_t bucket, const void *key, * Cycle through the cells in the bucket, starting at a random position. * The randomness avoids worst-case search overhead as buckets fill up. */ - offset = (unsigned)prng_lg_range(&ckh->prng_state, LG_CKH_BUCKET_CELLS, - false); + offset = (unsigned)prng_lg_range_u64(&ckh->prng_state, + LG_CKH_BUCKET_CELLS); for (i = 0; i < (ZU(1) << LG_CKH_BUCKET_CELLS); i++) { cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + ((i + offset) & ((ZU(1) << LG_CKH_BUCKET_CELLS) - 1))]; @@ -142,8 +142,8 @@ ckh_evict_reloc_insert(ckh_t *ckh, size_t argbucket, void const **argkey, * were an item for which both hashes indicated the same * bucket. */ - i = (unsigned)prng_lg_range(&ckh->prng_state, - LG_CKH_BUCKET_CELLS, false); + i = (unsigned)prng_lg_range_u64(&ckh->prng_state, + LG_CKH_BUCKET_CELLS); cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + i]; assert(cell->key != NULL); diff --git a/src/prof.c b/src/prof.c index 4bafb39a..19c8fb71 100644 --- a/src/prof.c +++ b/src/prof.c @@ -878,7 +878,7 @@ prof_sample_threshold_update(prof_tdata_t *tdata) * pp 500 * (http://luc.devroye.org/rnbookindex.html) */ - r = prng_lg_range(&tdata->prng_state, 53, false); + r = prng_lg_range_u64(&tdata->prng_state, 53); u = (double)r * (1.0/9007199254740992.0L); tdata->bytes_until_sample = (uint64_t)(log(u) / log(1.0 - (1.0 / (double)((uint64_t)1U << lg_prof_sample)))) diff --git a/test/unit/prng.c b/test/unit/prng.c index f3234455..111fa59f 100644 --- a/test/unit/prng.c +++ b/test/unit/prng.c @@ -1,34 +1,71 @@ #include "test/jemalloc_test.h" static void -test_prng_lg_range(bool atomic) +test_prng_lg_range_u32(bool atomic) +{ + uint32_t sa, sb, ra, rb; + unsigned lg_range; + + sa = 42; + ra = prng_lg_range_u32(&sa, 32, atomic); + sa = 42; + rb = prng_lg_range_u32(&sa, 32, atomic); + assert_u32_eq(ra, rb, + "Repeated generation should produce repeated results"); + + sb = 42; + rb = prng_lg_range_u32(&sb, 32, atomic); + assert_u32_eq(ra, rb, + "Equivalent generation should produce equivalent results"); + + sa = 42; + ra = prng_lg_range_u32(&sa, 32, atomic); + rb = prng_lg_range_u32(&sa, 32, atomic); + assert_u32_ne(ra, rb, + "Full-width results must not immediately repeat"); + + sa = 42; + ra = prng_lg_range_u32(&sa, 32, atomic); + for (lg_range = 31; lg_range > 0; lg_range--) { + sb = 42; + rb = prng_lg_range_u32(&sb, lg_range, atomic); + assert_u32_eq((rb & (UINT32_C(0xffffffff) << lg_range)), + 0, "High order bits should be 0, lg_range=%u", lg_range); + assert_u32_eq(rb, (ra >> (32 - lg_range)), + "Expected high order bits of full-width result, " + "lg_range=%u", lg_range); + } +} + +static void +test_prng_lg_range_u64(void) { uint64_t sa, sb, ra, rb; unsigned lg_range; sa = 42; - ra = prng_lg_range(&sa, 64, atomic); + ra = prng_lg_range_u64(&sa, 64); sa = 42; - rb = prng_lg_range(&sa, 64, atomic); + rb = prng_lg_range_u64(&sa, 64); assert_u64_eq(ra, rb, "Repeated generation should produce repeated results"); sb = 42; - rb = prng_lg_range(&sb, 64, atomic); + rb = prng_lg_range_u64(&sb, 64); assert_u64_eq(ra, rb, "Equivalent generation should produce equivalent results"); sa = 42; - ra = prng_lg_range(&sa, 64, atomic); - rb = prng_lg_range(&sa, 64, atomic); + ra = prng_lg_range_u64(&sa, 64); + rb = prng_lg_range_u64(&sa, 64); assert_u64_ne(ra, rb, "Full-width results must not immediately repeat"); sa = 42; - ra = prng_lg_range(&sa, 64, atomic); + ra = prng_lg_range_u64(&sa, 64); for (lg_range = 63; lg_range > 0; lg_range--) { sb = 42; - rb = prng_lg_range(&sb, lg_range, atomic); + rb = prng_lg_range_u64(&sb, lg_range); assert_u64_eq((rb & (UINT64_C(0xffffffffffffffff) << lg_range)), 0, "High order bits should be 0, lg_range=%u", lg_range); assert_u64_eq(rb, (ra >> (64 - lg_range)), @@ -37,22 +74,102 @@ test_prng_lg_range(bool atomic) } } -TEST_BEGIN(test_prng_lg_range_nonatomic) +static void +test_prng_lg_range_zu(bool atomic) +{ + uint64_t sa, sb, ra, rb; + unsigned lg_range; + + sa = 42; + ra = prng_lg_range_zu(&sa, 64, atomic); + sa = 42; + rb = prng_lg_range_zu(&sa, 64, atomic); + assert_zu_eq(ra, rb, + "Repeated generation should produce repeated results"); + + sb = 42; + rb = prng_lg_range_zu(&sb, 64, atomic); + assert_zu_eq(ra, rb, + "Equivalent generation should produce equivalent results"); + + sa = 42; + ra = prng_lg_range_zu(&sa, 64, atomic); + rb = prng_lg_range_zu(&sa, 64, atomic); + assert_zu_ne(ra, rb, + "Full-width results must not immediately repeat"); + + sa = 42; + ra = prng_lg_range_zu(&sa, 64, atomic); + for (lg_range = (ZU(1) << (3 + LG_SIZEOF_PTR)) - 1; lg_range > 0; + lg_range--) { + sb = 42; + rb = prng_lg_range_zu(&sb, lg_range, atomic); + assert_zu_eq((rb & (SIZE_T_MAX << lg_range)), + 0, "High order bits should be 0, lg_range=%u", lg_range); + assert_zu_eq(rb, (ra >> (64 - lg_range)), + "Expected high order bits of full-width result, " + "lg_range=%u", lg_range); + } +} + +TEST_BEGIN(test_prng_lg_range_u32_nonatomic) { - test_prng_lg_range(false); + test_prng_lg_range_u32(false); } TEST_END -TEST_BEGIN(test_prng_lg_range_atomic) +TEST_BEGIN(test_prng_lg_range_u32_atomic) { - test_prng_lg_range(true); + test_prng_lg_range_u32(true); +} +TEST_END + +TEST_BEGIN(test_prng_lg_range_u64_nonatomic) +{ + + test_prng_lg_range_u64(); +} +TEST_END + +TEST_BEGIN(test_prng_lg_range_zu_nonatomic) +{ + + test_prng_lg_range_zu(false); +} +TEST_END + +TEST_BEGIN(test_prng_lg_range_zu_atomic) +{ + + test_prng_lg_range_zu(true); } TEST_END static void -test_prng_range(bool atomic) +test_prng_range_u32(bool atomic) +{ + uint32_t range; +#define MAX_RANGE 10000000 +#define RANGE_STEP 97 +#define NREPS 10 + + for (range = 2; range < MAX_RANGE; range += RANGE_STEP) { + uint32_t s; + unsigned rep; + + s = range; + for (rep = 0; rep < NREPS; rep++) { + uint32_t r = prng_range_u32(&s, range, atomic); + + assert_u32_lt(r, range, "Out of range"); + } + } +} + +static void +test_prng_range_u64(void) { uint64_t range; #define MAX_RANGE 10000000 @@ -65,24 +182,66 @@ test_prng_range(bool atomic) s = range; for (rep = 0; rep < NREPS; rep++) { - uint64_t r = prng_range(&s, range, atomic); + uint64_t r = prng_range_u64(&s, range); assert_u64_lt(r, range, "Out of range"); } } } -TEST_BEGIN(test_prng_range_nonatomic) +static void +test_prng_range_zu(bool atomic) +{ + size_t range; +#define MAX_RANGE 10000000 +#define RANGE_STEP 97 +#define NREPS 10 + + for (range = 2; range < MAX_RANGE; range += RANGE_STEP) { + size_t s; + unsigned rep; + + s = range; + for (rep = 0; rep < NREPS; rep++) { + size_t r = prng_range_zu(&s, range, atomic); + + assert_zu_lt(r, range, "Out of range"); + } + } +} + +TEST_BEGIN(test_prng_range_u32_nonatomic) +{ + + test_prng_range_u32(false); +} +TEST_END + +TEST_BEGIN(test_prng_range_u32_atomic) +{ + + test_prng_range_u32(true); +} +TEST_END + +TEST_BEGIN(test_prng_range_u64_nonatomic) +{ + + test_prng_range_u64(); +} +TEST_END + +TEST_BEGIN(test_prng_range_zu_nonatomic) { - test_prng_range(false); + test_prng_range_zu(false); } TEST_END -TEST_BEGIN(test_prng_range_atomic) +TEST_BEGIN(test_prng_range_zu_atomic) { - test_prng_range(true); + test_prng_range_zu(true); } TEST_END @@ -91,8 +250,14 @@ main(void) { return (test( - test_prng_lg_range_nonatomic, - test_prng_lg_range_atomic, - test_prng_range_nonatomic, - test_prng_range_atomic)); + test_prng_lg_range_u32_nonatomic, + test_prng_lg_range_u32_atomic, + test_prng_lg_range_u64_nonatomic, + test_prng_lg_range_zu_nonatomic, + test_prng_lg_range_zu_atomic, + test_prng_range_u32_nonatomic, + test_prng_range_u32_atomic, + test_prng_range_u64_nonatomic, + test_prng_range_zu_nonatomic, + test_prng_range_zu_atomic)); } -- GitLab From 2e46b13ad545c599679f931c9c60ce06adae3859 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 7 Nov 2016 10:53:35 -0800 Subject: [PATCH 171/544] Revert "Define 64-bits atomics unconditionally" This reverts commit c2942e2c0e097e7c75a3addd0b9c87758f91692e. This resolves #495. --- include/jemalloc/internal/atomic.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/include/jemalloc/internal/atomic.h b/include/jemalloc/internal/atomic.h index 3936f68b..3f15ea14 100644 --- a/include/jemalloc/internal/atomic.h +++ b/include/jemalloc/internal/atomic.h @@ -66,7 +66,8 @@ void atomic_write_u(unsigned *p, unsigned x); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ATOMIC_C_)) /******************************************************************************/ /* 64-bit operations. */ -#if (defined(__amd64__) || defined(__x86_64__)) +#if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) +# if (defined(__amd64__) || defined(__x86_64__)) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) { @@ -124,7 +125,7 @@ atomic_write_uint64(uint64_t *p, uint64_t x) : "memory" /* Clobbers. */ ); } -#elif (defined(JEMALLOC_C11ATOMICS)) +# elif (defined(JEMALLOC_C11ATOMICS)) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) { @@ -152,7 +153,7 @@ atomic_write_uint64(uint64_t *p, uint64_t x) volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; atomic_store(a, x); } -#elif (defined(JEMALLOC_ATOMIC9)) +# elif (defined(JEMALLOC_ATOMIC9)) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) { @@ -192,7 +193,7 @@ atomic_write_uint64(uint64_t *p, uint64_t x) atomic_store_rel_long(p, x); } -#elif (defined(JEMALLOC_OSATOMIC)) +# elif (defined(JEMALLOC_OSATOMIC)) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) { @@ -224,7 +225,7 @@ atomic_write_uint64(uint64_t *p, uint64_t x) o = atomic_read_uint64(p); } while (atomic_cas_uint64(p, o, x)); } -#elif (defined(_MSC_VER)) +# elif (defined(_MSC_VER)) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) { @@ -254,7 +255,7 @@ atomic_write_uint64(uint64_t *p, uint64_t x) InterlockedExchange64(p, x); } -#elif (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || \ +# elif (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || \ defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8)) JEMALLOC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) @@ -283,8 +284,9 @@ atomic_write_uint64(uint64_t *p, uint64_t x) __sync_lock_test_and_set(p, x); } -#else -# error "Missing implementation for 64-bit atomic operations" +# else +# error "Missing implementation for 64-bit atomic operations" +# endif #endif /******************************************************************************/ -- GitLab From cda59f99701bc3acc569023e197abddc548330f4 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 7 Nov 2016 11:27:48 -0800 Subject: [PATCH 172/544] Rename atomic_*_{uint32,uint64,u}() to atomic_*_{u32,u64,zu}(). This change conforms to naming conventions throughout the codebase. --- include/jemalloc/internal/arena.h | 6 +- include/jemalloc/internal/atomic.h | 198 +++++++++--------- include/jemalloc/internal/private_symbols.txt | 24 +-- include/jemalloc/internal/prng.h | 8 +- include/jemalloc/internal/stats.h | 2 +- src/arena.c | 4 +- src/extent.c | 12 +- test/unit/atomic.c | 24 +-- 8 files changed, 139 insertions(+), 139 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index dbd334e6..f518c31f 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -365,21 +365,21 @@ JEMALLOC_INLINE void arena_metadata_add(arena_t *arena, size_t size) { - atomic_add_z(&arena->stats.metadata, size); + atomic_add_zu(&arena->stats.metadata, size); } JEMALLOC_INLINE void arena_metadata_sub(arena_t *arena, size_t size) { - atomic_sub_z(&arena->stats.metadata, size); + atomic_sub_zu(&arena->stats.metadata, size); } JEMALLOC_INLINE size_t arena_metadata_get(arena_t *arena) { - return (atomic_read_z(&arena->stats.metadata)); + return (atomic_read_zu(&arena->stats.metadata)); } JEMALLOC_INLINE bool diff --git a/include/jemalloc/internal/atomic.h b/include/jemalloc/internal/atomic.h index 3f15ea14..4b5b4ea9 100644 --- a/include/jemalloc/internal/atomic.h +++ b/include/jemalloc/internal/atomic.h @@ -9,10 +9,12 @@ /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS -#define atomic_read_uint64(p) atomic_add_uint64(p, 0) -#define atomic_read_uint32(p) atomic_add_uint32(p, 0) +#if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) +#define atomic_read_u64(p) atomic_add_u64(p, 0) +#endif +#define atomic_read_u32(p) atomic_add_u32(p, 0) #define atomic_read_p(p) atomic_add_p(p, NULL) -#define atomic_read_z(p) atomic_add_z(p, 0) +#define atomic_read_zu(p) atomic_add_zu(p, 0) #define atomic_read_u(p) atomic_add_u(p, 0) #endif /* JEMALLOC_H_EXTERNS */ @@ -41,22 +43,24 @@ */ #ifndef JEMALLOC_ENABLE_INLINE -uint64_t atomic_add_uint64(uint64_t *p, uint64_t x); -uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x); -bool atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s); -void atomic_write_uint64(uint64_t *p, uint64_t x); -uint32_t atomic_add_uint32(uint32_t *p, uint32_t x); -uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x); -bool atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s); -void atomic_write_uint32(uint32_t *p, uint32_t x); +# if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) +uint64_t atomic_add_u64(uint64_t *p, uint64_t x); +uint64_t atomic_sub_u64(uint64_t *p, uint64_t x); +bool atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s); +void atomic_write_u64(uint64_t *p, uint64_t x); +# endif +uint32_t atomic_add_u32(uint32_t *p, uint32_t x); +uint32_t atomic_sub_u32(uint32_t *p, uint32_t x); +bool atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s); +void atomic_write_u32(uint32_t *p, uint32_t x); void *atomic_add_p(void **p, void *x); void *atomic_sub_p(void **p, void *x); bool atomic_cas_p(void **p, void *c, void *s); void atomic_write_p(void **p, const void *x); -size_t atomic_add_z(size_t *p, size_t x); -size_t atomic_sub_z(size_t *p, size_t x); -bool atomic_cas_z(size_t *p, size_t c, size_t s); -void atomic_write_z(size_t *p, size_t x); +size_t atomic_add_zu(size_t *p, size_t x); +size_t atomic_sub_zu(size_t *p, size_t x); +bool atomic_cas_zu(size_t *p, size_t c, size_t s); +void atomic_write_zu(size_t *p, size_t x); unsigned atomic_add_u(unsigned *p, unsigned x); unsigned atomic_sub_u(unsigned *p, unsigned x); bool atomic_cas_u(unsigned *p, unsigned c, unsigned s); @@ -69,7 +73,7 @@ void atomic_write_u(unsigned *p, unsigned x); #if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) # if (defined(__amd64__) || defined(__x86_64__)) JEMALLOC_INLINE uint64_t -atomic_add_uint64(uint64_t *p, uint64_t x) +atomic_add_u64(uint64_t *p, uint64_t x) { uint64_t t = x; @@ -83,7 +87,7 @@ atomic_add_uint64(uint64_t *p, uint64_t x) } JEMALLOC_INLINE uint64_t -atomic_sub_uint64(uint64_t *p, uint64_t x) +atomic_sub_u64(uint64_t *p, uint64_t x) { uint64_t t; @@ -99,7 +103,7 @@ atomic_sub_uint64(uint64_t *p, uint64_t x) } JEMALLOC_INLINE bool -atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s) +atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { uint8_t success; @@ -115,7 +119,7 @@ atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s) } JEMALLOC_INLINE void -atomic_write_uint64(uint64_t *p, uint64_t x) +atomic_write_u64(uint64_t *p, uint64_t x) { asm volatile ( @@ -127,35 +131,35 @@ atomic_write_uint64(uint64_t *p, uint64_t x) } # elif (defined(JEMALLOC_C11ATOMICS)) JEMALLOC_INLINE uint64_t -atomic_add_uint64(uint64_t *p, uint64_t x) +atomic_add_u64(uint64_t *p, uint64_t x) { volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; return (atomic_fetch_add(a, x) + x); } JEMALLOC_INLINE uint64_t -atomic_sub_uint64(uint64_t *p, uint64_t x) +atomic_sub_u64(uint64_t *p, uint64_t x) { volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; return (atomic_fetch_sub(a, x) - x); } JEMALLOC_INLINE bool -atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s) +atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; return (!atomic_compare_exchange_strong(a, &c, s)); } JEMALLOC_INLINE void -atomic_write_uint64(uint64_t *p, uint64_t x) +atomic_write_u64(uint64_t *p, uint64_t x) { volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; atomic_store(a, x); } # elif (defined(JEMALLOC_ATOMIC9)) JEMALLOC_INLINE uint64_t -atomic_add_uint64(uint64_t *p, uint64_t x) +atomic_add_u64(uint64_t *p, uint64_t x) { /* @@ -168,7 +172,7 @@ atomic_add_uint64(uint64_t *p, uint64_t x) } JEMALLOC_INLINE uint64_t -atomic_sub_uint64(uint64_t *p, uint64_t x) +atomic_sub_u64(uint64_t *p, uint64_t x) { assert(sizeof(uint64_t) == sizeof(unsigned long)); @@ -177,7 +181,7 @@ atomic_sub_uint64(uint64_t *p, uint64_t x) } JEMALLOC_INLINE bool -atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s) +atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { assert(sizeof(uint64_t) == sizeof(unsigned long)); @@ -186,7 +190,7 @@ atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s) } JEMALLOC_INLINE void -atomic_write_uint64(uint64_t *p, uint64_t x) +atomic_write_u64(uint64_t *p, uint64_t x) { assert(sizeof(uint64_t) == sizeof(unsigned long)); @@ -195,53 +199,53 @@ atomic_write_uint64(uint64_t *p, uint64_t x) } # elif (defined(JEMALLOC_OSATOMIC)) JEMALLOC_INLINE uint64_t -atomic_add_uint64(uint64_t *p, uint64_t x) +atomic_add_u64(uint64_t *p, uint64_t x) { return (OSAtomicAdd64((int64_t)x, (int64_t *)p)); } JEMALLOC_INLINE uint64_t -atomic_sub_uint64(uint64_t *p, uint64_t x) +atomic_sub_u64(uint64_t *p, uint64_t x) { return (OSAtomicAdd64(-((int64_t)x), (int64_t *)p)); } JEMALLOC_INLINE bool -atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s) +atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { return (!OSAtomicCompareAndSwap64(c, s, (int64_t *)p)); } JEMALLOC_INLINE void -atomic_write_uint64(uint64_t *p, uint64_t x) +atomic_write_u64(uint64_t *p, uint64_t x) { uint64_t o; /*The documented OSAtomic*() API does not expose an atomic exchange. */ do { - o = atomic_read_uint64(p); - } while (atomic_cas_uint64(p, o, x)); + o = atomic_read_u64(p); + } while (atomic_cas_u64(p, o, x)); } # elif (defined(_MSC_VER)) JEMALLOC_INLINE uint64_t -atomic_add_uint64(uint64_t *p, uint64_t x) +atomic_add_u64(uint64_t *p, uint64_t x) { return (InterlockedExchangeAdd64(p, x) + x); } JEMALLOC_INLINE uint64_t -atomic_sub_uint64(uint64_t *p, uint64_t x) +atomic_sub_u64(uint64_t *p, uint64_t x) { return (InterlockedExchangeAdd64(p, -((int64_t)x)) - x); } JEMALLOC_INLINE bool -atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s) +atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { uint64_t o; @@ -250,7 +254,7 @@ atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s) } JEMALLOC_INLINE void -atomic_write_uint64(uint64_t *p, uint64_t x) +atomic_write_u64(uint64_t *p, uint64_t x) { InterlockedExchange64(p, x); @@ -258,28 +262,28 @@ atomic_write_uint64(uint64_t *p, uint64_t x) # elif (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || \ defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8)) JEMALLOC_INLINE uint64_t -atomic_add_uint64(uint64_t *p, uint64_t x) +atomic_add_u64(uint64_t *p, uint64_t x) { return (__sync_add_and_fetch(p, x)); } JEMALLOC_INLINE uint64_t -atomic_sub_uint64(uint64_t *p, uint64_t x) +atomic_sub_u64(uint64_t *p, uint64_t x) { return (__sync_sub_and_fetch(p, x)); } JEMALLOC_INLINE bool -atomic_cas_uint64(uint64_t *p, uint64_t c, uint64_t s) +atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { return (!__sync_bool_compare_and_swap(p, c, s)); } JEMALLOC_INLINE void -atomic_write_uint64(uint64_t *p, uint64_t x) +atomic_write_u64(uint64_t *p, uint64_t x) { __sync_lock_test_and_set(p, x); @@ -293,7 +297,7 @@ atomic_write_uint64(uint64_t *p, uint64_t x) /* 32-bit operations. */ #if (defined(__i386__) || defined(__amd64__) || defined(__x86_64__)) JEMALLOC_INLINE uint32_t -atomic_add_uint32(uint32_t *p, uint32_t x) +atomic_add_u32(uint32_t *p, uint32_t x) { uint32_t t = x; @@ -307,7 +311,7 @@ atomic_add_uint32(uint32_t *p, uint32_t x) } JEMALLOC_INLINE uint32_t -atomic_sub_uint32(uint32_t *p, uint32_t x) +atomic_sub_u32(uint32_t *p, uint32_t x) { uint32_t t; @@ -323,7 +327,7 @@ atomic_sub_uint32(uint32_t *p, uint32_t x) } JEMALLOC_INLINE bool -atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s) +atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { uint8_t success; @@ -339,7 +343,7 @@ atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s) } JEMALLOC_INLINE void -atomic_write_uint32(uint32_t *p, uint32_t x) +atomic_write_u32(uint32_t *p, uint32_t x) { asm volatile ( @@ -351,109 +355,109 @@ atomic_write_uint32(uint32_t *p, uint32_t x) } # elif (defined(JEMALLOC_C11ATOMICS)) JEMALLOC_INLINE uint32_t -atomic_add_uint32(uint32_t *p, uint32_t x) +atomic_add_u32(uint32_t *p, uint32_t x) { volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; return (atomic_fetch_add(a, x) + x); } JEMALLOC_INLINE uint32_t -atomic_sub_uint32(uint32_t *p, uint32_t x) +atomic_sub_u32(uint32_t *p, uint32_t x) { volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; return (atomic_fetch_sub(a, x) - x); } JEMALLOC_INLINE bool -atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s) +atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; return (!atomic_compare_exchange_strong(a, &c, s)); } JEMALLOC_INLINE void -atomic_write_uint32(uint32_t *p, uint32_t x) +atomic_write_u32(uint32_t *p, uint32_t x) { volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; atomic_store(a, x); } #elif (defined(JEMALLOC_ATOMIC9)) JEMALLOC_INLINE uint32_t -atomic_add_uint32(uint32_t *p, uint32_t x) +atomic_add_u32(uint32_t *p, uint32_t x) { return (atomic_fetchadd_32(p, x) + x); } JEMALLOC_INLINE uint32_t -atomic_sub_uint32(uint32_t *p, uint32_t x) +atomic_sub_u32(uint32_t *p, uint32_t x) { return (atomic_fetchadd_32(p, (uint32_t)(-(int32_t)x)) - x); } JEMALLOC_INLINE bool -atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s) +atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { return (!atomic_cmpset_32(p, c, s)); } JEMALLOC_INLINE void -atomic_write_uint32(uint32_t *p, uint32_t x) +atomic_write_u32(uint32_t *p, uint32_t x) { atomic_store_rel_32(p, x); } #elif (defined(JEMALLOC_OSATOMIC)) JEMALLOC_INLINE uint32_t -atomic_add_uint32(uint32_t *p, uint32_t x) +atomic_add_u32(uint32_t *p, uint32_t x) { return (OSAtomicAdd32((int32_t)x, (int32_t *)p)); } JEMALLOC_INLINE uint32_t -atomic_sub_uint32(uint32_t *p, uint32_t x) +atomic_sub_u32(uint32_t *p, uint32_t x) { return (OSAtomicAdd32(-((int32_t)x), (int32_t *)p)); } JEMALLOC_INLINE bool -atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s) +atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { return (!OSAtomicCompareAndSwap32(c, s, (int32_t *)p)); } JEMALLOC_INLINE void -atomic_write_uint32(uint32_t *p, uint32_t x) +atomic_write_u32(uint32_t *p, uint32_t x) { uint32_t o; /*The documented OSAtomic*() API does not expose an atomic exchange. */ do { - o = atomic_read_uint32(p); - } while (atomic_cas_uint32(p, o, x)); + o = atomic_read_u32(p); + } while (atomic_cas_u32(p, o, x)); } #elif (defined(_MSC_VER)) JEMALLOC_INLINE uint32_t -atomic_add_uint32(uint32_t *p, uint32_t x) +atomic_add_u32(uint32_t *p, uint32_t x) { return (InterlockedExchangeAdd(p, x) + x); } JEMALLOC_INLINE uint32_t -atomic_sub_uint32(uint32_t *p, uint32_t x) +atomic_sub_u32(uint32_t *p, uint32_t x) { return (InterlockedExchangeAdd(p, -((int32_t)x)) - x); } JEMALLOC_INLINE bool -atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s) +atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { uint32_t o; @@ -462,7 +466,7 @@ atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s) } JEMALLOC_INLINE void -atomic_write_uint32(uint32_t *p, uint32_t x) +atomic_write_u32(uint32_t *p, uint32_t x) { InterlockedExchange(p, x); @@ -470,28 +474,28 @@ atomic_write_uint32(uint32_t *p, uint32_t x) #elif (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || \ defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4)) JEMALLOC_INLINE uint32_t -atomic_add_uint32(uint32_t *p, uint32_t x) +atomic_add_u32(uint32_t *p, uint32_t x) { return (__sync_add_and_fetch(p, x)); } JEMALLOC_INLINE uint32_t -atomic_sub_uint32(uint32_t *p, uint32_t x) +atomic_sub_u32(uint32_t *p, uint32_t x) { return (__sync_sub_and_fetch(p, x)); } JEMALLOC_INLINE bool -atomic_cas_uint32(uint32_t *p, uint32_t c, uint32_t s) +atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { return (!__sync_bool_compare_and_swap(p, c, s)); } JEMALLOC_INLINE void -atomic_write_uint32(uint32_t *p, uint32_t x) +atomic_write_u32(uint32_t *p, uint32_t x) { __sync_lock_test_and_set(p, x); @@ -507,9 +511,9 @@ atomic_add_p(void **p, void *x) { #if (LG_SIZEOF_PTR == 3) - return ((void *)atomic_add_uint64((uint64_t *)p, (uint64_t)x)); + return ((void *)atomic_add_u64((uint64_t *)p, (uint64_t)x)); #elif (LG_SIZEOF_PTR == 2) - return ((void *)atomic_add_uint32((uint32_t *)p, (uint32_t)x)); + return ((void *)atomic_add_u32((uint32_t *)p, (uint32_t)x)); #endif } @@ -518,11 +522,9 @@ atomic_sub_p(void **p, void *x) { #if (LG_SIZEOF_PTR == 3) - return ((void *)atomic_add_uint64((uint64_t *)p, - (uint64_t)-((int64_t)x))); + return ((void *)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x))); #elif (LG_SIZEOF_PTR == 2) - return ((void *)atomic_add_uint32((uint32_t *)p, - (uint32_t)-((int32_t)x))); + return ((void *)atomic_add_u32((uint32_t *)p, (uint32_t)-((int32_t)x))); #endif } @@ -531,9 +533,9 @@ atomic_cas_p(void **p, void *c, void *s) { #if (LG_SIZEOF_PTR == 3) - return (atomic_cas_uint64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); + return (atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); #elif (LG_SIZEOF_PTR == 2) - return (atomic_cas_uint32((uint32_t *)p, (uint32_t)c, (uint32_t)s)); + return (atomic_cas_u32((uint32_t *)p, (uint32_t)c, (uint32_t)s)); #endif } @@ -542,57 +544,55 @@ atomic_write_p(void **p, const void *x) { #if (LG_SIZEOF_PTR == 3) - atomic_write_uint64((uint64_t *)p, (uint64_t)x); + atomic_write_u64((uint64_t *)p, (uint64_t)x); #elif (LG_SIZEOF_PTR == 2) - atomic_write_uint32((uint32_t *)p, (uint32_t)x); + atomic_write_u32((uint32_t *)p, (uint32_t)x); #endif } /******************************************************************************/ /* size_t operations. */ JEMALLOC_INLINE size_t -atomic_add_z(size_t *p, size_t x) +atomic_add_zu(size_t *p, size_t x) { #if (LG_SIZEOF_PTR == 3) - return ((size_t)atomic_add_uint64((uint64_t *)p, (uint64_t)x)); + return ((size_t)atomic_add_u64((uint64_t *)p, (uint64_t)x)); #elif (LG_SIZEOF_PTR == 2) - return ((size_t)atomic_add_uint32((uint32_t *)p, (uint32_t)x)); + return ((size_t)atomic_add_u32((uint32_t *)p, (uint32_t)x)); #endif } JEMALLOC_INLINE size_t -atomic_sub_z(size_t *p, size_t x) +atomic_sub_zu(size_t *p, size_t x) { #if (LG_SIZEOF_PTR == 3) - return ((size_t)atomic_add_uint64((uint64_t *)p, - (uint64_t)-((int64_t)x))); + return ((size_t)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x))); #elif (LG_SIZEOF_PTR == 2) - return ((size_t)atomic_add_uint32((uint32_t *)p, - (uint32_t)-((int32_t)x))); + return ((size_t)atomic_add_u32((uint32_t *)p, (uint32_t)-((int32_t)x))); #endif } JEMALLOC_INLINE bool -atomic_cas_z(size_t *p, size_t c, size_t s) +atomic_cas_zu(size_t *p, size_t c, size_t s) { #if (LG_SIZEOF_PTR == 3) - return (atomic_cas_uint64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); + return (atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); #elif (LG_SIZEOF_PTR == 2) - return (atomic_cas_uint32((uint32_t *)p, (uint32_t)c, (uint32_t)s)); + return (atomic_cas_u32((uint32_t *)p, (uint32_t)c, (uint32_t)s)); #endif } JEMALLOC_INLINE void -atomic_write_z(size_t *p, size_t x) +atomic_write_zu(size_t *p, size_t x) { #if (LG_SIZEOF_PTR == 3) - atomic_write_uint64((uint64_t *)p, (uint64_t)x); + atomic_write_u64((uint64_t *)p, (uint64_t)x); #elif (LG_SIZEOF_PTR == 2) - atomic_write_uint32((uint32_t *)p, (uint32_t)x); + atomic_write_u32((uint32_t *)p, (uint32_t)x); #endif } @@ -603,9 +603,9 @@ atomic_add_u(unsigned *p, unsigned x) { #if (LG_SIZEOF_INT == 3) - return ((unsigned)atomic_add_uint64((uint64_t *)p, (uint64_t)x)); + return ((unsigned)atomic_add_u64((uint64_t *)p, (uint64_t)x)); #elif (LG_SIZEOF_INT == 2) - return ((unsigned)atomic_add_uint32((uint32_t *)p, (uint32_t)x)); + return ((unsigned)atomic_add_u32((uint32_t *)p, (uint32_t)x)); #endif } @@ -614,10 +614,10 @@ atomic_sub_u(unsigned *p, unsigned x) { #if (LG_SIZEOF_INT == 3) - return ((unsigned)atomic_add_uint64((uint64_t *)p, + return ((unsigned)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x))); #elif (LG_SIZEOF_INT == 2) - return ((unsigned)atomic_add_uint32((uint32_t *)p, + return ((unsigned)atomic_add_u32((uint32_t *)p, (uint32_t)-((int32_t)x))); #endif } @@ -627,9 +627,9 @@ atomic_cas_u(unsigned *p, unsigned c, unsigned s) { #if (LG_SIZEOF_INT == 3) - return (atomic_cas_uint64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); + return (atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); #elif (LG_SIZEOF_INT == 2) - return (atomic_cas_uint32((uint32_t *)p, (uint32_t)c, (uint32_t)s)); + return (atomic_cas_u32((uint32_t *)p, (uint32_t)c, (uint32_t)s)); #endif } @@ -638,9 +638,9 @@ atomic_write_u(unsigned *p, unsigned x) { #if (LG_SIZEOF_INT == 3) - atomic_write_uint64((uint64_t *)p, (uint64_t)x); + atomic_write_u64((uint64_t *)p, (uint64_t)x); #elif (LG_SIZEOF_INT == 2) - atomic_write_uint32((uint32_t *)p, (uint32_t)x); + atomic_write_u32((uint32_t *)p, (uint32_t)x); #endif } diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index f178daf7..707ede3a 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -73,24 +73,24 @@ arenas arenas_tdata_cleanup atomic_add_p atomic_add_u -atomic_add_uint32 -atomic_add_uint64 -atomic_add_z +atomic_add_u32 +atomic_add_u64 +atomic_add_zu atomic_cas_p atomic_cas_u -atomic_cas_uint32 -atomic_cas_uint64 -atomic_cas_z +atomic_cas_u32 +atomic_cas_u64 +atomic_cas_zu atomic_sub_p atomic_sub_u -atomic_sub_uint32 -atomic_sub_uint64 -atomic_sub_z +atomic_sub_u32 +atomic_sub_u64 +atomic_sub_zu atomic_write_p atomic_write_u -atomic_write_uint32 -atomic_write_uint64 -atomic_write_z +atomic_write_u32 +atomic_write_u64 +atomic_write_zu base_alloc base_boot base_postfork_child diff --git a/include/jemalloc/internal/prng.h b/include/jemalloc/internal/prng.h index c2bda19c..94fd55a7 100644 --- a/include/jemalloc/internal/prng.h +++ b/include/jemalloc/internal/prng.h @@ -93,9 +93,9 @@ prng_lg_range_u32(uint32_t *state, unsigned lg_range, bool atomic) uint32_t state0; do { - state0 = atomic_read_uint32(state); + state0 = atomic_read_u32(state); state1 = prng_state_next_u32(state0); - } while (atomic_cas_uint32(state, state0, state1)); + } while (atomic_cas_u32(state, state0, state1)); } else { state1 = prng_state_next_u32(*state); *state = state1; @@ -133,9 +133,9 @@ prng_lg_range_zu(size_t *state, unsigned lg_range, bool atomic) size_t state0; do { - state0 = atomic_read_z(state); + state0 = atomic_read_zu(state); state1 = prng_state_next_zu(state0); - } while (atomic_cas_z(state, state0, state1)); + } while (atomic_cas_zu(state, state0, state1)); } else { state1 = prng_state_next_zu(*state); *state = state1; diff --git a/include/jemalloc/internal/stats.h b/include/jemalloc/internal/stats.h index 52279f56..a7368a72 100644 --- a/include/jemalloc/internal/stats.h +++ b/include/jemalloc/internal/stats.h @@ -101,7 +101,7 @@ struct arena_stats_s { uint64_t purged; /* Number of bytes currently allocated for internal metadata. */ - size_t metadata; /* Protected via atomic_*_z(). */ + size_t metadata; /* Protected via atomic_*_zu(). */ size_t allocated_large; uint64_t nmalloc_large; diff --git a/src/arena.c b/src/arena.c index 4b104a0e..ff7b0cd0 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1541,7 +1541,7 @@ ssize_t arena_decay_time_default_get(void) { - return ((ssize_t)atomic_read_z((size_t *)&decay_time_default)); + return ((ssize_t)atomic_read_zu((size_t *)&decay_time_default)); } bool @@ -1550,7 +1550,7 @@ arena_decay_time_default_set(ssize_t decay_time) if (!arena_decay_time_valid(decay_time)) return (true); - atomic_write_z((size_t *)&decay_time_default, (size_t)decay_time); + atomic_write_zu((size_t *)&decay_time_default, (size_t)decay_time); return (false); } diff --git a/src/extent.c b/src/extent.c index 4027e8b7..34ac63e8 100644 --- a/src/extent.c +++ b/src/extent.c @@ -291,14 +291,14 @@ extent_register(tsdn_t *tsdn, const extent_t *extent) if (config_prof && opt_prof && extent_active_get(extent)) { size_t nadd = extent_size_get(extent) >> LG_PAGE; - size_t cur = atomic_add_z(&curpages, nadd); - size_t high = atomic_read_z(&highpages); - while (cur > high && atomic_cas_z(&highpages, high, cur)) { + size_t cur = atomic_add_zu(&curpages, nadd); + size_t high = atomic_read_zu(&highpages); + while (cur > high && atomic_cas_zu(&highpages, high, cur)) { /* * Don't refresh cur, because it may have decreased * since this thread lost the highpages update race. */ - high = atomic_read_z(&highpages); + high = atomic_read_zu(&highpages); } if (cur > high && prof_gdump_get_unlocked()) prof_gdump(tsdn); @@ -347,8 +347,8 @@ extent_deregister(tsdn_t *tsdn, extent_t *extent) if (config_prof && opt_prof && extent_active_get(extent)) { size_t nsub = extent_size_get(extent) >> LG_PAGE; - assert(atomic_read_z(&curpages) >= nsub); - atomic_sub_z(&curpages, nsub); + assert(atomic_read_zu(&curpages) >= nsub); + atomic_sub_zu(&curpages, nsub); } } diff --git a/test/unit/atomic.c b/test/unit/atomic.c index bdd74f65..b8933a69 100644 --- a/test/unit/atomic.c +++ b/test/unit/atomic.c @@ -65,23 +65,23 @@ typedef struct p##_test_s p##_test_t; } \ } while (0) -TEST_STRUCT(uint64, uint64_t) -TEST_BEGIN(test_atomic_uint64) +TEST_STRUCT(u64, uint64_t) +TEST_BEGIN(test_atomic_u64) { #if !(LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) test_skip("64-bit atomic operations not supported"); #else - TEST_BODY(uint64, uint64_t, uint64_t, u64, FMTx64); + TEST_BODY(u64, uint64_t, uint64_t, u64, FMTx64); #endif } TEST_END -TEST_STRUCT(uint32, uint32_t) -TEST_BEGIN(test_atomic_uint32) +TEST_STRUCT(u32, uint32_t) +TEST_BEGIN(test_atomic_u32) { - TEST_BODY(uint32, uint32_t, uint32_t, u32, "#"FMTx32); + TEST_BODY(u32, uint32_t, uint32_t, u32, "#"FMTx32); } TEST_END @@ -93,11 +93,11 @@ TEST_BEGIN(test_atomic_p) } TEST_END -TEST_STRUCT(z, size_t) -TEST_BEGIN(test_atomic_z) +TEST_STRUCT(zu, size_t) +TEST_BEGIN(test_atomic_zu) { - TEST_BODY(z, size_t, size_t, zu, "#zx"); + TEST_BODY(zu, size_t, size_t, zu, "#zx"); } TEST_END @@ -114,9 +114,9 @@ main(void) { return (test( - test_atomic_uint64, - test_atomic_uint32, + test_atomic_u64, + test_atomic_u32, test_atomic_p, - test_atomic_z, + test_atomic_zu, test_atomic_u)); } -- GitLab From 5e0373c81506b89707471ef25f0f94d0fb6c0255 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 7 Nov 2016 11:50:11 -0800 Subject: [PATCH 173/544] Fix test_prng_lg_range_zu() to work on 32-bit systems. --- test/unit/prng.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/unit/prng.c b/test/unit/prng.c index 111fa59f..80c9d733 100644 --- a/test/unit/prng.c +++ b/test/unit/prng.c @@ -77,38 +77,38 @@ test_prng_lg_range_u64(void) static void test_prng_lg_range_zu(bool atomic) { - uint64_t sa, sb, ra, rb; + size_t sa, sb, ra, rb; unsigned lg_range; sa = 42; - ra = prng_lg_range_zu(&sa, 64, atomic); + ra = prng_lg_range_zu(&sa, ZU(1) << (3 + LG_SIZEOF_PTR), atomic); sa = 42; - rb = prng_lg_range_zu(&sa, 64, atomic); + rb = prng_lg_range_zu(&sa, ZU(1) << (3 + LG_SIZEOF_PTR), atomic); assert_zu_eq(ra, rb, "Repeated generation should produce repeated results"); sb = 42; - rb = prng_lg_range_zu(&sb, 64, atomic); + rb = prng_lg_range_zu(&sb, ZU(1) << (3 + LG_SIZEOF_PTR), atomic); assert_zu_eq(ra, rb, "Equivalent generation should produce equivalent results"); sa = 42; - ra = prng_lg_range_zu(&sa, 64, atomic); - rb = prng_lg_range_zu(&sa, 64, atomic); + ra = prng_lg_range_zu(&sa, ZU(1) << (3 + LG_SIZEOF_PTR), atomic); + rb = prng_lg_range_zu(&sa, ZU(1) << (3 + LG_SIZEOF_PTR), atomic); assert_zu_ne(ra, rb, "Full-width results must not immediately repeat"); sa = 42; - ra = prng_lg_range_zu(&sa, 64, atomic); + ra = prng_lg_range_zu(&sa, ZU(1) << (3 + LG_SIZEOF_PTR), atomic); for (lg_range = (ZU(1) << (3 + LG_SIZEOF_PTR)) - 1; lg_range > 0; lg_range--) { sb = 42; rb = prng_lg_range_zu(&sb, lg_range, atomic); assert_zu_eq((rb & (SIZE_T_MAX << lg_range)), 0, "High order bits should be 0, lg_range=%u", lg_range); - assert_zu_eq(rb, (ra >> (64 - lg_range)), - "Expected high order bits of full-width result, " - "lg_range=%u", lg_range); + assert_zu_eq(rb, (ra >> ((ZU(1) << (3 + LG_SIZEOF_PTR)) - + lg_range)), "Expected high order bits of full-width " + "result, lg_range=%u", lg_range); } } -- GitLab From 85dae2ff4990d86644cf1b2bcce98e6b4afa340b Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 7 Nov 2016 16:22:02 -0800 Subject: [PATCH 174/544] Update ChangeLog for 4.3.1. --- ChangeLog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index 118df96f..587685d0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,14 @@ brevity. Much more detail can be found in the git revision history: https://github.com/jemalloc/jemalloc +* 4.3.1 (November 7, 2016) + + Bug fixes: + - Fix a severe virtual memory leak. This regression was first released in + 4.3.0. (@interwq, @jasone) + - Refactor atomic and prng APIs to restore support for 32-bit platforms that + use pre-C11 toolchains, e.g. FreeBSD's mips. (@jasone) + * 4.3.0 (November 4, 2016) This is the first release that passes the test suite for multiple Windows -- GitLab From c233dd5e40ad7a6c79ff39f4ea8a3936b95b0458 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 10 Nov 2016 15:02:05 -0800 Subject: [PATCH 175/544] Update config.{guess,sub} from upstream. --- build-aux/config.guess | 174 +++++++++++++++++++++++++---------------- build-aux/config.sub | 76 ++++++++++++------ 2 files changed, 160 insertions(+), 90 deletions(-) diff --git a/build-aux/config.guess b/build-aux/config.guess index 1f5c50c0..2e9ad7fe 100755 --- a/build-aux/config.guess +++ b/build-aux/config.guess @@ -1,8 +1,8 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2014 Free Software Foundation, Inc. +# Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2014-03-23' +timestamp='2016-10-02' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -24,12 +24,12 @@ timestamp='2014-03-23' # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # -# Originally written by Per Bothner. +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2014 Free Software Foundation, Inc. +Copyright 1992-2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -168,19 +168,29 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched - # to ELF recently, or will in the future. + # to ELF recently (or will in the future) and ABI. case "${UNAME_MACHINE_ARCH}" in + earm*) + os=netbsdelf + ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ @@ -197,6 +207,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in os=netbsd ;; esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need @@ -207,13 +224,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in release='-gnu' ;; *) - release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}" + echo "${machine}-${os}${release}${abi}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` @@ -223,6 +240,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; @@ -235,6 +256,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) @@ -251,42 +275,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV4.5 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV5 (21164)") - UNAME_MACHINE="alphaev5" ;; + UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") - UNAME_MACHINE="alphaev56" ;; + UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") - UNAME_MACHINE="alphapca56" ;; + UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") - UNAME_MACHINE="alphapca57" ;; + UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") - UNAME_MACHINE="alphaev6" ;; + UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") - UNAME_MACHINE="alphaev67" ;; + UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") - UNAME_MACHINE="alphaev69" ;; + UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") - UNAME_MACHINE="alphaev7" ;; + UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") - UNAME_MACHINE="alphaev79" ;; + UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 @@ -359,16 +383,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build - SUN_ARCH="i386" + SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then - SUN_ARCH="x86_64" + SUN_ARCH=x86_64 fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` @@ -393,7 +417,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} @@ -579,8 +603,9 @@ EOF else IBM_ARCH=powerpc fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi @@ -617,13 +642,13 @@ EOF sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; - '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi @@ -662,11 +687,11 @@ EOF exit (0); } EOF - (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac - if [ ${HP_ARCH} = "hppa2.0w" ] + if [ ${HP_ARCH} = hppa2.0w ] then eval $set_cc_for_build @@ -679,12 +704,12 @@ EOF # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 - if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then - HP_ARCH="hppa2.0w" + HP_ARCH=hppa2.0w else - HP_ARCH="hppa64" + HP_ARCH=hppa64 fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} @@ -789,14 +814,14 @@ EOF echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) @@ -878,7 +903,7 @@ EOF exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix @@ -901,7 +926,7 @@ EOF EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) @@ -932,6 +957,9 @@ EOF crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; @@ -944,6 +972,9 @@ EOF ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; + k1om:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; @@ -969,6 +1000,9 @@ EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; + mips64el:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; @@ -1001,6 +1035,9 @@ EOF ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; @@ -1020,7 +1057,7 @@ EOF echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} @@ -1099,7 +1136,7 @@ EOF # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configury will decide that + # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; @@ -1248,6 +1285,9 @@ EOF SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; @@ -1261,9 +1301,9 @@ EOF UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in @@ -1285,7 +1325,7 @@ EOF exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = "x86"; then + if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi @@ -1316,7 +1356,7 @@ EOF # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. - if test "$cputype" = "386"; then + if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" @@ -1358,7 +1398,7 @@ EOF echo i386-pc-xenix exit ;; i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos @@ -1369,23 +1409,25 @@ EOF x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; esac cat >&2 < in order to provide the needed -information to handle your system. +If $0 has already been updated, send the following data and any +information you think might be pertinent to config-patches@gnu.org to +provide the necessary information to handle your system. config.guess timestamp = $timestamp diff --git a/build-aux/config.sub b/build-aux/config.sub index 0ccff770..dd2ca93c 100755 --- a/build-aux/config.sub +++ b/build-aux/config.sub @@ -1,8 +1,8 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2014 Free Software Foundation, Inc. +# Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2014-05-01' +timestamp='2016-11-04' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ timestamp='2014-05-01' # of the GNU General Public License, version 3 ("GPLv3"). -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. @@ -33,7 +33,7 @@ timestamp='2014-05-01' # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases @@ -53,8 +53,7 @@ timestamp='2014-05-01' me=`echo "$0" | sed -e 's,.*/,,'` usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS - $0 [OPTION] ALIAS +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. @@ -68,7 +67,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2014 Free Software Foundation, Inc. +Copyright 1992-2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -117,8 +116,8 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | \ - kopensolaris*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | cloudabi*-eabi* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` @@ -255,12 +254,13 @@ case $basic_machine in | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ + | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ - | epiphany \ - | fido | fr30 | frv \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ @@ -301,10 +301,12 @@ case $basic_machine in | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pru \ | pyramid \ + | riscv32 | riscv64 \ | rl78 | rx \ | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ @@ -312,6 +314,7 @@ case $basic_machine in | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) @@ -326,6 +329,9 @@ case $basic_machine in c6x) basic_machine=tic6x-unknown ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none @@ -371,12 +377,13 @@ case $basic_machine in | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ + | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ - | elxsi-* \ + | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ @@ -422,13 +429,15 @@ case $basic_machine in | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ | pyramid-* \ + | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ @@ -436,6 +445,7 @@ case $basic_machine in | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ + | visium-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ @@ -512,6 +522,9 @@ case $basic_machine in basic_machine=i386-pc os=-aros ;; + asmjs) + basic_machine=asmjs-unknown + ;; aux) basic_machine=m68k-apple os=-aux @@ -632,6 +645,14 @@ case $basic_machine in basic_machine=m68k-bull os=-sysv3 ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; ebmon29k) basic_machine=a29k-amd os=-ebmon @@ -773,6 +794,9 @@ case $basic_machine in basic_machine=m68k-isi os=-sysv ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; m68knommu) basic_machine=m68k-unknown os=-linux @@ -828,6 +852,10 @@ case $basic_machine in basic_machine=powerpc-unknown os=-morphos ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; msdos) basic_machine=i386-pc os=-msdos @@ -1004,7 +1032,7 @@ case $basic_machine in ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppcle | powerpclittle | ppc-le | powerpc-little) + ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) @@ -1014,7 +1042,7 @@ case $basic_machine in ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppc64le | powerpc64little | ppc64-le | powerpc64-little) + ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) @@ -1360,27 +1388,28 @@ case $os in | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix* | -fuchsia*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1404,9 +1433,6 @@ case $os in -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; - # Apple iOS - -ios*) - ;; -linux-dietlibc) os=-linux-dietlibc ;; @@ -1515,6 +1541,8 @@ case $os in ;; -nacl*) ;; + -ios) + ;; -none) ;; *) -- GitLab From 32d69e967e40fd5546d2705551dd6f37575ffe81 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 10 Nov 2016 15:35:29 -0800 Subject: [PATCH 176/544] Add configure support for *-*-linux-android. This is tailored to Android, i.e. more specific than the *-*-linux* configuration. This resolves #471. --- configure.ac | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/configure.ac b/configure.ac index 6f29ce0a..053e5d7e 100644 --- a/configure.ac +++ b/configure.ac @@ -384,6 +384,18 @@ case "${host}" in abi="elf" AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) ;; + *-*-linux-android) + dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. + CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" + abi="elf" + AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) + AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) + AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED], [ ]) + AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) + AC_DEFINE([JEMALLOC_C11ATOMICS]) + force_tls="0" + default_munmap="0" + ;; *-*-linux* | *-*-kfreebsd*) dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" -- GitLab From c25e711cf97bc64d31e6bbc35fe24e0f55c657d8 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 11 Nov 2016 23:49:40 -0800 Subject: [PATCH 177/544] Reduce memory usage for sdallocx() test_alignment_and_size. --- test/integration/sdallocx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/sdallocx.c b/test/integration/sdallocx.c index b84817d7..f92e0589 100644 --- a/test/integration/sdallocx.c +++ b/test/integration/sdallocx.c @@ -1,7 +1,7 @@ #include "test/jemalloc_test.h" -#define MAXALIGN (((size_t)1) << 25) -#define NITER 4 +#define MAXALIGN (((size_t)1) << 22) +#define NITER 3 TEST_BEGIN(test_basic) { -- GitLab From a2e601a2236315fb6f994ff364ea442ed0aed07b Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 12 Nov 2016 09:47:07 -0800 Subject: [PATCH 178/544] Add JE_RUNNABLE() and use it for os_unfair_lock_*() test. This resolves #494. --- configure.ac | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 053e5d7e..24136736 100644 --- a/configure.ac +++ b/configure.ac @@ -43,6 +43,17 @@ AC_CACHE_CHECK([whether $1 is compilable], [$4=no])]) ]) +dnl JE_RUNNABLE(label, hcode, mcode, rvar) +AC_DEFUN([JE_RUNNABLE], +[ +AC_CACHE_CHECK([whether $1 is runnable], + [$4], + [AC_RUN_IFELSE([AC_LANG_PROGRAM([$2], + [$3])], + [$4=yes], + [$4=no])]) +]) + dnl ============================================================================ CONFIG=`echo ${ac_configure_args} | sed -e 's#'"'"'\([^ ]*\)'"'"'#\1#g'` @@ -1649,7 +1660,11 @@ fi dnl ============================================================================ dnl Check for os_unfair_lock operations as provided on Darwin. -JE_COMPILABLE([Darwin os_unfair_lock_*()], [ +dnl Run the test program rather than merely compiling so that dyld lazy symbol +dnl binding doesn't result in a false positive if building with a version of +dnl XCode (>7) that supports the API on a system that is too old to actually +dnl implement it (<10.12). +JE_RUNNABLE([Darwin os_unfair_lock_*()], [ #include ], [ os_unfair_lock lock = OS_UNFAIR_LOCK_INIT; -- GitLab From c0a667112cf33968b425dfbb50594aba54ea850b Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 15 Nov 2016 10:31:06 -0800 Subject: [PATCH 179/544] Fix arena_reset() crashing bug. This regression was caused by 498856f44a30b31fe713a18eb2fc7c6ecf3a9f63 (Move slabs out of chunks.). --- src/arena.c | 83 +++++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/src/arena.c b/src/arena.c index ff7b0cd0..ef374d35 100644 --- a/src/arena.c +++ b/src/arena.c @@ -799,6 +799,47 @@ arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) arena_extent_cache_dalloc_locked(tsdn, arena, &extent_hooks, slab); } +static void +arena_bin_slabs_nonfull_insert(arena_bin_t *bin, extent_t *slab) +{ + + assert(extent_slab_data_get(slab)->nfree > 0); + extent_heap_insert(&bin->slabs_nonfull, slab); +} + +static void +arena_bin_slabs_nonfull_remove(arena_bin_t *bin, extent_t *slab) +{ + + extent_heap_remove(&bin->slabs_nonfull, slab); +} + +static extent_t * +arena_bin_slabs_nonfull_tryget(arena_bin_t *bin) +{ + extent_t *slab = extent_heap_remove_first(&bin->slabs_nonfull); + if (slab == NULL) + return (NULL); + if (config_stats) + bin->stats.reslabs++; + return (slab); +} + +static void +arena_bin_slabs_full_insert(arena_bin_t *bin, extent_t *slab) +{ + + assert(extent_slab_data_get(slab)->nfree == 0); + extent_ring_insert(&bin->slabs_full, slab); +} + +static void +arena_bin_slabs_full_remove(extent_t *slab) +{ + + extent_ring_remove(slab); +} + void arena_reset(tsd_t *tsd, arena_t *arena) { @@ -863,6 +904,7 @@ arena_reset(tsd_t *tsd, arena_t *arena) for (slab = qr_next(&bin->slabs_full, qr_link); slab != &bin->slabs_full; slab = qr_next(&bin->slabs_full, qr_link)) { + arena_bin_slabs_full_remove(slab); malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); arena_slab_dalloc(tsd_tsdn(tsd), arena, slab); malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); @@ -880,47 +922,6 @@ arena_reset(tsd_t *tsd, arena_t *arena) malloc_mutex_unlock(tsd_tsdn(tsd), &arena->lock); } -static void -arena_bin_slabs_nonfull_insert(arena_bin_t *bin, extent_t *slab) -{ - - assert(extent_slab_data_get(slab)->nfree > 0); - extent_heap_insert(&bin->slabs_nonfull, slab); -} - -static void -arena_bin_slabs_nonfull_remove(arena_bin_t *bin, extent_t *slab) -{ - - extent_heap_remove(&bin->slabs_nonfull, slab); -} - -static extent_t * -arena_bin_slabs_nonfull_tryget(arena_bin_t *bin) -{ - extent_t *slab = extent_heap_remove_first(&bin->slabs_nonfull); - if (slab == NULL) - return (NULL); - if (config_stats) - bin->stats.reslabs++; - return (slab); -} - -static void -arena_bin_slabs_full_insert(arena_bin_t *bin, extent_t *slab) -{ - - assert(extent_slab_data_get(slab)->nfree == 0); - extent_ring_insert(&bin->slabs_full, slab); -} - -static void -arena_bin_slabs_full_remove(extent_t *slab) -{ - - extent_ring_remove(slab); -} - static extent_t * arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, const arena_bin_info_t *bin_info) -- GitLab From a38acf716eefc5284e89a35be74229ef3545d007 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 15 Nov 2016 13:07:53 -0800 Subject: [PATCH 180/544] Add extent serial numbers. Add extent serial numbers and use them where appropriate as a sort key that is higher priority than address, so that the allocation policy prefers older extents. This resolves #147. --- include/jemalloc/internal/arena.h | 11 ++- include/jemalloc/internal/extent.h | 74 ++++++++++++++++++- include/jemalloc/internal/private_symbols.txt | 6 ++ src/arena.c | 27 ++++--- src/base.c | 12 ++- src/extent.c | 28 +++---- src/extent_dss.c | 3 +- 7 files changed, 126 insertions(+), 35 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index f518c31f..28d63c68 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -130,7 +130,8 @@ struct arena_bin_s { /* * Heap of non-full slabs. This heap is used to assure that new - * allocations come from the non-full slab that is lowest in memory. + * allocations come from the non-full slab that is oldest/lowest in + * memory. */ extent_heap_t slabs_nonfull; @@ -184,6 +185,9 @@ struct arena_s { */ size_t offset_state; + /* Extent serial number generator state. */ + size_t extent_sn_next; + dss_prec_t dss_prec; /* True if a thread is currently executing arena_purge_to_limit(). */ @@ -224,8 +228,8 @@ struct arena_s { /* User-configurable extent hook functions. */ union { - extent_hooks_t *extent_hooks; - void *extent_hooks_pun; + extent_hooks_t *extent_hooks; + void *extent_hooks_pun; }; /* Cache of extent structures that were allocated via base_alloc(). */ @@ -320,6 +324,7 @@ void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, unsigned arena_nthreads_get(arena_t *arena, bool internal); void arena_nthreads_inc(arena_t *arena, bool internal); void arena_nthreads_dec(arena_t *arena, bool internal); +size_t arena_extent_sn_next(arena_t *arena); arena_t *arena_new(tsdn_t *tsdn, unsigned ind); void arena_boot(void); void arena_prefork0(tsdn_t *tsdn, arena_t *arena); diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 531d853c..3c5573ee 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -26,6 +26,20 @@ struct extent_s { */ size_t e_usize; + /* + * Serial number (potentially non-unique). + * + * In principle serial numbers can wrap around on 32-bit systems if + * JEMALLOC_MUNMAP is defined, but as long as comparison functions fall + * back on address comparison for equal serial numbers, stable (if + * imperfect) ordering is maintained. + * + * Serial numbers may not be unique even in the absence of wrap-around, + * e.g. when splitting an extent and assigning the same serial number to + * both resulting adjacent extents. + */ + size_t e_sn; + /* True if extent is active (in use). */ bool e_active; @@ -66,7 +80,7 @@ struct extent_s { qr(extent_t) qr_link; union { - /* Linkage for per size class address-ordered heaps. */ + /* Linkage for per size class sn/address-ordered heaps. */ phn(extent_t) ph_link; /* Linkage for arena's large and extent_cache lists. */ @@ -144,6 +158,7 @@ size_t extent_usize_get(const extent_t *extent); void *extent_before_get(const extent_t *extent); void *extent_last_get(const extent_t *extent); void *extent_past_get(const extent_t *extent); +size_t extent_sn_get(const extent_t *extent); bool extent_active_get(const extent_t *extent); bool extent_retained_get(const extent_t *extent); bool extent_zeroed_get(const extent_t *extent); @@ -157,16 +172,20 @@ void extent_addr_set(extent_t *extent, void *addr); void extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment); void extent_size_set(extent_t *extent, size_t size); void extent_usize_set(extent_t *extent, size_t usize); +void extent_sn_set(extent_t *extent, size_t sn); void extent_active_set(extent_t *extent, bool active); void extent_zeroed_set(extent_t *extent, bool zeroed); void extent_committed_set(extent_t *extent, bool committed); void extent_slab_set(extent_t *extent, bool slab); void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx); void extent_init(extent_t *extent, arena_t *arena, void *addr, - size_t size, size_t usize, bool active, bool zeroed, bool committed, - bool slab); + size_t size, size_t usize, size_t sn, bool active, bool zeroed, + bool committed, bool slab); void extent_ring_insert(extent_t *sentinel, extent_t *extent); void extent_ring_remove(extent_t *extent); +int extent_sn_comp(const extent_t *a, const extent_t *b); +int extent_ad_comp(const extent_t *a, const extent_t *b); +int extent_snad_comp(const extent_t *a, const extent_t *b); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_)) @@ -243,6 +262,13 @@ extent_past_get(const extent_t *extent) extent_size_get(extent))); } +JEMALLOC_INLINE size_t +extent_sn_get(const extent_t *extent) +{ + + return (extent->e_sn); +} + JEMALLOC_INLINE bool extent_active_get(const extent_t *extent) { @@ -351,6 +377,13 @@ extent_usize_set(extent_t *extent, size_t usize) extent->e_usize = usize; } +JEMALLOC_INLINE void +extent_sn_set(extent_t *extent, size_t sn) +{ + + extent->e_sn = sn; +} + JEMALLOC_INLINE void extent_active_set(extent_t *extent, bool active) { @@ -388,7 +421,8 @@ extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) JEMALLOC_INLINE void extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, - size_t usize, bool active, bool zeroed, bool committed, bool slab) + size_t usize, size_t sn, bool active, bool zeroed, bool committed, + bool slab) { assert(addr == PAGE_ADDR2BASE(addr) || !slab); @@ -397,6 +431,7 @@ extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, extent_addr_set(extent, addr); extent_size_set(extent, size); extent_usize_set(extent, usize); + extent_sn_set(extent, sn); extent_active_set(extent, active); extent_zeroed_set(extent, zeroed); extent_committed_set(extent, committed); @@ -419,6 +454,37 @@ extent_ring_remove(extent_t *extent) qr_remove(extent, qr_link); } + +JEMALLOC_INLINE int +extent_sn_comp(const extent_t *a, const extent_t *b) +{ + size_t a_sn = extent_sn_get(a); + size_t b_sn = extent_sn_get(b); + + return ((a_sn > b_sn) - (a_sn < b_sn)); +} + +JEMALLOC_INLINE int +extent_ad_comp(const extent_t *a, const extent_t *b) +{ + uintptr_t a_addr = (uintptr_t)extent_addr_get(a); + uintptr_t b_addr = (uintptr_t)extent_addr_get(b); + + return ((a_addr > b_addr) - (a_addr < b_addr)); +} + +JEMALLOC_INLINE int +extent_snad_comp(const extent_t *a, const extent_t *b) +{ + int ret; + + ret = extent_sn_comp(a, b); + if (ret != 0) + return (ret); + + ret = extent_ad_comp(a, b); + return (ret); +} #endif #endif /* JEMALLOC_H_INLINES */ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 707ede3a..4560d702 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -31,6 +31,7 @@ arena_extent_cache_maybe_remove arena_extent_dalloc_large arena_extent_ralloc_large_expand arena_extent_ralloc_large_shrink +arena_extent_sn_next arena_get arena_ichoose arena_init @@ -132,6 +133,7 @@ decay_ticker_get dss_prec_names extent_active_get extent_active_set +extent_ad_comp extent_addr_get extent_addr_randomize extent_addr_set @@ -188,6 +190,10 @@ extent_slab_data_get extent_slab_data_get_const extent_slab_get extent_slab_set +extent_sn_comp +extent_sn_get +extent_sn_set +extent_snad_comp extent_split_wrapper extent_usize_get extent_usize_set diff --git a/src/arena.c b/src/arena.c index ef374d35..75a92edc 100644 --- a/src/arena.c +++ b/src/arena.c @@ -760,7 +760,7 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) size_t ndirty = arena_dirty_count(tsdn, arena); assert(ndirty == arena->ndirty); } - extent_init(&purge_extents_sentinel, arena, NULL, 0, 0, false, false, + extent_init(&purge_extents_sentinel, arena, NULL, 0, 0, 0, false, false, false, false); npurge = arena_stash_dirty(tsdn, arena, &extent_hooks, ndirty_limit, @@ -1351,12 +1351,12 @@ arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, assert(extent_slab_data_get(slab)->nfree > 0); /* - * Make sure that if bin->slabcur is non-NULL, it refers to the lowest - * non-full slab. It is okay to NULL slabcur out rather than - * proactively keeping it pointing at the lowest non-full slab. + * Make sure that if bin->slabcur is non-NULL, it refers to the + * oldest/lowest non-full slab. It is okay to NULL slabcur out rather + * than proactively keeping it pointing at the oldest/lowest non-full + * slab. */ - if (bin->slabcur != NULL && (uintptr_t)extent_addr_get(slab) < - (uintptr_t)extent_addr_get(bin->slabcur)) { + if (bin->slabcur != NULL && extent_snad_comp(bin->slabcur, slab) > 0) { /* Switch slabcur. */ if (extent_slab_data_get(bin->slabcur)->nfree > 0) arena_bin_slabs_nonfull_insert(bin, bin->slabcur); @@ -1651,6 +1651,13 @@ arena_nthreads_dec(arena_t *arena, bool internal) atomic_sub_u(&arena->nthreads[internal], 1); } +size_t +arena_extent_sn_next(arena_t *arena) +{ + + return (atomic_add_zu(&arena->extent_sn_next, 1) - 1); +} + arena_t * arena_new(tsdn_t *tsdn, unsigned ind) { @@ -1684,6 +1691,8 @@ arena_new(tsdn_t *tsdn, unsigned ind) (size_t)(uintptr_t)arena; } + arena->extent_sn_next = 0; + arena->dss_prec = extent_dss_prec_get(); arena->purging = false; @@ -1702,7 +1711,7 @@ arena_new(tsdn_t *tsdn, unsigned ind) extent_heap_new(&arena->extents_retained[i]); } - extent_init(&arena->extents_dirty, arena, NULL, 0, 0, false, false, + extent_init(&arena->extents_dirty, arena, NULL, 0, 0, 0, false, false, false, false); if (malloc_mutex_init(&arena->extents_mtx, "arena_extents", @@ -1724,8 +1733,8 @@ arena_new(tsdn_t *tsdn, unsigned ind) return (NULL); bin->slabcur = NULL; extent_heap_new(&bin->slabs_nonfull); - extent_init(&bin->slabs_full, arena, NULL, 0, 0, false, false, - false, false); + extent_init(&bin->slabs_full, arena, NULL, 0, 0, 0, false, + false, false, false); if (config_stats) memset(&bin->stats, 0, sizeof(malloc_bin_stats_t)); } diff --git a/src/base.c b/src/base.c index 9c3f36cd..4764d9c9 100644 --- a/src/base.c +++ b/src/base.c @@ -5,6 +5,7 @@ /* Data. */ static malloc_mutex_t base_mtx; +static size_t base_extent_sn_next; static extent_heap_t base_avail[NSIZES]; static extent_t *base_extents; static size_t base_allocated; @@ -37,6 +38,14 @@ base_extent_dalloc(tsdn_t *tsdn, extent_t *extent) base_extents = extent; } +static void +base_extent_init(extent_t *extent, void *addr, size_t size) +{ + size_t sn = atomic_add_zu(&base_extent_sn_next, 1) - 1; + + extent_init(extent, NULL, addr, size, 0, sn, true, true, true, false); +} + static extent_t * base_extent_alloc(tsdn_t *tsdn, size_t minsize) { @@ -74,7 +83,7 @@ base_extent_alloc(tsdn_t *tsdn, size_t minsize) base_resident += PAGE_CEILING(nsize); } } - extent_init(extent, NULL, addr, esize, 0, true, true, true, false); + base_extent_init(extent, addr, esize); return (extent); } @@ -164,6 +173,7 @@ base_boot(void) if (malloc_mutex_init(&base_mtx, "base", WITNESS_RANK_BASE)) return (true); + base_extent_sn_next = 0; for (i = 0; i < NSIZES; i++) extent_heap_new(&base_avail[i]); base_extents = NULL; diff --git a/src/extent.c b/src/extent.c index 34ac63e8..be6cadc3 100644 --- a/src/extent.c +++ b/src/extent.c @@ -177,17 +177,8 @@ extent_size_quantize_t *extent_size_quantize_ceil = JEMALLOC_N(n_extent_size_quantize_ceil); #endif -JEMALLOC_INLINE_C int -extent_ad_comp(const extent_t *a, const extent_t *b) -{ - uintptr_t a_addr = (uintptr_t)extent_addr_get(a); - uintptr_t b_addr = (uintptr_t)extent_addr_get(b); - - return ((a_addr > b_addr) - (a_addr < b_addr)); -} - /* Generate pairing heap functions. */ -ph_gen(, extent_heap_, extent_heap_t, extent_t, ph_link, extent_ad_comp) +ph_gen(, extent_heap_, extent_heap_t, extent_t, ph_link, extent_snad_comp) static void extent_heaps_insert(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES+1], @@ -353,8 +344,8 @@ extent_deregister(tsdn_t *tsdn, extent_t *extent) } /* - * Do first-best-fit extent selection, i.e. select the lowest extent that best - * fits. + * Do first-best-fit extent selection, i.e. select the oldest/lowest extent that + * best fits. */ static extent_t * extent_first_best_fit(tsdn_t *tsdn, arena_t *arena, @@ -708,7 +699,8 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, extent_dalloc(tsdn, arena, extent); return (NULL); } - extent_init(extent, arena, addr, size, usize, true, zero, commit, slab); + extent_init(extent, arena, addr, size, usize, + arena_extent_sn_next(arena), true, zero, commit, slab); if (pad != 0) extent_addr_randomize(tsdn, extent, alignment); if (extent_register(tsdn, extent)) { @@ -1036,7 +1028,7 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_t lead; extent_init(&lead, arena, extent_addr_get(extent), size_a, - usize_a, extent_active_get(extent), + usize_a, extent_sn_get(extent), extent_active_get(extent), extent_zeroed_get(extent), extent_committed_get(extent), extent_slab_get(extent)); @@ -1046,9 +1038,9 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, } extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) + - size_a), size_b, usize_b, extent_active_get(extent), - extent_zeroed_get(extent), extent_committed_get(extent), - extent_slab_get(extent)); + size_a), size_b, usize_b, extent_sn_get(extent), + extent_active_get(extent), extent_zeroed_get(extent), + extent_committed_get(extent), extent_slab_get(extent)); if (extent_rtree_acquire(tsdn, rtree_ctx, trail, false, true, &trail_elm_a, &trail_elm_b)) goto label_error_c; @@ -1145,6 +1137,8 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_size_set(a, extent_size_get(a) + extent_size_get(b)); extent_usize_set(a, extent_usize_get(a) + extent_usize_get(b)); + extent_sn_set(a, (extent_sn_get(a) < extent_sn_get(b)) ? + extent_sn_get(a) : extent_sn_get(b)); extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b)); extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a); diff --git a/src/extent_dss.c b/src/extent_dss.c index 31fe8fe2..1169d496 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -142,7 +142,8 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, gap_size = (uintptr_t)ret - (uintptr_t)gap_addr; if (gap_size != 0) { extent_init(gap, arena, gap_addr, gap_size, - gap_size, false, false, true, false); + gap_size, arena_extent_sn_next(arena), + false, false, true, false); } dss_next = (void *)((uintptr_t)ret + size); if ((uintptr_t)ret < (uintptr_t)max_cur || -- GitLab From 2c951545011f201c89765b9ada656e99538d95aa Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 14 Nov 2016 23:29:21 -0800 Subject: [PATCH 181/544] Add packing test, which verifies stable layout policy. --- Makefile.in | 1 + test/unit/pack.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 test/unit/pack.c diff --git a/Makefile.in b/Makefile.in index e4aaaf21..5e6f0c1a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -160,6 +160,7 @@ TESTS_UNIT := \ $(srcroot)test/unit/math.c \ $(srcroot)test/unit/mq.c \ $(srcroot)test/unit/mtx.c \ + $(srcroot)test/unit/pack.c \ $(srcroot)test/unit/ph.c \ $(srcroot)test/unit/prng.c \ $(srcroot)test/unit/prof_accum.c \ diff --git a/test/unit/pack.c b/test/unit/pack.c new file mode 100644 index 00000000..8071183e --- /dev/null +++ b/test/unit/pack.c @@ -0,0 +1,167 @@ +#include "test/jemalloc_test.h" + +/* Immediately purge to minimize fragmentation. */ +const char *malloc_conf = "decay_time:-1"; + +/* + * Size class that is a divisor of the page size, ideally 4+ regions per run. + */ +#if LG_PAGE <= 14 +#define SZ (ZU(1) << (LG_PAGE - 2)) +#else +#define SZ 4096 +#endif + +/* + * Number of slabs to consume at high water mark. Should be at least 2 so that + * if mmap()ed memory grows downward, downward growth of mmap()ed memory is + * tested. + */ +#define NSLABS 8 + +static unsigned +binind_compute(void) +{ + size_t sz; + unsigned nbins, i; + + sz = sizeof(nbins); + assert_d_eq(mallctl("arenas.nbins", &nbins, &sz, NULL, 0), 0, + "Unexpected mallctl failure"); + + for (i = 0; i < nbins; i++) { + size_t mib[4]; + size_t miblen = sizeof(mib)/sizeof(size_t); + size_t size; + + assert_d_eq(mallctlnametomib("arenas.bin.0.size", mib, + &miblen), 0, "Unexpected mallctlnametomb failure"); + mib[2] = (size_t)i; + + sz = sizeof(size); + assert_d_eq(mallctlbymib(mib, miblen, &size, &sz, NULL, 0), 0, + "Unexpected mallctlbymib failure"); + if (size == SZ) + return (i); + } + + test_fail("Unable to compute nregs_per_run"); + return (0); +} + +static size_t +nregs_per_run_compute(void) +{ + uint32_t nregs; + size_t sz; + unsigned binind = binind_compute(); + size_t mib[4]; + size_t miblen = sizeof(mib)/sizeof(size_t); + + assert_d_eq(mallctlnametomib("arenas.bin.0.nregs", mib, &miblen), 0, + "Unexpected mallctlnametomb failure"); + mib[2] = (size_t)binind; + sz = sizeof(nregs); + assert_d_eq(mallctlbymib(mib, miblen, &nregs, &sz, NULL, + 0), 0, "Unexpected mallctlbymib failure"); + return (nregs); +} + +static unsigned +arenas_extend_mallctl(void) +{ + unsigned arena_ind; + size_t sz; + + sz = sizeof(arena_ind); + assert_d_eq(mallctl("arenas.extend", &arena_ind, &sz, NULL, 0), 0, + "Error in arenas.extend"); + + return (arena_ind); +} + +static void +arena_reset_mallctl(unsigned arena_ind) +{ + size_t mib[3]; + size_t miblen = sizeof(mib)/sizeof(size_t); + + assert_d_eq(mallctlnametomib("arena.0.reset", mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + mib[1] = (size_t)arena_ind; + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, + "Unexpected mallctlbymib() failure"); +} + +TEST_BEGIN(test_pack) +{ + unsigned arena_ind = arenas_extend_mallctl(); + size_t nregs_per_run = nregs_per_run_compute(); + size_t nregs = nregs_per_run * NSLABS; + VARIABLE_ARRAY(void *, ptrs, nregs); + size_t i, j, offset; + + /* Fill matrix. */ + for (i = offset = 0; i < NSLABS; i++) { + for (j = 0; j < nregs_per_run; j++) { + void *p = mallocx(SZ, MALLOCX_ARENA(arena_ind) | + MALLOCX_TCACHE_NONE); + assert_ptr_not_null(p, + "Unexpected mallocx(%zu, MALLOCX_ARENA(%u) |" + " MALLOCX_TCACHE_NONE) failure, run=%zu, reg=%zu", + SZ, arena_ind, i, j); + ptrs[(i * nregs_per_run) + j] = p; + } + } + + /* + * Free all but one region of each run, but rotate which region is + * preserved, so that subsequent allocations exercise the within-run + * layout policy. + */ + offset = 0; + for (i = offset = 0; + i < NSLABS; + i++, offset = (offset + 1) % nregs_per_run) { + for (j = 0; j < nregs_per_run; j++) { + void *p = ptrs[(i * nregs_per_run) + j]; + if (offset == j) + continue; + dallocx(p, MALLOCX_ARENA(arena_ind) | + MALLOCX_TCACHE_NONE); + } + } + + /* + * Logically refill matrix, skipping preserved regions and verifying + * that the matrix is unmodified. + */ + offset = 0; + for (i = offset = 0; + i < NSLABS; + i++, offset = (offset + 1) % nregs_per_run) { + for (j = 0; j < nregs_per_run; j++) { + void *p; + + if (offset == j) + continue; + p = mallocx(SZ, MALLOCX_ARENA(arena_ind) | + MALLOCX_TCACHE_NONE); + assert_ptr_eq(p, ptrs[(i * nregs_per_run) + j], + "Unexpected refill discrepancy, run=%zu, reg=%zu\n", + i, j); + } + } + + /* Clean up. */ + arena_reset_mallctl(arena_ind); +} +TEST_END + +int +main(void) +{ + + return (test( + test_pack)); +} -- GitLab From 8a4528bdd16eee1b1c00c4305ee246568d382b0a Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 15 Nov 2016 15:01:03 -0800 Subject: [PATCH 182/544] Uniformly cast mallctl[bymib]() oldp/newp arguments to (void *). This avoids warnings in some cases, and is otherwise generally good hygiene. --- doc/jemalloc.xml.in | 2 +- src/stats.c | 7 ++++--- test/unit/pack.c | 12 ++++++------ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 747cc071..250a2a83 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -406,7 +406,7 @@ for (i = 0; i < nbins; i++) { mib[2] = i; len = sizeof(bin_size); - mallctlbymib(mib, miblen, &bin_size, &len, NULL, 0); + mallctlbymib(mib, miblen, (void *)&bin_size, &len, NULL, 0); /* Do something with bin_size... */ }]]> diff --git a/src/stats.c b/src/stats.c index 44f8c528..3072b2ab 100644 --- a/src/stats.c +++ b/src/stats.c @@ -513,7 +513,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, #define OPT_WRITE_BOOL_MUTABLE(n, m, c) { \ bool bv2; \ if (je_mallctl("opt."#n, (void *)&bv, &bsz, NULL, 0) == 0 && \ - je_mallctl(#m, &bv2, &bsz, NULL, 0) == 0) { \ + je_mallctl(#m, (void *)&bv2, &bsz, NULL, 0) == 0) { \ if (json) { \ malloc_cprintf(write_cb, cbopaque, \ "\t\t\t\""#n"\": %s%s\n", bv ? "true" : \ @@ -548,7 +548,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, #define OPT_WRITE_SSIZE_T_MUTABLE(n, m, c) { \ ssize_t ssv2; \ if (je_mallctl("opt."#n, (void *)&ssv, &sssz, NULL, 0) == 0 && \ - je_mallctl(#m, &ssv2, &sssz, NULL, 0) == 0) { \ + je_mallctl(#m, (void *)&ssv2, &sssz, NULL, 0) == 0) { \ if (json) { \ malloc_cprintf(write_cb, cbopaque, \ "\t\t\t\""#n"\": %zd%s\n", ssv, (c)); \ @@ -886,7 +886,8 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, * */ epoch = 1; u64sz = sizeof(uint64_t); - err = je_mallctl("epoch", &epoch, &u64sz, &epoch, sizeof(uint64_t)); + err = je_mallctl("epoch", (void *)&epoch, &u64sz, (void *)&epoch, + sizeof(uint64_t)); if (err != 0) { if (err == EAGAIN) { malloc_write(": Memory allocation failure in " diff --git a/test/unit/pack.c b/test/unit/pack.c index 8071183e..10df08e3 100644 --- a/test/unit/pack.c +++ b/test/unit/pack.c @@ -26,7 +26,7 @@ binind_compute(void) unsigned nbins, i; sz = sizeof(nbins); - assert_d_eq(mallctl("arenas.nbins", &nbins, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arenas.nbins", (void *)&nbins, &sz, NULL, 0), 0, "Unexpected mallctl failure"); for (i = 0; i < nbins; i++) { @@ -39,8 +39,8 @@ binind_compute(void) mib[2] = (size_t)i; sz = sizeof(size); - assert_d_eq(mallctlbymib(mib, miblen, &size, &sz, NULL, 0), 0, - "Unexpected mallctlbymib failure"); + assert_d_eq(mallctlbymib(mib, miblen, (void *)&size, &sz, NULL, + 0), 0, "Unexpected mallctlbymib failure"); if (size == SZ) return (i); } @@ -62,7 +62,7 @@ nregs_per_run_compute(void) "Unexpected mallctlnametomb failure"); mib[2] = (size_t)binind; sz = sizeof(nregs); - assert_d_eq(mallctlbymib(mib, miblen, &nregs, &sz, NULL, + assert_d_eq(mallctlbymib(mib, miblen, (void *)&nregs, &sz, NULL, 0), 0, "Unexpected mallctlbymib failure"); return (nregs); } @@ -74,8 +74,8 @@ arenas_extend_mallctl(void) size_t sz; sz = sizeof(arena_ind); - assert_d_eq(mallctl("arenas.extend", &arena_ind, &sz, NULL, 0), 0, - "Error in arenas.extend"); + assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, NULL, 0), + 0, "Error in arenas.extend"); return (arena_ind); } -- GitLab From 4066b4ef57c3b14bb57696539455809ce4a714c3 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 16 Nov 2016 10:40:00 -0800 Subject: [PATCH 183/544] Revert "Add JE_RUNNABLE() and use it for os_unfair_lock_*() test." This reverts commit a2e601a2236315fb6f994ff364ea442ed0aed07b. JE_RUNNABLE() causes general cross-compilation issues. --- configure.ac | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/configure.ac b/configure.ac index 24136736..053e5d7e 100644 --- a/configure.ac +++ b/configure.ac @@ -43,17 +43,6 @@ AC_CACHE_CHECK([whether $1 is compilable], [$4=no])]) ]) -dnl JE_RUNNABLE(label, hcode, mcode, rvar) -AC_DEFUN([JE_RUNNABLE], -[ -AC_CACHE_CHECK([whether $1 is runnable], - [$4], - [AC_RUN_IFELSE([AC_LANG_PROGRAM([$2], - [$3])], - [$4=yes], - [$4=no])]) -]) - dnl ============================================================================ CONFIG=`echo ${ac_configure_args} | sed -e 's#'"'"'\([^ ]*\)'"'"'#\1#g'` @@ -1660,11 +1649,7 @@ fi dnl ============================================================================ dnl Check for os_unfair_lock operations as provided on Darwin. -dnl Run the test program rather than merely compiling so that dyld lazy symbol -dnl binding doesn't result in a false positive if building with a version of -dnl XCode (>7) that supports the API on a system that is too old to actually -dnl implement it (<10.12). -JE_RUNNABLE([Darwin os_unfair_lock_*()], [ +JE_COMPILABLE([Darwin os_unfair_lock_*()], [ #include ], [ os_unfair_lock lock = OS_UNFAIR_LOCK_INIT; -- GitLab From 9b94c015af7fe7f86b19c71059be8758afd06fe3 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 16 Nov 2016 10:56:40 -0800 Subject: [PATCH 184/544] Document how to use --cache configure option. This resolves #494. --- INSTALL | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/INSTALL b/INSTALL index a31871b0..2e963546 100644 --- a/INSTALL +++ b/INSTALL @@ -324,6 +324,21 @@ LDFLAGS="?" PATH="?" 'configure' uses this to find programs. +In some cases it may be necessary to work around configuration results that do +not match reality. For example, OS X 10.12 in conjunction with XCode 8 adds +the os_unfair_lock_*() API, but if XCode 8 is used to build jemalloc on older +versions of OS X, the configure script will determine that os_unfair_lock_*() +is compilable, yet run-time failures will result. To work around this +(ignoring that MACOSX_DEPLOYMENT_TARGET may be the correct fix), create a cache +file (called e.g. darwin.cache) with the following contents to override the +relevant configuration variable defined in configure.ac: + + je_cv_os_unfair_lock=no + +Invoke configure as such: + + ./configure --cache=darwin.cache + === Advanced compilation ======================================================= To build only parts of jemalloc, use the following targets: -- GitLab From 95974c04403bbfb2fe3031e86785d354ef5e5906 Mon Sep 17 00:00:00 2001 From: Maks Naumov Date: Wed, 16 Nov 2016 09:56:29 +0200 Subject: [PATCH 185/544] Remove size_t -> unsigned -> size_t conversion. --- src/arena.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/arena.c b/src/arena.c index 75a92edc..488bfd47 100644 --- a/src/arena.c +++ b/src/arena.c @@ -131,8 +131,7 @@ arena_slab_reg_alloc(tsdn_t *tsdn, extent_t *slab, assert(slab_data->nfree > 0); assert(!bitmap_full(slab_data->bitmap, &bin_info->bitmap_info)); - regind = (unsigned)bitmap_sfu(slab_data->bitmap, - &bin_info->bitmap_info); + regind = bitmap_sfu(slab_data->bitmap, &bin_info->bitmap_info); ret = (void *)((uintptr_t)extent_addr_get(slab) + (uintptr_t)(bin_info->reg_size * regind)); slab_data->nfree--; -- GitLab From aec5a051e8848f06aa041c9ebfc092a2626356fc Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 16 Nov 2016 18:28:38 -0800 Subject: [PATCH 186/544] Avoid gcc type-limits warnings. --- src/jemalloc.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index dc0add49..2c405b72 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -976,7 +976,11 @@ malloc_conf_init(void) if (cont) \ continue; \ } -#define CONF_HANDLE_T_U(t, o, n, min, max, clip) \ +#define CONF_MIN_no(um, min) false +#define CONF_MIN_yes(um, min) ((um) < (min)) +#define CONF_MAX_no(um, max) false +#define CONF_MAX_yes(um, max) ((um) > (max)) +#define CONF_HANDLE_T_U(t, o, n, min, max, check_min, check_max, clip) \ if (CONF_MATCH(n)) { \ uintmax_t um; \ char *end; \ @@ -989,15 +993,19 @@ malloc_conf_init(void) "Invalid conf value", \ k, klen, v, vlen); \ } else if (clip) { \ - if ((min) != 0 && um < (min)) \ + if (CONF_MIN_##check_min(um, \ + (min))) \ o = (t)(min); \ - else if (um > (max)) \ + else if (CONF_MAX_##check_max( \ + um, (max))) \ o = (t)(max); \ else \ o = (t)um; \ } else { \ - if (((min) != 0 && um < (min)) \ - || um > (max)) { \ + if (CONF_MIN_##check_min(um, \ + (min)) || \ + CONF_MAX_##check_max(um, \ + (max))) { \ malloc_conf_error( \ "Out-of-range " \ "conf value", \ @@ -1007,10 +1015,13 @@ malloc_conf_init(void) } \ continue; \ } -#define CONF_HANDLE_UNSIGNED(o, n, min, max, clip) \ - CONF_HANDLE_T_U(unsigned, o, n, min, max, clip) -#define CONF_HANDLE_SIZE_T(o, n, min, max, clip) \ - CONF_HANDLE_T_U(size_t, o, n, min, max, clip) +#define CONF_HANDLE_UNSIGNED(o, n, min, max, check_min, check_max, \ + clip) \ + CONF_HANDLE_T_U(unsigned, o, n, min, max, \ + check_min, check_max, clip) +#define CONF_HANDLE_SIZE_T(o, n, min, max, check_min, check_max, clip) \ + CONF_HANDLE_T_U(size_t, o, n, min, max, \ + check_min, check_max, clip) #define CONF_HANDLE_SSIZE_T(o, n, min, max) \ if (CONF_MATCH(n)) { \ long l; \ @@ -1068,7 +1079,7 @@ malloc_conf_init(void) continue; } CONF_HANDLE_UNSIGNED(opt_narenas, "narenas", 1, - UINT_MAX, false) + UINT_MAX, yes, no, false) CONF_HANDLE_SSIZE_T(opt_decay_time, "decay_time", -1, NSTIME_SEC_MAX); CONF_HANDLE_BOOL(opt_stats_print, "stats_print", true) @@ -1120,8 +1131,8 @@ malloc_conf_init(void) CONF_HANDLE_BOOL(opt_prof_thread_active_init, "prof_thread_active_init", true) CONF_HANDLE_SIZE_T(opt_lg_prof_sample, - "lg_prof_sample", 0, - (sizeof(uint64_t) << 3) - 1, true) + "lg_prof_sample", 0, (sizeof(uint64_t) << 3) + - 1, no, yes, true) CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum", true) CONF_HANDLE_SSIZE_T(opt_lg_prof_interval, @@ -1137,7 +1148,14 @@ malloc_conf_init(void) malloc_conf_error("Invalid conf pair", k, klen, v, vlen); #undef CONF_MATCH +#undef CONF_MATCH_VALUE #undef CONF_HANDLE_BOOL +#undef CONF_MIN_no +#undef CONF_MIN_yes +#undef CONF_MAX_no +#undef CONF_MAX_yes +#undef CONF_HANDLE_T_U +#undef CONF_HANDLE_UNSIGNED #undef CONF_HANDLE_SIZE_T #undef CONF_HANDLE_SSIZE_T #undef CONF_HANDLE_CHAR_P -- GitLab From f7ca1c9bc321feffe056f5d154c287f63e324020 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 16 Nov 2016 19:41:09 -0800 Subject: [PATCH 187/544] Remove a residual comment. --- configure.ac | 1 - 1 file changed, 1 deletion(-) diff --git a/configure.ac b/configure.ac index 053e5d7e..72021e09 100644 --- a/configure.ac +++ b/configure.ac @@ -171,7 +171,6 @@ fi if test "x$CFLAGS" = "x" ; then no_CFLAGS="yes" if test "x$GCC" = "xyes" ; then -dnl JE_CFLAGS_APPEND([-std=gnu99]) JE_CFLAGS_APPEND([-std=gnu11]) if test "x$je_cv_cflags_appended" = "x-std=gnu11" ; then AC_DEFINE_UNQUOTED([JEMALLOC_HAS_RESTRICT]) -- GitLab From a64123ce13545ef57a36285cc9d33978e59fc3da Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 17 Nov 2016 10:24:51 -0800 Subject: [PATCH 188/544] Refactor madvise(2) configuration. Add feature tests for the MADV_FREE and MADV_DONTNEED flags to madvise(2), so that MADV_FREE is detected and used for Linux kernel versions 4.5 and newer. Refactor pages_purge() so that on systems which support both flags, MADV_FREE is preferred over MADV_DONTNEED. This resolves #387. --- configure.ac | 38 ++++++++++++------- .../internal/jemalloc_internal_defs.h.in | 21 +++++----- src/pages.c | 10 ++--- 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/configure.ac b/configure.ac index 72021e09..15897bee 100644 --- a/configure.ac +++ b/configure.ac @@ -354,7 +354,6 @@ maps_coalesce="1" case "${host}" in *-*-darwin* | *-*-ios*) abi="macho" - AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) RPATH="" LD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES" so="dylib" @@ -367,21 +366,17 @@ case "${host}" in *-*-freebsd*) abi="elf" AC_DEFINE([JEMALLOC_SYSCTL_VM_OVERCOMMIT], [ ]) - AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) force_lazy_lock="1" ;; *-*-dragonfly*) abi="elf" - AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) ;; *-*-openbsd*) abi="elf" - AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) force_tls="0" ;; *-*-bitrig*) abi="elf" - AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) ;; *-*-linux-android) dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. @@ -389,7 +384,6 @@ case "${host}" in abi="elf" AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) - AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED], [ ]) AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) AC_DEFINE([JEMALLOC_C11ATOMICS]) force_tls="0" @@ -401,7 +395,6 @@ case "${host}" in abi="elf" AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) - AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED], [ ]) AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) AC_DEFINE([JEMALLOC_USE_CXX_THROW], [ ]) default_munmap="0" @@ -418,11 +411,9 @@ case "${host}" in [abi="elf"], [abi="aout"]) AC_MSG_RESULT([$abi]) - AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) ;; *-*-solaris2*) abi="elf" - AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) RPATH='-Wl,-R,$(1)' dnl Solaris needs this for sigwait(). CPPFLAGS="$CPPFLAGS -D_POSIX_PTHREAD_SEMANTICS" @@ -1580,12 +1571,33 @@ dnl Check for madvise(2). JE_COMPILABLE([madvise(2)], [ #include ], [ - { - madvise((void *)0, 0, 0); - } + madvise((void *)0, 0, 0); ], [je_cv_madvise]) if test "x${je_cv_madvise}" = "xyes" ; then - AC_DEFINE([JEMALLOC_HAVE_MADVISE], [ ]) + dnl Check for madvise(..., MADV_FREE). + JE_COMPILABLE([madvise(..., MADV_FREE)], [ +#include +], [ + madvise((void *)0, 0, MADV_FREE); +], [je_cv_madv_free]) + if test "x${je_cv_madv_free}" = "xyes" ; then + AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ]) + fi + + dnl Check for madvise(..., MADV_DONTNEED). + JE_COMPILABLE([madvise(..., MADV_DONTNEED)], [ +#include +], [ + madvise((void *)0, 0, MADV_DONTNEED); +], [je_cv_madv_dontneed]) + if test "x${je_cv_madv_dontneed}" = "xyes" ; then + AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED], [ ]) + fi + + if test "x${je_cv_madv_free}" = "xyes" \ + -o "x${je_cv_madv_dontneed}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_MADVISE], [ ]) + fi fi dnl ============================================================================ diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 4d2daea8..baf12d43 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -55,11 +55,6 @@ */ #undef JEMALLOC_HAVE_BUILTIN_CLZ -/* - * Defined if madvise(2) is available. - */ -#undef JEMALLOC_HAVE_MADVISE - /* * Defined if os_unfair_lock_*() functions are available, as provided by Darwin. */ @@ -249,18 +244,20 @@ #undef JEMALLOC_SYSCTL_VM_OVERCOMMIT #undef JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY +/* Defined if madvise(2) is available. */ +#undef JEMALLOC_HAVE_MADVISE + /* * Methods for purging unused pages differ between operating systems. * - * madvise(..., MADV_DONTNEED) : On Linux, this immediately discards pages, - * such that new pages will be demand-zeroed if - * the address region is later touched. - * madvise(..., MADV_FREE) : On FreeBSD and Darwin, this marks pages as being - * unused, such that they will be discarded rather - * than swapped out. + * madvise(..., MADV_FREE) : This marks pages as being unused, such that they + * will be discarded rather than swapped out. + * madvise(..., MADV_DONTNEED) : This immediately discards pages, such that + * new pages will be demand-zeroed if the + * address region is later touched. */ -#undef JEMALLOC_PURGE_MADVISE_DONTNEED #undef JEMALLOC_PURGE_MADVISE_FREE +#undef JEMALLOC_PURGE_MADVISE_DONTNEED /* Define if operating system has alloca.h header. */ #undef JEMALLOC_HAS_ALLOCA_H diff --git a/src/pages.c b/src/pages.c index 647952ac..395ace99 100644 --- a/src/pages.c +++ b/src/pages.c @@ -171,14 +171,14 @@ pages_purge(void *addr, size_t size) VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE); unzeroed = true; #elif defined(JEMALLOC_HAVE_MADVISE) -# ifdef JEMALLOC_PURGE_MADVISE_DONTNEED -# define JEMALLOC_MADV_PURGE MADV_DONTNEED -# define JEMALLOC_MADV_ZEROS true -# elif defined(JEMALLOC_PURGE_MADVISE_FREE) +# if defined(JEMALLOC_PURGE_MADVISE_FREE) # define JEMALLOC_MADV_PURGE MADV_FREE # define JEMALLOC_MADV_ZEROS false +# elif defined(JEMALLOC_PURGE_MADVISE_DONTNEED) +# define JEMALLOC_MADV_PURGE MADV_DONTNEED +# define JEMALLOC_MADV_ZEROS true # else -# error "No madvise(2) flag defined for purging unused dirty pages." +# error No madvise(2) flag defined for purging unused dirty pages # endif int err = madvise(addr, size, JEMALLOC_MADV_PURGE); unzeroed = (!JEMALLOC_MADV_ZEROS || err != 0); -- GitLab From fda60be799e7929191f3844dd55b685549b6d867 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 17 Nov 2016 11:50:52 -0800 Subject: [PATCH 189/544] Update a comment. --- include/jemalloc/internal/arena.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 28d63c68..ad400839 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -165,7 +165,7 @@ struct arena_s { * perspective: * 1) Thread assignment (modifies nthreads) is synchronized via atomics. * 2) Bin-related operations are protected by bin locks. - * 3) Chunk-related operations are protected by this mutex. + * 3) Extent-related operations are protected by this mutex. */ malloc_mutex_t lock; -- GitLab From 5234be21333e341252ed7223570d790970694d80 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 17 Nov 2016 15:14:57 -0800 Subject: [PATCH 190/544] Add pthread_atfork(3) feature test. Some versions of Android provide a pthreads library without providing pthread_atfork(), so in practice a separate feature test is necessary for the latter. --- configure.ac | 8 ++++++++ include/jemalloc/internal/jemalloc_internal_defs.h.in | 3 +++ src/jemalloc.c | 5 +++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 15897bee..25dcc2c2 100644 --- a/configure.ac +++ b/configure.ac @@ -1299,6 +1299,14 @@ if test "x$abi" != "xpecoff" ; then AC_CHECK_LIB([pthread], [pthread_create], [LIBS="$LIBS -lpthread"], [AC_SEARCH_LIBS([pthread_create], , , AC_MSG_ERROR([libpthread is missing]))]) + JE_COMPILABLE([pthread_atfork(3)], [ +#include +], [ + pthread_atfork((void *)0, (void *)0, (void *)0); +], [je_cv_pthread_atfork]) + if test "x${je_cv_pthread_atfork}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_PTHREAD_ATFORK], [ ]) + fi fi CPPFLAGS="$CPPFLAGS -D_REENTRANT" diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index baf12d43..c345214b 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -79,6 +79,9 @@ */ #undef JEMALLOC_HAVE_ISSETUGID +/* Defined if pthread_atfork(3) is available. */ +#undef JEMALLOC_HAVE_PTHREAD_ATFORK + /* * Defined if clock_gettime(CLOCK_MONOTONIC_COARSE, ...) is available. */ diff --git a/src/jemalloc.c b/src/jemalloc.c index 2c405b72..7df3fc9e 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1264,8 +1264,9 @@ malloc_init_hard_recursible(void) ncpus = malloc_ncpus(); -#if (!defined(JEMALLOC_MUTEX_INIT_CB) && !defined(JEMALLOC_ZONE) \ - && !defined(_WIN32) && !defined(__native_client__)) +#if (defined(JEMALLOC_HAVE_PTHREAD_ATFORK) && !defined(JEMALLOC_MUTEX_INIT_CB) \ + && !defined(JEMALLOC_ZONE) && !defined(_WIN32) && \ + !defined(__native_client__)) /* LinuxThreads' pthread_atfork() allocates. */ if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent, jemalloc_postfork_child) != 0) { -- GitLab From c3b85f25857cf4022be7b186adc1e20206d4c74f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 22 Nov 2016 10:58:23 -0800 Subject: [PATCH 191/544] Style fixes. --- include/jemalloc/internal/util.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/jemalloc/internal/util.h b/include/jemalloc/internal/util.h index aee00d6d..119696bb 100644 --- a/include/jemalloc/internal/util.h +++ b/include/jemalloc/internal/util.h @@ -56,17 +56,17 @@ * uninitialized. */ #ifdef JEMALLOC_CC_SILENCE -# define JEMALLOC_CC_SILENCE_INIT(v) = v +# define JEMALLOC_CC_SILENCE_INIT(v) = v #else -# define JEMALLOC_CC_SILENCE_INIT(v) +# define JEMALLOC_CC_SILENCE_INIT(v) #endif #ifdef __GNUC__ -# define likely(x) __builtin_expect(!!(x), 1) -# define unlikely(x) __builtin_expect(!!(x), 0) +# define likely(x) __builtin_expect(!!(x), 1) +# define unlikely(x) __builtin_expect(!!(x), 0) #else -# define likely(x) !!(x) -# define unlikely(x) !!(x) +# define likely(x) !!(x) +# define unlikely(x) !!(x) #endif #if !defined(JEMALLOC_INTERNAL_UNREACHABLE) -- GitLab From 32127949a3045330b8058bbf474e619e1bf2f05f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 22 Nov 2016 10:58:58 -0800 Subject: [PATCH 192/544] Enable overriding JEMALLOC_{ALLOC,FREE}_JUNK. This resolves #509. --- include/jemalloc/internal/util.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/jemalloc/internal/util.h b/include/jemalloc/internal/util.h index 119696bb..d9f97416 100644 --- a/include/jemalloc/internal/util.h +++ b/include/jemalloc/internal/util.h @@ -41,8 +41,12 @@ #define MALLOC_PRINTF_BUFSIZE 4096 /* Junk fill patterns. */ -#define JEMALLOC_ALLOC_JUNK ((uint8_t)0xa5) -#define JEMALLOC_FREE_JUNK ((uint8_t)0x5a) +#ifndef JEMALLOC_ALLOC_JUNK +# define JEMALLOC_ALLOC_JUNK ((uint8_t)0xa5) +#endif +#ifndef JEMALLOC_FREE_JUNK +# define JEMALLOC_FREE_JUNK ((uint8_t)0x5a) +#endif /* * Wrap a cpp argument that contains commas such that it isn't broken up into -- GitLab From eb29d7ec0e2c4994e10ec40d42265a86e569500c Mon Sep 17 00:00:00 2001 From: John Szakmeister Date: Wed, 23 Nov 2016 15:32:35 -0500 Subject: [PATCH 193/544] Implement a more reliable detection scheme for os_unfair_lock. The core issue here is the weak linking of the symbol, and in certain environments--for instance, using the latest Xcode (8.1) with the latest SDK (10.12)--os_unfair_lock may resolve even though you're compiling on a host that doesn't support it (10.11). We can use the availability macros to circumvent this problem, and detect that we're not compiling for a target that is going to support them and error out at compile time. The other alternative is to do a runtime check, but that presents issues for cross-compiling. --- configure.ac | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configure.ac b/configure.ac index 25dcc2c2..2e3ef364 100644 --- a/configure.ac +++ b/configure.ac @@ -1670,10 +1670,15 @@ dnl Check for os_unfair_lock operations as provided on Darwin. JE_COMPILABLE([Darwin os_unfair_lock_*()], [ #include +#include ], [ + #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200 + #error "os_unfair_lock is not supported" + #else os_unfair_lock lock = OS_UNFAIR_LOCK_INIT; os_unfair_lock_lock(&lock); os_unfair_lock_unlock(&lock); + #endif ], [je_cv_os_unfair_lock]) if test "x${je_cv_os_unfair_lock}" = "xyes" ; then AC_DEFINE([JEMALLOC_OS_UNFAIR_LOCK], [ ]) -- GitLab From 7179351a45f00fa943cfe23b555036615b91ce9d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 30 Nov 2016 09:57:12 -0800 Subject: [PATCH 194/544] Update configure cache file example. --- INSTALL | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/INSTALL b/INSTALL index 2e963546..48025e84 100644 --- a/INSTALL +++ b/INSTALL @@ -325,19 +325,13 @@ PATH="?" 'configure' uses this to find programs. In some cases it may be necessary to work around configuration results that do -not match reality. For example, OS X 10.12 in conjunction with XCode 8 adds -the os_unfair_lock_*() API, but if XCode 8 is used to build jemalloc on older -versions of OS X, the configure script will determine that os_unfair_lock_*() -is compilable, yet run-time failures will result. To work around this -(ignoring that MACOSX_DEPLOYMENT_TARGET may be the correct fix), create a cache -file (called e.g. darwin.cache) with the following contents to override the -relevant configuration variable defined in configure.ac: +not match reality. For example, Linux 4.5 added support for the MADV_FREE flag +to madvise(2), which can cause problems if building on a host with MADV_FREE +support and deploying to a target without. To work around this, use a cache +file to override the relevant configuration variable defined in configure.ac, +e.g.: - je_cv_os_unfair_lock=no - -Invoke configure as such: - - ./configure --cache=darwin.cache + echo "je_cv_madv_free=no" > config.cache && ./configure -C === Advanced compilation ======================================================= -- GitLab From acb7b1f53e25fcad89375512e6eaea8115dc6af5 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 3 Dec 2016 16:47:36 -0800 Subject: [PATCH 195/544] Add --disable-syscall. This resolves #517. --- INSTALL | 5 +++ configure.ac | 31 +++++++++++++------ .../internal/jemalloc_internal_defs.h.in | 4 +-- src/pages.c | 6 ++-- src/util.c | 2 +- 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/INSTALL b/INSTALL index 48025e84..4cad3ee2 100644 --- a/INSTALL +++ b/INSTALL @@ -203,6 +203,11 @@ any of the following arguments (not a definitive list) to 'configure': most extreme case increases physical memory usage for the 16 KiB size class to 20 KiB. +--disable-syscall + Disable use of syscall(2) rather than {open,read,write,close}(2). This is + intended as a workaround for systems that place security limitations on + syscall(2). + --with-xslroot= Specify where to find DocBook XSL stylesheets when building the documentation. diff --git a/configure.ac b/configure.ac index 2e3ef364..ab2c0bee 100644 --- a/configure.ac +++ b/configure.ac @@ -1366,20 +1366,33 @@ if test "x${je_cv_mach_absolute_time}" = "xyes" ; then AC_DEFINE([JEMALLOC_HAVE_MACH_ABSOLUTE_TIME]) fi -dnl Check if syscall(2) is usable. Treat warnings as errors, so that e.g. OS X -dnl 10.12's deprecation warning prevents use. -SAVED_CFLAGS="${CFLAGS}" -JE_CFLAGS_APPEND([-Werror]) -JE_COMPILABLE([syscall(2)], [ +dnl Use syscall(2) (if available) by default. +AC_ARG_ENABLE([syscall], + [AS_HELP_STRING([--disable-syscall], [Disable use of syscall(2)])], +[if test "x$enable_syscall" = "xno" ; then + enable_syscall="0" +else + enable_syscall="1" +fi +], +[enable_syscall="1"] +) +if test "x$enable_syscall" = "x1" ; then + dnl Check if syscall(2) is usable. Treat warnings as errors, so that e.g. OS + dnl X 10.12's deprecation warning prevents use. + SAVED_CFLAGS="${CFLAGS}" + JE_CFLAGS_APPEND([-Werror]) + JE_COMPILABLE([syscall(2)], [ #include #include ], [ syscall(SYS_write, 2, "hello", 5); ], - [je_cv_syscall]) -CFLAGS="${SAVED_CFLAGS}" -if test "x$je_cv_syscall" = "xyes" ; then - AC_DEFINE([JEMALLOC_HAVE_SYSCALL], [ ]) + [je_cv_syscall]) + CFLAGS="${SAVED_CFLAGS}" + if test "x$je_cv_syscall" = "xyes" ; then + AC_DEFINE([JEMALLOC_USE_SYSCALL], [ ]) + fi fi dnl Check if the GNU-specific secure_getenv function exists. diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index c345214b..aa0c0474 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -66,8 +66,8 @@ */ #undef JEMALLOC_OSSPIN -/* Defined if syscall(2) is available. */ -#undef JEMALLOC_HAVE_SYSCALL +/* Defined if syscall(2) is usable. */ +#undef JEMALLOC_USE_SYSCALL /* * Defined if secure_getenv(3) is available. diff --git a/src/pages.c b/src/pages.c index 395ace99..6af228ac 100644 --- a/src/pages.c +++ b/src/pages.c @@ -219,7 +219,7 @@ os_overcommits_proc(void) char buf[1]; ssize_t nread; -#if defined(JEMALLOC_HAVE_SYSCALL) && defined(SYS_open) +#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_open) fd = (int)syscall(SYS_open, "/proc/sys/vm/overcommit_memory", O_RDONLY); #else fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY); @@ -227,13 +227,13 @@ os_overcommits_proc(void) if (fd == -1) return (false); /* Error. */ -#if defined(JEMALLOC_HAVE_SYSCALL) && defined(SYS_read) +#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_read) nread = (ssize_t)syscall(SYS_read, fd, &buf, sizeof(buf)); #else nread = read(fd, &buf, sizeof(buf)); #endif -#if defined(JEMALLOC_HAVE_SYSCALL) && defined(SYS_close) +#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_close) syscall(SYS_close, fd); #else close(fd); diff --git a/src/util.c b/src/util.c index 5b8175bc..dd8c2363 100644 --- a/src/util.c +++ b/src/util.c @@ -49,7 +49,7 @@ static void wrtmessage(void *cbopaque, const char *s) { -#if defined(JEMALLOC_HAVE_SYSCALL) && defined(SYS_write) +#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_write) /* * Use syscall(2) rather than write(2) when possible in order to avoid * the possibility of memory allocation within libc. This is necessary -- GitLab From fbe30158184c28f00f109cf4b8870c554e996bab Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 3 Dec 2016 12:22:59 -0800 Subject: [PATCH 196/544] Update ChangeLog for 4.4.0. --- ChangeLog | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/ChangeLog b/ChangeLog index 587685d0..f75edd93 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,33 @@ brevity. Much more detail can be found in the git revision history: https://github.com/jemalloc/jemalloc +* 4.4.0 (December 3, 2016) + + New features: + - Add configure support for *-*-linux-android. (@cferris1000, @jasone) + - Add the --disable-syscall configure option, for use on systems that place + security-motivated limitations on syscall(2). (@jasone) + - Add support for Debian GNU/kFreeBSD. (@thesam) + + Optimizations: + - Add extent serial numbers and use them where appropriate as a sort key that + is higher priority than address, so that the allocation policy prefers older + extents. This tends to improve locality (decrease fragmentation) when + memory grows downward. (@jasone) + - Refactor madvise(2) configuration so that MADV_FREE is detected and utilized + on Linux 4.5 and newer. (@jasone) + - Mark partially purged arena chunks as non-huge-page. This improves + interaction with Linux's transparent huge page functionality. (@jasone) + + Bug fixes: + - Fix size class computations for edge conditions involving extremely large + allocations. This regression was first released in 4.0.0. (@jasone, + @ingvarha) + - Remove overly restrictive assertions related to the cactive statistic. This + regression was first released in 4.1.0. (@jasone) + - Implement a more reliable detection scheme for os_unfair_lock on macOS. + (@jszakmeister) + * 4.3.1 (November 7, 2016) Bug fixes: -- GitLab From d4c5aceb7cb5c5cf7a6dfd62e072c7dd12188998 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 12 Dec 2016 18:04:20 -0800 Subject: [PATCH 197/544] Add a_type parameter to qr_{meld,split}(). --- include/jemalloc/internal/extent.h | 2 +- include/jemalloc/internal/qr.h | 8 ++++---- test/unit/qr.c | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 3c5573ee..d5690c08 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -445,7 +445,7 @@ JEMALLOC_INLINE void extent_ring_insert(extent_t *sentinel, extent_t *extent) { - qr_meld(sentinel, extent, qr_link); + qr_meld(sentinel, extent, extent_t, qr_link); } JEMALLOC_INLINE void diff --git a/include/jemalloc/internal/qr.h b/include/jemalloc/internal/qr.h index 0fbaec25..3b5d0276 100644 --- a/include/jemalloc/internal/qr.h +++ b/include/jemalloc/internal/qr.h @@ -31,8 +31,8 @@ struct { \ (a_qrelm)->a_field.qre_next = (a_qr); \ } while (0) -#define qr_meld(a_qr_a, a_qr_b, a_field) do { \ - void *t; \ +#define qr_meld(a_qr_a, a_qr_b, a_type, a_field) do { \ + a_type *t; \ (a_qr_a)->a_field.qre_prev->a_field.qre_next = (a_qr_b); \ (a_qr_b)->a_field.qre_prev->a_field.qre_next = (a_qr_a); \ t = (a_qr_a)->a_field.qre_prev; \ @@ -44,8 +44,8 @@ struct { \ * qr_meld() and qr_split() are functionally equivalent, so there's no need to * have two copies of the code. */ -#define qr_split(a_qr_a, a_qr_b, a_field) \ - qr_meld((a_qr_a), (a_qr_b), a_field) +#define qr_split(a_qr_a, a_qr_b, a_type, a_field) \ + qr_meld((a_qr_a), (a_qr_b), a_type, a_field) #define qr_remove(a_qr, a_field) do { \ (a_qr)->a_field.qre_prev->a_field.qre_next \ diff --git a/test/unit/qr.c b/test/unit/qr.c index a2a2d902..8b764e11 100644 --- a/test/unit/qr.c +++ b/test/unit/qr.c @@ -215,22 +215,22 @@ TEST_BEGIN(test_qr_meld_split) for (i = 1; i < NENTRIES; i++) qr_after_insert(&entries[i - 1], &entries[i], link); - qr_split(&entries[0], &entries[SPLIT_INDEX], link); + qr_split(&entries[0], &entries[SPLIT_INDEX], ring_t, link); test_split_entries(entries); - qr_meld(&entries[0], &entries[SPLIT_INDEX], link); + qr_meld(&entries[0], &entries[SPLIT_INDEX], ring_t, link); test_entries_ring(entries); - qr_meld(&entries[0], &entries[SPLIT_INDEX], link); + qr_meld(&entries[0], &entries[SPLIT_INDEX], ring_t, link); test_split_entries(entries); - qr_split(&entries[0], &entries[SPLIT_INDEX], link); + qr_split(&entries[0], &entries[SPLIT_INDEX], ring_t, link); test_entries_ring(entries); - qr_split(&entries[0], &entries[0], link); + qr_split(&entries[0], &entries[0], ring_t, link); test_entries_ring(entries); - qr_meld(&entries[0], &entries[0], link); + qr_meld(&entries[0], &entries[0], ring_t, link); test_entries_ring(entries); } TEST_END -- GitLab From 2319152d9f5d9b33eebc36a50ccf4239f31c1ad9 Mon Sep 17 00:00:00 2001 From: Dave Watson Date: Sun, 23 Oct 2016 15:56:30 -0700 Subject: [PATCH 198/544] jemalloc cpp new/delete bindings Adds cpp bindings for jemalloc, along with necessary autoconf settings. This is mostly to add sized deallocation support, which can't be added from C directly. Sized deallocation is ~10% microbench improvement. * Import ax_cxx_compile_stdcxx.m4 from the autoconf repo, seems like the easiest way to get c++14 detection. * Adds various other changes, like CXXFLAGS, to configure.ac. * Adds new rules to Makefile.in for src/jemalloc-cpp.cpp, and a basic unittest. * Both new and delete are overridden, to ensure jemalloc is used for both. * TODO future enhancement of avoiding extra PLT thunks for new and delete - sdallocx and malloc are publicly exported jemalloc symbols, using an alias would link them directly. Unfortunately, was having trouble getting it to play nice with jemalloc's namespace support. Testing: Tested gcc 4.8, gcc 5, gcc 5.2, clang 4.0. Only gcc >= 5 has sized deallocation support, verified that the rest build correctly. Tested mac osx and Centos. Tested --with-jemalloc-prefix and --without-export. This resolves #202. --- .gitignore | 7 + INSTALL | 4 + Makefile.in | 85 ++- bin/jemalloc-config.in | 4 + configure.ac | 72 +++ .../jemalloc/internal/jemalloc_internal.h.in | 13 +- .../internal/jemalloc_internal_macros.h | 2 +- include/jemalloc/internal/rtree.h | 8 +- m4/ax_cxx_compile_stdcxx.m4 | 562 ++++++++++++++++++ src/jemalloc_cpp.cpp | 140 +++++ test/include/test/jemalloc_test.h.in | 11 +- test/include/test/test.h | 4 +- test/integration/cpp/basic.cpp | 18 + 13 files changed, 905 insertions(+), 25 deletions(-) create mode 100644 m4/ax_cxx_compile_stdcxx.m4 create mode 100644 src/jemalloc_cpp.cpp create mode 100644 test/integration/cpp/basic.cpp diff --git a/.gitignore b/.gitignore index 08278d08..548c7d1a 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,13 @@ test/include/test/jemalloc_test_defs.h /test/integration/*.gcno /test/integration/*.out +/test/integration/cpp/[A-Za-z]* +!/test/integration/cpp/[A-Za-z]*.* +/test/integration/cpp/*.[od] +/test/integration/cpp/*.gcda +/test/integration/cpp/*.gcno +/test/integration/cpp/*.out + /test/src/*.[od] /test/src/*.gcda /test/src/*.gcno diff --git a/INSTALL b/INSTALL index 4cad3ee2..c7ca5a73 100644 --- a/INSTALL +++ b/INSTALL @@ -208,6 +208,10 @@ any of the following arguments (not a definitive list) to 'configure': intended as a workaround for systems that place security limitations on syscall(2). +--disable-cxx + Disable C++ integration. This will cause new and delete operator + implementations to be omitted. + --with-xslroot= Specify where to find DocBook XSL stylesheets when building the documentation. diff --git a/Makefile.in b/Makefile.in index 5e6f0c1a..22d9d86f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -9,6 +9,7 @@ vpath % . SHELL := /bin/sh CC := @CC@ +CXX := @CXX@ # Configuration parameters. DESTDIR = @@ -26,6 +27,8 @@ abs_objroot := @abs_objroot@ CPPFLAGS := @CPPFLAGS@ -I$(srcroot)include -I$(objroot)include EXTRA_CFLAGS := @EXTRA_CFLAGS@ CFLAGS := @CFLAGS@ $(EXTRA_CFLAGS) +EXTRA_CXXFLAGS := @EXTRA_CXXFLAGS@ +CXXFLAGS := @CXXFLAGS@ $(EXTRA_CXXFLAGS) LDFLAGS := @LDFLAGS@ EXTRA_LDFLAGS := @EXTRA_LDFLAGS@ LIBS := @LIBS@ @@ -140,8 +143,10 @@ C_TESTLIB_SRCS := $(srcroot)test/src/btalloc.c $(srcroot)test/src/btalloc_0.c \ $(srcroot)test/src/thd.c $(srcroot)test/src/timer.c ifeq (1, $(link_whole_archive)) C_UTIL_INTEGRATION_SRCS := +C_UTIL_CPP_SRCS := else C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/util.c +C_UTIL_CPP_SRCS := $(srcroot)src/nstime.c $(srcroot)src/util.c endif TESTS_UNIT := \ $(srcroot)test/unit/a0.c \ @@ -195,11 +200,21 @@ TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \ $(srcroot)test/integration/thread_arena.c \ $(srcroot)test/integration/thread_tcache_enabled.c \ $(srcroot)test/integration/xallocx.c +ifeq (@enable_cxx@, 1) +CPP_SRCS := $(srcroot)src/jemalloc_cpp.cpp +TESTS_INTEGRATION_CPP := $(srcroot)test/integration/cpp/basic.cpp +else +CPP_SRCS := +TESTS_INTEGRATION_CPP := +endif TESTS_STRESS := $(srcroot)test/stress/microbench.c -TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_STRESS) + +TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_INTEGRATION_CPP) $(TESTS_STRESS) C_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.$(O)) +CPP_OBJS := $(CPP_SRCS:$(srcroot)%.cpp=$(objroot)%.$(O)) C_PIC_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.pic.$(O)) +CPP_PIC_OBJS := $(CPP_SRCS:$(srcroot)%.cpp=$(objroot)%.pic.$(O)) C_JET_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.$(O)) C_TESTLIB_UNIT_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.unit.$(O)) C_TESTLIB_INTEGRATION_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.integration.$(O)) @@ -209,15 +224,17 @@ C_TESTLIB_OBJS := $(C_TESTLIB_UNIT_OBJS) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_ TESTS_UNIT_OBJS := $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%.$(O)) TESTS_INTEGRATION_OBJS := $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%.$(O)) +TESTS_INTEGRATION_CPP_OBJS := $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%.$(O)) TESTS_STRESS_OBJS := $(TESTS_STRESS:$(srcroot)%.c=$(objroot)%.$(O)) TESTS_OBJS := $(TESTS_UNIT_OBJS) $(TESTS_INTEGRATION_OBJS) $(TESTS_STRESS_OBJS) +TESTS_CPP_OBJS := $(TESTS_INTEGRATION_CPP_OBJS) .PHONY: all dist build_doc_html build_doc_man build_doc .PHONY: install_bin install_include install_lib .PHONY: install_doc_html install_doc_man install_doc install .PHONY: tests check clean distclean relclean -.SECONDARY : $(TESTS_OBJS) +.SECONDARY : $(TESTS_OBJS) $(TESTS_CPP_OBJS) # Default target. all: build_lib @@ -239,15 +256,21 @@ build_doc: $(DOCS) # ifdef CC_MM -include $(C_OBJS:%.$(O)=%.d) +-include $(CPP_OBJS:%.$(O)=%.d) -include $(C_PIC_OBJS:%.$(O)=%.d) +-include $(CPP_PIC_OBJS:%.$(O)=%.d) -include $(C_JET_OBJS:%.$(O)=%.d) -include $(C_TESTLIB_OBJS:%.$(O)=%.d) -include $(TESTS_OBJS:%.$(O)=%.d) +-include $(TESTS_CPP_OBJS:%.$(O)=%.d) endif $(C_OBJS): $(objroot)src/%.$(O): $(srcroot)src/%.c +$(CPP_OBJS): $(objroot)src/%.$(O): $(srcroot)src/%.cpp $(C_PIC_OBJS): $(objroot)src/%.pic.$(O): $(srcroot)src/%.c $(C_PIC_OBJS): CFLAGS += $(PIC_CFLAGS) +$(CPP_PIC_OBJS): $(objroot)src/%.pic.$(O): $(srcroot)src/%.cpp +$(CPP_PIC_OBJS): CXXFLAGS += $(PIC_CFLAGS) $(C_JET_OBJS): $(objroot)src/%.jet.$(O): $(srcroot)src/%.c $(C_JET_OBJS): CFLAGS += -DJEMALLOC_JET $(C_TESTLIB_UNIT_OBJS): $(objroot)test/src/%.unit.$(O): $(srcroot)test/src/%.c @@ -260,11 +283,14 @@ $(C_TESTLIB_STRESS_OBJS): CPPFLAGS += -DJEMALLOC_STRESS_TEST -DJEMALLOC_STRESS_T $(C_TESTLIB_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include $(TESTS_UNIT_OBJS): CPPFLAGS += -DJEMALLOC_UNIT_TEST $(TESTS_INTEGRATION_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_TEST +$(TESTS_INTEGRATION_CPP_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_CPP_TEST $(TESTS_STRESS_OBJS): CPPFLAGS += -DJEMALLOC_STRESS_TEST $(TESTS_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.c +$(TESTS_CPP_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.cpp $(TESTS_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include +$(TESTS_CPP_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include ifneq ($(IMPORTLIB),$(SO)) -$(C_OBJS) $(C_JET_OBJS): CPPFLAGS += -DDLLEXPORT +$(CPP_OBJS) $(C_OBJS) $(C_JET_OBJS): CPPFLAGS += -DDLLEXPORT endif ifndef CC_MM @@ -272,8 +298,8 @@ ifndef CC_MM HEADER_DIRS = $(srcroot)include/jemalloc/internal \ $(objroot)include/jemalloc $(objroot)include/jemalloc/internal HEADERS = $(wildcard $(foreach dir,$(HEADER_DIRS),$(dir)/*.h)) -$(C_OBJS) $(C_PIC_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): $(HEADERS) -$(TESTS_OBJS): $(objroot)test/include/test/jemalloc_test.h +$(C_OBJS) $(CPP_OBJS) $(C_PIC_OBJS) $(CPP_PIC_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): $(HEADERS) +$(TESTS_OBJS) $(TESTS_CPP_OBJS): $(objroot)test/include/test/jemalloc_test.h endif $(C_OBJS) $(C_PIC_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): %.$(O): @@ -283,19 +309,26 @@ ifdef CC_MM @$(CC) -MM $(CPPFLAGS) -MT $@ -o $(@:%.$(O)=%.d) $< endif +$(CPP_OBJS) $(CPP_PIC_OBJS) $(TESTS_CPP_OBJS): %.$(O): + @mkdir -p $(@D) + $(CXX) $(CXXFLAGS) -c $(CPPFLAGS) $(CTARGET) $< +ifdef CC_MM + @$(CXX) -MM $(CPPFLAGS) -MT $@ -o $(@:%.$(O)=%.d) $< +endif + ifneq ($(SOREV),$(SO)) %.$(SO) : %.$(SOREV) @mkdir -p $(@D) ln -sf $( +], [[ + int *arr = (int *)malloc(sizeof(int) * 42); + if (arr == NULL) + return (1); +]], [je_cv_libstdcxx]) + if test "x${je_cv_libstdcxx}" = "xno" ; then + LIBS="${SAVED_LIBS}" + fi + else + enable_cxx="0" + fi +fi +AC_SUBST([enable_cxx]) +AC_SUBST([CXXFLAGS]) +AC_SUBST([EXTRA_CXXFLAGS]) + AC_C_BIGENDIAN([ac_cv_big_endian=1], [ac_cv_big_endian=0]) if test "x${ac_cv_big_endian}" = "x1" ; then AC_DEFINE_UNQUOTED([JEMALLOC_BIG_ENDIAN], [ ]) @@ -516,6 +579,7 @@ if test "x${je_cv_attribute}" = "xyes" ; then AC_DEFINE([JEMALLOC_HAVE_ATTR], [ ]) if test "x${GCC}" = "xyes" -a "x${abi}" = "xelf"; then JE_CFLAGS_APPEND([-fvisibility=hidden]) + JE_CXXFLAGS_APPEND([-fvisibility=hidden]) fi fi dnl Check for tls_model attribute support (clang 3.0 still lacks support). @@ -824,11 +888,14 @@ if test "x$enable_debug" = "x0" -a "x$no_CFLAGS" = "xyes" ; then if test "x${optimize}" = "xyes" ; then if test "x$GCC" = "xyes" ; then JE_CFLAGS_APPEND([-O3]) + JE_CXXFLAGS_APPEND([-O3]) JE_CFLAGS_APPEND([-funroll-loops]) elif test "x$je_cv_msvc" = "xyes" ; then JE_CFLAGS_APPEND([-O2]) + JE_CXXFLAGS_APPEND([-O2]) else JE_CFLAGS_APPEND([-O]) + JE_CXXFLAGS_APPEND([-O]) fi fi fi @@ -1943,8 +2010,12 @@ AC_MSG_RESULT([CC : ${CC}]) AC_MSG_RESULT([CFLAGS : ${CFLAGS}]) AC_MSG_RESULT([EXTRA_CFLAGS : ${EXTRA_CFLAGS}]) AC_MSG_RESULT([CPPFLAGS : ${CPPFLAGS}]) +AC_MSG_RESULT([CXX : ${CXX}]) +AC_MSG_RESULT([CXXFLAGS : ${CXXFLAGS}]) +AC_MSG_RESULT([EXTRA_CXXFLAGS : ${EXTRA_CXXFLAGS}]) AC_MSG_RESULT([LDFLAGS : ${LDFLAGS}]) AC_MSG_RESULT([EXTRA_LDFLAGS : ${EXTRA_LDFLAGS}]) +AC_MSG_RESULT([DSO_LDFLAGS : ${DSO_LDFLAGS}]) AC_MSG_RESULT([LIBS : ${LIBS}]) AC_MSG_RESULT([RPATH_EXTRA : ${RPATH_EXTRA}]) AC_MSG_RESULT([]) @@ -1985,4 +2056,5 @@ AC_MSG_RESULT([munmap : ${enable_munmap}]) AC_MSG_RESULT([lazy_lock : ${enable_lazy_lock}]) AC_MSG_RESULT([tls : ${enable_tls}]) AC_MSG_RESULT([cache-oblivious : ${enable_cache_oblivious}]) +AC_MSG_RESULT([cxx : ${enable_cxx}]) AC_MSG_RESULT([===============================================================================]) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 85b34012..ba5207d8 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -1,6 +1,10 @@ #ifndef JEMALLOC_INTERNAL_H #define JEMALLOC_INTERNAL_H +#ifdef __cplusplus +extern "C" { +#endif + #include "jemalloc_internal_defs.h" #include "jemalloc/internal/jemalloc_internal_decls.h" @@ -135,7 +139,7 @@ static const bool config_cache_oblivious = #endif ; -#ifdef JEMALLOC_C11ATOMICS +#if defined(JEMALLOC_C11ATOMICS) && !defined(__cplusplus) #include #endif @@ -888,7 +892,7 @@ arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing) ret = arenas[ind]; if (unlikely(ret == NULL)) { - ret = atomic_read_p((void *)&arenas[ind]); + ret = (arena_t *)atomic_read_p((void **)&arenas[ind]); if (init_if_missing && unlikely(ret == NULL)) ret = arena_init(tsdn, ind); } @@ -1194,4 +1198,9 @@ ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, #undef JEMALLOC_H_INLINES /******************************************************************************/ + +#ifdef __cplusplus +} +#endif + #endif /* JEMALLOC_INTERNAL_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_macros.h b/include/jemalloc/internal/jemalloc_internal_macros.h index a08ba772..57492049 100644 --- a/include/jemalloc/internal/jemalloc_internal_macros.h +++ b/include/jemalloc/internal/jemalloc_internal_macros.h @@ -52,6 +52,6 @@ # define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) #endif -#ifndef JEMALLOC_HAS_RESTRICT +#if !defined(JEMALLOC_HAS_RESTRICT) || defined(__cplusplus) # define restrict #endif diff --git a/include/jemalloc/internal/rtree.h b/include/jemalloc/internal/rtree.h index 9c6cc22f..b2a2800e 100644 --- a/include/jemalloc/internal/rtree.h +++ b/include/jemalloc/internal/rtree.h @@ -260,7 +260,7 @@ rtree_child_tryread(rtree_elm_t *elm, bool dependent) /* Double-checked read (first read may be stale). */ child = elm->child; if (!dependent && !rtree_node_valid(child)) - child = atomic_read_p(&elm->pun); + child = (rtree_elm_t *)atomic_read_p(&elm->pun); assert(!dependent || child != NULL); return (child); } @@ -320,8 +320,10 @@ rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent) /* Double-checked read (first read may be stale). */ subtree = rtree->levels[level].subtree; - if (!dependent && unlikely(!rtree_node_valid(subtree))) - subtree = atomic_read_p(&rtree->levels[level].subtree_pun); + if (!dependent && unlikely(!rtree_node_valid(subtree))) { + subtree = (rtree_elm_t *)atomic_read_p( + &rtree->levels[level].subtree_pun); + } assert(!dependent || subtree != NULL); return (subtree); } diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4 new file mode 100644 index 00000000..2c18e49c --- /dev/null +++ b/m4/ax_cxx_compile_stdcxx.m4 @@ -0,0 +1,562 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the specified +# version of the C++ standard. If necessary, add switches to CXX and +# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) +# or '14' (for the C++14 standard). +# +# The second argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The third argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline support for the specified C++ standard is +# required and that the macro should error out if no mode with that +# support is found. If specified 'optional', then configuration proceeds +# regardless, after defining HAVE_CXX${VERSION} if and only if a +# supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik +# Copyright (c) 2012 Zack Weinberg +# Copyright (c) 2013 Roy Stogner +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov +# Copyright (c) 2015 Paul Norman +# Copyright (c) 2015 Moritz Klammler +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 4 + +dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro +dnl (serial version number 13). + +AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl + m4_if([$1], [11], [], + [$1], [14], [], + [$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])], + [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$2], [], [], + [$2], [ext], [], + [$2], [noext], [], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl + m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], + [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], + [$3], [optional], [ax_cxx_compile_cxx$1_required=false], + [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, + ax_cv_cxx_compile_cxx$1, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [ax_cv_cxx_compile_cxx$1=yes], + [ax_cv_cxx_compile_cxx$1=no])]) + if test x$ax_cv_cxx_compile_cxx$1 = xyes; then + ac_success=yes + fi + + m4_if([$2], [noext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=gnu++$1 -std=gnu++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + fi]) + + m4_if([$2], [ext], [], [dnl + if test x$ac_success = xno; then + dnl HP's aCC needs +std=c++11 according to: + dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf + dnl Cray's crayCC needs "-h std=c++11" + for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, + $cachevar, + [ac_save_CXX="$CXX" + CXX="$CXX $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXX="$ac_save_CXX"]) + if eval test x\$$cachevar = xyes; then + CXX="$CXX $switch" + if test -n "$CXXCPP" ; then + CXXCPP="$CXXCPP $switch" + fi + ac_success=yes + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx$1_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) + fi + fi + if test x$ac_success = xno; then + HAVE_CXX$1=0 + AC_MSG_NOTICE([No compiler with C++$1 support was found]) + else + HAVE_CXX$1=1 + AC_DEFINE(HAVE_CXX$1,1, + [define if the compiler supports basic C++$1 syntax]) + fi + AC_SUBST(HAVE_CXX$1) +]) + + +dnl Test body for checking C++11 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 +) + + +dnl Test body for checking C++14 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 +) + + +dnl Tests for new features in C++11 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ + +// If the compiler admits that it is not ready for C++11, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201103L + +#error "This is not a C++11 compiler" + +#else + +namespace cxx11 +{ + + namespace test_static_assert + { + + template + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + } + + namespace test_final_override + { + + struct Base + { + virtual void f() {} + }; + + struct Derived : public Base + { + virtual void f() override {} + }; + + } + + namespace test_double_right_angle_brackets + { + + template < typename T > + struct check {}; + + typedef check single_type; + typedef check> double_type; + typedef check>> triple_type; + typedef check>>> quadruple_type; + + } + + namespace test_decltype + { + + int + f() + { + int a = 1; + decltype(a) b = 2; + return a + b; + } + + } + + namespace test_type_deduction + { + + template < typename T1, typename T2 > + struct is_same + { + static const bool value = false; + }; + + template < typename T > + struct is_same + { + static const bool value = true; + }; + + template < typename T1, typename T2 > + auto + add(T1 a1, T2 a2) -> decltype(a1 + a2) + { + return a1 + a2; + } + + int + test(const int c, volatile int v) + { + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == false, ""); + auto ac = c; + auto av = v; + auto sumi = ac + av + 'x'; + auto sumf = ac + av + 1.0; + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == true, ""); + static_assert(is_same::value == false, ""); + static_assert(is_same::value == true, ""); + return (sumf > 0.0) ? sumi : add(c, v); + } + + } + + namespace test_noexcept + { + + int f() { return 0; } + int g() noexcept { return 0; } + + static_assert(noexcept(f()) == false, ""); + static_assert(noexcept(g()) == true, ""); + + } + + namespace test_constexpr + { + + template < typename CharT > + unsigned long constexpr + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept + { + return *s ? strlen_c_r(s + 1, acc + 1) : acc; + } + + template < typename CharT > + unsigned long constexpr + strlen_c(const CharT *const s) noexcept + { + return strlen_c_r(s, 0UL); + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("1") == 1UL, ""); + static_assert(strlen_c("example") == 7UL, ""); + static_assert(strlen_c("another\0example") == 7UL, ""); + + } + + namespace test_rvalue_references + { + + template < int N > + struct answer + { + static constexpr int value = N; + }; + + answer<1> f(int&) { return answer<1>(); } + answer<2> f(const int&) { return answer<2>(); } + answer<3> f(int&&) { return answer<3>(); } + + void + test() + { + int i = 0; + const int c = 0; + static_assert(decltype(f(i))::value == 1, ""); + static_assert(decltype(f(c))::value == 2, ""); + static_assert(decltype(f(0))::value == 3, ""); + } + + } + + namespace test_uniform_initialization + { + + struct test + { + static const int zero {}; + static const int one {1}; + }; + + static_assert(test::zero == 0, ""); + static_assert(test::one == 1, ""); + + } + + namespace test_lambdas + { + + void + test1() + { + auto lambda1 = [](){}; + auto lambda2 = lambda1; + lambda1(); + lambda2(); + } + + int + test2() + { + auto a = [](int i, int j){ return i + j; }(1, 2); + auto b = []() -> int { return '0'; }(); + auto c = [=](){ return a + b; }(); + auto d = [&](){ return c; }(); + auto e = [a, &b](int x) mutable { + const auto identity = [](int y){ return y; }; + for (auto i = 0; i < a; ++i) + a += b--; + return x + identity(a + b); + }(0); + return a + b + c + d + e; + } + + int + test3() + { + const auto nullary = [](){ return 0; }; + const auto unary = [](int x){ return x; }; + using nullary_t = decltype(nullary); + using unary_t = decltype(unary); + const auto higher1st = [](nullary_t f){ return f(); }; + const auto higher2nd = [unary](nullary_t f1){ + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; + }; + return higher1st(nullary) + higher2nd(nullary)(unary); + } + + } + + namespace test_variadic_templates + { + + template + struct sum; + + template + struct sum + { + static constexpr auto value = N0 + sum::value; + }; + + template <> + struct sum<> + { + static constexpr auto value = 0; + }; + + static_assert(sum<>::value == 0, ""); + static_assert(sum<1>::value == 1, ""); + static_assert(sum<23>::value == 23, ""); + static_assert(sum<1, 2>::value == 3, ""); + static_assert(sum<5, 5, 11>::value == 21, ""); + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); + + } + + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function + // because of this. + namespace test_template_alias_sfinae + { + + struct foo {}; + + template + using member = typename T::member_type; + + template + void func(...) {} + + template + void func(member*) {} + + void test(); + + void test() { func(0); } + + } + +} // namespace cxx11 + +#endif // __cplusplus >= 201103L + +]]) + + +dnl Tests for new features in C++14 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ + +// If the compiler admits that it is not ready for C++14, why torture it? +// Hopefully, this will speed up the test. + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif __cplusplus < 201402L + +#error "This is not a C++14 compiler" + +#else + +namespace cxx14 +{ + + namespace test_polymorphic_lambdas + { + + int + test() + { + const auto lambda = [](auto&&... args){ + const auto istiny = [](auto x){ + return (sizeof(x) == 1UL) ? 1 : 0; + }; + const int aretiny[] = { istiny(args)... }; + return aretiny[0]; + }; + return lambda(1, 1L, 1.0f, '1'); + } + + } + + namespace test_binary_literals + { + + constexpr auto ivii = 0b0000000000101010; + static_assert(ivii == 42, "wrong value"); + + } + + namespace test_generalized_constexpr + { + + template < typename CharT > + constexpr unsigned long + strlen_c(const CharT *const s) noexcept + { + auto length = 0UL; + for (auto p = s; *p; ++p) + ++length; + return length; + } + + static_assert(strlen_c("") == 0UL, ""); + static_assert(strlen_c("x") == 1UL, ""); + static_assert(strlen_c("test") == 4UL, ""); + static_assert(strlen_c("another\0test") == 7UL, ""); + + } + + namespace test_lambda_init_capture + { + + int + test() + { + auto x = 0; + const auto lambda1 = [a = x](int b){ return a + b; }; + const auto lambda2 = [a = lambda1(x)](){ return a; }; + return lambda2(); + } + + } + + namespace test_digit_seperators + { + + constexpr auto ten_million = 100'000'000; + static_assert(ten_million == 100000000, ""); + + } + + namespace test_return_type_deduction + { + + auto f(int& x) { return x; } + decltype(auto) g(int& x) { return x; } + + template < typename T1, typename T2 > + struct is_same + { + static constexpr auto value = false; + }; + + template < typename T > + struct is_same + { + static constexpr auto value = true; + }; + + int + test() + { + auto x = 0; + static_assert(is_same::value, ""); + static_assert(is_same::value, ""); + return x; + } + + } + +} // namespace cxx14 + +#endif // __cplusplus >= 201402L + +]]) diff --git a/src/jemalloc_cpp.cpp b/src/jemalloc_cpp.cpp new file mode 100644 index 00000000..4c5756b3 --- /dev/null +++ b/src/jemalloc_cpp.cpp @@ -0,0 +1,140 @@ +#include +#include + +#define JEMALLOC_CPP_CPP_ +#include "jemalloc/internal/jemalloc_internal.h" + +// All operators in this file are exported. + +// Possibly alias hidden versions of malloc and sdallocx to avoid an extra plt +// thunk? +// +// extern __typeof (sdallocx) sdallocx_int +// __attribute ((alias ("sdallocx"), +// visibility ("hidden"))); +// +// ... but it needs to work with jemalloc namespaces. + +void *operator new(std::size_t size); +void *operator new[](std::size_t size); +void *operator new(std::size_t size, const std::nothrow_t&) noexcept; +void *operator new[](std::size_t size, const std::nothrow_t&) noexcept; +void operator delete(void* ptr) noexcept; +void operator delete[](void* ptr) noexcept; +void operator delete(void* ptr, const std::nothrow_t&) noexcept; +void operator delete[](void* ptr, const std::nothrow_t&) noexcept; + +#if __cpp_sized_deallocation >= 201309 +/* C++14's sized-delete operators. */ +void operator delete(void* ptr, std::size_t size) noexcept; +void operator delete[](void* ptr, std::size_t size) noexcept; +#endif + + +template +JEMALLOC_INLINE +void * +newImpl(std::size_t size) noexcept(IsNoExcept) +{ + void* ptr = je_malloc(size); + if (likely(ptr != nullptr)) + return (ptr); + + while (ptr == nullptr) { + std::new_handler handler; + // GCC-4.8 and clang 4.0 do not have std::get_new_handler. + { + static std::mutex mtx; + std::lock_guard lock(mtx); + + handler = std::set_new_handler(nullptr); + std::set_new_handler(handler); + } + if (handler == nullptr) + break; + + try { + handler(); + } catch (const std::bad_alloc&) { + break; + } + + ptr = je_malloc(size); + } + + if (ptr == nullptr && !IsNoExcept) + std::__throw_bad_alloc(); + return (ptr); +} + +void * +operator new(std::size_t size) +{ + + return (newImpl(size)); +} + +void * +operator new[](std::size_t size) +{ + + return (newImpl(size)); +} + +void * +operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + + return (newImpl(size)); +} + +void * +operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + + return (newImpl(size)); +} + +void +operator delete(void* ptr) noexcept +{ + + je_free(ptr); +} + +void +operator delete[](void* ptr) noexcept +{ + + je_free(ptr); +} + +void +operator delete(void* ptr, const std::nothrow_t&) noexcept +{ + + je_free(ptr); +} + +void operator delete[](void* ptr, const std::nothrow_t&) noexcept +{ + + je_free(ptr); +} + +#if __cpp_sized_deallocation >= 201309 + +void +operator delete(void* ptr, std::size_t size) noexcept +{ + + je_sdallocx(ptr, size, /*flags=*/0); +} + +void operator delete[](void* ptr, std::size_t size) noexcept +{ + + je_sdallocx(ptr, size, /*flags=*/0); +} + +#endif // __cpp_sized_deallocation diff --git a/test/include/test/jemalloc_test.h.in b/test/include/test/jemalloc_test.h.in index 1f36e469..66485c0e 100644 --- a/test/include/test/jemalloc_test.h.in +++ b/test/include/test/jemalloc_test.h.in @@ -1,3 +1,7 @@ +#ifdef __cplusplus +extern "C" { +#endif + #include #ifndef SIZE_T_MAX # define SIZE_T_MAX SIZE_MAX @@ -47,7 +51,8 @@ * expose the minimum necessary internal utility code (to avoid re-implementing * essentially identical code within the test infrastructure). */ -#elif defined(JEMALLOC_INTEGRATION_TEST) +#elif defined(JEMALLOC_INTEGRATION_TEST) || \ + defined(JEMALLOC_INTEGRATION_CPP_TEST) # define JEMALLOC_MANGLE # include "jemalloc/jemalloc@install_suffix@.h" # include "jemalloc/internal/jemalloc_internal_defs.h" @@ -161,3 +166,7 @@ static const bool config_debug = if (!(e)) \ not_implemented(); \ } while (0) + +#ifdef __cplusplus +} +#endif diff --git a/test/include/test/test.h b/test/include/test/test.h index c8112eb8..8c69fc2e 100644 --- a/test/include/test/test.h +++ b/test/include/test/test.h @@ -8,8 +8,8 @@ char message[ASSERT_BUFSIZE]; \ malloc_snprintf(prefix, sizeof(prefix), \ "%s:%s:%d: Failed assertion: " \ - "(%s) "#cmp" (%s) --> " \ - "%"pri" "#neg_cmp" %"pri": ", \ + "(%s) " #cmp " (%s) --> " \ + "%" pri " " #neg_cmp " %" pri ": ", \ __func__, __FILE__, __LINE__, \ #a, #b, a_, b_); \ malloc_snprintf(message, sizeof(message), __VA_ARGS__); \ diff --git a/test/integration/cpp/basic.cpp b/test/integration/cpp/basic.cpp new file mode 100644 index 00000000..eeb93c47 --- /dev/null +++ b/test/integration/cpp/basic.cpp @@ -0,0 +1,18 @@ +#include +#include "test/jemalloc_test.h" + +TEST_BEGIN(test_basic) +{ + auto foo = new long(4); + assert_ptr_not_null(foo, "Unexpected new[] failure"); + delete foo; +} +TEST_END + +int +main() +{ + + return (test( + test_basic)); +} -- GitLab From 69c26cdb01d9d42c3317ca0bdf8632e351d805e4 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 13 Dec 2016 13:38:11 -0800 Subject: [PATCH 199/544] Add some missing explicit casts. --- include/jemalloc/internal/tsd.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h index b33de703..c4f010ae 100644 --- a/include/jemalloc/internal/tsd.h +++ b/include/jemalloc/internal/tsd.h @@ -482,13 +482,14 @@ a_name##tsd_wrapper_get(bool init) \ \ if (init && unlikely(wrapper == NULL)) { \ tsd_init_block_t block; \ - wrapper = tsd_init_check_recursion( \ - &a_name##tsd_init_head, &block); \ + wrapper = (a_name##tsd_wrapper_t *) \ + tsd_init_check_recursion(&a_name##tsd_init_head, \ + &block); \ if (wrapper) \ return (wrapper); \ wrapper = (a_name##tsd_wrapper_t *) \ malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ - block.data = wrapper; \ + block.data = (void *)wrapper; \ if (wrapper == NULL) { \ malloc_write(": Error allocating" \ " TSD for "#a_name"\n"); \ -- GitLab From 590ee2a6e0fcb3de63809473f0da8c9aff627e1e Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 13 Dec 2016 14:53:10 -0800 Subject: [PATCH 200/544] Update Travis-CI config for C++ integration. --- .travis.yml | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1fed4f8e..bda54773 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,27 +1,24 @@ -language: c +language: generic matrix: include: - os: linux - compiler: gcc + env: CC=gcc CXX=g++ + env: CC=clang CXX=clang++ - os: linux - compiler: gcc - env: - - EXTRA_FLAGS=-m32 + env: CC=gcc CXX=g++ EXTRA_FLAGS=-m32 + env: CC=clang CXX=clang++ EXTRA_FLAGS=-m32 addons: apt: packages: - gcc-multilib - os: osx - compiler: clang - - os: osx - compiler: clang - env: - - EXTRA_FLAGS=-m32 + env: CC=clang CXX=clang++ + env: CC=clang CXX=clang++ EXTRA_FLAGS=-m32 before_script: - autoconf - - ./configure${EXTRA_FLAGS:+ CC="$CC $EXTRA_FLAGS"} + - ./configure${EXTRA_FLAGS:+ CC="$CC $EXTRA_FLAGS" CXX="$CXX $EXTRA_FLAGS"} - make -j3 - make -j3 tests -- GitLab From a965a9cb12ac9d01cb0ff114e486c63585b72999 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 13 Dec 2016 16:19:20 -0800 Subject: [PATCH 201/544] Re-expand the Travis-CI build matrix. --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index bda54773..97641eca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,15 @@ matrix: include: - os: linux env: CC=gcc CXX=g++ + - os: linux env: CC=clang CXX=clang++ - os: linux env: CC=gcc CXX=g++ EXTRA_FLAGS=-m32 + addons: + apt: + packages: + - gcc-multilib + - os: linux env: CC=clang CXX=clang++ EXTRA_FLAGS=-m32 addons: apt: @@ -14,6 +20,7 @@ matrix: - gcc-multilib - os: osx env: CC=clang CXX=clang++ + - os: osx env: CC=clang CXX=clang++ EXTRA_FLAGS=-m32 before_script: -- GitLab From 194d6f9de8ff92841b67f38a2a6a06818e3240dd Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 16 Dec 2016 07:18:55 -0800 Subject: [PATCH 202/544] Restructure *CFLAGS/*CXXFLAGS configuration. Convert CFLAGS/CXXFLAGS to be concatenations: CFLAGS := CONFIGURE_CFLAGS SPECIFIED_CFLAGS EXTRA_CFLAGS CXXFLAGS := CONFIGURE_CXXFLAGS SPECIFIED_CXXFLAGS EXTRA_CXXFLAGS This ordering makes it possible to override the flags set by the configure script both during and after configuration, with CFLAGS/CXXFLAGS and EXTRA_CFLAGS/EXTRA_CXXFLAGS, respectively. This resolves #504. --- INSTALL | 19 ++-- Makefile.in | 8 +- configure.ac | 274 ++++++++++++++++++++++++++++----------------------- 3 files changed, 168 insertions(+), 133 deletions(-) diff --git a/INSTALL b/INSTALL index c7ca5a73..6e593219 100644 --- a/INSTALL +++ b/INSTALL @@ -307,17 +307,18 @@ The following environment variables (not a definitive list) impact configure's behavior: CFLAGS="?" - Pass these flags to the compiler. You probably shouldn't define this unless - you know what you are doing. (Use EXTRA_CFLAGS instead.) +CXXFLAGS="?" + Pass these flags to the C/C++ compiler. Any flags set by the configure + script are prepended, which means explicitly set flags generally take + precedence. Take care when specifying flags such as -Werror, because + configure tests may be affected in undesirable ways. EXTRA_CFLAGS="?" - Append these flags to CFLAGS. This makes it possible to add flags such as - -Werror, while allowing the configure script to determine what other flags - are appropriate for the specified configuration. - - The configure script specifically checks whether an optimization flag (-O*) - is specified in EXTRA_CFLAGS, and refrains from specifying an optimization - level if it finds that one has already been specified. +EXTRA_CXXFLAGS="?" + Append these flags to CFLAGS/CXXFLAGS, without passing them to the + compiler(s) during configuration. This makes it possible to add flags such + as -Werror, while allowing the configure script to determine what other + flags are appropriate for the specified configuration. CPPFLAGS="?" Pass these flags to the C preprocessor. Note that CFLAGS is not passed to diff --git a/Makefile.in b/Makefile.in index 22d9d86f..7c1989b8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -25,10 +25,14 @@ abs_objroot := @abs_objroot@ # Build parameters. CPPFLAGS := @CPPFLAGS@ -I$(srcroot)include -I$(objroot)include +CONFIGURE_CFLAGS := @CONFIGURE_CFLAGS@ +SPECIFIED_CFLAGS := @SPECIFIED_CFLAGS@ EXTRA_CFLAGS := @EXTRA_CFLAGS@ -CFLAGS := @CFLAGS@ $(EXTRA_CFLAGS) +CFLAGS := $(strip $(CONFIGURE_CFLAGS) $(SPECIFIED_CFLAGS) $(EXTRA_CFLAGS)) +CONFIGURE_CXXFLAGS := @CONFIGURE_CXXFLAGS@ +SPECIFIED_CXXFLAGS := @SPECIFIED_CXXFLAGS@ EXTRA_CXXFLAGS := @EXTRA_CXXFLAGS@ -CXXFLAGS := @CXXFLAGS@ $(EXTRA_CXXFLAGS) +CXXFLAGS := $(strip $(CONFIGURE_CXXFLAGS) $(SPECIFIED_CXXFLAGS) $(EXTRA_CXXFLAGS)) LDFLAGS := @LDFLAGS@ EXTRA_LDFLAGS := @EXTRA_LDFLAGS@ LIBS := @LIBS@ diff --git a/configure.ac b/configure.ac index f85b2693..bf4ea8f7 100644 --- a/configure.ac +++ b/configure.ac @@ -6,50 +6,87 @@ AC_CONFIG_AUX_DIR([build-aux]) dnl ============================================================================ dnl Custom macro definitions. -dnl JE_CFLAGS_APPEND(cflag) -AC_DEFUN([JE_CFLAGS_APPEND], -[ -AC_MSG_CHECKING([whether compiler supports $1]) -TCFLAGS="${CFLAGS}" -if test "x${CFLAGS}" = "x" ; then - CFLAGS="$1" +dnl JE_CONCAT_VVV(r, a, b) +dnl +dnl Set $r to the concatenation of $a and $b, with a space separating them iff +dnl both $a and $b are non-emty. +AC_DEFUN([JE_CONCAT_VVV], +if test "x[$]{$2}" = "x" -o "x[$]{$3}" = "x" ; then + $1="[$]{$2}[$]{$3}" else - CFLAGS="${CFLAGS} $1" + $1="[$]{$2} [$]{$3}" fi +) + +dnl JE_APPEND_VS(a, b) +dnl +dnl Set $a to the concatenation of $a and b, with a space separating them iff +dnl both $a and b are non-empty. +AC_DEFUN([JE_APPEND_VS], + T_APPEND_V=$2 + JE_CONCAT_VVV($1, $1, T_APPEND_V) +) + +CONFIGURE_CFLAGS= +SPECIFIED_CFLAGS="${CFLAGS}" +dnl JE_CFLAGS_ADD(cflag) +dnl +dnl CFLAGS is the concatenation of CONFIGURE_CFLAGS and SPECIFIED_CFLAGS +dnl (ignoring EXTRA_CFLAGS, which does not impact configure tests. This macro +dnl appends to CONFIGURE_CFLAGS and regenerates CFLAGS. +AC_DEFUN([JE_CFLAGS_ADD], +[ +AC_MSG_CHECKING([whether compiler supports $1]) +T_CONFIGURE_CFLAGS="${CONFIGURE_CFLAGS}" +JE_APPEND_VS(CONFIGURE_CFLAGS, $1) +JE_CONCAT_VVV(CFLAGS, CONFIGURE_CFLAGS, SPECIFIED_CFLAGS) AC_COMPILE_IFELSE([AC_LANG_PROGRAM( [[ ]], [[ return 0; ]])], - [je_cv_cflags_appended=$1] + [je_cv_cflags_added=$1] AC_MSG_RESULT([yes]), - [je_cv_cflags_appended=] + [je_cv_cflags_added=] AC_MSG_RESULT([no]) - [CFLAGS="${TCFLAGS}"] + [CONFIGURE_CFLAGS="${T_CONFIGURE_CFLAGS}"] ) +JE_CONCAT_VVV(CFLAGS, CONFIGURE_CFLAGS, SPECIFIED_CFLAGS) ]) -dnl JE_CXXFLAGS_APPEND(cflag) -AC_DEFUN([JE_CXXFLAGS_APPEND], +dnl JE_CFLAGS_SAVE() +dnl JE_CFLAGS_RESTORE() +dnl +dnl Save/restore CFLAGS. Nesting is not supported. +AC_DEFUN([JE_CFLAGS_SAVE], +SAVED_CONFIGURE_CFLAGS="${CONFIGURE_CFLAGS}" +) +AC_DEFUN([JE_CFLAGS_RESTORE], +CONFIGURE_CFLAGS="${SAVED_CONFIGURE_CFLAGS}" +JE_CONCAT_VVV(CFLAGS, CONFIGURE_CFLAGS, SPECIFIED_CFLAGS) +) + +CONFIGURE_CXXFLAGS= +SPECIFIED_CXXFLAGS="${CXXFLAGS}" +dnl JE_CXXFLAGS_ADD(cxxflag) +AC_DEFUN([JE_CXXFLAGS_ADD], [ AC_MSG_CHECKING([whether compiler supports $1]) -TCXXFLAGS="${CXXFLAGS}" -if test "x${CXXFLAGS}" = "x" ; then - CXXFLAGS="$1" -else - CXXFLAGS="${CXXFLAGS} $1" -fi +T_CONFIGURE_CXXFLAGS="${CONFIGURE_CXXFLAGS}" +JE_APPEND_VS(CONFIGURE_CXXFLAGS, $1) +JE_CONCAT_VVV(CXXFLAGS, CONFIGURE_CXXFLAGS, SPECIFIED_CXXFLAGS) AC_COMPILE_IFELSE([AC_LANG_PROGRAM( [[ ]], [[ return 0; ]])], - [je_cv_cflags_appended=$1] + [je_cv_cxxflags_added=$1] AC_MSG_RESULT([yes]), - [je_cv_cflags_appended=] + [je_cv_cxxflags_added=] AC_MSG_RESULT([no]) - [CXXFLAGS="${TCXXFLAGS}"] + [CONFIGURE_CXXFLAGS="${T_CONFIGURE_CXXFLAGS}"] ) +JE_CONCAT_VVV(CXXFLAGS, CONFIGURE_CXXFLAGS, SPECIFIED_CXXFLAGS) ]) dnl JE_COMPILABLE(label, hcode, mcode, rvar) @@ -191,46 +228,45 @@ if test "x${je_cv_cray}" = "xyes" ; then [je_cv_cray_84=no])]) fi -if test "x$CFLAGS" = "x" ; then - no_CFLAGS="yes" - if test "x$GCC" = "xyes" ; then - JE_CFLAGS_APPEND([-std=gnu11]) - if test "x$je_cv_cflags_appended" = "x-std=gnu11" ; then +if test "x$GCC" = "xyes" ; then + JE_CFLAGS_ADD([-std=gnu11]) + if test "x$je_cv_cflags_added" = "x-std=gnu11" ; then + AC_DEFINE_UNQUOTED([JEMALLOC_HAS_RESTRICT]) + else + JE_CFLAGS_ADD([-std=gnu99]) + if test "x$je_cv_cflags_added" = "x-std=gnu99" ; then AC_DEFINE_UNQUOTED([JEMALLOC_HAS_RESTRICT]) - else - JE_CFLAGS_APPEND([-std=gnu99]) - if test "x$je_cv_cflags_appended" = "x-std=gnu99" ; then - AC_DEFINE_UNQUOTED([JEMALLOC_HAS_RESTRICT]) - fi fi - JE_CFLAGS_APPEND([-Wall]) - JE_CFLAGS_APPEND([-Werror=declaration-after-statement]) - JE_CFLAGS_APPEND([-Wshorten-64-to-32]) - JE_CFLAGS_APPEND([-Wsign-compare]) - JE_CFLAGS_APPEND([-pipe]) - JE_CFLAGS_APPEND([-g3]) - elif test "x$je_cv_msvc" = "xyes" ; then - CC="$CC -nologo" - JE_CFLAGS_APPEND([-Zi]) - JE_CFLAGS_APPEND([-MT]) - JE_CFLAGS_APPEND([-W3]) - JE_CFLAGS_APPEND([-FS]) - CPPFLAGS="$CPPFLAGS -I${srcdir}/include/msvc_compat" fi - if test "x$je_cv_cray" = "xyes" ; then - dnl cray compiler 8.4 has an inlining bug - if test "x$je_cv_cray_84" = "xyes" ; then - JE_CFLAGS_APPEND([-hipa2]) - JE_CFLAGS_APPEND([-hnognu]) - fi - if test "x$enable_cc_silence" != "xno" ; then - dnl ignore unreachable code warning - JE_CFLAGS_APPEND([-hnomessage=128]) - dnl ignore redefinition of "malloc", "free", etc warning - JE_CFLAGS_APPEND([-hnomessage=1357]) - fi + JE_CFLAGS_ADD([-Wall]) + JE_CFLAGS_ADD([-Werror=declaration-after-statement]) + JE_CFLAGS_ADD([-Wshorten-64-to-32]) + JE_CFLAGS_ADD([-Wsign-compare]) + JE_CFLAGS_ADD([-pipe]) + JE_CFLAGS_ADD([-g3]) +elif test "x$je_cv_msvc" = "xyes" ; then + CC="$CC -nologo" + JE_CFLAGS_ADD([-Zi]) + JE_CFLAGS_ADD([-MT]) + JE_CFLAGS_ADD([-W3]) + JE_CFLAGS_ADD([-FS]) + JE_APPEND_VS(CPPFLAGS, -I${srcdir}/include/msvc_compat) +fi +if test "x$je_cv_cray" = "xyes" ; then + dnl cray compiler 8.4 has an inlining bug + if test "x$je_cv_cray_84" = "xyes" ; then + JE_CFLAGS_ADD([-hipa2]) + JE_CFLAGS_ADD([-hnognu]) + fi + if test "x$enable_cc_silence" != "xno" ; then + dnl ignore unreachable code warning + JE_CFLAGS_ADD([-hnomessage=128]) + dnl ignore redefinition of "malloc", "free", etc warning + JE_CFLAGS_ADD([-hnomessage=1357]) fi fi +AC_SUBST([CONFIGURE_CFLAGS]) +AC_SUBST([SPECIFIED_CFLAGS]) AC_SUBST([EXTRA_CFLAGS]) AC_PROG_CPP @@ -245,17 +281,16 @@ fi enable_cxx="1" ) if test "x$enable_cxx" = "x1" ; then - CXXFLAGS="" dnl Require at least c++14, which is the first version to support sized dnl deallocation. C++ support is not compiled otherwise. m4_include([m4/ax_cxx_compile_stdcxx.m4]) AX_CXX_COMPILE_STDCXX([14], [noext], [optional]) if test "x${HAVE_CXX14}" = "x1" ; then - JE_CXXFLAGS_APPEND([-Wall]) - JE_CXXFLAGS_APPEND([-g3]) + JE_CXXFLAGS_ADD([-Wall]) + JE_CXXFLAGS_ADD([-g3]) SAVED_LIBS="${LIBS}" - LIBS="${LIBS} -lstdc++" + JE_APPEND_VS(LIBS, -lstdc++) JE_COMPILABLE([libstdc++ linkage], [ #include ], [[ @@ -271,7 +306,8 @@ if test "x$enable_cxx" = "x1" ; then fi fi AC_SUBST([enable_cxx]) -AC_SUBST([CXXFLAGS]) +AC_SUBST([CONFIGURE_CXXFLAGS]) +AC_SUBST([SPECIFIED_CXXFLAGS]) AC_SUBST([EXTRA_CXXFLAGS]) AC_C_BIGENDIAN([ac_cv_big_endian=1], [ac_cv_big_endian=0]) @@ -280,7 +316,7 @@ if test "x${ac_cv_big_endian}" = "x1" ; then fi if test "x${je_cv_msvc}" = "xyes" -a "x${ac_cv_header_inttypes_h}" = "xno"; then - CPPFLAGS="$CPPFLAGS -I${srcdir}/include/msvc_compat/C99" + JE_APPEND_VS(CPPFLAGS, -I${srcdir}/include/msvc_compat/C99) fi if test "x${je_cv_msvc}" = "xyes" ; then @@ -411,7 +447,6 @@ dnl dnl Define cpp macros in CPPFLAGS, rather than doing AC_DEFINE(macro), since the dnl definitions need to be seen before any headers are included, which is a pain dnl to make happen otherwise. -CFLAGS="$CFLAGS" default_munmap="1" maps_coalesce="1" case "${host}" in @@ -443,7 +478,7 @@ case "${host}" in ;; *-*-linux-android) dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. - CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" + JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE) abi="elf" AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) @@ -454,7 +489,7 @@ case "${host}" in ;; *-*-linux* | *-*-kfreebsd*) dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. - CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" + JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE) abi="elf" AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) @@ -479,8 +514,8 @@ case "${host}" in abi="elf" RPATH='-Wl,-R,$(1)' dnl Solaris needs this for sigwait(). - CPPFLAGS="$CPPFLAGS -D_POSIX_PTHREAD_SEMANTICS" - LIBS="$LIBS -lposix4 -lsocket -lnsl" + JE_APPEND_VS(CPPFLAGS, -D_POSIX_PTHREAD_SEMANTICS) + JE_APPEND_VS(LIBS, -lposix4 -lsocket -lnsl) ;; *-ibm-aix*) if "$LG_SIZEOF_PTR" = "8"; then @@ -578,20 +613,20 @@ JE_COMPILABLE([__attribute__ syntax], if test "x${je_cv_attribute}" = "xyes" ; then AC_DEFINE([JEMALLOC_HAVE_ATTR], [ ]) if test "x${GCC}" = "xyes" -a "x${abi}" = "xelf"; then - JE_CFLAGS_APPEND([-fvisibility=hidden]) - JE_CXXFLAGS_APPEND([-fvisibility=hidden]) + JE_CFLAGS_ADD([-fvisibility=hidden]) + JE_CXXFLAGS_ADD([-fvisibility=hidden]) fi fi dnl Check for tls_model attribute support (clang 3.0 still lacks support). -SAVED_CFLAGS="${CFLAGS}" -JE_CFLAGS_APPEND([-Werror]) -JE_CFLAGS_APPEND([-herror_on_warning]) +JE_CFLAGS_SAVE() +JE_CFLAGS_ADD([-Werror]) +JE_CFLAGS_ADD([-herror_on_warning]) JE_COMPILABLE([tls_model attribute], [], [static __thread int __attribute__((tls_model("initial-exec"), unused)) foo; foo = 0;], [je_cv_tls_model]) -CFLAGS="${SAVED_CFLAGS}" +JE_CFLAGS_RESTORE() if test "x${je_cv_tls_model}" = "xyes" ; then AC_DEFINE([JEMALLOC_TLS_MODEL], [__attribute__((tls_model("initial-exec")))]) @@ -599,35 +634,35 @@ else AC_DEFINE([JEMALLOC_TLS_MODEL], [ ]) fi dnl Check for alloc_size attribute support. -SAVED_CFLAGS="${CFLAGS}" -JE_CFLAGS_APPEND([-Werror]) -JE_CFLAGS_APPEND([-herror_on_warning]) +JE_CFLAGS_SAVE() +JE_CFLAGS_ADD([-Werror]) +JE_CFLAGS_ADD([-herror_on_warning]) JE_COMPILABLE([alloc_size attribute], [#include ], [void *foo(size_t size) __attribute__((alloc_size(1)));], [je_cv_alloc_size]) -CFLAGS="${SAVED_CFLAGS}" +JE_CFLAGS_RESTORE() if test "x${je_cv_alloc_size}" = "xyes" ; then AC_DEFINE([JEMALLOC_HAVE_ATTR_ALLOC_SIZE], [ ]) fi dnl Check for format(gnu_printf, ...) attribute support. -SAVED_CFLAGS="${CFLAGS}" -JE_CFLAGS_APPEND([-Werror]) -JE_CFLAGS_APPEND([-herror_on_warning]) +JE_CFLAGS_SAVE() +JE_CFLAGS_ADD([-Werror]) +JE_CFLAGS_ADD([-herror_on_warning]) JE_COMPILABLE([format(gnu_printf, ...) attribute], [#include ], [void *foo(const char *format, ...) __attribute__((format(gnu_printf, 1, 2)));], [je_cv_format_gnu_printf]) -CFLAGS="${SAVED_CFLAGS}" +JE_CFLAGS_RESTORE() if test "x${je_cv_format_gnu_printf}" = "xyes" ; then AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF], [ ]) fi dnl Check for format(printf, ...) attribute support. -SAVED_CFLAGS="${CFLAGS}" -JE_CFLAGS_APPEND([-Werror]) -JE_CFLAGS_APPEND([-herror_on_warning]) +JE_CFLAGS_SAVE() +JE_CFLAGS_ADD([-Werror]) +JE_CFLAGS_ADD([-herror_on_warning]) JE_COMPILABLE([format(printf, ...) attribute], [#include ], [void *foo(const char *format, ...) __attribute__((format(printf, 1, 2)));], [je_cv_format_printf]) -CFLAGS="${SAVED_CFLAGS}" +JE_CFLAGS_RESTORE() if test "x${je_cv_format_printf}" = "xyes" ; then AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_PRINTF], [ ]) fi @@ -689,9 +724,9 @@ if test "x$enable_code_coverage" = "x1" ; then deoptimize="no" echo "$CFLAGS $EXTRA_CFLAGS" | grep '\-O' >/dev/null || deoptimize="yes" if test "x${deoptimize}" = "xyes" ; then - JE_CFLAGS_APPEND([-O0]) + JE_CFLAGS_ADD([-O0]) fi - JE_CFLAGS_APPEND([-fprofile-arcs -ftest-coverage]) + JE_CFLAGS_ADD([-fprofile-arcs -ftest-coverage]) EXTRA_LDFLAGS="$EXTRA_LDFLAGS -fprofile-arcs -ftest-coverage" AC_DEFINE([JEMALLOC_CODE_COVERAGE], [ ]) fi @@ -881,22 +916,17 @@ if test "x$enable_ivsalloc" = "x1" ; then fi dnl Only optimize if not debugging. -if test "x$enable_debug" = "x0" -a "x$no_CFLAGS" = "xyes" ; then - dnl Make sure that an optimization flag was not specified in EXTRA_CFLAGS. - optimize="no" - echo "$CFLAGS $EXTRA_CFLAGS" | grep '\-O' >/dev/null || optimize="yes" - if test "x${optimize}" = "xyes" ; then - if test "x$GCC" = "xyes" ; then - JE_CFLAGS_APPEND([-O3]) - JE_CXXFLAGS_APPEND([-O3]) - JE_CFLAGS_APPEND([-funroll-loops]) - elif test "x$je_cv_msvc" = "xyes" ; then - JE_CFLAGS_APPEND([-O2]) - JE_CXXFLAGS_APPEND([-O2]) - else - JE_CFLAGS_APPEND([-O]) - JE_CXXFLAGS_APPEND([-O]) - fi +if test "x$enable_debug" = "x0" ; then + if test "x$GCC" = "xyes" ; then + JE_CFLAGS_ADD([-O3]) + JE_CXXFLAGS_ADD([-O3]) + JE_CFLAGS_ADD([-funroll-loops]) + elif test "x$je_cv_msvc" = "xyes" ; then + JE_CFLAGS_ADD([-O2]) + JE_CXXFLAGS_ADD([-O2]) + else + JE_CFLAGS_ADD([-O]) + JE_CXXFLAGS_ADD([-O]) fi fi @@ -960,10 +990,10 @@ fi, if test "x$backtrace_method" = "x" -a "x$enable_prof_libunwind" = "x1" ; then AC_CHECK_HEADERS([libunwind.h], , [enable_prof_libunwind="0"]) if test "x$LUNWIND" = "x-lunwind" ; then - AC_CHECK_LIB([unwind], [unw_backtrace], [LIBS="$LIBS $LUNWIND"], + AC_CHECK_LIB([unwind], [unw_backtrace], [JE_APPEND_VS(LIBS, $LUNWIND)], [enable_prof_libunwind="0"]) else - LIBS="$LIBS $LUNWIND" + JE_APPEND_VS(LIBS, $LUNWIND) fi if test "x${enable_prof_libunwind}" = "x1" ; then backtrace_method="libunwind" @@ -985,7 +1015,7 @@ fi if test "x$backtrace_method" = "x" -a "x$enable_prof_libgcc" = "x1" \ -a "x$GCC" = "xyes" ; then AC_CHECK_HEADERS([unwind.h], , [enable_prof_libgcc="0"]) - AC_CHECK_LIB([gcc], [_Unwind_Backtrace], [LIBS="$LIBS -lgcc"], [enable_prof_libgcc="0"]) + AC_CHECK_LIB([gcc], [_Unwind_Backtrace], [JE_APPEND_VS(LIBS, -lgcc)], [enable_prof_libgcc="0"]) if test "x${enable_prof_libgcc}" = "x1" ; then backtrace_method="libgcc" AC_DEFINE([JEMALLOC_PROF_LIBGCC], [ ]) @@ -1007,7 +1037,7 @@ fi ) if test "x$backtrace_method" = "x" -a "x$enable_prof_gcc" = "x1" \ -a "x$GCC" = "xyes" ; then - JE_CFLAGS_APPEND([-fno-omit-frame-pointer]) + JE_CFLAGS_ADD([-fno-omit-frame-pointer]) backtrace_method="gcc intrinsics" AC_DEFINE([JEMALLOC_PROF_GCC], [ ]) else @@ -1022,9 +1052,7 @@ AC_MSG_CHECKING([configured backtracing method]) AC_MSG_RESULT([$backtrace_method]) if test "x$enable_prof" = "x1" ; then dnl Heap profiling uses the log(3) function. - if test "x$LM" != "x" ; then - LIBS="$LIBS $LM" - fi + JE_APPEND_VS(LIBS, $LM) AC_DEFINE([JEMALLOC_PROF], [ ]) fi @@ -1363,7 +1391,7 @@ if test "x$abi" != "xpecoff" ; then AC_CHECK_HEADERS([pthread.h], , [AC_MSG_ERROR([pthread.h is missing])]) dnl Some systems may embed pthreads functionality in libc; check for libpthread dnl first, but try libc too before failing. - AC_CHECK_LIB([pthread], [pthread_create], [LIBS="$LIBS -lpthread"], + AC_CHECK_LIB([pthread], [pthread_create], [JE_APPEND_VS(LIBS, -lpthread)], [AC_SEARCH_LIBS([pthread_create], , , AC_MSG_ERROR([libpthread is missing]))]) JE_COMPILABLE([pthread_atfork(3)], [ @@ -1376,7 +1404,7 @@ if test "x$abi" != "xpecoff" ; then fi fi -CPPFLAGS="$CPPFLAGS -D_REENTRANT" +JE_APPEND_VS(CFLAGS, -D_REENTRANT) dnl Check whether clock_gettime(2) is in libc or librt. AC_SEARCH_LIBS([clock_gettime], [rt]) @@ -1385,13 +1413,13 @@ dnl Cray wrapper compiler often adds `-lrt` when using `-static`. Check with dnl `-dynamic` as well in case a user tries to dynamically link in jemalloc if test "x$je_cv_cray_prgenv_wrapper" = "xyes" ; then if test "$ac_cv_search_clock_gettime" != "-lrt"; then - SAVED_CFLAGS="${CFLAGS}" + JE_CFLAGS_SAVE() unset ac_cv_search_clock_gettime - JE_CFLAGS_APPEND([-dynamic]) + JE_CFLAGS_ADD([-dynamic]) AC_SEARCH_LIBS([clock_gettime], [rt]) - CFLAGS="${SAVED_CFLAGS}" + JE_CFLAGS_RESTORE() fi fi @@ -1447,8 +1475,8 @@ fi if test "x$enable_syscall" = "x1" ; then dnl Check if syscall(2) is usable. Treat warnings as errors, so that e.g. OS dnl X 10.12's deprecation warning prevents use. - SAVED_CFLAGS="${CFLAGS}" - JE_CFLAGS_APPEND([-Werror]) + JE_CFLAGS_SAVE() + JE_CFLAGS_ADD([-Werror]) JE_COMPILABLE([syscall(2)], [ #include #include @@ -1456,7 +1484,7 @@ if test "x$enable_syscall" = "x1" ; then syscall(SYS_write, 2, "hello", 5); ], [je_cv_syscall]) - CFLAGS="${SAVED_CFLAGS}" + JE_CFLAGS_RESTORE() if test "x$je_cv_syscall" = "xyes" ; then AC_DEFINE([JEMALLOC_USE_SYSCALL], [ ]) fi @@ -1532,7 +1560,7 @@ if test "x$enable_lazy_lock" = "x1" ; then if test "x$abi" != "xpecoff" ; then AC_CHECK_HEADERS([dlfcn.h], , [AC_MSG_ERROR([dlfcn.h is missing])]) AC_CHECK_FUNC([dlsym], [], - [AC_CHECK_LIB([dl], [dlsym], [LIBS="$LIBS -ldl"], + [AC_CHECK_LIB([dl], [dlsym], [JE_APPEND_VS(LIBS, -ldl)], [AC_MSG_ERROR([libdl is missing])]) ]) fi @@ -2007,11 +2035,13 @@ AC_MSG_RESULT([library revision : ${rev}]) AC_MSG_RESULT([]) AC_MSG_RESULT([CONFIG : ${CONFIG}]) AC_MSG_RESULT([CC : ${CC}]) -AC_MSG_RESULT([CFLAGS : ${CFLAGS}]) +AC_MSG_RESULT([CONFIGURE_CFLAGS : ${CONFIGURE_CFLAGS}]) +AC_MSG_RESULT([SPECIFIED_CFLAGS : ${SPECIFIED_CFLAGS}]) AC_MSG_RESULT([EXTRA_CFLAGS : ${EXTRA_CFLAGS}]) AC_MSG_RESULT([CPPFLAGS : ${CPPFLAGS}]) AC_MSG_RESULT([CXX : ${CXX}]) -AC_MSG_RESULT([CXXFLAGS : ${CXXFLAGS}]) +AC_MSG_RESULT([CONFIGURE_CXXFLAGS : ${CONFIGURE_CXXFLAGS}]) +AC_MSG_RESULT([SPECIFIED_CXXFLAGS : ${SPECIFIED_CXXFLAGS}]) AC_MSG_RESULT([EXTRA_CXXFLAGS : ${EXTRA_CXXFLAGS}]) AC_MSG_RESULT([LDFLAGS : ${LDFLAGS}]) AC_MSG_RESULT([EXTRA_LDFLAGS : ${EXTRA_LDFLAGS}]) -- GitLab From bacb6afc6c5a83c5bf2e5e04a6db99600046e971 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 21 Dec 2016 12:33:17 -0800 Subject: [PATCH 203/544] Simplify arena_slab_regind(). Rewrite arena_slab_regind() to provide sufficient constant data for the compiler to perform division strength reduction. This replaces more general manual strength reduction that was implemented before arena_bin_info was compile-time-constant. It would be possible to slightly improve on the compiler-generated division code by taking advantage of range limits that the compiler doesn't know about. --- Makefile.in | 1 + include/jemalloc/internal/arena.h | 3 + include/jemalloc/internal/private_symbols.txt | 1 + src/arena.c | 85 ++++++------------- test/unit/slab.c | 35 ++++++++ 5 files changed, 66 insertions(+), 59 deletions(-) create mode 100644 test/unit/slab.c diff --git a/Makefile.in b/Makefile.in index 7c1989b8..22b11349 100644 --- a/Makefile.in +++ b/Makefile.in @@ -184,6 +184,7 @@ TESTS_UNIT := \ $(srcroot)test/unit/rtree.c \ $(srcroot)test/unit/SFMT.c \ $(srcroot)test/unit/size_classes.c \ + $(srcroot)test/unit/slab.c \ $(srcroot)test/unit/smoothstep.c \ $(srcroot)test/unit/stats.c \ $(srcroot)test/unit/ticker.c \ diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index ad400839..d6b1a2b0 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -271,6 +271,9 @@ void arena_extent_cache_maybe_insert(tsdn_t *tsdn, arena_t *arena, extent_t *extent, bool cache); void arena_extent_cache_maybe_remove(tsdn_t *tsdn, arena_t *arena, extent_t *extent, bool cache); +#ifdef JEMALLOC_JET +size_t arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr); +#endif extent_t *arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero); void arena_extent_dalloc_large(tsdn_t *tsdn, arena_t *arena, diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 4560d702..63974880 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -66,6 +66,7 @@ arena_ralloc_no_move arena_reset arena_salloc arena_sdalloc +arena_slab_regind arena_stats_merge arena_tcache_fill_small arena_tdata_get diff --git a/src/arena.c b/src/arena.c index 488bfd47..73fea528 100644 --- a/src/arena.c +++ b/src/arena.c @@ -138,73 +138,41 @@ arena_slab_reg_alloc(tsdn_t *tsdn, extent_t *slab, return (ret); } -JEMALLOC_INLINE_C size_t -arena_slab_regind(extent_t *slab, const arena_bin_info_t *bin_info, - const void *ptr) +#ifndef JEMALLOC_JET +JEMALLOC_INLINE_C +#endif +size_t +arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr) { - size_t diff, interval, shift, regind; + size_t diff, regind; /* Freeing a pointer outside the slab can cause assertion failure. */ assert((uintptr_t)ptr >= (uintptr_t)extent_addr_get(slab)); assert((uintptr_t)ptr < (uintptr_t)extent_past_get(slab)); /* Freeing an interior pointer can cause assertion failure. */ assert(((uintptr_t)ptr - (uintptr_t)extent_addr_get(slab)) % - (uintptr_t)bin_info->reg_size == 0); + (uintptr_t)arena_bin_info[binind].reg_size == 0); - /* - * Avoid doing division with a variable divisor if possible. Using - * actual division here can reduce allocator throughput by over 20%! - */ + /* Avoid doing division with a variable divisor. */ diff = (size_t)((uintptr_t)ptr - (uintptr_t)extent_addr_get(slab)); - - /* Rescale (factor powers of 2 out of the numerator and denominator). */ - interval = bin_info->reg_size; - shift = ffs_zu(interval) - 1; - diff >>= shift; - interval >>= shift; - - if (interval == 1) { - /* The divisor was a power of 2. */ - regind = diff; - } else { - /* - * To divide by a number D that is not a power of two we - * multiply by (2^21 / D) and then right shift by 21 positions. - * - * X / D - * - * becomes - * - * (X * interval_invs[D - 3]) >> SIZE_INV_SHIFT - * - * We can omit the first three elements, because we never - * divide by 0, and 1 and 2 are both powers of two, which are - * handled above. - */ -#define SIZE_INV_SHIFT ((sizeof(size_t) << 3) - LG_SLAB_MAXREGS) -#define SIZE_INV(s) (((ZU(1) << SIZE_INV_SHIFT) / (s)) + 1) - static const size_t interval_invs[] = { - SIZE_INV(3), - SIZE_INV(4), SIZE_INV(5), SIZE_INV(6), SIZE_INV(7), - SIZE_INV(8), SIZE_INV(9), SIZE_INV(10), SIZE_INV(11), - SIZE_INV(12), SIZE_INV(13), SIZE_INV(14), SIZE_INV(15), - SIZE_INV(16), SIZE_INV(17), SIZE_INV(18), SIZE_INV(19), - SIZE_INV(20), SIZE_INV(21), SIZE_INV(22), SIZE_INV(23), - SIZE_INV(24), SIZE_INV(25), SIZE_INV(26), SIZE_INV(27), - SIZE_INV(28), SIZE_INV(29), SIZE_INV(30), SIZE_INV(31) - }; - - if (likely(interval <= ((sizeof(interval_invs) / sizeof(size_t)) - + 2))) { - regind = (diff * interval_invs[interval - 3]) >> - SIZE_INV_SHIFT; - } else - regind = diff / interval; -#undef SIZE_INV -#undef SIZE_INV_SHIFT + switch (binind) { +#define REGIND_bin_yes(index, reg_size) \ + case index: \ + regind = diff / (reg_size); \ + assert(diff == regind * (reg_size)); \ + break; +#define REGIND_bin_no(index, reg_size) +#define SC(index, lg_grp, lg_delta, ndelta, psz, bin, pgs, \ + lg_delta_lookup) \ + REGIND_bin_##bin(index, (1U<nregs); + + assert(regind < arena_bin_info[binind].nregs); return (regind); } @@ -215,7 +183,7 @@ arena_slab_reg_dalloc(tsdn_t *tsdn, extent_t *slab, { szind_t binind = slab_data->binind; const arena_bin_info_t *bin_info = &arena_bin_info[binind]; - size_t regind = arena_slab_regind(slab, bin_info, ptr); + size_t regind = arena_slab_regind(slab, binind, ptr); assert(slab_data->nfree < bin_info->nregs); /* Freeing an unallocated pointer can cause assertion failure. */ @@ -1022,7 +990,6 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, const arena_bin_info_t *bin_info; extent_t *slab; - bin_info = &arena_bin_info[binind]; if (bin->slabcur != NULL) { arena_bin_slabs_full_insert(bin, bin->slabcur); diff --git a/test/unit/slab.c b/test/unit/slab.c new file mode 100644 index 00000000..42e82a8b --- /dev/null +++ b/test/unit/slab.c @@ -0,0 +1,35 @@ +#include "test/jemalloc_test.h" + +TEST_BEGIN(test_arena_slab_regind) +{ + szind_t binind; + + for (binind = 0; binind < NBINS; binind++) { + size_t regind; + extent_t slab; + const arena_bin_info_t *bin_info = &arena_bin_info[binind]; + extent_init(&slab, NULL, mallocx(bin_info->slab_size, + MALLOCX_LG_ALIGN(LG_PAGE)), bin_info->slab_size, 0, 0, true, + false, true, true); + assert_ptr_not_null(extent_addr_get(&slab), + "Unexpected malloc() failure"); + for (regind = 0; regind < bin_info->nregs; regind++) { + void *reg = (void *)((uintptr_t)extent_addr_get(&slab) + + (bin_info->reg_size * regind)); + assert_zu_eq(arena_slab_regind(&slab, binind, reg), + regind, + "Incorrect region index computed for size %zu", + bin_info->reg_size); + } + free(extent_addr_get(&slab)); + } +} +TEST_END + +int +main(void) +{ + + return (test( + test_arena_slab_regind)); +} -- GitLab From eab3b180e59d6b23fee5fd2165f96402e7341cba Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 23 Dec 2016 11:15:44 -0800 Subject: [PATCH 204/544] Fix JSON-mode output for !config_stats and/or !config_prof cases. These bugs were introduced by 0ba5b9b6189e16a983d8922d8c5cb6ab421906e8 (Add "J" (JSON) support to malloc_stats_print().), which was backported as b599b32280e1142856b0b96293a71e1684b1ccfb (with the same bugs except the inapplicable "metatata" misspelling) and first released in 4.3.0. --- src/stats.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/stats.c b/src/stats.c index 3072b2ab..e150a27f 100644 --- a/src/stats.c +++ b/src/stats.c @@ -407,7 +407,7 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, CTL_M2_GET("stats.arenas.0.metadata", i, &metadata, size_t); if (json) { malloc_cprintf(write_cb, cbopaque, - "\t\t\t\t\"metatata\": %zu%s\n", metadata, (bins || large) ? + "\t\t\t\t\"metadata\": %zu%s\n", metadata, (bins || large) ? "," : ""); } else { malloc_cprintf(write_cb, cbopaque, @@ -422,7 +422,7 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, static void stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, - bool json, bool merged, bool unmerged) + bool json, bool more) { const char *cpv; bool bv; @@ -717,11 +717,11 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, "\t\t\t]\n"); malloc_cprintf(write_cb, cbopaque, - "\t\t},\n"); + "\t\t}%s\n", (config_prof || more) ? "," : ""); } /* prof. */ - if (json) { + if (config_prof && json) { malloc_cprintf(write_cb, cbopaque, "\t\t\"prof\": {\n"); @@ -747,8 +747,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, "\t\t\t\"lg_sample\": %zd\n", ssv); malloc_cprintf(write_cb, cbopaque, - "\t\t}%s\n", (config_stats || merged || unmerged) ? "," : - ""); + "\t\t}%s\n", more ? "," : ""); } } @@ -872,8 +871,8 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, size_t u64sz; bool json = false; bool general = true; - bool merged = true; - bool unmerged = true; + bool merged = config_stats; + bool unmerged = config_stats; bool bins = true; bool large = true; @@ -936,8 +935,10 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, "___ Begin jemalloc statistics ___\n"); } - if (general) - stats_general_print(write_cb, cbopaque, json, merged, unmerged); + if (general) { + bool more = (merged || unmerged); + stats_general_print(write_cb, cbopaque, json, more); + } if (config_stats) { stats_print_helper(write_cb, cbopaque, json, merged, unmerged, bins, large); -- GitLab From c1baa0a9b7b05ebf98221dc7deb12c28e170a399 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 17 Nov 2016 13:36:17 -0800 Subject: [PATCH 205/544] Add huge page configuration and pages_[no}huge(). Add the --with-lg-hugepage configure option, but automatically configure LG_HUGEPAGE even if it isn't specified. Add the pages_[no]huge() functions, which toggle huge page state via madvise(..., MADV_[NO]HUGEPAGE) calls. --- INSTALL | 5 +++ Makefile.in | 1 + configure.ac | 44 +++++++++++++++++-- .../jemalloc/internal/jemalloc_internal.h.in | 7 +++ .../internal/jemalloc_internal_defs.h.in | 13 ++++++ include/jemalloc/internal/pages.h | 14 +++++- include/jemalloc/internal/private_symbols.txt | 2 + src/pages.c | 31 ++++++++++++- test/unit/pages.c | 30 +++++++++++++ 9 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 test/unit/pages.c diff --git a/INSTALL b/INSTALL index 6e593219..d7496612 100644 --- a/INSTALL +++ b/INSTALL @@ -227,6 +227,11 @@ any of the following arguments (not a definitive list) to 'configure': --with-lg-page, but its primary use case is for integration with FreeBSD's libc, wherein jemalloc is embedded. +--with-lg-hugepage= + Specify the base 2 log of the system huge page size. This option is useful + when cross compiling, or when overriding the default for systems that do + not explicitly support huge pages. + --with-lg-size-class-group= Specify the base 2 log of how many size classes to use for each doubling in size. By default jemalloc uses =2, which results in diff --git a/Makefile.in b/Makefile.in index 22b11349..052688bd 100644 --- a/Makefile.in +++ b/Makefile.in @@ -170,6 +170,7 @@ TESTS_UNIT := \ $(srcroot)test/unit/mq.c \ $(srcroot)test/unit/mtx.c \ $(srcroot)test/unit/pack.c \ + $(srcroot)test/unit/pages.c \ $(srcroot)test/unit/ph.c \ $(srcroot)test/unit/prng.c \ $(srcroot)test/unit/prof_accum.c \ diff --git a/configure.ac b/configure.ac index bf4ea8f7..f886aeb5 100644 --- a/configure.ac +++ b/configure.ac @@ -1317,6 +1317,36 @@ else AC_MSG_ERROR([cannot determine value for LG_PAGE]) fi +AC_ARG_WITH([lg_hugepage], + [AS_HELP_STRING([--with-lg-hugepage=], + [Base 2 log of sytem huge page size])], + [je_cv_lg_hugepage="${with_lg_hugepage}"], + [je_cv_lg_hugepage=""]) +if test "x${je_cv_lg_hugepage}" = "x" ; then + dnl Look in /proc/meminfo (Linux-specific) for information on the default huge + dnl page size, if any. The relevant line looks like: + dnl + dnl Hugepagesize: 2048 kB + if test -e "/proc/meminfo" ; then + hpsk=[`cat /proc/meminfo 2>/dev/null | \ + grep -e '^Hugepagesize:[[:space:]]\+[0-9]\+[[:space:]]kB$' | \ + awk '{print $2}'`] + if test "x${hpsk}" != "x" ; then + je_cv_lg_hugepage=10 + while test "${hpsk}" -gt 1 ; do + hpsk="$((hpsk / 2))" + je_cv_lg_hugepage="$((je_cv_lg_hugepage + 1))" + done + fi + fi + + dnl Set default if unable to automatically configure. + if test "x${je_cv_lg_hugepage}" = "x" ; then + je_cv_lg_hugepage=21 + fi +fi +AC_DEFINE_UNQUOTED([LG_HUGEPAGE], [${je_cv_lg_hugepage}]) + AC_ARG_WITH([lg_page_sizes], [AS_HELP_STRING([--with-lg-page-sizes=], [Base 2 logs of system page sizes to support])], @@ -1690,6 +1720,8 @@ JE_COMPILABLE([madvise(2)], [ madvise((void *)0, 0, 0); ], [je_cv_madvise]) if test "x${je_cv_madvise}" = "xyes" ; then + AC_DEFINE([JEMALLOC_HAVE_MADVISE], [ ]) + dnl Check for madvise(..., MADV_FREE). JE_COMPILABLE([madvise(..., MADV_FREE)], [ #include @@ -1710,9 +1742,15 @@ if test "x${je_cv_madvise}" = "xyes" ; then AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED], [ ]) fi - if test "x${je_cv_madv_free}" = "xyes" \ - -o "x${je_cv_madv_dontneed}" = "xyes" ; then - AC_DEFINE([JEMALLOC_HAVE_MADVISE], [ ]) + dnl Check for madvise(..., MADV_[NO]HUGEPAGE). + JE_COMPILABLE([madvise(..., MADV_[[NO]]HUGEPAGE)], [ +#include +], [ + madvise((void *)0, 0, MADV_HUGEPAGE); + madvise((void *)0, 0, MADV_NOHUGEPAGE); +], [je_cv_thp]) + if test "x${je_cv_thp}" = "xyes" ; then + AC_DEFINE([JEMALLOC_THP], [ ]) fi fi diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index ba5207d8..bfa84a22 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -138,6 +138,13 @@ static const bool config_cache_oblivious = false #endif ; +static const bool have_thp = +#ifdef JEMALLOC_THP + true +#else + false +#endif + ; #if defined(JEMALLOC_C11ATOMICS) && !defined(__cplusplus) #include diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index aa0c0474..722c41dd 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -187,6 +187,13 @@ /* One page is 2^LG_PAGE bytes. */ #undef LG_PAGE +/* + * One huge page is 2^LG_HUGEPAGE bytes. Note that this is defined even if the + * system does not explicitly support huge pages; system calls that require + * explicit huge page support are separately configured. + */ +#undef LG_HUGEPAGE + /* * If defined, adjacent virtual memory mappings with identical attributes * automatically coalesce, and they fragment when changes are made to subranges. @@ -262,6 +269,12 @@ #undef JEMALLOC_PURGE_MADVISE_FREE #undef JEMALLOC_PURGE_MADVISE_DONTNEED +/* + * Defined if transparent huge pages are supported via the MADV_[NO]HUGEPAGE + * arguments to madvise(2). + */ +#undef JEMALLOC_THP + /* Define if operating system has alloca.h header. */ #undef JEMALLOC_HAS_ALLOCA_H diff --git a/include/jemalloc/internal/pages.h b/include/jemalloc/internal/pages.h index 16c657a0..034a8aac 100644 --- a/include/jemalloc/internal/pages.h +++ b/include/jemalloc/internal/pages.h @@ -7,15 +7,23 @@ #endif #define PAGE ((size_t)(1U << LG_PAGE)) #define PAGE_MASK ((size_t)(PAGE - 1)) - /* Return the page base address for the page containing address a. */ #define PAGE_ADDR2BASE(a) \ ((void *)((uintptr_t)(a) & ~PAGE_MASK)) - /* Return the smallest pagesize multiple that is >= s. */ #define PAGE_CEILING(s) \ (((s) + PAGE_MASK) & ~PAGE_MASK) +/* Huge page size. LG_HUGEPAGE is determined by the configure script. */ +#define HUGEPAGE ((size_t)(1U << LG_HUGEPAGE)) +#define HUGEPAGE_MASK ((size_t)(HUGEPAGE - 1)) +/* Return the huge page base address for the huge page containing address a. */ +#define HUGEPAGE_ADDR2BASE(a) \ + ((void *)((uintptr_t)(a) & ~HUGEPAGE_MASK)) +/* Return the smallest pagesize multiple that is >= s. */ +#define HUGEPAGE_CEILING(s) \ + (((s) + HUGEPAGE_MASK) & ~HUGEPAGE_MASK) + #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ #ifdef JEMALLOC_H_STRUCTS @@ -31,6 +39,8 @@ void *pages_trim(void *addr, size_t alloc_size, size_t leadsize, bool pages_commit(void *addr, size_t size); bool pages_decommit(void *addr, size_t size); bool pages_purge(void *addr, size_t size); +bool pages_huge(void *addr, size_t size); +bool pages_nohuge(void *addr, size_t size); void pages_boot(void); #endif /* JEMALLOC_H_EXTERNS */ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 63974880..1facc928 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -324,7 +324,9 @@ opt_zero pages_boot pages_commit pages_decommit +pages_huge pages_map +pages_nohuge pages_purge pages_trim pages_unmap diff --git a/src/pages.c b/src/pages.c index 6af228ac..8bef6fac 100644 --- a/src/pages.c +++ b/src/pages.c @@ -170,7 +170,8 @@ pages_purge(void *addr, size_t size) #ifdef _WIN32 VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE); unzeroed = true; -#elif defined(JEMALLOC_HAVE_MADVISE) +#elif (defined(JEMALLOC_PURGE_MADVISE_FREE) || \ + defined(JEMALLOC_PURGE_MADVISE_DONTNEED)) # if defined(JEMALLOC_PURGE_MADVISE_FREE) # define JEMALLOC_MADV_PURGE MADV_FREE # define JEMALLOC_MADV_ZEROS false @@ -191,6 +192,34 @@ pages_purge(void *addr, size_t size) return (unzeroed); } +bool +pages_huge(void *addr, size_t size) +{ + + assert(HUGEPAGE_ADDR2BASE(addr) == addr); + assert(HUGEPAGE_CEILING(size) == size); + +#ifdef JEMALLOC_THP + return (madvise(addr, size, MADV_HUGEPAGE) != 0); +#else + return (true); +#endif +} + +bool +pages_nohuge(void *addr, size_t size) +{ + + assert(HUGEPAGE_ADDR2BASE(addr) == addr); + assert(HUGEPAGE_CEILING(size) == size); + +#ifdef JEMALLOC_THP + return (madvise(addr, size, MADV_NOHUGEPAGE) != 0); +#else + return (false); +#endif +} + #ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT static bool os_overcommits_sysctl(void) diff --git a/test/unit/pages.c b/test/unit/pages.c new file mode 100644 index 00000000..f297215a --- /dev/null +++ b/test/unit/pages.c @@ -0,0 +1,30 @@ +#include "test/jemalloc_test.h" + +TEST_BEGIN(test_pages_huge) +{ + size_t alloc_size; + bool commit; + void *pages, *hugepage; + + alloc_size = HUGEPAGE * 2 - PAGE; + commit = true; + pages = pages_map(NULL, alloc_size, &commit); + assert_ptr_not_null(pages, "Unexpected pages_map() error"); + + hugepage = (void *)(ALIGNMENT_CEILING((uintptr_t)pages, HUGEPAGE)); + assert_b_ne(pages_huge(hugepage, HUGEPAGE), have_thp, + "Unexpected pages_huge() result"); + assert_false(pages_nohuge(hugepage, HUGEPAGE), + "Unexpected pages_nohuge() result"); + + pages_unmap(pages, alloc_size); +} +TEST_END + +int +main(void) +{ + + return (test( + test_pages_huge)); +} -- GitLab From 411697adcda2fd75e135cdcdafb95f2bd295dc7f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 21 Nov 2016 23:23:03 -0800 Subject: [PATCH 206/544] Use exponential series to size extents. If virtual memory is retained, allocate extents such that their sizes form an exponentially growing series. This limits the number of disjoint virtual memory ranges so that extent merging can be effective even if multiple arenas' extent allocation requests are highly interleaved. This resolves #462. --- include/jemalloc/internal/arena.h | 9 ++ src/arena.c | 3 + src/extent.c | 217 +++++++++++++++++++++++++----- 3 files changed, 198 insertions(+), 31 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index d6b1a2b0..afa8984d 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -232,6 +232,15 @@ struct arena_s { void *extent_hooks_pun; }; + /* + * Next extent size class in a growing series to use when satisfying a + * request via the extent hooks (only if !config_munmap). This limits + * the number of disjoint virtual memory ranges so that extent merging + * can be effective even if multiple arenas' extent allocation requests + * are highly interleaved. + */ + pszind_t extent_grow_next; + /* Cache of extent structures that were allocated via base_alloc(). */ ql_head(extent_t) extent_cache; malloc_mutex_t extent_cache_mtx; diff --git a/src/arena.c b/src/arena.c index 73fea528..c3587044 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1686,6 +1686,9 @@ arena_new(tsdn_t *tsdn, unsigned ind) arena->extent_hooks = (extent_hooks_t *)&extent_hooks_default; + if (!config_munmap) + arena->extent_grow_next = psz2ind(HUGEPAGE); + ql_new(&arena->extent_cache); if (malloc_mutex_init(&arena->extent_cache_mtx, "arena_extent_cache", WITNESS_RANK_ARENA_EXTENT_CACHE)) diff --git a/src/extent.c b/src/extent.c index be6cadc3..586e8d33 100644 --- a/src/extent.c +++ b/src/extent.c @@ -265,22 +265,13 @@ extent_interior_register(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, } } -static bool -extent_register(tsdn_t *tsdn, const extent_t *extent) +static void +extent_gprof_add(tsdn_t *tsdn, const extent_t *extent) { - rtree_ctx_t rtree_ctx_fallback; - rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - rtree_elm_t *elm_a, *elm_b; - if (extent_rtree_acquire(tsdn, rtree_ctx, extent, false, true, &elm_a, - &elm_b)) - return (true); - extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent); - if (extent_slab_get(extent)) - extent_interior_register(tsdn, rtree_ctx, extent); - extent_rtree_release(tsdn, elm_a, elm_b); + cassert(config_prof); - if (config_prof && opt_prof && extent_active_get(extent)) { + if (opt_prof && extent_active_get(extent)) { size_t nadd = extent_size_get(extent) >> LG_PAGE; size_t cur = atomic_add_zu(&curpages, nadd); size_t high = atomic_read_zu(&highpages); @@ -294,6 +285,38 @@ extent_register(tsdn_t *tsdn, const extent_t *extent) if (cur > high && prof_gdump_get_unlocked()) prof_gdump(tsdn); } +} + +static void +extent_gprof_sub(tsdn_t *tsdn, const extent_t *extent) +{ + + cassert(config_prof); + + if (opt_prof && extent_active_get(extent)) { + size_t nsub = extent_size_get(extent) >> LG_PAGE; + assert(atomic_read_zu(&curpages) >= nsub); + atomic_sub_zu(&curpages, nsub); + } +} + +static bool +extent_register(tsdn_t *tsdn, const extent_t *extent) +{ + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + rtree_elm_t *elm_a, *elm_b; + + if (extent_rtree_acquire(tsdn, rtree_ctx, extent, false, true, &elm_a, + &elm_b)) + return (true); + extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent); + if (extent_slab_get(extent)) + extent_interior_register(tsdn, rtree_ctx, extent); + extent_rtree_release(tsdn, elm_a, elm_b); + + if (config_prof) + extent_gprof_add(tsdn, extent); return (false); } @@ -336,11 +359,8 @@ extent_deregister(tsdn_t *tsdn, extent_t *extent) } extent_rtree_release(tsdn, elm_a, elm_b); - if (config_prof && opt_prof && extent_active_get(extent)) { - size_t nsub = extent_size_get(extent) >> LG_PAGE; - assert(atomic_read_zu(&curpages) >= nsub); - atomic_sub_zu(&curpages, nsub); - } + if (config_prof) + extent_gprof_sub(tsdn, extent); } /* @@ -507,14 +527,16 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_usize_set(extent, usize); } - if (commit && !extent_committed_get(extent) && - extent_commit_wrapper(tsdn, arena, r_extent_hooks, extent, 0, - extent_size_get(extent))) { - if (!locked) - malloc_mutex_unlock(tsdn, &arena->extents_mtx); - extent_record(tsdn, arena, r_extent_hooks, extent_heaps, cache, - extent); - return (NULL); + if (*commit && !extent_committed_get(extent)) { + if (extent_commit_wrapper(tsdn, arena, r_extent_hooks, extent, + 0, extent_size_get(extent))) { + if (!locked) + malloc_mutex_unlock(tsdn, &arena->extents_mtx); + extent_record(tsdn, arena, r_extent_hooks, extent_heaps, + cache, extent); + return (NULL); + } + extent_zeroed_set(extent, true); } if (pad != 0) @@ -591,8 +613,6 @@ extent_alloc_cache_impl(tsdn_t *tsdn, arena_t *arena, extent = extent_recycle(tsdn, arena, r_extent_hooks, arena->extents_cached, locked, true, new_addr, usize, pad, alignment, zero, commit, slab); - if (extent == NULL) - return (NULL); return (extent); } @@ -626,9 +646,6 @@ extent_alloc_default_impl(tsdn_t *tsdn, arena_t *arena, void *new_addr, ret = extent_alloc_core(tsdn, arena, new_addr, size, alignment, zero, commit, arena->dss_prec); - if (ret == NULL) - return (NULL); - return (ret); } @@ -653,6 +670,136 @@ extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, size_t size, alignment, zero, commit)); } +static void +extent_retain(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, + extent_t *extent) +{ + + if (config_stats) + arena->stats.retained += extent_size_get(extent); + extent_record(tsdn, arena, r_extent_hooks, arena->extents_retained, + false, extent); +} + +/* + * If virtual memory is retained, create increasingly larger extents from which + * to split requested extents in order to limit the total number of disjoint + * virtual memory ranges retained by each arena. + */ +static extent_t * +extent_grow_retained(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool *commit, bool slab) +{ + extent_t *extent; + void *ptr; + size_t size, alloc_size, alloc_size_min, leadsize, trailsize; + bool zeroed, committed; + + /* + * Check whether the next extent size in the series would be large + * enough to satisfy this request. If no, just bail, so that e.g. a + * series of unsatisfiable allocation requests doesn't cause unused + * extent creation as a side effect. + */ + size = usize + pad; + alloc_size = pind2sz(arena->extent_grow_next); + alloc_size_min = size + PAGE_CEILING(alignment) - PAGE; + /* Beware size_t wrap-around. */ + if (alloc_size_min < usize) + return (NULL); + if (alloc_size < alloc_size_min) + return (NULL); + extent = extent_alloc(tsdn, arena); + if (extent == NULL) + return (NULL); + zeroed = false; + committed = false; + ptr = extent_alloc_core(tsdn, arena, new_addr, alloc_size, PAGE, + &zeroed, &committed, arena->dss_prec); + extent_init(extent, arena, ptr, alloc_size, alloc_size, + arena_extent_sn_next(arena), false, zeroed, committed, false); + if (ptr == NULL || extent_register(tsdn, extent)) { + extent_dalloc(tsdn, arena, extent); + return (NULL); + } + /* + * Set the extent as active *after registration so that no gprof-related + * accounting occurs during registration. + */ + extent_active_set(extent, true); + + leadsize = ALIGNMENT_CEILING((uintptr_t)ptr, PAGE_CEILING(alignment)) - + (uintptr_t)ptr; + assert(new_addr == NULL || leadsize == 0); + assert(alloc_size >= leadsize + size); + trailsize = alloc_size - leadsize - size; + if (extent_zeroed_get(extent)) + *zero = true; + if (extent_committed_get(extent)) + *commit = true; + + /* Split the lead. */ + if (leadsize != 0) { + extent_t *lead = extent; + extent = extent_split_wrapper(tsdn, arena, r_extent_hooks, lead, + leadsize, leadsize, size + trailsize, usize + trailsize); + if (extent == NULL) { + extent_deregister(tsdn, lead); + extent_leak(tsdn, arena, r_extent_hooks, false, lead); + return (NULL); + } + extent_retain(tsdn, arena, r_extent_hooks, lead); + } + + /* Split the trail. */ + if (trailsize != 0) { + extent_t *trail = extent_split_wrapper(tsdn, arena, + r_extent_hooks, extent, size, usize, trailsize, trailsize); + if (trail == NULL) { + extent_deregister(tsdn, extent); + extent_leak(tsdn, arena, r_extent_hooks, false, extent); + return (NULL); + } + extent_retain(tsdn, arena, r_extent_hooks, trail); + } else if (leadsize == 0) { + /* + * Splitting causes usize to be set as a side effect, but no + * splitting occurred. + */ + extent_usize_set(extent, usize); + } + + if (*commit && !extent_committed_get(extent)) { + if (extent_commit_wrapper(tsdn, arena, r_extent_hooks, extent, + 0, extent_size_get(extent))) { + extent_retain(tsdn, arena, r_extent_hooks, extent); + return (NULL); + } + extent_zeroed_set(extent, true); + } + + if (config_prof) { + /* Adjust gprof stats now that extent is final size. */ + extent_gprof_add(tsdn, extent); + } + if (pad != 0) + extent_addr_randomize(tsdn, extent, alignment); + if (slab) { + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, + &rtree_ctx_fallback); + + extent_slab_set(extent, true); + extent_interior_register(tsdn, rtree_ctx, extent); + } + if (*zero && !extent_zeroed_get(extent)) + memset(extent_addr_get(extent), 0, extent_usize_get(extent)); + if (arena->extent_grow_next + 1 < NPSIZES) + arena->extent_grow_next++; + return (extent); +} + static extent_t * extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, @@ -669,6 +816,12 @@ extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, if (extent != NULL && config_stats) { size_t size = usize + pad; arena->stats.retained -= size; + if (config_prof) + extent_gprof_add(tsdn, extent); + } + if (!config_munmap && extent == NULL) { + extent = extent_grow_retained(tsdn, arena, r_extent_hooks, + new_addr, usize, pad, alignment, zero, commit, slab); } return (extent); @@ -909,6 +1062,8 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, if (config_stats) arena->stats.retained += extent_size_get(extent); + if (config_prof) + extent_gprof_sub(tsdn, extent); extent_record(tsdn, arena, r_extent_hooks, arena->extents_retained, false, extent); -- GitLab From 884fa22b8c8a23831eb4090fa92d191d6e3e394e Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 3 Dec 2016 12:40:36 -0800 Subject: [PATCH 207/544] Rename arena_decay_t's ndirty to nunpurged. --- include/jemalloc/internal/arena.h | 2 +- src/arena.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index afa8984d..6532b08a 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -106,7 +106,7 @@ struct arena_decay_s { * arena->ndirty to determine how many dirty pages, if any, were * generated. */ - size_t ndirty; + size_t nunpurged; /* * Trailing log of how many unused dirty pages were generated during * each of the past SMOOTHSTEP_NSTEPS decay epochs, where the last diff --git a/src/arena.c b/src/arena.c index c3587044..0eb6150b 100644 --- a/src/arena.c +++ b/src/arena.c @@ -431,8 +431,8 @@ arena_decay_backlog_npages_limit(const arena_t *arena) static void arena_decay_backlog_update_last(arena_t *arena) { - size_t ndirty_delta = (arena->ndirty > arena->decay.ndirty) ? - arena->ndirty - arena->decay.ndirty : 0; + size_t ndirty_delta = (arena->ndirty > arena->decay.nunpurged) ? + arena->ndirty - arena->decay.nunpurged : 0; arena->decay.backlog[SMOOTHSTEP_NSTEPS-1] = ndirty_delta; } @@ -491,7 +491,7 @@ arena_decay_epoch_advance_purge(tsdn_t *tsdn, arena_t *arena) if (arena->ndirty > ndirty_limit) arena_purge_to_limit(tsdn, arena, ndirty_limit); - arena->decay.ndirty = arena->ndirty; + arena->decay.nunpurged = arena->ndirty; } static void @@ -516,7 +516,7 @@ arena_decay_init(arena_t *arena, ssize_t decay_time) nstime_update(&arena->decay.epoch); arena->decay.jitter_state = (uint64_t)(uintptr_t)arena; arena_decay_deadline_init(arena); - arena->decay.ndirty = arena->ndirty; + arena->decay.nunpurged = arena->ndirty; memset(arena->decay.backlog, 0, SMOOTHSTEP_NSTEPS * sizeof(size_t)); } -- GitLab From a6e86810d83aba0d94d0f6423ed09e8e6e0909fa Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 3 Dec 2016 15:38:25 -0800 Subject: [PATCH 208/544] Refactor purging and splitting/merging. Split purging into lazy and forced variants. Use the forced variant for zeroing dss. Add support for NULL function pointers as an opt-out mechanism for the dalloc, commit, decommit, purge_lazy, purge_forced, split, and merge fields of extent_hooks_t. Add short-circuiting checks in large_ralloc_no_move_{shrink,expand}() so that no attempt is made if splitting/merging is not supported. This resolves #268. --- doc/jemalloc.xml.in | 29 ++-- include/jemalloc/internal/arena.h | 4 +- include/jemalloc/internal/extent.h | 5 +- include/jemalloc/internal/pages.h | 35 ++++- include/jemalloc/internal/private_symbols.txt | 6 +- include/jemalloc/jemalloc_typedefs.h.in | 3 +- src/extent.c | 134 ++++++++++++++---- src/extent_dss.c | 14 +- src/large.c | 6 + src/pages.c | 43 +++--- test/integration/extent.c | 63 +++++--- 11 files changed, 258 insertions(+), 84 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 250a2a83..990aacf3 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -1512,7 +1512,8 @@ struct extent_hooks_s { extent_dalloc_t *dalloc; extent_commit_t *commit; extent_decommit_t *decommit; - extent_purge_t *purge; + extent_purge_t *purge_lazy; + extent_purge_t *purge_forced; extent_split_t *split; extent_merge_t *merge; };]]> @@ -1522,13 +1523,12 @@ struct extent_hooks_s { mapped committed memory, in the simplest case followed by deallocation. However, there are performance and platform reasons to retain extents for later reuse. Cleanup attempts cascade from deallocation to decommit - to purging, which gives the extent management functions opportunities to - reject the most permanent cleanup operations in favor of less permanent - (and often less costly) operations. The extent splitting and merging - operations can also be opted out of, but this is mainly intended to - support platforms on which virtual memory mappings provided by the - operating system kernel do not automatically coalesce and split, e.g. - Windows. + to lazy purging to forced purging, which gives the extent management + functions opportunities to reject the most permanent cleanup operations + in favor of less permanent (and often less costly) operations. All + operations except allocation can be universally opted out of by setting + the hook pointers to NULL, or selectively opted out + of by returning failure. typedef void *(extent_alloc_t) @@ -1634,21 +1634,24 @@ struct extent_hooks_s { typedef bool (extent_purge_t) extent_hooks_t *extent_hooks void *addr - size_tsize + size_t size size_t offset size_t length unsigned arena_ind An extent purge function conforms to the - extent_purge_t type and optionally discards physical pages + extent_purge_t type and discards physical pages within the virtual memory mapping associated with an extent at given addr and size at offset bytes, extending for length on behalf of arena - arena_ind, returning false if pages within the - purged virtual memory range will be zero-filled the next time they are - accessed. + arena_ind. A lazy extent purge function can + delay purging indefinitely and leave the pages within the purged virtual + memory range in an indeterminite state, whereas a forced extent purge + function immediately purges, and the pages within the virtual memory + range will be zero-filled the next time they are accessed. If the + function returns true, this indicates failure to purge. typedef bool (extent_split_t) diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 6532b08a..a8c2976c 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -198,8 +198,8 @@ struct arena_s { /* * Current count of pages within unused extents that are potentially - * dirty, and for which madvise(... MADV_DONTNEED) has not been called. - * By tracking this, we can institute a limit on how much dirty unused + * dirty, and for which pages_purge_*() has not been called. By + * tracking this, we can institute a limit on how much dirty unused * memory is mapped for each arena. */ size_t ndirty; diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index d5690c08..33b85145 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -133,7 +133,10 @@ bool extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, bool extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length); -bool extent_purge_wrapper(tsdn_t *tsdn, arena_t *arena, +bool extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, + size_t length); +bool extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length); extent_t *extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, diff --git a/include/jemalloc/internal/pages.h b/include/jemalloc/internal/pages.h index 034a8aac..98e4f38a 100644 --- a/include/jemalloc/internal/pages.h +++ b/include/jemalloc/internal/pages.h @@ -24,6 +24,23 @@ #define HUGEPAGE_CEILING(s) \ (((s) + HUGEPAGE_MASK) & ~HUGEPAGE_MASK) +/* PAGES_CAN_PURGE_LAZY is defined if lazy purging is supported. */ +#if defined(_WIN32) || defined(JEMALLOC_PURGE_MADVISE_FREE) +# define PAGES_CAN_PURGE_LAZY +#endif +/* + * PAGES_CAN_PURGE_FORCED is defined if forced purging is supported. + * + * The only supported way to hard-purge on Windows is to decommit and then + * re-commit, but doing so is racy, and if re-commit fails it's a pain to + * propagate the "poisoned" memory state. Since we typically decommit as the + * next step after purging on Windows anyway, there's no point in adding such + * complexity. + */ +#if !defined(_WIN32) && defined(JEMALLOC_PURGE_MADVISE_DONTNEED) +# define PAGES_CAN_PURGE_FORCED +#endif + #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ #ifdef JEMALLOC_H_STRUCTS @@ -32,13 +49,29 @@ /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS +static const bool pages_can_purge_lazy = +#ifdef PAGES_CAN_PURGE_LAZY + true +#else + false +#endif + ; +static const bool pages_can_purge_forced = +#ifdef PAGES_CAN_PURGE_FORCED + true +#else + false +#endif + ; + void *pages_map(void *addr, size_t size, bool *commit); void pages_unmap(void *addr, size_t size); void *pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size, bool *commit); bool pages_commit(void *addr, size_t size); bool pages_decommit(void *addr, size_t size); -bool pages_purge(void *addr, size_t size); +bool pages_purge_lazy(void *addr, size_t size); +bool pages_purge_forced(void *addr, size_t size); bool pages_huge(void *addr, size_t size); bool pages_nohuge(void *addr, size_t size); void pages_boot(void); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 1facc928..7aa622fb 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -179,7 +179,8 @@ extent_merge_wrapper extent_past_get extent_prof_tctx_get extent_prof_tctx_set -extent_purge_wrapper +extent_purge_forced_wrapper +extent_purge_lazy_wrapper extent_retained_get extent_ring_insert extent_ring_remove @@ -327,7 +328,8 @@ pages_decommit pages_huge pages_map pages_nohuge -pages_purge +pages_purge_forced +pages_purge_lazy pages_trim pages_unmap pind2sz diff --git a/include/jemalloc/jemalloc_typedefs.h.in b/include/jemalloc/jemalloc_typedefs.h.in index 1049d7c7..91b5a8dc 100644 --- a/include/jemalloc/jemalloc_typedefs.h.in +++ b/include/jemalloc/jemalloc_typedefs.h.in @@ -61,7 +61,8 @@ struct extent_hooks_s { extent_dalloc_t *dalloc; extent_commit_t *commit; extent_decommit_t *decommit; - extent_purge_t *purge; + extent_purge_t *purge_lazy; + extent_purge_t *purge_forced; extent_split_t *split; extent_merge_t *merge; }; diff --git a/src/extent.c b/src/extent.c index 586e8d33..827a9213 100644 --- a/src/extent.c +++ b/src/extent.c @@ -15,23 +15,47 @@ static bool extent_commit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); static bool extent_decommit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); -static bool extent_purge_default(extent_hooks_t *extent_hooks, void *addr, - size_t size, size_t offset, size_t length, unsigned arena_ind); +#ifdef PAGES_CAN_PURGE_LAZY +static bool extent_purge_lazy_default(extent_hooks_t *extent_hooks, + void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); +#endif +#ifdef PAGES_CAN_PURGE_FORCED +static bool extent_purge_forced_default(extent_hooks_t *extent_hooks, + void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); +#endif +#ifdef JEMALLOC_MAPS_COALESCE static bool extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t size_a, size_t size_b, bool committed, unsigned arena_ind); static bool extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, void *addr_b, size_t size_b, bool committed, unsigned arena_ind); +#endif const extent_hooks_t extent_hooks_default = { extent_alloc_default, extent_dalloc_default, extent_commit_default, - extent_decommit_default, - extent_purge_default, + extent_decommit_default +#ifdef PAGES_CAN_PURGE_LAZY + , + extent_purge_lazy_default +#else + , + NULL +#endif +#ifdef PAGES_CAN_PURGE_FORCED + , + extent_purge_forced_default +#else + , + NULL +#endif +#ifdef JEMALLOC_MAPS_COALESCE + , extent_split_default, extent_merge_default +#endif }; /* Used exclusively for gdump triggering. */ @@ -395,8 +419,11 @@ extent_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, * that this is only a virtual memory leak. */ if (cache) { - extent_purge_wrapper(tsdn, arena, r_extent_hooks, extent, 0, - extent_size_get(extent)); + if (extent_purge_lazy_wrapper(tsdn, arena, r_extent_hooks, + extent, 0, extent_size_get(extent))) { + extent_purge_forced_wrapper(tsdn, arena, r_extent_hooks, + extent, 0, extent_size_get(extent)); + } } extent_dalloc(tsdn, arena, extent); } @@ -1023,7 +1050,7 @@ void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { - bool err; + bool err, zeroed; assert(extent_base_get(extent) != NULL); assert(extent_size_get(extent) != 0); @@ -1041,9 +1068,10 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, err = extent_dalloc_default_impl(extent_base_get(extent), extent_size_get(extent)); } else { - err = (*r_extent_hooks)->dalloc(*r_extent_hooks, + err = ((*r_extent_hooks)->dalloc == NULL || + (*r_extent_hooks)->dalloc(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), - extent_committed_get(extent), arena->ind); + extent_committed_get(extent), arena->ind)); } if (!err) { @@ -1052,13 +1080,24 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, } extent_reregister(tsdn, extent); /* Try to decommit; purge if that fails. */ - if (extent_committed_get(extent)) { - extent_decommit_wrapper(tsdn, arena, r_extent_hooks, extent, - 0, extent_size_get(extent)); - } - extent_zeroed_set(extent, !extent_committed_get(extent) || - !(*r_extent_hooks)->purge(*r_extent_hooks, extent_base_get(extent), - extent_size_get(extent), 0, extent_size_get(extent), arena->ind)); + if (!extent_committed_get(extent)) + zeroed = true; + else if (!extent_decommit_wrapper(tsdn, arena, r_extent_hooks, extent, + 0, extent_size_get(extent))) + zeroed = true; + else if ((*r_extent_hooks)->purge_lazy != NULL && + !(*r_extent_hooks)->purge_lazy(*r_extent_hooks, + extent_base_get(extent), extent_size_get(extent), 0, + extent_size_get(extent), arena->ind)) + zeroed = false; + else if ((*r_extent_hooks)->purge_forced != NULL && + !(*r_extent_hooks)->purge_forced(*r_extent_hooks, + extent_base_get(extent), extent_size_get(extent), 0, + extent_size_get(extent), arena->ind)) + zeroed = true; + else + zeroed = false; + extent_zeroed_set(extent, zeroed); if (config_stats) arena->stats.retained += extent_size_get(extent); @@ -1088,9 +1127,9 @@ extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, bool err; extent_hooks_assure_initialized(arena, r_extent_hooks); - err = (*r_extent_hooks)->commit(*r_extent_hooks, - extent_base_get(extent), extent_size_get(extent), offset, length, - arena->ind); + err = ((*r_extent_hooks)->commit == NULL || + (*r_extent_hooks)->commit(*r_extent_hooks, extent_base_get(extent), + extent_size_get(extent), offset, length, arena->ind)); extent_committed_set(extent, extent_committed_get(extent) || !err); return (err); } @@ -1115,15 +1154,17 @@ extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_assure_initialized(arena, r_extent_hooks); - err = (*r_extent_hooks)->decommit(*r_extent_hooks, + err = ((*r_extent_hooks)->decommit == NULL || + (*r_extent_hooks)->decommit(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), offset, length, - arena->ind); + arena->ind)); extent_committed_set(extent, extent_committed_get(extent) && err); return (err); } +#ifdef PAGES_CAN_PURGE_LAZY static bool -extent_purge_default(extent_hooks_t *extent_hooks, void *addr, size_t size, +extent_purge_lazy_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { @@ -1133,22 +1174,55 @@ extent_purge_default(extent_hooks_t *extent_hooks, void *addr, size_t size, assert(length != 0); assert((length & PAGE_MASK) == 0); - return (pages_purge((void *)((uintptr_t)addr + (uintptr_t)offset), + return (pages_purge_lazy((void *)((uintptr_t)addr + (uintptr_t)offset), length)); } +#endif bool -extent_purge_wrapper(tsdn_t *tsdn, arena_t *arena, +extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { extent_hooks_assure_initialized(arena, r_extent_hooks); - return ((*r_extent_hooks)->purge(*r_extent_hooks, + return ((*r_extent_hooks)->purge_lazy == NULL || + (*r_extent_hooks)->purge_lazy(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), offset, length, arena->ind)); } +#ifdef PAGES_CAN_PURGE_FORCED +static bool +extent_purge_forced_default(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t offset, size_t length, unsigned arena_ind) +{ + + assert(extent_hooks == &extent_hooks_default); + assert(addr != NULL); + assert((offset & PAGE_MASK) == 0); + assert(length != 0); + assert((length & PAGE_MASK) == 0); + + return (pages_purge_forced((void *)((uintptr_t)addr + + (uintptr_t)offset), length)); +} +#endif + +bool +extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, + size_t length) +{ + + extent_hooks_assure_initialized(arena, r_extent_hooks); + return ((*r_extent_hooks)->purge_forced == NULL || + (*r_extent_hooks)->purge_forced(*r_extent_hooks, + extent_base_get(extent), extent_size_get(extent), offset, length, + arena->ind)); +} + +#ifdef JEMALLOC_MAPS_COALESCE static bool extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t size_a, size_t size_b, bool committed, unsigned arena_ind) @@ -1160,6 +1234,7 @@ extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size, return (true); return (false); } +#endif extent_t * extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, @@ -1175,6 +1250,9 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_assure_initialized(arena, r_extent_hooks); + if ((*r_extent_hooks)->split == NULL) + return (NULL); + trail = extent_alloc(tsdn, arena); if (trail == NULL) goto label_error_a; @@ -1237,6 +1315,7 @@ extent_merge_default_impl(void *addr_a, void *addr_b) return (false); } +#ifdef JEMALLOC_MAPS_COALESCE static bool extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, void *addr_b, size_t size_b, bool committed, unsigned arena_ind) @@ -1246,6 +1325,7 @@ extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, return (extent_merge_default_impl(addr_a, addr_b)); } +#endif bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, @@ -1257,6 +1337,10 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; extent_hooks_assure_initialized(arena, r_extent_hooks); + + if ((*r_extent_hooks)->merge == NULL) + return (true); + if (*r_extent_hooks == &extent_hooks_default) { /* Call directly to propagate tsdn. */ err = extent_merge_default_impl(extent_base_get(a), diff --git a/src/extent_dss.c b/src/extent_dss.c index 1169d496..0f0c689b 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -168,10 +168,20 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, extent_dalloc_gap(tsdn, arena, gap); else extent_dalloc(tsdn, arena, gap); - if (*zero) - memset(ret, 0, size); if (!*commit) *commit = pages_decommit(ret, size); + if (*zero && *commit) { + extent_hooks_t *extent_hooks = + EXTENT_HOOKS_INITIALIZER; + extent_t extent; + + extent_init(&extent, arena, ret, size, + size, 0, true, false, true, false); + if (extent_purge_forced_wrapper(tsdn, + arena, &extent_hooks, &extent, 0, + size)) + memset(ret, 0, size); + } return (ret); } /* diff --git a/src/large.c b/src/large.c index 1bae9399..ec22e64c 100644 --- a/src/large.c +++ b/src/large.c @@ -110,6 +110,9 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) assert(oldusize > usize); + if (extent_hooks->split == NULL) + return (true); + /* Split excess pages. */ if (diff != 0) { extent_t *trail = extent_split_wrapper(tsdn, arena, @@ -142,6 +145,9 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, size_t trailsize = usize - extent_usize_get(extent); extent_t *trail; + if (extent_hooks->merge == NULL) + return (true); + if ((trail = arena_extent_cache_alloc(tsdn, arena, &extent_hooks, extent_past_get(extent), trailsize, CACHELINE, &is_zeroed_trail)) == NULL) { diff --git a/src/pages.c b/src/pages.c index 8bef6fac..d5a0a21c 100644 --- a/src/pages.c +++ b/src/pages.c @@ -163,33 +163,34 @@ pages_decommit(void *addr, size_t size) } bool -pages_purge(void *addr, size_t size) +pages_purge_lazy(void *addr, size_t size) { - bool unzeroed; + + if (!pages_can_purge_lazy) + return (true); #ifdef _WIN32 VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE); - unzeroed = true; -#elif (defined(JEMALLOC_PURGE_MADVISE_FREE) || \ - defined(JEMALLOC_PURGE_MADVISE_DONTNEED)) -# if defined(JEMALLOC_PURGE_MADVISE_FREE) -# define JEMALLOC_MADV_PURGE MADV_FREE -# define JEMALLOC_MADV_ZEROS false -# elif defined(JEMALLOC_PURGE_MADVISE_DONTNEED) -# define JEMALLOC_MADV_PURGE MADV_DONTNEED -# define JEMALLOC_MADV_ZEROS true -# else -# error No madvise(2) flag defined for purging unused dirty pages -# endif - int err = madvise(addr, size, JEMALLOC_MADV_PURGE); - unzeroed = (!JEMALLOC_MADV_ZEROS || err != 0); -# undef JEMALLOC_MADV_PURGE -# undef JEMALLOC_MADV_ZEROS +#elif defined(JEMALLOC_PURGE_MADVISE_FREE) + madvise(addr, size, MADV_FREE); +#else + not_reached(); +#endif + return (false); +} + +bool +pages_purge_forced(void *addr, size_t size) +{ + + if (!pages_can_purge_forced) + return (true); + +#if defined(JEMALLOC_PURGE_MADVISE_DONTNEED) + return (madvise(addr, size, MADV_DONTNEED) != 0); #else - /* Last resort no-op. */ - unzeroed = true; + not_reached(); #endif - return (unzeroed); } bool diff --git a/test/integration/extent.c b/test/integration/extent.c index 2af20ce2..b0fc52d6 100644 --- a/test/integration/extent.c +++ b/test/integration/extent.c @@ -13,7 +13,9 @@ static bool extent_commit(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); static bool extent_decommit(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); -static bool extent_purge(extent_hooks_t *extent_hooks, void *addr, +static bool extent_purge_lazy(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t offset, size_t length, unsigned arena_ind); +static bool extent_purge_forced(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); static bool extent_split(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t size_a, size_t size_b, bool committed, @@ -27,7 +29,8 @@ static extent_hooks_t hooks = { extent_dalloc, extent_commit, extent_decommit, - extent_purge, + extent_purge_lazy, + extent_purge_forced, extent_split, extent_merge }; @@ -42,7 +45,8 @@ static bool did_alloc; static bool did_dalloc; static bool did_commit; static bool did_decommit; -static bool did_purge; +static bool did_purge_lazy; +static bool did_purge_forced; static bool tried_split; static bool did_split; static bool did_merge; @@ -129,7 +133,25 @@ extent_decommit(extent_hooks_t *extent_hooks, void *addr, size_t size, } static bool -extent_purge(extent_hooks_t *extent_hooks, void *addr, size_t size, +extent_purge_lazy(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t offset, size_t length, unsigned arena_ind) +{ + + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " + "length=%zu arena_ind=%u)\n", __func__, extent_hooks, addr, size, + offset, length, arena_ind); + assert_ptr_eq(extent_hooks, new_hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->purge_lazy, extent_purge_lazy, + "Wrong hook function"); + did_purge_lazy = true; + return (old_hooks->purge_lazy == NULL || + old_hooks->purge_lazy(old_hooks, addr, size, offset, length, + arena_ind)); +} + +static bool +extent_purge_forced(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { @@ -138,9 +160,11 @@ extent_purge(extent_hooks_t *extent_hooks, void *addr, size_t size, offset, length, arena_ind); assert_ptr_eq(extent_hooks, new_hooks, "extent_hooks should be same as pointer used to set hooks"); - assert_ptr_eq(extent_hooks->purge, extent_purge, "Wrong hook function"); - did_purge = true; - return (old_hooks->purge(old_hooks, addr, size, offset, length, + assert_ptr_eq(extent_hooks->purge_forced, extent_purge_forced, + "Wrong hook function"); + did_purge_forced = true; + return (old_hooks->purge_forced == NULL || + old_hooks->purge_forced(old_hooks, addr, size, offset, length, arena_ind)); } @@ -158,8 +182,8 @@ extent_split(extent_hooks_t *extent_hooks, void *addr, size_t size, "extent_hooks should be same as pointer used to set hooks"); assert_ptr_eq(extent_hooks->split, extent_split, "Wrong hook function"); tried_split = true; - err = old_hooks->split(old_hooks, addr, size, size_a, size_b, committed, - arena_ind); + err = (old_hooks->split == NULL || old_hooks->split(old_hooks, addr, + size, size_a, size_b, committed, arena_ind)); did_split = !err; return (err); } @@ -177,8 +201,8 @@ extent_merge(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, assert_ptr_eq(extent_hooks, new_hooks, "extent_hooks should be same as pointer used to set hooks"); assert_ptr_eq(extent_hooks->merge, extent_merge, "Wrong hook function"); - err = old_hooks->merge(old_hooks, addr_a, size_a, addr_b, size_b, - committed, arena_ind); + err = (old_hooks->merge == NULL || old_hooks->merge(old_hooks, addr_a, + size_a, addr_b, size_b, committed, arena_ind)); did_merge = !err; return (err); } @@ -216,7 +240,10 @@ TEST_BEGIN(test_extent) "Unexpected commit error"); assert_ptr_ne(old_hooks->decommit, extent_decommit, "Unexpected decommit error"); - assert_ptr_ne(old_hooks->purge, extent_purge, "Unexpected purge error"); + assert_ptr_ne(old_hooks->purge_lazy, extent_purge_lazy, + "Unexpected purge_lazy error"); + assert_ptr_ne(old_hooks->purge_forced, extent_purge_forced, + "Unexpected purge_forced error"); assert_ptr_ne(old_hooks->split, extent_split, "Unexpected split error"); assert_ptr_ne(old_hooks->merge, extent_merge, "Unexpected merge error"); @@ -240,7 +267,8 @@ TEST_BEGIN(test_extent) assert_ptr_not_null(p, "Unexpected mallocx() error"); did_dalloc = false; did_decommit = false; - did_purge = false; + did_purge_lazy = false; + did_purge_forced = false; tried_split = false; did_split = false; xallocx_success_a = (xallocx(p, large0, 0, flags) == large0); @@ -249,7 +277,8 @@ TEST_BEGIN(test_extent) if (xallocx_success_a) { assert_true(did_dalloc, "Expected dalloc"); assert_false(did_decommit, "Unexpected decommit"); - assert_true(did_purge, "Expected purge"); + assert_true(did_purge_lazy || did_purge_forced, + "Expected purge"); } assert_true(tried_split, "Expected split"); dallocx(p, flags); @@ -300,8 +329,10 @@ TEST_BEGIN(test_extent) "Unexpected commit error"); assert_ptr_eq(old_hooks->decommit, orig_hooks->decommit, "Unexpected decommit error"); - assert_ptr_eq(old_hooks->purge, orig_hooks->purge, - "Unexpected purge error"); + assert_ptr_eq(old_hooks->purge_lazy, orig_hooks->purge_lazy, + "Unexpected purge_lazy error"); + assert_ptr_eq(old_hooks->purge_forced, orig_hooks->purge_forced, + "Unexpected purge_forced error"); assert_ptr_eq(old_hooks->split, orig_hooks->split, "Unexpected split error"); assert_ptr_eq(old_hooks->merge, orig_hooks->merge, -- GitLab From a0dd3a4483e2e72ee80e70424a6522f873f2c7ff Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 22 Dec 2016 16:39:10 -0600 Subject: [PATCH 209/544] Implement per arena base allocators. Add/rename related mallctls: - Add stats.arenas..base . - Rename stats.arenas..metadata to stats.arenas..internal . - Add stats.arenas..resident . Modify the arenas.extend mallctl to take an optional (extent_hooks_t *) argument so that it is possible for all base allocations to be serviced by the specified extent hooks. This resolves #463. --- Makefile.in | 1 + doc/jemalloc.xml.in | 63 ++- include/jemalloc/internal/arena.h | 42 +- include/jemalloc/internal/base.h | 76 +++- .../jemalloc/internal/jemalloc_internal.h.in | 53 +-- include/jemalloc/internal/private_symbols.txt | 13 +- include/jemalloc/internal/stats.h | 5 +- src/arena.c | 48 ++- src/base.c | 407 +++++++++++++----- src/ctl.c | 50 ++- src/extent.c | 36 +- src/jemalloc.c | 35 +- src/prof.c | 6 +- src/rtree.c | 3 +- src/stats.c | 27 +- src/tcache.c | 8 +- test/integration/extent.c | 115 +++-- test/unit/base.c | 274 ++++++++++++ 18 files changed, 939 insertions(+), 323 deletions(-) create mode 100644 test/unit/base.c diff --git a/Makefile.in b/Makefile.in index 052688bd..d8704923 100644 --- a/Makefile.in +++ b/Makefile.in @@ -156,6 +156,7 @@ TESTS_UNIT := \ $(srcroot)test/unit/a0.c \ $(srcroot)test/unit/arena_reset.c \ $(srcroot)test/unit/atomic.c \ + $(srcroot)test/unit/base.c \ $(srcroot)test/unit/bitmap.c \ $(srcroot)test/unit/ckh.c \ $(srcroot)test/unit/decay.c \ diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 990aacf3..5923481a 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -1500,9 +1500,9 @@ malloc_conf = "xmalloc:true";]]> to control allocation for arenas created via arenas.extend such that all extents originate from an application-supplied extent allocator - (by setting custom extent hook functions just after arena creation), but - the automatically created arenas may have already created extents prior - to the application having an opportunity to take over extent + (by specifying the custom extent hook functions during arena creation), + but the automatically created arenas will have already created extents + prior to the application having an opportunity to take over extent allocation. arenas.extend - (unsigned) - r- + (unsigned, extent_hooks_t *) + rw - Extend the array of arenas by appending a new arena, - and returning the new arena index. + Extend the array of arenas by appending a new arena with + optionally specified extent hooks, and returning the new arena + index. @@ -1976,9 +1977,11 @@ struct extent_hooks_s { [] Total number of bytes dedicated to metadata, which - comprise base allocations used for bootstrap-sensitive internal - allocator data structures and internal allocations (see stats.arenas.<i>.metadata). + comprise base allocations used for bootstrap-sensitive allocator + metadata structures (see stats.arenas.<i>.base) + and internal allocations (see stats.arenas.<i>.internal). @@ -2114,9 +2117,21 @@ struct extent_hooks_s { details. - + + + stats.arenas.<i>.base + (size_t) + r- + [] + + + Number of bytes dedicated to bootstrap-sensitive allocator metadata + structures. + + + - stats.arenas.<i>.metadata + stats.arenas.<i>.internal (size_t) r- [] @@ -2124,13 +2139,23 @@ struct extent_hooks_s { Number of bytes dedicated to internal allocations. Internal allocations differ from application-originated allocations in that they are for internal use, and that they are omitted from heap - profiles. This statistic is reported separately from stats.metadata - because it overlaps with e.g. the stats.allocated and - stats.active - statistics, whereas the other metadata statistics do - not. + profiles. + + + + + stats.arenas.<i>.resident + (size_t) + r- + [] + + Maximum number of bytes in physically resident data + pages mapped by the arena, comprising all pages dedicated to allocator + metadata, pages backing active allocations, and unused dirty pages. + This is a maximum rather than precise because pages may not actually be + physically resident if they correspond to demand-zeroed virtual memory + that has not yet been touched. This is a multiple of the page + size. diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index a8c2976c..d889852e 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -143,9 +143,6 @@ struct arena_bin_s { }; struct arena_s { - /* This arena's index within the arenas array. */ - unsigned ind; - /* * Number of threads currently assigned to this arena, synchronized via * atomic operations. Each thread has two distinct assignments, one for @@ -226,12 +223,6 @@ struct arena_s { /* Protects extents_{cached,retained,dirty}. */ malloc_mutex_t extents_mtx; - /* User-configurable extent hook functions. */ - union { - extent_hooks_t *extent_hooks; - void *extent_hooks_pun; - }; - /* * Next extent size class in a growing series to use when satisfying a * request via the extent hooks (only if !config_munmap). This limits @@ -247,6 +238,9 @@ struct arena_s { /* bins is used to store heaps of free regions. */ arena_bin_t bins[NBINS]; + + /* Base allocator, from which arena metadata are allocated. */ + base_t *base; }; /* Used in conjunction with tsd for fast arena-related context lookup. */ @@ -337,7 +331,7 @@ unsigned arena_nthreads_get(arena_t *arena, bool internal); void arena_nthreads_inc(arena_t *arena, bool internal); void arena_nthreads_dec(arena_t *arena, bool internal); size_t arena_extent_sn_next(arena_t *arena); -arena_t *arena_new(tsdn_t *tsdn, unsigned ind); +arena_t *arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); void arena_boot(void); void arena_prefork0(tsdn_t *tsdn, arena_t *arena); void arena_prefork1(tsdn_t *tsdn, arena_t *arena); @@ -351,9 +345,10 @@ void arena_postfork_child(tsdn_t *tsdn, arena_t *arena); #ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE -void arena_metadata_add(arena_t *arena, size_t size); -void arena_metadata_sub(arena_t *arena, size_t size); -size_t arena_metadata_get(arena_t *arena); +unsigned arena_ind_get(const arena_t *arena); +void arena_internal_add(arena_t *arena, size_t size); +void arena_internal_sub(arena_t *arena, size_t size); +size_t arena_internal_get(arena_t *arena); bool arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes); bool arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes); bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes); @@ -378,25 +373,32 @@ void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) # ifdef JEMALLOC_ARENA_INLINE_A +JEMALLOC_INLINE unsigned +arena_ind_get(const arena_t *arena) +{ + + return (base_ind_get(arena->base)); +} + JEMALLOC_INLINE void -arena_metadata_add(arena_t *arena, size_t size) +arena_internal_add(arena_t *arena, size_t size) { - atomic_add_zu(&arena->stats.metadata, size); + atomic_add_zu(&arena->stats.internal, size); } JEMALLOC_INLINE void -arena_metadata_sub(arena_t *arena, size_t size) +arena_internal_sub(arena_t *arena, size_t size) { - atomic_sub_zu(&arena->stats.metadata, size); + atomic_sub_zu(&arena->stats.internal, size); } JEMALLOC_INLINE size_t -arena_metadata_get(arena_t *arena) +arena_internal_get(arena_t *arena) { - return (atomic_read_zu(&arena->stats.metadata)); + return (atomic_read_zu(&arena->stats.internal)); } JEMALLOC_INLINE bool @@ -499,7 +501,7 @@ arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) if (unlikely(tsdn_null(tsdn))) return; tsd = tsdn_tsd(tsdn); - decay_ticker = decay_ticker_get(tsd, arena->ind); + decay_ticker = decay_ticker_get(tsd, arena_ind_get(arena)); if (unlikely(decay_ticker == NULL)) return; if (unlikely(ticker_ticks(decay_ticker, nticks))) diff --git a/include/jemalloc/internal/base.h b/include/jemalloc/internal/base.h index d6b81e16..a54a5502 100644 --- a/include/jemalloc/internal/base.h +++ b/include/jemalloc/internal/base.h @@ -1,25 +1,87 @@ /******************************************************************************/ #ifdef JEMALLOC_H_TYPES +typedef struct base_block_s base_block_t; +typedef struct base_s base_t; + #endif /* JEMALLOC_H_TYPES */ /******************************************************************************/ #ifdef JEMALLOC_H_STRUCTS +/* Embedded at the beginning of every block of base-managed virtual memory. */ +struct base_block_s { + /* Total size of block's virtual memory mapping. */ + size_t size; + + /* Next block in list of base's blocks. */ + base_block_t *next; + + /* Tracks unused trailing space. */ + extent_t extent; +}; + +struct base_s { + /* Associated arena's index within the arenas array. */ + unsigned ind; + + /* User-configurable extent hook functions. */ + union { + extent_hooks_t *extent_hooks; + void *extent_hooks_pun; + }; + + /* Protects base_alloc() and base_stats_get() operations. */ + malloc_mutex_t mtx; + + /* Serial number generation state. */ + size_t extent_sn_next; + + /* Chain of all blocks associated with base. */ + base_block_t *blocks; + + /* Heap of extents that track unused trailing space within blocks. */ + extent_heap_t avail[NSIZES]; + + /* Stats, only maintained if config_stats. */ + size_t allocated; + size_t resident; + size_t mapped; +}; + #endif /* JEMALLOC_H_STRUCTS */ /******************************************************************************/ #ifdef JEMALLOC_H_EXTERNS -void *base_alloc(tsdn_t *tsdn, size_t size); -void base_stats_get(tsdn_t *tsdn, size_t *allocated, size_t *resident, - size_t *mapped); -bool base_boot(void); -void base_prefork(tsdn_t *tsdn); -void base_postfork_parent(tsdn_t *tsdn); -void base_postfork_child(tsdn_t *tsdn); +base_t *b0get(void); +base_t *base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); +void base_delete(base_t *base); +extent_hooks_t *base_extent_hooks_get(base_t *base); +extent_hooks_t *base_extent_hooks_set(base_t *base, + extent_hooks_t *extent_hooks); +void *base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment); +void base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated, + size_t *resident, size_t *mapped); +void base_prefork(tsdn_t *tsdn, base_t *base); +void base_postfork_parent(tsdn_t *tsdn, base_t *base); +void base_postfork_child(tsdn_t *tsdn, base_t *base); +bool base_boot(tsdn_t *tsdn); #endif /* JEMALLOC_H_EXTERNS */ /******************************************************************************/ #ifdef JEMALLOC_H_INLINES +#ifndef JEMALLOC_ENABLE_INLINE +unsigned base_ind_get(const base_t *base); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BASE_C_)) +JEMALLOC_INLINE unsigned +base_ind_get(const base_t *base) +{ + + return (base->ind); +} +#endif + #endif /* JEMALLOC_H_INLINES */ /******************************************************************************/ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index bfa84a22..11a27366 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -370,9 +370,9 @@ typedef unsigned szind_t; #include "jemalloc/internal/tsd.h" #include "jemalloc/internal/mb.h" #include "jemalloc/internal/extent.h" +#include "jemalloc/internal/base.h" #include "jemalloc/internal/arena.h" #include "jemalloc/internal/bitmap.h" -#include "jemalloc/internal/base.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/pages.h" #include "jemalloc/internal/large.h" @@ -403,10 +403,10 @@ typedef unsigned szind_t; #include "jemalloc/internal/arena.h" #undef JEMALLOC_ARENA_STRUCTS_A #include "jemalloc/internal/extent.h" +#include "jemalloc/internal/base.h" #define JEMALLOC_ARENA_STRUCTS_B #include "jemalloc/internal/arena.h" #undef JEMALLOC_ARENA_STRUCTS_B -#include "jemalloc/internal/base.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/pages.h" #include "jemalloc/internal/large.h" @@ -464,7 +464,7 @@ void *bootstrap_malloc(size_t size); void *bootstrap_calloc(size_t num, size_t size); void bootstrap_free(void *ptr); unsigned narenas_total_get(void); -arena_t *arena_init(tsdn_t *tsdn, unsigned ind); +arena_t *arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); arena_tdata_t *arena_tdata_get_hard(tsd_t *tsd, unsigned ind); arena_t *arena_choose_hard(tsd_t *tsd, bool internal); void arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind); @@ -491,8 +491,8 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/mb.h" #include "jemalloc/internal/bitmap.h" #include "jemalloc/internal/extent.h" -#include "jemalloc/internal/arena.h" #include "jemalloc/internal/base.h" +#include "jemalloc/internal/arena.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/pages.h" #include "jemalloc/internal/large.h" @@ -900,8 +900,10 @@ arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing) ret = arenas[ind]; if (unlikely(ret == NULL)) { ret = (arena_t *)atomic_read_p((void **)&arenas[ind]); - if (init_if_missing && unlikely(ret == NULL)) - ret = arena_init(tsdn, ind); + if (init_if_missing && unlikely(ret == NULL)) { + ret = arena_init(tsdn, ind, + (extent_hooks_t *)&extent_hooks_default); + } } return (ret); } @@ -950,17 +952,17 @@ iealloc(tsdn_t *tsdn, const void *ptr) arena_t *iaalloc(tsdn_t *tsdn, const void *ptr); size_t isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr); void *iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, - tcache_t *tcache, bool is_metadata, arena_t *arena, bool slow_path); + tcache_t *tcache, bool is_internal, arena_t *arena, bool slow_path); void *ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, bool slow_path); void *ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, - tcache_t *tcache, bool is_metadata, arena_t *arena); + tcache_t *tcache, bool is_internal, arena_t *arena); void *ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); void *ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero); size_t ivsalloc(tsdn_t *tsdn, const void *ptr); void idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, - bool is_metadata, bool slow_path); + bool is_internal, bool slow_path); void idalloc(tsd_t *tsd, extent_t *extent, void *ptr); void isdalloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, tcache_t *tcache, bool slow_path); @@ -1003,17 +1005,18 @@ isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) JEMALLOC_ALWAYS_INLINE void * iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, - bool is_metadata, arena_t *arena, bool slow_path) + bool is_internal, arena_t *arena, bool slow_path) { void *ret; assert(size != 0); - assert(!is_metadata || tcache == NULL); - assert(!is_metadata || arena == NULL || arena->ind < narenas_auto); + assert(!is_internal || tcache == NULL); + assert(!is_internal || arena == NULL || arena_ind_get(arena) < + narenas_auto); ret = arena_malloc(tsdn, arena, size, ind, zero, tcache, slow_path); - if (config_stats && is_metadata && likely(ret != NULL)) { - arena_metadata_add(iaalloc(tsdn, ret), isalloc(tsdn, + if (config_stats && is_internal && likely(ret != NULL)) { + arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn, iealloc(tsdn, ret), ret)); } return (ret); @@ -1029,19 +1032,20 @@ ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, bool slow_path) JEMALLOC_ALWAYS_INLINE void * ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, - tcache_t *tcache, bool is_metadata, arena_t *arena) + tcache_t *tcache, bool is_internal, arena_t *arena) { void *ret; assert(usize != 0); assert(usize == sa2u(usize, alignment)); - assert(!is_metadata || tcache == NULL); - assert(!is_metadata || arena == NULL || arena->ind < narenas_auto); + assert(!is_internal || tcache == NULL); + assert(!is_internal || arena == NULL || arena_ind_get(arena) < + narenas_auto); ret = arena_palloc(tsdn, arena, usize, alignment, zero, tcache); assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret); - if (config_stats && is_metadata && likely(ret != NULL)) { - arena_metadata_add(iaalloc(tsdn, ret), isalloc(tsdn, + if (config_stats && is_internal && likely(ret != NULL)) { + arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn, iealloc(tsdn, ret), ret)); } return (ret); @@ -1088,14 +1092,15 @@ ivsalloc(tsdn_t *tsdn, const void *ptr) JEMALLOC_ALWAYS_INLINE void idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, - bool is_metadata, bool slow_path) + bool is_internal, bool slow_path) { assert(ptr != NULL); - assert(!is_metadata || tcache == NULL); - assert(!is_metadata || iaalloc(tsdn, ptr)->ind < narenas_auto); - if (config_stats && is_metadata) { - arena_metadata_sub(iaalloc(tsdn, ptr), isalloc(tsdn, extent, + assert(!is_internal || tcache == NULL); + assert(!is_internal || arena_ind_get(iaalloc(tsdn, ptr)) < + narenas_auto); + if (config_stats && is_internal) { + arena_internal_sub(iaalloc(tsdn, ptr), isalloc(tsdn, extent, ptr)); } diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 7aa622fb..36960f08 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -34,13 +34,14 @@ arena_extent_ralloc_large_shrink arena_extent_sn_next arena_get arena_ichoose +arena_ind_get arena_init +arena_internal_add +arena_internal_get +arena_internal_sub arena_malloc arena_malloc_hard arena_maybe_purge -arena_metadata_add -arena_metadata_get -arena_metadata_sub arena_migrate arena_new arena_nthreads_dec @@ -93,8 +94,14 @@ atomic_write_u atomic_write_u32 atomic_write_u64 atomic_write_zu +b0get base_alloc base_boot +base_delete +base_extent_hooks_get +base_extent_hooks_set +base_ind_get +base_new base_postfork_child base_postfork_parent base_prefork diff --git a/include/jemalloc/internal/stats.h b/include/jemalloc/internal/stats.h index a7368a72..bea4e3e7 100644 --- a/include/jemalloc/internal/stats.h +++ b/include/jemalloc/internal/stats.h @@ -100,8 +100,9 @@ struct arena_stats_s { uint64_t nmadvise; uint64_t purged; - /* Number of bytes currently allocated for internal metadata. */ - size_t metadata; /* Protected via atomic_*_zu(). */ + size_t base; + size_t internal; /* Protected via atomic_*_zu(). */ + size_t resident; size_t allocated_large; uint64_t nmalloc_large; diff --git a/src/arena.c b/src/arena.c index 0eb6150b..d5e87ead 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1550,6 +1550,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, arena_stats_t *astats, malloc_bin_stats_t *bstats, malloc_large_stats_t *lstats) { + size_t base_allocated, base_resident, base_mapped; unsigned i; cassert(config_stats); @@ -1558,12 +1559,18 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, arena_basic_stats_merge_locked(arena, nthreads, dss, decay_time, nactive, ndirty); - astats->mapped += arena->stats.mapped; + base_stats_get(tsdn, arena->base, &base_allocated, &base_resident, + &base_mapped); + + astats->mapped += base_mapped + arena->stats.mapped; astats->retained += arena->stats.retained; astats->npurge += arena->stats.npurge; astats->nmadvise += arena->stats.nmadvise; astats->purged += arena->stats.purged; - astats->metadata += arena_metadata_get(arena); + astats->base += base_allocated; + astats->internal += arena_internal_get(arena); + astats->resident += base_resident + (((arena->nactive + arena->ndirty) + << LG_PAGE)); astats->allocated_large += arena->stats.allocated_large; astats->nmalloc_large += arena->stats.nmalloc_large; astats->ndalloc_large += arena->stats.ndalloc_large; @@ -1625,19 +1632,27 @@ arena_extent_sn_next(arena_t *arena) } arena_t * -arena_new(tsdn_t *tsdn, unsigned ind) +arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena_t *arena; + base_t *base; unsigned i; - arena = (arena_t *)base_alloc(tsdn, sizeof(arena_t)); + if (ind == 0) + base = b0get(); + else { + base = base_new(tsdn, ind, extent_hooks); + if (base == NULL) + return (NULL); + } + + arena = (arena_t *)base_alloc(tsdn, base, sizeof(arena_t), CACHELINE); if (arena == NULL) - return (NULL); + goto label_error; - arena->ind = ind; arena->nthreads[0] = arena->nthreads[1] = 0; if (malloc_mutex_init(&arena->lock, "arena", WITNESS_RANK_ARENA)) - return (NULL); + goto label_error; if (config_stats && config_tcache) ql_new(&arena->tcache_ql); @@ -1670,7 +1685,7 @@ arena_new(tsdn_t *tsdn, unsigned ind) ql_new(&arena->large); if (malloc_mutex_init(&arena->large_mtx, "arena_large", WITNESS_RANK_ARENA_LARGE)) - return (NULL); + goto label_error; for (i = 0; i < NPSIZES+1; i++) { extent_heap_new(&arena->extents_cached[i]); @@ -1682,9 +1697,7 @@ arena_new(tsdn_t *tsdn, unsigned ind) if (malloc_mutex_init(&arena->extents_mtx, "arena_extents", WITNESS_RANK_ARENA_EXTENTS)) - return (NULL); - - arena->extent_hooks = (extent_hooks_t *)&extent_hooks_default; + goto label_error; if (!config_munmap) arena->extent_grow_next = psz2ind(HUGEPAGE); @@ -1692,14 +1705,14 @@ arena_new(tsdn_t *tsdn, unsigned ind) ql_new(&arena->extent_cache); if (malloc_mutex_init(&arena->extent_cache_mtx, "arena_extent_cache", WITNESS_RANK_ARENA_EXTENT_CACHE)) - return (NULL); + goto label_error; /* Initialize bins. */ for (i = 0; i < NBINS; i++) { arena_bin_t *bin = &arena->bins[i]; if (malloc_mutex_init(&bin->lock, "arena_bin", WITNESS_RANK_ARENA_BIN)) - return (NULL); + goto label_error; bin->slabcur = NULL; extent_heap_new(&bin->slabs_nonfull); extent_init(&bin->slabs_full, arena, NULL, 0, 0, 0, false, @@ -1708,7 +1721,13 @@ arena_new(tsdn_t *tsdn, unsigned ind) memset(&bin->stats, 0, sizeof(malloc_bin_stats_t)); } + arena->base = base; + return (arena); +label_error: + if (ind != 0) + base_delete(base); + return (NULL); } void @@ -1744,6 +1763,7 @@ arena_prefork3(tsdn_t *tsdn, arena_t *arena) { unsigned i; + base_prefork(tsdn, arena->base); for (i = 0; i < NBINS; i++) malloc_mutex_prefork(tsdn, &arena->bins[i].lock); malloc_mutex_prefork(tsdn, &arena->large_mtx); @@ -1757,6 +1777,7 @@ arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) malloc_mutex_postfork_parent(tsdn, &arena->large_mtx); for (i = 0; i < NBINS; i++) malloc_mutex_postfork_parent(tsdn, &arena->bins[i].lock); + base_postfork_parent(tsdn, arena->base); malloc_mutex_postfork_parent(tsdn, &arena->extent_cache_mtx); malloc_mutex_postfork_parent(tsdn, &arena->extents_mtx); malloc_mutex_postfork_parent(tsdn, &arena->lock); @@ -1770,6 +1791,7 @@ arena_postfork_child(tsdn_t *tsdn, arena_t *arena) malloc_mutex_postfork_child(tsdn, &arena->large_mtx); for (i = 0; i < NBINS; i++) malloc_mutex_postfork_child(tsdn, &arena->bins[i].lock); + base_postfork_child(tsdn, arena->base); malloc_mutex_postfork_child(tsdn, &arena->extent_cache_mtx); malloc_mutex_postfork_child(tsdn, &arena->extents_mtx); malloc_mutex_postfork_child(tsdn, &arena->lock); diff --git a/src/base.c b/src/base.c index 4764d9c9..5eab7cd5 100644 --- a/src/base.c +++ b/src/base.c @@ -4,112 +4,308 @@ /******************************************************************************/ /* Data. */ -static malloc_mutex_t base_mtx; -static size_t base_extent_sn_next; -static extent_heap_t base_avail[NSIZES]; -static extent_t *base_extents; -static size_t base_allocated; -static size_t base_resident; -static size_t base_mapped; +static base_t *b0; /******************************************************************************/ -static extent_t * -base_extent_try_alloc(tsdn_t *tsdn) +static void * +base_map(extent_hooks_t *extent_hooks, unsigned ind, size_t size) { - extent_t *extent; + void *addr; + bool zero = true; + bool commit = true; - malloc_mutex_assert_owner(tsdn, &base_mtx); + assert(size == HUGEPAGE_CEILING(size)); - if (base_extents == NULL) - return (NULL); - extent = base_extents; - base_extents = *(extent_t **)extent; - return (extent); + if (extent_hooks == &extent_hooks_default) + addr = extent_alloc_mmap(NULL, size, PAGE, &zero, &commit); + else { + addr = extent_hooks->alloc(extent_hooks, NULL, size, PAGE, + &zero, &commit, ind); + } + + return (addr); } static void -base_extent_dalloc(tsdn_t *tsdn, extent_t *extent) +base_unmap(extent_hooks_t *extent_hooks, unsigned ind, void *addr, size_t size) { - malloc_mutex_assert_owner(tsdn, &base_mtx); - - *(extent_t **)extent = base_extents; - base_extents = extent; + /* + * Cascade through dalloc, decommit, purge_lazy, and purge_forced, + * stopping at first success. This cascade is performed for consistency + * with the cascade in extent_dalloc_wrapper() because an application's + * custom hooks may not support e.g. dalloc. This function is only ever + * called as a side effect of arena destruction, so although it might + * seem pointless to do anything besides dalloc here, the application + * may in fact want the end state of all associated virtual memory to in + * some consistent-but-allocated state. + */ + if (extent_hooks == &extent_hooks_default) { + if (!extent_dalloc_mmap(addr, size)) + return; + if (!pages_decommit(addr, size)) + return; + if (!pages_purge_lazy(addr, size)) + return; + if (!pages_purge_forced(addr, size)) + return; + /* Nothing worked. This should never happen. */ + not_reached(); + } else { + if (extent_hooks->dalloc != NULL && + !extent_hooks->dalloc(extent_hooks, addr, size, true, ind)) + return; + if (extent_hooks->decommit != NULL && + !extent_hooks->decommit(extent_hooks, addr, size, 0, size, + ind)) + return; + if (extent_hooks->purge_lazy != NULL && + !extent_hooks->purge_lazy(extent_hooks, addr, size, 0, size, + ind)) + return; + if (extent_hooks->purge_forced != NULL && + !extent_hooks->purge_forced(extent_hooks, addr, size, 0, + size, ind)) + return; + /* Nothing worked. That's the application's problem. */ + } } static void -base_extent_init(extent_t *extent, void *addr, size_t size) +base_extent_init(size_t *extent_sn_next, extent_t *extent, void *addr, + size_t size) { - size_t sn = atomic_add_zu(&base_extent_sn_next, 1) - 1; + size_t sn; + + sn = *extent_sn_next; + (*extent_sn_next)++; extent_init(extent, NULL, addr, size, 0, sn, true, true, true, false); } +static void * +base_extent_bump_alloc_helper(extent_t *extent, size_t *gap_size, size_t size, + size_t alignment) +{ + void *ret; + + assert(alignment == ALIGNMENT_CEILING(alignment, QUANTUM)); + assert(size == ALIGNMENT_CEILING(size, alignment)); + + *gap_size = ALIGNMENT_CEILING((uintptr_t)extent_addr_get(extent), + alignment) - (uintptr_t)extent_addr_get(extent); + ret = (void *)((uintptr_t)extent_addr_get(extent) + *gap_size); + assert(extent_size_get(extent) >= *gap_size + size); + extent_init(extent, NULL, (void *)((uintptr_t)extent_addr_get(extent) + + *gap_size + size), extent_size_get(extent) - *gap_size - size, 0, + extent_sn_get(extent), true, true, true, false); + return (ret); +} + +static void +base_extent_bump_alloc_post(tsdn_t *tsdn, base_t *base, extent_t *extent, + size_t gap_size, void *addr, size_t size) +{ + + if (extent_size_get(extent) > 0) { + /* + * Compute the index for the largest size class that does not + * exceed extent's size. + */ + szind_t index_floor = size2index(extent_size_get(extent) + 1) - + 1; + extent_heap_insert(&base->avail[index_floor], extent); + } + + if (config_stats) { + base->allocated += size; + /* + * Add one PAGE to base_resident for every page boundary that is + * crossed by the new allocation. + */ + base->resident += PAGE_CEILING((uintptr_t)addr + size) - + PAGE_CEILING((uintptr_t)addr - gap_size); + assert(base->allocated <= base->resident); + assert(base->resident <= base->mapped); + } +} + +static void * +base_extent_bump_alloc(tsdn_t *tsdn, base_t *base, extent_t *extent, + size_t size, size_t alignment) +{ + void *ret; + size_t gap_size; + + ret = base_extent_bump_alloc_helper(extent, &gap_size, size, alignment); + base_extent_bump_alloc_post(tsdn, base, extent, gap_size, ret, size); + return (ret); +} + +/* + * Allocate a block of virtual memory that is large enough to start with a + * base_block_t header, followed by an object of specified size and alignment. + * On success a pointer to the initialized base_block_t header is returned. + */ +static base_block_t * +base_block_alloc(extent_hooks_t *extent_hooks, unsigned ind, + size_t *extent_sn_next, size_t size, size_t alignment) +{ + base_block_t *block; + size_t usize, header_size, gap_size, block_size; + + alignment = ALIGNMENT_CEILING(alignment, QUANTUM); + usize = ALIGNMENT_CEILING(size, alignment); + header_size = sizeof(base_block_t); + gap_size = ALIGNMENT_CEILING(header_size, alignment) - header_size; + block_size = HUGEPAGE_CEILING(header_size + gap_size + usize); + block = (base_block_t *)base_map(extent_hooks, ind, block_size); + if (block == NULL) + return (NULL); + block->size = block_size; + block->next = NULL; + assert(block_size >= header_size); + base_extent_init(extent_sn_next, &block->extent, + (void *)((uintptr_t)block + header_size), block_size - header_size); + return (block); +} + +/* + * Allocate an extent that is at least as large as specified size, with + * specified alignment. + */ static extent_t * -base_extent_alloc(tsdn_t *tsdn, size_t minsize) +base_extent_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) { - extent_t *extent; - size_t esize, nsize; - void *addr; + extent_hooks_t *extent_hooks = base_extent_hooks_get(base); + base_block_t *block; - malloc_mutex_assert_owner(tsdn, &base_mtx); - assert(minsize != 0); - extent = base_extent_try_alloc(tsdn); - /* Allocate enough space to also carve an extent out if necessary. */ - nsize = (extent == NULL) ? CACHELINE_CEILING(sizeof(extent_t)) : 0; - esize = PAGE_CEILING(minsize + nsize); - /* - * Directly call extent_alloc_mmap() because it's critical to allocate - * untouched demand-zeroed virtual memory. - */ - { - bool zero = true; - bool commit = true; - addr = extent_alloc_mmap(NULL, esize, PAGE, &zero, &commit); + malloc_mutex_assert_owner(tsdn, &base->mtx); + + block = base_block_alloc(extent_hooks, base_ind_get(base), + &base->extent_sn_next, size, alignment); + if (block == NULL) + return (NULL); + block->next = base->blocks; + base->blocks = block; + if (config_stats) { + base->allocated += sizeof(base_block_t); + base->resident += PAGE_CEILING(sizeof(base_block_t)); + base->mapped += block->size; + assert(base->allocated <= base->resident); + assert(base->resident <= base->mapped); } - if (addr == NULL) { - if (extent != NULL) - base_extent_dalloc(tsdn, extent); + return (&block->extent); +} + +base_t * +b0get(void) +{ + + return (b0); +} + +base_t * +base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) +{ + base_t *base; + size_t extent_sn_next, base_alignment, base_size, gap_size; + base_block_t *block; + szind_t i; + + extent_sn_next = 0; + block = base_block_alloc(extent_hooks, ind, &extent_sn_next, + sizeof(base_t), QUANTUM); + if (block == NULL) + return (NULL); + + base_alignment = CACHELINE; + base_size = ALIGNMENT_CEILING(sizeof(base_t), base_alignment); + base = (base_t *)base_extent_bump_alloc_helper(&block->extent, + &gap_size, base_size, base_alignment); + base->ind = ind; + base->extent_hooks = extent_hooks; + if (malloc_mutex_init(&base->mtx, "base", WITNESS_RANK_BASE)) { + base_unmap(extent_hooks, ind, block, block->size); return (NULL); } - base_mapped += esize; - if (extent == NULL) { - extent = (extent_t *)addr; - addr = (void *)((uintptr_t)addr + nsize); - esize -= nsize; - if (config_stats) { - base_allocated += nsize; - base_resident += PAGE_CEILING(nsize); - } + base->extent_sn_next = extent_sn_next; + base->blocks = block; + for (i = 0; i < NSIZES; i++) + extent_heap_new(&base->avail[i]); + if (config_stats) { + base->allocated = sizeof(base_block_t); + base->resident = PAGE_CEILING(sizeof(base_block_t)); + base->mapped = block->size; + assert(base->allocated <= base->resident); + assert(base->resident <= base->mapped); } - base_extent_init(extent, addr, esize); - return (extent); + base_extent_bump_alloc_post(tsdn, base, &block->extent, gap_size, base, + base_size); + + return (base); +} + +void +base_delete(base_t *base) +{ + extent_hooks_t *extent_hooks = base_extent_hooks_get(base); + base_block_t *next = base->blocks; + do { + base_block_t *block = next; + next = block->next; + base_unmap(extent_hooks, base_ind_get(base), block, + block->size); + } while (next != NULL); +} + +extent_hooks_t * +base_extent_hooks_get(base_t *base) +{ + + return ((extent_hooks_t *)atomic_read_p(&base->extent_hooks_pun)); +} + +extent_hooks_t * +base_extent_hooks_set(base_t *base, extent_hooks_t *extent_hooks) +{ + extent_hooks_t *old_extent_hooks = base_extent_hooks_get(base); + union { + extent_hooks_t **h; + void **v; + } u; + + u.h = &base->extent_hooks; + atomic_write_p(u.v, extent_hooks); + + return (old_extent_hooks); } /* - * base_alloc() guarantees demand-zeroed memory, in order to make multi-page - * sparse data structures such as radix tree nodes efficient with respect to - * physical memory usage. + * base_alloc() returns zeroed memory, which is always demand-zeroed for the + * auto arenas, in order to make multi-page sparse data structures such as radix + * tree nodes efficient with respect to physical memory usage. Upon success a + * pointer to at least size bytes with specified alignment is returned. Note + * that size is rounded up to the nearest multiple of alignment to avoid false + * sharing. */ void * -base_alloc(tsdn_t *tsdn, size_t size) +base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) { void *ret; - size_t csize; + size_t usize, asize; szind_t i; extent_t *extent; - /* - * Round size up to nearest multiple of the cacheline size, so that - * there is no chance of false cache line sharing. - */ - csize = CACHELINE_CEILING(size); + alignment = QUANTUM_CEILING(alignment); + usize = ALIGNMENT_CEILING(size, alignment); + asize = usize + alignment - QUANTUM; extent = NULL; - malloc_mutex_lock(tsdn, &base_mtx); - for (i = size2index(csize); i < NSIZES; i++) { - extent = extent_heap_remove_first(&base_avail[i]); + malloc_mutex_lock(tsdn, &base->mtx); + for (i = size2index(asize); i < NSIZES; i++) { + extent = extent_heap_remove_first(&base->avail[i]); if (extent != NULL) { /* Use existing space. */ break; @@ -117,87 +313,60 @@ base_alloc(tsdn_t *tsdn, size_t size) } if (extent == NULL) { /* Try to allocate more space. */ - extent = base_extent_alloc(tsdn, csize); + extent = base_extent_alloc(tsdn, base, usize, alignment); } if (extent == NULL) { ret = NULL; goto label_return; } - ret = extent_addr_get(extent); - if (extent_size_get(extent) > csize) { - szind_t index_floor; - - extent_addr_set(extent, (void *)((uintptr_t)ret + csize)); - extent_size_set(extent, extent_size_get(extent) - csize); - /* - * Compute the index for the largest size class that does not - * exceed extent's size. - */ - index_floor = size2index(extent_size_get(extent) + 1) - 1; - extent_heap_insert(&base_avail[index_floor], extent); - } else - base_extent_dalloc(tsdn, extent); - if (config_stats) { - base_allocated += csize; - /* - * Add one PAGE to base_resident for every page boundary that is - * crossed by the new allocation. - */ - base_resident += PAGE_CEILING((uintptr_t)ret + csize) - - PAGE_CEILING((uintptr_t)ret); - } + ret = base_extent_bump_alloc(tsdn, base, extent, usize, alignment); label_return: - malloc_mutex_unlock(tsdn, &base_mtx); + malloc_mutex_unlock(tsdn, &base->mtx); return (ret); } void -base_stats_get(tsdn_t *tsdn, size_t *allocated, size_t *resident, +base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated, size_t *resident, size_t *mapped) { - malloc_mutex_lock(tsdn, &base_mtx); - assert(base_allocated <= base_resident); - assert(base_resident <= base_mapped); - *allocated = base_allocated; - *resident = base_resident; - *mapped = base_mapped; - malloc_mutex_unlock(tsdn, &base_mtx); + cassert(config_stats); + + malloc_mutex_lock(tsdn, &base->mtx); + assert(base->allocated <= base->resident); + assert(base->resident <= base->mapped); + *allocated = base->allocated; + *resident = base->resident; + *mapped = base->mapped; + malloc_mutex_unlock(tsdn, &base->mtx); } -bool -base_boot(void) +void +base_prefork(tsdn_t *tsdn, base_t *base) { - szind_t i; - - if (malloc_mutex_init(&base_mtx, "base", WITNESS_RANK_BASE)) - return (true); - base_extent_sn_next = 0; - for (i = 0; i < NSIZES; i++) - extent_heap_new(&base_avail[i]); - base_extents = NULL; - return (false); + malloc_mutex_prefork(tsdn, &base->mtx); } void -base_prefork(tsdn_t *tsdn) +base_postfork_parent(tsdn_t *tsdn, base_t *base) { - malloc_mutex_prefork(tsdn, &base_mtx); + malloc_mutex_postfork_parent(tsdn, &base->mtx); } void -base_postfork_parent(tsdn_t *tsdn) +base_postfork_child(tsdn_t *tsdn, base_t *base) { - malloc_mutex_postfork_parent(tsdn, &base_mtx); + malloc_mutex_postfork_child(tsdn, &base->mtx); } -void -base_postfork_child(tsdn_t *tsdn) +bool +base_boot(tsdn_t *tsdn) { - malloc_mutex_postfork_child(tsdn, &base_mtx); + b0 = base_new(tsdn, 0, (extent_hooks_t *)&extent_hooks_default); + return (b0 == NULL); } diff --git a/src/ctl.c b/src/ctl.c index 47b4768b..964896ab 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -55,7 +55,7 @@ static void ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_stats_t *cstats, static void ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats); static void ctl_arena_refresh(tsdn_t *tsdn, arena_t *arena, unsigned i); -static bool ctl_grow(tsdn_t *tsdn); +static bool ctl_grow(tsdn_t *tsdn, extent_hooks_t *extent_hooks); static void ctl_refresh(tsdn_t *tsdn); static bool ctl_init(tsdn_t *tsdn); static int ctl_lookup(tsdn_t *tsdn, const char *name, @@ -174,7 +174,9 @@ CTL_PROTO(stats_arenas_i_retained) CTL_PROTO(stats_arenas_i_npurge) CTL_PROTO(stats_arenas_i_nmadvise) CTL_PROTO(stats_arenas_i_purged) -CTL_PROTO(stats_arenas_i_metadata) +CTL_PROTO(stats_arenas_i_base) +CTL_PROTO(stats_arenas_i_internal) +CTL_PROTO(stats_arenas_i_resident) INDEX_PROTO(stats_arenas_i) CTL_PROTO(stats_allocated) CTL_PROTO(stats_active) @@ -392,7 +394,9 @@ static const ctl_named_node_t stats_arenas_i_node[] = { {NAME("npurge"), CTL(stats_arenas_i_npurge)}, {NAME("nmadvise"), CTL(stats_arenas_i_nmadvise)}, {NAME("purged"), CTL(stats_arenas_i_purged)}, - {NAME("metadata"), CTL(stats_arenas_i_metadata)}, + {NAME("base"), CTL(stats_arenas_i_base)}, + {NAME("internal"), CTL(stats_arenas_i_internal)}, + {NAME("resident"), CTL(stats_arenas_i_resident)}, {NAME("small"), CHILD(named, stats_arenas_i_small)}, {NAME("large"), CHILD(named, stats_arenas_i_large)}, {NAME("bins"), CHILD(indexed, stats_arenas_i_bins)}, @@ -500,7 +504,9 @@ ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats) sstats->astats.nmadvise += astats->astats.nmadvise; sstats->astats.purged += astats->astats.purged; - sstats->astats.metadata += astats->astats.metadata; + sstats->astats.base += astats->astats.base; + sstats->astats.internal += astats->astats.internal; + sstats->astats.resident += astats->astats.resident; sstats->allocated_small += astats->allocated_small; sstats->nmalloc_small += astats->nmalloc_small; @@ -556,12 +562,12 @@ ctl_arena_refresh(tsdn_t *tsdn, arena_t *arena, unsigned i) } static bool -ctl_grow(tsdn_t *tsdn) +ctl_grow(tsdn_t *tsdn, extent_hooks_t *extent_hooks) { ctl_arena_stats_t *astats; /* Initialize new arena. */ - if (arena_init(tsdn, ctl_stats.narenas) == NULL) + if (arena_init(tsdn, ctl_stats.narenas, extent_hooks) == NULL) return (true); /* Allocate extended arena stats. */ @@ -615,20 +621,17 @@ ctl_refresh(tsdn_t *tsdn) } if (config_stats) { - size_t base_allocated, base_resident, base_mapped; - base_stats_get(tsdn, &base_allocated, &base_resident, - &base_mapped); ctl_stats.allocated = ctl_stats.arenas[ctl_stats.narenas].allocated_small + ctl_stats.arenas[ctl_stats.narenas].astats.allocated_large; ctl_stats.active = (ctl_stats.arenas[ctl_stats.narenas].pactive << LG_PAGE); - ctl_stats.metadata = base_allocated + - ctl_stats.arenas[ctl_stats.narenas].astats.metadata; - ctl_stats.resident = base_resident + - ((ctl_stats.arenas[ctl_stats.narenas].pactive + - ctl_stats.arenas[ctl_stats.narenas].pdirty) << LG_PAGE); - ctl_stats.mapped = base_mapped + + ctl_stats.metadata = + ctl_stats.arenas[ctl_stats.narenas].astats.base + + ctl_stats.arenas[ctl_stats.narenas].astats.internal; + ctl_stats.resident = + ctl_stats.arenas[ctl_stats.narenas].astats.resident; + ctl_stats.mapped = ctl_stats.arenas[ctl_stats.narenas].astats.mapped; ctl_stats.retained = ctl_stats.arenas[ctl_stats.narenas].astats.retained; @@ -1167,7 +1170,7 @@ thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, if (oldarena == NULL) return (EAGAIN); - newind = oldind = oldarena->ind; + newind = oldind = arena_ind_get(oldarena); WRITE(newind, unsigned); READ(oldind, unsigned); if (newind != oldind) { @@ -1738,11 +1741,14 @@ arenas_extend_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; + extent_hooks_t *extent_hooks; unsigned narenas; malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); - READONLY(); - if (ctl_grow(tsd_tsdn(tsd))) { + + extent_hooks = (extent_hooks_t *)&extent_hooks_default; + WRITE(extent_hooks, extent_hooks_t *); + if (ctl_grow(tsd_tsdn(tsd), extent_hooks)) { ret = EAGAIN; goto label_return; } @@ -1906,8 +1912,12 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise, ctl_stats.arenas[mib[2]].astats.nmadvise, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_purged, ctl_stats.arenas[mib[2]].astats.purged, uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_metadata, - ctl_stats.arenas[mib[2]].astats.metadata, size_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_base, + ctl_stats.arenas[mib[2]].astats.base, size_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_internal, + ctl_stats.arenas[mib[2]].astats.internal, size_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_resident, + ctl_stats.arenas[mib[2]].astats.resident, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated, ctl_stats.arenas[mib[2]].allocated_small, size_t) diff --git a/src/extent.c b/src/extent.c index 827a9213..6eabde31 100644 --- a/src/extent.c +++ b/src/extent.c @@ -83,7 +83,8 @@ extent_alloc(tsdn_t *tsdn, arena_t *arena) extent = ql_last(&arena->extent_cache, ql_link); if (extent == NULL) { malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); - return (base_alloc(tsdn, sizeof(extent_t))); + return (base_alloc(tsdn, arena->base, sizeof(extent_t), + QUANTUM)); } ql_tail_remove(&arena->extent_cache, extent_t, ql_link); malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); @@ -104,22 +105,14 @@ extent_hooks_t * extent_hooks_get(arena_t *arena) { - return ((extent_hooks_t *)atomic_read_p(&arena->extent_hooks_pun)); + return (base_extent_hooks_get(arena->base)); } extent_hooks_t * extent_hooks_set(arena_t *arena, extent_hooks_t *extent_hooks) { - extent_hooks_t *old_extent_hooks = extent_hooks_get(arena); - union { - extent_hooks_t **h; - void **v; - } u; - u.h = &arena->extent_hooks; - atomic_write_p(u.v, extent_hooks); - - return (old_extent_hooks); + return (base_extent_hooks_set(arena->base, extent_hooks)); } static void @@ -873,7 +866,7 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, alignment, zero, commit); } else { addr = (*r_extent_hooks)->alloc(*r_extent_hooks, new_addr, size, - alignment, zero, commit, arena->ind); + alignment, zero, commit, arena_ind_get(arena)); } if (addr == NULL) { extent_dalloc(tsdn, arena, extent); @@ -1071,7 +1064,7 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, err = ((*r_extent_hooks)->dalloc == NULL || (*r_extent_hooks)->dalloc(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), - extent_committed_get(extent), arena->ind)); + extent_committed_get(extent), arena_ind_get(arena))); } if (!err) { @@ -1088,12 +1081,12 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, else if ((*r_extent_hooks)->purge_lazy != NULL && !(*r_extent_hooks)->purge_lazy(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), 0, - extent_size_get(extent), arena->ind)) + extent_size_get(extent), arena_ind_get(arena))) zeroed = false; else if ((*r_extent_hooks)->purge_forced != NULL && !(*r_extent_hooks)->purge_forced(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), 0, - extent_size_get(extent), arena->ind)) + extent_size_get(extent), arena_ind_get(arena))) zeroed = true; else zeroed = false; @@ -1129,7 +1122,7 @@ extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_assure_initialized(arena, r_extent_hooks); err = ((*r_extent_hooks)->commit == NULL || (*r_extent_hooks)->commit(*r_extent_hooks, extent_base_get(extent), - extent_size_get(extent), offset, length, arena->ind)); + extent_size_get(extent), offset, length, arena_ind_get(arena))); extent_committed_set(extent, extent_committed_get(extent) || !err); return (err); } @@ -1157,7 +1150,7 @@ extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, err = ((*r_extent_hooks)->decommit == NULL || (*r_extent_hooks)->decommit(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), offset, length, - arena->ind)); + arena_ind_get(arena))); extent_committed_set(extent, extent_committed_get(extent) && err); return (err); } @@ -1189,7 +1182,7 @@ extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, return ((*r_extent_hooks)->purge_lazy == NULL || (*r_extent_hooks)->purge_lazy(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), offset, length, - arena->ind)); + arena_ind_get(arena))); } #ifdef PAGES_CAN_PURGE_FORCED @@ -1219,7 +1212,7 @@ extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, return ((*r_extent_hooks)->purge_forced == NULL || (*r_extent_hooks)->purge_forced(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), offset, length, - arena->ind)); + arena_ind_get(arena))); } #ifdef JEMALLOC_MAPS_COALESCE @@ -1280,7 +1273,7 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, if ((*r_extent_hooks)->split(*r_extent_hooks, extent_base_get(extent), size_a + size_b, size_a, size_b, extent_committed_get(extent), - arena->ind)) + arena_ind_get(arena))) goto label_error_d; extent_size_set(extent, size_a); @@ -1348,7 +1341,8 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, } else { err = (*r_extent_hooks)->merge(*r_extent_hooks, extent_base_get(a), extent_size_get(a), extent_base_get(b), - extent_size_get(b), extent_committed_get(a), arena->ind); + extent_size_get(b), extent_committed_get(a), + arena_ind_get(arena)); } if (err) diff --git a/src/jemalloc.c b/src/jemalloc.c index 7df3fc9e..2c49401f 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -304,21 +304,21 @@ malloc_init(void) */ static void * -a0ialloc(size_t size, bool zero, bool is_metadata) +a0ialloc(size_t size, bool zero, bool is_internal) { if (unlikely(malloc_init_a0())) return (NULL); return (iallocztm(TSDN_NULL, size, size2index(size), zero, NULL, - is_metadata, arena_get(TSDN_NULL, 0, true), true)); + is_internal, arena_get(TSDN_NULL, 0, true), true)); } static void -a0idalloc(extent_t *extent, void *ptr, bool is_metadata) +a0idalloc(extent_t *extent, void *ptr, bool is_internal) { - idalloctm(TSDN_NULL, extent, ptr, false, is_metadata, true); + idalloctm(TSDN_NULL, extent, ptr, false, is_internal, true); } void * @@ -405,7 +405,7 @@ narenas_total_get(void) /* Create a new arena and insert it into the arenas array at index ind. */ static arena_t * -arena_init_locked(tsdn_t *tsdn, unsigned ind) +arena_init_locked(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena_t *arena; @@ -426,18 +426,18 @@ arena_init_locked(tsdn_t *tsdn, unsigned ind) } /* Actually initialize the arena. */ - arena = arena_new(tsdn, ind); + arena = arena_new(tsdn, ind, extent_hooks); arena_set(ind, arena); return (arena); } arena_t * -arena_init(tsdn_t *tsdn, unsigned ind) +arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena_t *arena; malloc_mutex_lock(tsdn, &arenas_lock); - arena = arena_init_locked(tsdn, ind); + arena = arena_init_locked(tsdn, ind, extent_hooks); malloc_mutex_unlock(tsdn, &arenas_lock); return (arena); } @@ -629,7 +629,8 @@ arena_choose_hard(tsd_t *tsd, bool internal) /* Initialize a new arena. */ choose[j] = first_null; arena = arena_init_locked(tsd_tsdn(tsd), - choose[j]); + choose[j], + (extent_hooks_t *)&extent_hooks_default); if (arena == NULL) { malloc_mutex_unlock(tsd_tsdn(tsd), &arenas_lock); @@ -657,7 +658,7 @@ iarena_cleanup(tsd_t *tsd) iarena = tsd_iarena_get(tsd); if (iarena != NULL) - arena_unbind(tsd, iarena->ind, true); + arena_unbind(tsd, arena_ind_get(iarena), true); } void @@ -667,7 +668,7 @@ arena_cleanup(tsd_t *tsd) arena = tsd_arena_get(tsd); if (arena != NULL) - arena_unbind(tsd, arena->ind, false); + arena_unbind(tsd, arena_ind_get(arena), false); } void @@ -1211,7 +1212,7 @@ malloc_init_hard_a0_locked() } } pages_boot(); - if (base_boot()) + if (base_boot(TSDN_NULL)) return (true); if (extent_boot()) return (true); @@ -1236,7 +1237,8 @@ malloc_init_hard_a0_locked() * Initialize one arena here. The rest are lazily created in * arena_choose_hard(). */ - if (arena_init(TSDN_NULL, 0) == NULL) + if (arena_init(TSDN_NULL, 0, (extent_hooks_t *)&extent_hooks_default) == + NULL) return (true); malloc_init_state = malloc_init_a0_initialized; @@ -1309,8 +1311,8 @@ malloc_init_hard_finish(tsdn_t *tsdn) narenas_total_set(narenas_auto); /* Allocate and initialize arenas. */ - arenas = (arena_t **)base_alloc(tsdn, sizeof(arena_t *) * - (MALLOCX_ARENA_MAX+1)); + arenas = (arena_t **)base_alloc(tsdn, a0->base, sizeof(arena_t *) * + (MALLOCX_ARENA_MAX+1), CACHELINE); if (arenas == NULL) return (true); /* Copy the pointer to the one arena that was already initialized. */ @@ -2690,7 +2692,6 @@ _malloc_prefork(void) } } } - base_prefork(tsd_tsdn(tsd)); for (i = 0; i < narenas; i++) { if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) arena_prefork3(tsd_tsdn(tsd), arena); @@ -2719,7 +2720,6 @@ _malloc_postfork(void) witness_postfork_parent(tsd); /* Release all mutexes, now that fork() has completed. */ - base_postfork_parent(tsd_tsdn(tsd)); for (i = 0, narenas = narenas_total_get(); i < narenas; i++) { arena_t *arena; @@ -2743,7 +2743,6 @@ jemalloc_postfork_child(void) witness_postfork_child(tsd); /* Release all mutexes, now that fork() has completed. */ - base_postfork_child(tsd_tsdn(tsd)); for (i = 0, narenas = narenas_total_get(); i < narenas; i++) { arena_t *arena; diff --git a/src/prof.c b/src/prof.c index 19c8fb71..b9a9d659 100644 --- a/src/prof.c +++ b/src/prof.c @@ -2254,7 +2254,8 @@ prof_boot2(tsd_t *tsd) } gctx_locks = (malloc_mutex_t *)base_alloc(tsd_tsdn(tsd), - PROF_NCTX_LOCKS * sizeof(malloc_mutex_t)); + b0get(), PROF_NCTX_LOCKS * sizeof(malloc_mutex_t), + CACHELINE); if (gctx_locks == NULL) return (true); for (i = 0; i < PROF_NCTX_LOCKS; i++) { @@ -2264,7 +2265,8 @@ prof_boot2(tsd_t *tsd) } tdata_locks = (malloc_mutex_t *)base_alloc(tsd_tsdn(tsd), - PROF_NTDATA_LOCKS * sizeof(malloc_mutex_t)); + b0get(), PROF_NTDATA_LOCKS * sizeof(malloc_mutex_t), + CACHELINE); if (tdata_locks == NULL) return (true); for (i = 0; i < PROF_NTDATA_LOCKS; i++) { diff --git a/src/rtree.c b/src/rtree.c index b6b9ed76..fd5e85df 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -72,7 +72,8 @@ static rtree_elm_t * rtree_node_alloc(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { - return ((rtree_elm_t *)base_alloc(tsdn, nelms * sizeof(rtree_elm_t))); + return ((rtree_elm_t *)base_alloc(tsdn, b0get(), nelms * + sizeof(rtree_elm_t), CACHELINE)); } #ifdef JEMALLOC_JET #undef rtree_node_alloc diff --git a/src/stats.c b/src/stats.c index e150a27f..0a3deaaa 100644 --- a/src/stats.c +++ b/src/stats.c @@ -254,7 +254,8 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, unsigned nthreads; const char *dss; ssize_t decay_time; - size_t page, pactive, pdirty, mapped, retained, metadata; + size_t page, pactive, pdirty, mapped, retained; + size_t base, internal, resident; uint64_t npurge, nmadvise, purged; size_t small_allocated; uint64_t small_nmalloc, small_ndalloc, small_nrequests; @@ -404,14 +405,32 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, "retained: %12zu\n", retained); } - CTL_M2_GET("stats.arenas.0.metadata", i, &metadata, size_t); + CTL_M2_GET("stats.arenas.0.base", i, &base, size_t); if (json) { malloc_cprintf(write_cb, cbopaque, - "\t\t\t\t\"metadata\": %zu%s\n", metadata, (bins || large) ? + "\t\t\t\t\"base\": %zu,\n", base); + } else { + malloc_cprintf(write_cb, cbopaque, + "base: %12zu\n", base); + } + + CTL_M2_GET("stats.arenas.0.internal", i, &internal, size_t); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"internal\": %zu,\n", internal); + } else { + malloc_cprintf(write_cb, cbopaque, + "internal: %12zu\n", internal); + } + + CTL_M2_GET("stats.arenas.0.resident", i, &resident, size_t); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"resident\": %zu%s\n", resident, (bins || large) ? "," : ""); } else { malloc_cprintf(write_cb, cbopaque, - "metadata: %12zu\n", metadata); + "resident: %12zu\n", resident); } if (bins) diff --git a/src/tcache.c b/src/tcache.c index 7f5b291c..fad52777 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -440,8 +440,8 @@ tcaches_create(tsd_t *tsd, unsigned *r_ind) tcaches_t *elm; if (tcaches == NULL) { - tcaches = base_alloc(tsd_tsdn(tsd), sizeof(tcache_t *) * - (MALLOCX_TCACHE_MAX+1)); + tcaches = base_alloc(tsd_tsdn(tsd), b0get(), sizeof(tcache_t *) + * (MALLOCX_TCACHE_MAX+1), CACHELINE); if (tcaches == NULL) return (true); } @@ -510,8 +510,8 @@ tcache_boot(tsdn_t *tsdn) nhbins = size2index(tcache_maxclass) + 1; /* Initialize tcache_bin_info. */ - tcache_bin_info = (tcache_bin_info_t *)base_alloc(tsdn, nhbins * - sizeof(tcache_bin_info_t)); + tcache_bin_info = (tcache_bin_info_t *)base_alloc(tsdn, b0get(), nhbins + * sizeof(tcache_bin_info_t), CACHELINE); if (tcache_bin_info == NULL) return (true); stack_nelms = 0; diff --git a/test/integration/extent.c b/test/integration/extent.c index b0fc52d6..e2bd0054 100644 --- a/test/integration/extent.c +++ b/test/integration/extent.c @@ -71,7 +71,7 @@ extent_alloc(extent_hooks_t *extent_hooks, void *new_addr, size_t size, assert_ptr_eq(extent_hooks->alloc, extent_alloc, "Wrong hook function"); did_alloc = true; return (old_hooks->alloc(old_hooks, new_addr, size, alignment, zero, - commit, arena_ind)); + commit, 0)); } static bool @@ -89,7 +89,7 @@ extent_dalloc(extent_hooks_t *extent_hooks, void *addr, size_t size, did_dalloc = true; if (!do_dalloc) return (true); - return (old_hooks->dalloc(old_hooks, addr, size, committed, arena_ind)); + return (old_hooks->dalloc(old_hooks, addr, size, committed, 0)); } static bool @@ -105,8 +105,7 @@ extent_commit(extent_hooks_t *extent_hooks, void *addr, size_t size, "extent_hooks should be same as pointer used to set hooks"); assert_ptr_eq(extent_hooks->commit, extent_commit, "Wrong hook function"); - err = old_hooks->commit(old_hooks, addr, size, offset, length, - arena_ind); + err = old_hooks->commit(old_hooks, addr, size, offset, length, 0); did_commit = !err; return (err); } @@ -126,8 +125,7 @@ extent_decommit(extent_hooks_t *extent_hooks, void *addr, size_t size, "Wrong hook function"); if (!do_decommit) return (true); - err = old_hooks->decommit(old_hooks, addr, size, offset, length, - arena_ind); + err = old_hooks->decommit(old_hooks, addr, size, offset, length, 0); did_decommit = !err; return (err); } @@ -146,8 +144,7 @@ extent_purge_lazy(extent_hooks_t *extent_hooks, void *addr, size_t size, "Wrong hook function"); did_purge_lazy = true; return (old_hooks->purge_lazy == NULL || - old_hooks->purge_lazy(old_hooks, addr, size, offset, length, - arena_ind)); + old_hooks->purge_lazy(old_hooks, addr, size, offset, length, 0)); } static bool @@ -164,8 +161,7 @@ extent_purge_forced(extent_hooks_t *extent_hooks, void *addr, size_t size, "Wrong hook function"); did_purge_forced = true; return (old_hooks->purge_forced == NULL || - old_hooks->purge_forced(old_hooks, addr, size, offset, length, - arena_ind)); + old_hooks->purge_forced(old_hooks, addr, size, offset, length, 0)); } static bool @@ -183,7 +179,7 @@ extent_split(extent_hooks_t *extent_hooks, void *addr, size_t size, assert_ptr_eq(extent_hooks->split, extent_split, "Wrong hook function"); tried_split = true; err = (old_hooks->split == NULL || old_hooks->split(old_hooks, addr, - size, size_a, size_b, committed, arena_ind)); + size, size_a, size_b, committed, 0)); did_split = !err; return (err); } @@ -202,51 +198,23 @@ extent_merge(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, "extent_hooks should be same as pointer used to set hooks"); assert_ptr_eq(extent_hooks->merge, extent_merge, "Wrong hook function"); err = (old_hooks->merge == NULL || old_hooks->merge(old_hooks, addr_a, - size_a, addr_b, size_b, committed, arena_ind)); + size_a, addr_b, size_b, committed, 0)); did_merge = !err; return (err); } -TEST_BEGIN(test_extent) +static void +test_extent_body(unsigned arena_ind) { void *p; - size_t old_size, new_size, large0, large1, large2, sz; - unsigned arena_ind; + size_t large0, large1, large2, sz; + size_t purge_mib[3]; + size_t purge_miblen; int flags; - size_t hooks_mib[3], purge_mib[3]; - size_t hooks_miblen, purge_miblen; bool xallocx_success_a, xallocx_success_b, xallocx_success_c; - sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, NULL, 0), - 0, "Unexpected mallctl() failure"); flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; - /* Install custom extent hooks. */ - hooks_miblen = sizeof(hooks_mib)/sizeof(size_t); - assert_d_eq(mallctlnametomib("arena.0.extent_hooks", hooks_mib, - &hooks_miblen), 0, "Unexpected mallctlnametomib() failure"); - hooks_mib[1] = (size_t)arena_ind; - old_size = sizeof(extent_hooks_t *); - new_size = sizeof(extent_hooks_t *); - assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks, - &old_size, (void *)&new_hooks, new_size), 0, - "Unexpected extent_hooks error"); - orig_hooks = old_hooks; - assert_ptr_ne(old_hooks->alloc, extent_alloc, "Unexpected alloc error"); - assert_ptr_ne(old_hooks->dalloc, extent_dalloc, - "Unexpected dalloc error"); - assert_ptr_ne(old_hooks->commit, extent_commit, - "Unexpected commit error"); - assert_ptr_ne(old_hooks->decommit, extent_decommit, - "Unexpected decommit error"); - assert_ptr_ne(old_hooks->purge_lazy, extent_purge_lazy, - "Unexpected purge_lazy error"); - assert_ptr_ne(old_hooks->purge_forced, extent_purge_forced, - "Unexpected purge_forced error"); - assert_ptr_ne(old_hooks->split, extent_split, "Unexpected split error"); - assert_ptr_ne(old_hooks->merge, extent_merge, "Unexpected merge error"); - /* Get large size classes. */ sz = sizeof(size_t); assert_d_eq(mallctl("arenas.lextent.0.size", (void *)&large0, &sz, NULL, @@ -314,6 +282,45 @@ TEST_BEGIN(test_extent) p = mallocx(42, flags); assert_ptr_not_null(p, "Unexpected mallocx() error"); dallocx(p, flags); +} + +TEST_BEGIN(test_extent_manual_hook) +{ + unsigned arena_ind; + size_t old_size, new_size, sz; + size_t hooks_mib[3]; + size_t hooks_miblen; + + sz = sizeof(unsigned); + assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, NULL, 0), + 0, "Unexpected mallctl() failure"); + + /* Install custom extent hooks. */ + hooks_miblen = sizeof(hooks_mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("arena.0.extent_hooks", hooks_mib, + &hooks_miblen), 0, "Unexpected mallctlnametomib() failure"); + hooks_mib[1] = (size_t)arena_ind; + old_size = sizeof(extent_hooks_t *); + new_size = sizeof(extent_hooks_t *); + assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks, + &old_size, (void *)&new_hooks, new_size), 0, + "Unexpected extent_hooks error"); + orig_hooks = old_hooks; + assert_ptr_ne(old_hooks->alloc, extent_alloc, "Unexpected alloc error"); + assert_ptr_ne(old_hooks->dalloc, extent_dalloc, + "Unexpected dalloc error"); + assert_ptr_ne(old_hooks->commit, extent_commit, + "Unexpected commit error"); + assert_ptr_ne(old_hooks->decommit, extent_decommit, + "Unexpected decommit error"); + assert_ptr_ne(old_hooks->purge_lazy, extent_purge_lazy, + "Unexpected purge_lazy error"); + assert_ptr_ne(old_hooks->purge_forced, extent_purge_forced, + "Unexpected purge_forced error"); + assert_ptr_ne(old_hooks->split, extent_split, "Unexpected split error"); + assert_ptr_ne(old_hooks->merge, extent_merge, "Unexpected merge error"); + + test_extent_body(arena_ind); /* Restore extent hooks. */ assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, NULL, NULL, @@ -340,9 +347,25 @@ TEST_BEGIN(test_extent) } TEST_END +TEST_BEGIN(test_extent_auto_hook) +{ + unsigned arena_ind; + size_t new_size, sz; + + sz = sizeof(unsigned); + new_size = sizeof(extent_hooks_t *); + assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, + (void *)&new_hooks, new_size), 0, "Unexpected mallctl() failure"); + + test_extent_body(arena_ind); +} +TEST_END + int main(void) { - return (test(test_extent)); + return (test( + test_extent_manual_hook, + test_extent_auto_hook)); } diff --git a/test/unit/base.c b/test/unit/base.c new file mode 100644 index 00000000..6a082a5e --- /dev/null +++ b/test/unit/base.c @@ -0,0 +1,274 @@ +#include "test/jemalloc_test.h" + +static void *extent_alloc_hook(extent_hooks_t *extent_hooks, void *new_addr, + size_t size, size_t alignment, bool *zero, bool *commit, + unsigned arena_ind); +static bool extent_dalloc_hook(extent_hooks_t *extent_hooks, void *addr, + size_t size, bool committed, unsigned arena_ind); +static bool extent_decommit_hook(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t offset, size_t length, unsigned arena_ind); +static bool extent_purge_lazy_hook(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t offset, size_t length, unsigned arena_ind); +static bool extent_purge_forced_hook(extent_hooks_t *extent_hooks, + void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); + +static extent_hooks_t hooks_not_null = { + extent_alloc_hook, + extent_dalloc_hook, + NULL, /* commit */ + extent_decommit_hook, + extent_purge_lazy_hook, + extent_purge_forced_hook, + NULL, /* split */ + NULL /* merge */ +}; + +static extent_hooks_t hooks_null = { + extent_alloc_hook, + NULL, /* dalloc */ + NULL, /* commit */ + NULL, /* decommit */ + NULL, /* purge_lazy */ + NULL, /* purge_forced */ + NULL, /* split */ + NULL /* merge */ +}; + +static bool did_alloc; +static bool did_dalloc; +static bool did_decommit; +static bool did_purge_lazy; +static bool did_purge_forced; + +#if 0 +# define TRACE_HOOK(fmt, ...) malloc_printf(fmt, __VA_ARGS__) +#else +# define TRACE_HOOK(fmt, ...) +#endif + +static void * +extent_alloc_hook(extent_hooks_t *extent_hooks, void *new_addr, size_t size, + size_t alignment, bool *zero, bool *commit, unsigned arena_ind) +{ + + TRACE_HOOK("%s(extent_hooks=%p, new_addr=%p, size=%zu, alignment=%zu, " + "*zero=%s, *commit=%s, arena_ind=%u)\n", __func__, extent_hooks, + new_addr, size, alignment, *zero ? "true" : "false", *commit ? + "true" : "false", arena_ind); + did_alloc = true; + return (extent_hooks_default.alloc( + (extent_hooks_t *)&extent_hooks_default, new_addr, size, alignment, + zero, commit, 0)); +} + +static bool +extent_dalloc_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, + bool committed, unsigned arena_ind) +{ + + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, " + "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ? + "true" : "false", arena_ind); + did_dalloc = true; + return (true); /* Cause cascade. */ +} + +static bool +extent_decommit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t offset, size_t length, unsigned arena_ind) +{ + + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " + "length=%zu, arena_ind=%u)\n", __func__, extent_hooks, addr, size, + offset, length, arena_ind); + did_decommit = true; + return (true); /* Cause cascade. */ +} + +static bool +extent_purge_lazy_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t offset, size_t length, unsigned arena_ind) +{ + + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " + "length=%zu arena_ind=%u)\n", __func__, extent_hooks, addr, size, + offset, length, arena_ind); + did_purge_lazy = true; + return (true); /* Cause cascade. */ +} + +static bool +extent_purge_forced_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t offset, size_t length, unsigned arena_ind) +{ + + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " + "length=%zu arena_ind=%u)\n", __func__, extent_hooks, addr, size, + offset, length, arena_ind); + did_purge_forced = true; + return (true); /* Cause cascade. */ +} + +TEST_BEGIN(test_base_hooks_default) +{ + tsdn_t *tsdn; + base_t *base; + size_t allocated0, allocated1, resident, mapped; + + tsdn = tsdn_fetch(); + base = base_new(tsdn, 0, (extent_hooks_t *)&extent_hooks_default); + + base_stats_get(tsdn, base, &allocated0, &resident, &mapped); + assert_zu_ge(allocated0, sizeof(base_t), + "Base header should count as allocated"); + + assert_ptr_not_null(base_alloc(tsdn, base, 42, 1), + "Unexpected base_alloc() failure"); + + base_stats_get(tsdn, base, &allocated1, &resident, &mapped); + assert_zu_ge(allocated1 - allocated0, 42, + "At least 42 bytes were allocated by base_alloc()"); + + base_delete(base); +} +TEST_END + +TEST_BEGIN(test_base_hooks_null) +{ + tsdn_t *tsdn; + base_t *base; + size_t allocated0, allocated1, resident, mapped; + + tsdn = tsdn_fetch(); + base = base_new(tsdn, 0, (extent_hooks_t *)&hooks_null); + assert_ptr_not_null(base, "Unexpected base_new() failure"); + + base_stats_get(tsdn, base, &allocated0, &resident, &mapped); + assert_zu_ge(allocated0, sizeof(base_t), + "Base header should count as allocated"); + + assert_ptr_not_null(base_alloc(tsdn, base, 42, 1), + "Unexpected base_alloc() failure"); + + base_stats_get(tsdn, base, &allocated1, &resident, &mapped); + assert_zu_ge(allocated1 - allocated0, 42, + "At least 42 bytes were allocated by base_alloc()"); + + base_delete(base); +} +TEST_END + +TEST_BEGIN(test_base_hooks_not_null) +{ + tsdn_t *tsdn; + base_t *base; + void *p, *q, *r, *r_exp; + + tsdn = tsdn_fetch(); + did_alloc = false; + base = base_new(tsdn, 0, (extent_hooks_t *)&hooks_not_null); + assert_ptr_not_null(base, "Unexpected base_new() failure"); + assert_true(did_alloc, "Expected alloc hook call"); + + /* + * Check for tight packing at specified alignment under simple + * conditions. + */ + { + const size_t alignments[] = { + 1, + QUANTUM, + QUANTUM << 1, + CACHELINE, + CACHELINE << 1, + }; + unsigned i; + + for (i = 0; i < sizeof(alignments) / sizeof(size_t); i++) { + size_t alignment = alignments[i]; + size_t align_ceil = ALIGNMENT_CEILING(alignment, + QUANTUM); + p = base_alloc(tsdn, base, 1, alignment); + assert_ptr_not_null(p, + "Unexpected base_alloc() failure"); + assert_ptr_eq(p, + (void *)(ALIGNMENT_CEILING((uintptr_t)p, + alignment)), "Expected quantum alignment"); + q = base_alloc(tsdn, base, alignment, alignment); + assert_ptr_not_null(q, + "Unexpected base_alloc() failure"); + assert_ptr_eq((void *)((uintptr_t)p + align_ceil), q, + "Minimal allocation should take up %zu bytes", + align_ceil); + r = base_alloc(tsdn, base, 1, alignment); + assert_ptr_not_null(r, + "Unexpected base_alloc() failure"); + assert_ptr_eq((void *)((uintptr_t)q + align_ceil), r, + "Minimal allocation should take up %zu bytes", + align_ceil); + } + } + + /* + * Allocate an object that cannot fit in the first block, then verify + * that the first block's remaining space is considered for subsequent + * allocation. + */ + assert_zu_ge(extent_size_get(&base->blocks->extent), QUANTUM, + "Remainder insufficient for test"); + /* Use up all but one quantum of block. */ + while (extent_size_get(&base->blocks->extent) > QUANTUM) { + p = base_alloc(tsdn, base, QUANTUM, QUANTUM); + assert_ptr_not_null(p, "Unexpected base_alloc() failure"); + } + r_exp = extent_addr_get(&base->blocks->extent); + assert_zu_eq(base->extent_sn_next, 1, "One extant block expected"); + q = base_alloc(tsdn, base, QUANTUM + 1, QUANTUM); + assert_ptr_not_null(q, "Unexpected base_alloc() failure"); + assert_ptr_ne(q, r_exp, "Expected allocation from new block"); + assert_zu_eq(base->extent_sn_next, 2, "Two extant blocks expected"); + r = base_alloc(tsdn, base, QUANTUM, QUANTUM); + assert_ptr_not_null(r, "Unexpected base_alloc() failure"); + assert_ptr_eq(r, r_exp, "Expected allocation from first block"); + assert_zu_eq(base->extent_sn_next, 2, "Two extant blocks expected"); + + /* + * Check for proper alignment support when normal blocks are too small. + */ + { + const size_t alignments[] = { + HUGEPAGE, + HUGEPAGE << 1 + }; + unsigned i; + + for (i = 0; i < sizeof(alignments) / sizeof(size_t); i++) { + size_t alignment = alignments[i]; + p = base_alloc(tsdn, base, QUANTUM, alignment); + assert_ptr_not_null(p, + "Unexpected base_alloc() failure"); + assert_ptr_eq(p, + (void *)(ALIGNMENT_CEILING((uintptr_t)p, + alignment)), "Expected %zu-byte alignment", + alignment); + } + } + + did_dalloc = did_decommit = did_purge_lazy = did_purge_forced = false; + base_delete(base); + assert_true(did_dalloc, "Expected dalloc hook call"); + assert_true(did_decommit, "Expected decommit hook call"); + assert_true(did_purge_lazy, "Expected purge_lazy hook call"); + assert_true(did_purge_forced, "Expected purge_forced hook call"); +} +TEST_END + +int +main(void) +{ + + return (test( + test_base_hooks_default, + test_base_hooks_null, + test_base_hooks_not_null)); +} -- GitLab From 5c5ff8d121e1f8389d18dfe22912739b99e893a8 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 4 Jan 2017 20:09:03 -0800 Subject: [PATCH 210/544] Fix arena_large_reset_stats_cancel(). Decrement ndalloc_large rather than incrementing, in order to cancel out the increment in arena_large_dalloc_stats_update(). --- src/arena.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arena.c b/src/arena.c index d5e87ead..2c3cc5ca 100644 --- a/src/arena.c +++ b/src/arena.c @@ -260,7 +260,7 @@ arena_large_reset_stats_cancel(arena_t *arena, size_t usize) cassert(config_stats); - arena->stats.ndalloc_large++; + arena->stats.ndalloc_large--; arena->stats.lstats[hindex].ndalloc--; } -- GitLab From 363629df88fc9d32cd4efbcc3c1a3eef1bbfe525 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 6 Jan 2017 18:56:02 -0800 Subject: [PATCH 211/544] Fix allocated_large stats with respect to sampled small allocations. --- src/arena.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/arena.c b/src/arena.c index 2c3cc5ca..ec8d4790 100644 --- a/src/arena.c +++ b/src/arena.c @@ -211,11 +211,15 @@ arena_nactive_sub(arena_t *arena, size_t sub_pages) static void arena_large_malloc_stats_update(arena_t *arena, size_t usize) { - szind_t index = size2index(usize); - szind_t hindex = (index >= NBINS) ? index - NBINS : 0; + szind_t index, hindex; cassert(config_stats); + if (usize < LARGE_MINCLASS) + usize = LARGE_MINCLASS; + index = size2index(usize); + hindex = (index >= NBINS) ? index - NBINS : 0; + arena->stats.nmalloc_large++; arena->stats.allocated_large += usize; arena->stats.lstats[hindex].nmalloc++; @@ -226,11 +230,15 @@ arena_large_malloc_stats_update(arena_t *arena, size_t usize) static void arena_large_malloc_stats_update_undo(arena_t *arena, size_t usize) { - szind_t index = size2index(usize); - szind_t hindex = (index >= NBINS) ? index - NBINS : 0; + szind_t index, hindex; cassert(config_stats); + if (usize < LARGE_MINCLASS) + usize = LARGE_MINCLASS; + index = size2index(usize); + hindex = (index >= NBINS) ? index - NBINS : 0; + arena->stats.nmalloc_large--; arena->stats.allocated_large -= usize; arena->stats.lstats[hindex].nmalloc--; @@ -241,11 +249,15 @@ arena_large_malloc_stats_update_undo(arena_t *arena, size_t usize) static void arena_large_dalloc_stats_update(arena_t *arena, size_t usize) { - szind_t index = size2index(usize); - szind_t hindex = (index >= NBINS) ? index - NBINS : 0; + szind_t index, hindex; cassert(config_stats); + if (usize < LARGE_MINCLASS) + usize = LARGE_MINCLASS; + index = size2index(usize); + hindex = (index >= NBINS) ? index - NBINS : 0; + arena->stats.ndalloc_large++; arena->stats.allocated_large -= usize; arena->stats.lstats[hindex].ndalloc++; -- GitLab From d0a3129b8809b9f049dd0a0f8e7921d79cddc104 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 6 Jan 2017 18:57:18 -0800 Subject: [PATCH 212/544] Fix locking in arena_dirty_count(). This was a latent bug, since the function is (intentionally) not used. --- src/arena.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/arena.c b/src/arena.c index ec8d4790..3c31cc87 100644 --- a/src/arena.c +++ b/src/arena.c @@ -639,12 +639,14 @@ arena_dirty_count(tsdn_t *tsdn, arena_t *arena) extent_t *extent; size_t ndirty = 0; - malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); + malloc_mutex_lock(tsdn, &arena->extents_mtx); for (extent = qr_next(&arena->extents_dirty, qr_link); extent != &arena->extents_dirty; extent = qr_next(extent, qr_link)) ndirty += extent_size_get(extent) >> LG_PAGE; + malloc_mutex_unlock(tsdn, &arena->extents_mtx); + return (ndirty); } -- GitLab From 027ace8519eb4ed736568082cc7e96b3f9423de8 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 27 Dec 2016 19:16:41 -0800 Subject: [PATCH 213/544] Reindent. --- include/jemalloc/jemalloc_macros.h.in | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/jemalloc/jemalloc_macros.h.in b/include/jemalloc/jemalloc_macros.h.in index 673ffd9b..f1a8049d 100644 --- a/include/jemalloc/jemalloc_macros.h.in +++ b/include/jemalloc/jemalloc_macros.h.in @@ -11,25 +11,25 @@ #define JEMALLOC_VERSION_NREV @jemalloc_version_nrev@ #define JEMALLOC_VERSION_GID "@jemalloc_version_gid@" -# define MALLOCX_LG_ALIGN(la) ((int)(la)) -# if LG_SIZEOF_PTR == 2 -# define MALLOCX_ALIGN(a) ((int)(ffs((int)(a))-1)) -# else -# define MALLOCX_ALIGN(a) \ - ((int)(((size_t)(a) < (size_t)INT_MAX) ? ffs((int)(a))-1 : \ - ffs((int)(((size_t)(a))>>32))+31)) -# endif -# define MALLOCX_ZERO ((int)0x40) +#define MALLOCX_LG_ALIGN(la) ((int)(la)) +#if LG_SIZEOF_PTR == 2 +# define MALLOCX_ALIGN(a) ((int)(ffs((int)(a))-1)) +#else +# define MALLOCX_ALIGN(a) \ + ((int)(((size_t)(a) < (size_t)INT_MAX) ? ffs((int)(a))-1 : \ + ffs((int)(((size_t)(a))>>32))+31)) +#endif +#define MALLOCX_ZERO ((int)0x40) /* * Bias tcache index bits so that 0 encodes "automatic tcache management", and 1 * encodes MALLOCX_TCACHE_NONE. */ -# define MALLOCX_TCACHE(tc) ((int)(((tc)+2) << 8)) -# define MALLOCX_TCACHE_NONE MALLOCX_TCACHE(-1) +#define MALLOCX_TCACHE(tc) ((int)(((tc)+2) << 8)) +#define MALLOCX_TCACHE_NONE MALLOCX_TCACHE(-1) /* * Bias arena index bits so that 0 encodes "use an automatically chosen arena". */ -# define MALLOCX_ARENA(a) ((((int)(a))+1) << 20) +#define MALLOCX_ARENA(a) ((((int)(a))+1) << 20) #if defined(__cplusplus) && defined(JEMALLOC_USE_CXX_THROW) # define JEMALLOC_CXX_THROW throw() -- GitLab From 3dc4e83ccb448436894fbbd0b46f126cff0c1416 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 3 Jan 2017 07:27:42 -0800 Subject: [PATCH 214/544] Add MALLCTL_ARENAS_ALL. Add the MALLCTL_ARENAS_ALL cpp macro as a fixed index for use in accessing the arena..{purge,decay,dss} and stats.arenas..* mallctls, and deprecate access via the arenas.narenas index (to be removed in 6.0.0). --- doc/jemalloc.xml.in | 37 +++-- include/jemalloc/internal/util.h | 4 + include/jemalloc/jemalloc_macros.h.in | 14 ++ src/ctl.c | 198 ++++++++++++++++---------- src/stats.c | 2 +- test/unit/mallctl.c | 8 ++ 6 files changed, 171 insertions(+), 92 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 5923481a..f6b50627 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -694,12 +694,22 @@ for (i = 0; i < nbins; i++) { any. A name element encoded as <i> or <j> indicates an integer component, where the integer varies from 0 to some upper value that must be determined via - introspection. In the case of stats.arenas.<i>.*, - <i> equal to arenas.narenas can be - used to access the summation of statistics from all arenas. Take special - note of the epoch mallctl, - which controls refreshing of cached dynamic statistics. + introspection. In the case of stats.arenas.<i>.* + and arena.<i>.{purge,decay,dss}, + <i> equal to + MALLCTL_ARENAS_ALL can be used to operate on all arenas + or access the summation of statistics from all arenas. This constant can be + utilized either via mallctlnametomib() followed by + mallctlbymib(), or via code such as the following: + + Take special note of the + epoch mallctl, which + controls refreshing of cached dynamic statistics. @@ -1422,8 +1432,7 @@ malloc_conf = "xmalloc:true";]]> -- Purge all unused dirty pages for arena <i>, or for - all arenas if <i> equals arenas.narenas. + all arenas if <i> equals MALLCTL_ARENAS_ALL. @@ -1434,10 +1443,9 @@ malloc_conf = "xmalloc:true";]]> -- Trigger decay-based purging of unused dirty pages for - arena <i>, or for all arenas if <i> equals arenas.narenas. - The proportion of unused dirty pages to be purged depends on the current - time; see MALLCTL_ARENAS_ALL. The proportion of unused dirty + pages to be purged depends on the current time; see opt.decay_time for details. @@ -1465,9 +1473,8 @@ malloc_conf = "xmalloc:true";]]> Set the precedence of dss allocation as related to mmap allocation for arena <i>, or for all arenas if <i> equals - arenas.narenas. See - opt.dss for supported + MALLCTL_ARENAS_ALL. See opt.dss for supported settings. diff --git a/include/jemalloc/internal/util.h b/include/jemalloc/internal/util.h index d9f97416..592806dc 100644 --- a/include/jemalloc/internal/util.h +++ b/include/jemalloc/internal/util.h @@ -54,6 +54,10 @@ */ #define JEMALLOC_ARG_CONCAT(...) __VA_ARGS__ +/* cpp macro definition stringification. */ +#define STRINGIFY_HELPER(x) #x +#define STRINGIFY(x) STRINGIFY_HELPER(x) + /* * Silence compiler warnings due to uninitialized values. This is used * wherever the compiler fails to recognize that the variable is never used diff --git a/include/jemalloc/jemalloc_macros.h.in b/include/jemalloc/jemalloc_macros.h.in index f1a8049d..ea41e2e8 100644 --- a/include/jemalloc/jemalloc_macros.h.in +++ b/include/jemalloc/jemalloc_macros.h.in @@ -31,6 +31,20 @@ */ #define MALLOCX_ARENA(a) ((((int)(a))+1) << 20) +/* + * Use as arena index in "arena..{purge,decay,dss}" and + * "stats.arenas..*" mallctl interfaces to select all arenas. This + * definition is intentionally specified in raw decimal format to support + * cpp-based string concatenation, e.g. + * + * #define STRINGIFY_HELPER(x) #x + * #define STRINGIFY(x) STRINGIFY_HELPER(x) + * + * mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".purge", NULL, NULL, NULL, + * 0); + */ +#define MALLCTL_ARENAS_ALL 4096 + #if defined(__cplusplus) && defined(JEMALLOC_USE_CXX_THROW) # define JEMALLOC_CXX_THROW throw() #else diff --git a/src/ctl.c b/src/ctl.c index 964896ab..4e5511e4 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -443,6 +443,51 @@ static const ctl_named_node_t super_root_node[] = { /******************************************************************************/ +static unsigned +stats_arenas_i2a_impl(size_t i, bool compat, bool validate) +{ + unsigned a; + + cassert(config_stats); + + switch (i) { + case MALLCTL_ARENAS_ALL: + a = 0; + break; + default: + if (compat && i == ctl_stats.narenas) { + /* + * Provide deprecated backward compatibility for + * accessing the merged stats at index narenas rather + * than via MALLCTL_ARENAS_ALL. This is scheduled for + * removal in 6.0.0. + */ + a = 0; + } else if (validate && i >= ctl_stats.narenas) + a = UINT_MAX; + else { + /* + * This function should never be called for an index + * more than one past the range of indices that have + * initialized stats. + */ + assert(i < ctl_stats.narenas || (!validate && i == + ctl_stats.narenas)); + a = (unsigned)i + 1; + } + break; + } + + return (a); +} + +static ctl_arena_stats_t * +stats_arenas_i(size_t i) +{ + + return (&ctl_stats.arenas[stats_arenas_i2a_impl(i, true, false)]); +} + static void ctl_arena_clear(ctl_arena_stats_t *astats) { @@ -552,8 +597,8 @@ ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats) static void ctl_arena_refresh(tsdn_t *tsdn, arena_t *arena, unsigned i) { - ctl_arena_stats_t *astats = &ctl_stats.arenas[i]; - ctl_arena_stats_t *sstats = &ctl_stats.arenas[ctl_stats.narenas]; + ctl_arena_stats_t *astats = stats_arenas_i(i); + ctl_arena_stats_t *sstats = stats_arenas_i(MALLCTL_ARENAS_ALL); ctl_arena_clear(astats); ctl_arena_stats_amerge(tsdn, astats, arena); @@ -580,16 +625,6 @@ ctl_grow(tsdn_t *tsdn, extent_hooks_t *extent_hooks) memcpy(astats, ctl_stats.arenas, (ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t)); memset(&astats[ctl_stats.narenas + 1], 0, sizeof(ctl_arena_stats_t)); - /* Swap merged stats to their new location. */ - { - ctl_arena_stats_t tstats; - memcpy(&tstats, &astats[ctl_stats.narenas], - sizeof(ctl_arena_stats_t)); - memcpy(&astats[ctl_stats.narenas], - &astats[ctl_stats.narenas + 1], sizeof(ctl_arena_stats_t)); - memcpy(&astats[ctl_stats.narenas + 1], &tstats, - sizeof(ctl_arena_stats_t)); - } a0dalloc(ctl_stats.arenas); ctl_stats.arenas = astats; ctl_stats.narenas++; @@ -601,40 +636,36 @@ static void ctl_refresh(tsdn_t *tsdn) { unsigned i; + ctl_arena_stats_t *sstats = stats_arenas_i(MALLCTL_ARENAS_ALL); VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas); /* * Clear sum stats, since they will be merged into by * ctl_arena_refresh(). */ - ctl_arena_clear(&ctl_stats.arenas[ctl_stats.narenas]); + ctl_arena_clear(sstats); for (i = 0; i < ctl_stats.narenas; i++) tarenas[i] = arena_get(tsdn, i, false); for (i = 0; i < ctl_stats.narenas; i++) { + ctl_arena_stats_t *astats = stats_arenas_i(i); bool initialized = (tarenas[i] != NULL); - ctl_stats.arenas[i].initialized = initialized; + astats->initialized = initialized; if (initialized) ctl_arena_refresh(tsdn, tarenas[i], i); } if (config_stats) { - ctl_stats.allocated = - ctl_stats.arenas[ctl_stats.narenas].allocated_small + - ctl_stats.arenas[ctl_stats.narenas].astats.allocated_large; - ctl_stats.active = - (ctl_stats.arenas[ctl_stats.narenas].pactive << LG_PAGE); - ctl_stats.metadata = - ctl_stats.arenas[ctl_stats.narenas].astats.base + - ctl_stats.arenas[ctl_stats.narenas].astats.internal; - ctl_stats.resident = - ctl_stats.arenas[ctl_stats.narenas].astats.resident; - ctl_stats.mapped = - ctl_stats.arenas[ctl_stats.narenas].astats.mapped; - ctl_stats.retained = - ctl_stats.arenas[ctl_stats.narenas].astats.retained; + ctl_stats.allocated = sstats->allocated_small + + sstats->astats.allocated_large; + ctl_stats.active = (sstats->pactive << LG_PAGE); + ctl_stats.metadata = sstats->astats.base + + sstats->astats.internal; + ctl_stats.resident = sstats->astats.resident; + ctl_stats.mapped = sstats->astats.mapped; + ctl_stats.retained = sstats->astats.retained; } ctl_epoch++; @@ -660,7 +691,7 @@ ctl_init(tsdn_t *tsdn) } memset(ctl_stats.arenas, 0, (ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t)); - ctl_stats.arenas[ctl_stats.narenas].initialized = true; + stats_arenas_i(MALLCTL_ARENAS_ALL)->initialized = true; ctl_epoch = 0; ctl_refresh(tsdn); @@ -1399,7 +1430,11 @@ arena_i_purge(tsdn_t *tsdn, unsigned arena_ind, bool all) { unsigned narenas = ctl_stats.narenas; - if (arena_ind == narenas) { + /* + * Access via index narenas is deprecated, and scheduled for + * removal in 6.0.0. + */ + if (arena_ind == MALLCTL_ARENAS_ALL || arena_ind == narenas) { unsigned i; VARIABLE_ARRAY(arena_t *, tarenas, narenas); @@ -1482,6 +1517,10 @@ arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, assert(arena_ind >= opt_narenas); arena = arena_get(tsd_tsdn(tsd), arena_ind, false); + if (arena == NULL) { + ret = EFAULT; + goto label_return; + } arena_reset(tsd, arena); @@ -1520,21 +1559,25 @@ arena_i_dss_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, } } - if (arena_ind < ctl_stats.narenas) { - arena_t *arena = arena_get(tsd_tsdn(tsd), arena_ind, false); - if (arena == NULL || (dss_prec != dss_prec_limit && - arena_dss_prec_set(tsd_tsdn(tsd), arena, dss_prec))) { + /* + * Access via index narenas is deprecated, and scheduled for removal in + * 6.0.0. + */ + if (arena_ind == MALLCTL_ARENAS_ALL || arena_ind == ctl_stats.narenas) { + if (dss_prec != dss_prec_limit && + extent_dss_prec_set(dss_prec)) { ret = EFAULT; goto label_return; } - dss_prec_old = arena_dss_prec_get(tsd_tsdn(tsd), arena); + dss_prec_old = extent_dss_prec_get(); } else { - if (dss_prec != dss_prec_limit && - extent_dss_prec_set(dss_prec)) { + arena_t *arena = arena_get(tsd_tsdn(tsd), arena_ind, false); + if (arena == NULL || (dss_prec != dss_prec_limit && + arena_dss_prec_set(tsd_tsdn(tsd), arena, dss_prec))) { ret = EFAULT; goto label_return; } - dss_prec_old = extent_dss_prec_get(); + dss_prec_old = arena_dss_prec_get(tsd_tsdn(tsd), arena); } dss = dss_prec_names[dss_prec_old]; @@ -1621,7 +1664,7 @@ arena_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) const ctl_named_node_t *ret; malloc_mutex_lock(tsdn, &ctl_mtx); - if (i > ctl_stats.narenas) { + if (i > ctl_stats.narenas && i != MALLCTL_ARENAS_ALL) { ret = NULL; goto label_return; } @@ -1675,7 +1718,7 @@ arenas_initialized_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, } for (i = 0; i < nread; i++) - ((bool *)oldp)[i] = ctl_stats.arenas[i].initialized; + ((bool *)oldp)[i] = stats_arenas_i(i)->initialized; label_return: malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); @@ -1896,64 +1939,65 @@ CTL_RO_CGEN(config_stats, stats_resident, ctl_stats.resident, size_t) CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats.mapped, size_t) CTL_RO_CGEN(config_stats, stats_retained, ctl_stats.retained, size_t) -CTL_RO_GEN(stats_arenas_i_dss, ctl_stats.arenas[mib[2]].dss, const char *) -CTL_RO_GEN(stats_arenas_i_decay_time, ctl_stats.arenas[mib[2]].decay_time, +CTL_RO_GEN(stats_arenas_i_dss, stats_arenas_i(mib[2])->dss, const char *) +CTL_RO_GEN(stats_arenas_i_decay_time, stats_arenas_i(mib[2])->decay_time, ssize_t) -CTL_RO_GEN(stats_arenas_i_nthreads, ctl_stats.arenas[mib[2]].nthreads, unsigned) -CTL_RO_GEN(stats_arenas_i_pactive, ctl_stats.arenas[mib[2]].pactive, size_t) -CTL_RO_GEN(stats_arenas_i_pdirty, ctl_stats.arenas[mib[2]].pdirty, size_t) +CTL_RO_GEN(stats_arenas_i_nthreads, stats_arenas_i(mib[2])->nthreads, + unsigned) +CTL_RO_GEN(stats_arenas_i_pactive, stats_arenas_i(mib[2])->pactive, size_t) +CTL_RO_GEN(stats_arenas_i_pdirty, stats_arenas_i(mib[2])->pdirty, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_mapped, - ctl_stats.arenas[mib[2]].astats.mapped, size_t) + stats_arenas_i(mib[2])->astats.mapped, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_retained, - ctl_stats.arenas[mib[2]].astats.retained, size_t) + stats_arenas_i(mib[2])->astats.retained, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_npurge, - ctl_stats.arenas[mib[2]].astats.npurge, uint64_t) + stats_arenas_i(mib[2])->astats.npurge, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise, - ctl_stats.arenas[mib[2]].astats.nmadvise, uint64_t) + stats_arenas_i(mib[2])->astats.nmadvise, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_purged, - ctl_stats.arenas[mib[2]].astats.purged, uint64_t) + stats_arenas_i(mib[2])->astats.purged, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_base, - ctl_stats.arenas[mib[2]].astats.base, size_t) + stats_arenas_i(mib[2])->astats.base, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_internal, - ctl_stats.arenas[mib[2]].astats.internal, size_t) + stats_arenas_i(mib[2])->astats.internal, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_resident, - ctl_stats.arenas[mib[2]].astats.resident, size_t) + stats_arenas_i(mib[2])->astats.resident, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated, - ctl_stats.arenas[mib[2]].allocated_small, size_t) + stats_arenas_i(mib[2])->allocated_small, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_small_nmalloc, - ctl_stats.arenas[mib[2]].nmalloc_small, uint64_t) + stats_arenas_i(mib[2])->nmalloc_small, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc, - ctl_stats.arenas[mib[2]].ndalloc_small, uint64_t) + stats_arenas_i(mib[2])->ndalloc_small, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests, - ctl_stats.arenas[mib[2]].nrequests_small, uint64_t) + stats_arenas_i(mib[2])->nrequests_small, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated, - ctl_stats.arenas[mib[2]].astats.allocated_large, size_t) + stats_arenas_i(mib[2])->astats.allocated_large, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc, - ctl_stats.arenas[mib[2]].astats.nmalloc_large, uint64_t) + stats_arenas_i(mib[2])->astats.nmalloc_large, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc, - ctl_stats.arenas[mib[2]].astats.ndalloc_large, uint64_t) + stats_arenas_i(mib[2])->astats.ndalloc_large, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests, - ctl_stats.arenas[mib[2]].astats.nmalloc_large, uint64_t) /* Intentional. */ + stats_arenas_i(mib[2])->astats.nmalloc_large, uint64_t) /* Intentional. */ CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc, - ctl_stats.arenas[mib[2]].bstats[mib[4]].nmalloc, uint64_t) + stats_arenas_i(mib[2])->bstats[mib[4]].nmalloc, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_ndalloc, - ctl_stats.arenas[mib[2]].bstats[mib[4]].ndalloc, uint64_t) + stats_arenas_i(mib[2])->bstats[mib[4]].ndalloc, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nrequests, - ctl_stats.arenas[mib[2]].bstats[mib[4]].nrequests, uint64_t) + stats_arenas_i(mib[2])->bstats[mib[4]].nrequests, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curregs, - ctl_stats.arenas[mib[2]].bstats[mib[4]].curregs, size_t) + stats_arenas_i(mib[2])->bstats[mib[4]].curregs, size_t) CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nfills, - ctl_stats.arenas[mib[2]].bstats[mib[4]].nfills, uint64_t) + stats_arenas_i(mib[2])->bstats[mib[4]].nfills, uint64_t) CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nflushes, - ctl_stats.arenas[mib[2]].bstats[mib[4]].nflushes, uint64_t) + stats_arenas_i(mib[2])->bstats[mib[4]].nflushes, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nslabs, - ctl_stats.arenas[mib[2]].bstats[mib[4]].nslabs, uint64_t) + stats_arenas_i(mib[2])->bstats[mib[4]].nslabs, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreslabs, - ctl_stats.arenas[mib[2]].bstats[mib[4]].reslabs, uint64_t) + stats_arenas_i(mib[2])->bstats[mib[4]].reslabs, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curslabs, - ctl_stats.arenas[mib[2]].bstats[mib[4]].curslabs, size_t) + stats_arenas_i(mib[2])->bstats[mib[4]].curslabs, size_t) static const ctl_named_node_t * stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, @@ -1966,13 +2010,13 @@ stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, } CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nmalloc, - ctl_stats.arenas[mib[2]].lstats[mib[4]].nmalloc, uint64_t) + stats_arenas_i(mib[2])->lstats[mib[4]].nmalloc, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_ndalloc, - ctl_stats.arenas[mib[2]].lstats[mib[4]].ndalloc, uint64_t) + stats_arenas_i(mib[2])->lstats[mib[4]].ndalloc, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nrequests, - ctl_stats.arenas[mib[2]].lstats[mib[4]].nrequests, uint64_t) + stats_arenas_i(mib[2])->lstats[mib[4]].nrequests, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_curlextents, - ctl_stats.arenas[mib[2]].lstats[mib[4]].curlextents, size_t) + stats_arenas_i(mib[2])->lstats[mib[4]].curlextents, size_t) static const ctl_named_node_t * stats_arenas_i_lextents_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, @@ -1987,10 +2031,12 @@ stats_arenas_i_lextents_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, static const ctl_named_node_t * stats_arenas_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { - const ctl_named_node_t * ret; + const ctl_named_node_t *ret; + size_t a; malloc_mutex_lock(tsdn, &ctl_mtx); - if (i > ctl_stats.narenas || !ctl_stats.arenas[i].initialized) { + a = stats_arenas_i2a_impl(i, true, true); + if (a == UINT_MAX || !ctl_stats.arenas[a].initialized) { ret = NULL; goto label_return; } diff --git a/src/stats.c b/src/stats.c index 0a3deaaa..ad7d7ba4 100644 --- a/src/stats.c +++ b/src/stats.c @@ -841,7 +841,7 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, "\nMerged arenas stats:\n"); } stats_arena_print(write_cb, cbopaque, json, - narenas, bins, large); + MALLCTL_ARENAS_ALL, bins, large); if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t\t}%s\n", (ninitialized > 1) ? diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 5073c7b1..e0efdce1 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -402,6 +402,10 @@ TEST_BEGIN(test_arena_i_purge) mib[1] = narenas; assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, "Unexpected mallctlbymib() failure"); + + mib[1] = MALLCTL_ARENAS_ALL; + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, + "Unexpected mallctlbymib() failure"); } TEST_END @@ -422,6 +426,10 @@ TEST_BEGIN(test_arena_i_decay) mib[1] = narenas; assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, "Unexpected mallctlbymib() failure"); + + mib[1] = MALLCTL_ARENAS_ALL; + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, + "Unexpected mallctlbymib() failure"); } TEST_END -- GitLab From 0f04bb1d6fc27c7fa5f6268d045c78bdc600ff65 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 3 Jan 2017 08:21:29 -0800 Subject: [PATCH 215/544] Rename the arenas.extend mallctl to arenas.create. --- doc/jemalloc.xml.in | 18 +++++++++--------- include/jemalloc/internal/arena.h | 6 +++--- src/ctl.c | 6 +++--- src/jemalloc.c | 2 +- test/integration/MALLOCX_ARENA.c | 4 ++-- test/integration/extent.c | 4 ++-- test/integration/xallocx.c | 2 +- test/unit/arena_reset.c | 2 +- test/unit/mallctl.c | 6 +++--- test/unit/pack.c | 8 ++++---- 10 files changed, 29 insertions(+), 29 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index f6b50627..36aae37c 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -1457,8 +1457,8 @@ malloc_conf = "xmalloc:true";]]> -- Discard all of the arena's extant allocations. This - interface can only be used with arenas created via arenas.extend. None + interface can only be used with arenas explicitly created via arenas.create. None of the arena's discarded/cached allocations may accessed afterward. As part of this requirement, all thread caches which were used to allocate/deallocate in conjunction with the arena must be flushed @@ -1504,8 +1504,8 @@ malloc_conf = "xmalloc:true";]]> arena <i>. The functions must be capable of operating on all extant extents associated with arena <i>, usually by passing unknown extents to the replaced functions. In practice, it is feasible - to control allocation for arenas created via arenas.extend such + to control allocation for arenas explicitly created via arenas.create such that all extents originate from an application-supplied extent allocator (by specifying the custom extent hook functions during arena creation), but the automatically created arenas will have already created extents @@ -1836,15 +1836,15 @@ struct extent_hooks_s { class. - + - arenas.extend + arenas.create (unsigned, extent_hooks_t *) rw - Extend the array of arenas by appending a new arena with - optionally specified extent hooks, and returning the new arena - index. + Explicitly create a new arena outside the range of + automatically managed arenas, with optionally specified extent hooks, + and return the new arena index. diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index d889852e..929adbe9 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -148,9 +148,9 @@ struct arena_s { * atomic operations. Each thread has two distinct assignments, one for * application-serving allocation, and the other for internal metadata * allocation. Internal metadata must not be allocated from arenas - * created via the arenas.extend mallctl, because the arena..reset - * mallctl indiscriminately discards all allocations for the affected - * arena. + * explicitly created via the arenas.create mallctl, because the + * arena..reset mallctl indiscriminately discards all allocations for + * the affected arena. * * 0: Application allocation. * 1: Internal metadata allocation. diff --git a/src/ctl.c b/src/ctl.c index 4e5511e4..872da80f 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -133,7 +133,7 @@ CTL_PROTO(arenas_tcache_max) CTL_PROTO(arenas_nbins) CTL_PROTO(arenas_nhbins) CTL_PROTO(arenas_nlextents) -CTL_PROTO(arenas_extend) +CTL_PROTO(arenas_create) CTL_PROTO(prof_thread_active_init) CTL_PROTO(prof_active) CTL_PROTO(prof_dump) @@ -323,7 +323,7 @@ static const ctl_named_node_t arenas_node[] = { {NAME("bin"), CHILD(indexed, arenas_bin)}, {NAME("nlextents"), CTL(arenas_nlextents)}, {NAME("lextent"), CHILD(indexed, arenas_lextent)}, - {NAME("extend"), CTL(arenas_extend)} + {NAME("create"), CTL(arenas_create)} }; static const ctl_named_node_t prof_node[] = { @@ -1780,7 +1780,7 @@ arenas_lextent_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) } static int -arenas_extend_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, +arenas_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; diff --git a/src/jemalloc.c b/src/jemalloc.c index 2c49401f..2acab412 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -533,7 +533,7 @@ arena_tdata_get_hard(tsd_t *tsd, unsigned ind) * Copy to tdata array. It's possible that the actual number of arenas * has increased since narenas_total_get() was called above, but that * causes no correctness issues unless two threads concurrently execute - * the arenas.extend mallctl, which we trust mallctl synchronization to + * the arenas.create mallctl, which we trust mallctl synchronization to * prevent. */ diff --git a/test/integration/MALLOCX_ARENA.c b/test/integration/MALLOCX_ARENA.c index 910a096f..58032da8 100644 --- a/test/integration/MALLOCX_ARENA.c +++ b/test/integration/MALLOCX_ARENA.c @@ -19,8 +19,8 @@ thd_start(void *arg) size_t sz; sz = sizeof(arena_ind); - assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, NULL, 0), - 0, "Error in arenas.extend"); + assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), + 0, "Error in arenas.create"); if (thread_ind % 4 != 3) { size_t mib[3]; diff --git a/test/integration/extent.c b/test/integration/extent.c index e2bd0054..6be3b836 100644 --- a/test/integration/extent.c +++ b/test/integration/extent.c @@ -292,7 +292,7 @@ TEST_BEGIN(test_extent_manual_hook) size_t hooks_miblen; sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, NULL, 0), + assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); /* Install custom extent hooks. */ @@ -354,7 +354,7 @@ TEST_BEGIN(test_extent_auto_hook) sz = sizeof(unsigned); new_size = sizeof(extent_hooks_t *); - assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, + assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, (void *)&new_hooks, new_size), 0, "Unexpected mallctl() failure"); test_extent_body(arena_ind); diff --git a/test/integration/xallocx.c b/test/integration/xallocx.c index f6083728..d35ca39e 100644 --- a/test/integration/xallocx.c +++ b/test/integration/xallocx.c @@ -16,7 +16,7 @@ arena_ind(void) if (ind == 0) { size_t sz = sizeof(ind); - assert_d_eq(mallctl("arenas.extend", (void *)&ind, &sz, NULL, + assert_d_eq(mallctl("arenas.create", (void *)&ind, &sz, NULL, 0), 0, "Unexpected mallctl failure creating arena"); } diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 6c944b2e..3a1b30f5 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -90,7 +90,7 @@ TEST_BEGIN(test_arena_reset) tsdn_t *tsdn; sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, NULL, 0), + assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index e0efdce1..95c27753 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -584,14 +584,14 @@ TEST_BEGIN(test_arenas_lextent_constants) } TEST_END -TEST_BEGIN(test_arenas_extend) +TEST_BEGIN(test_arenas_create) { unsigned narenas_before, arena, narenas_after; size_t sz = sizeof(unsigned); assert_d_eq(mallctl("arenas.narenas", (void *)&narenas_before, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); - assert_d_eq(mallctl("arenas.extend", (void *)&arena, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arenas.create", (void *)&arena, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); assert_d_eq(mallctl("arenas.narenas", (void *)&narenas_after, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); @@ -647,6 +647,6 @@ main(void) test_arenas_constants, test_arenas_bin_constants, test_arenas_lextent_constants, - test_arenas_extend, + test_arenas_create, test_stats_arenas)); } diff --git a/test/unit/pack.c b/test/unit/pack.c index 10df08e3..81ded4ec 100644 --- a/test/unit/pack.c +++ b/test/unit/pack.c @@ -68,14 +68,14 @@ nregs_per_run_compute(void) } static unsigned -arenas_extend_mallctl(void) +arenas_create_mallctl(void) { unsigned arena_ind; size_t sz; sz = sizeof(arena_ind); - assert_d_eq(mallctl("arenas.extend", (void *)&arena_ind, &sz, NULL, 0), - 0, "Error in arenas.extend"); + assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), + 0, "Error in arenas.create"); return (arena_ind); } @@ -95,7 +95,7 @@ arena_reset_mallctl(unsigned arena_ind) TEST_BEGIN(test_pack) { - unsigned arena_ind = arenas_extend_mallctl(); + unsigned arena_ind = arenas_create_mallctl(); size_t nregs_per_run = nregs_per_run_compute(); size_t nregs = nregs_per_run * NSLABS; VARIABLE_ARRAY(void *, ptrs, nregs); -- GitLab From d778dd2afcc338cfd521c01382b8ed84a466aa1a Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 3 Jan 2017 12:40:54 -0800 Subject: [PATCH 216/544] Refactor ctl_stats_t. Refactor ctl_stats_t to be a demand-zeroed non-growing data structure. To keep the size from being onerous (~60 MiB) on 32-bit systems, convert the arenas field to contain pointers rather than directly embedded ctl_arena_stats_t elements. --- include/jemalloc/internal/ctl.h | 2 +- .../jemalloc/internal/jemalloc_internal.h.in | 21 ++- src/ctl.c | 149 +++++++++++------- 3 files changed, 106 insertions(+), 66 deletions(-) diff --git a/include/jemalloc/internal/ctl.h b/include/jemalloc/internal/ctl.h index 4d4f3043..dfb1e8ef 100644 --- a/include/jemalloc/internal/ctl.h +++ b/include/jemalloc/internal/ctl.h @@ -61,7 +61,7 @@ struct ctl_stats_s { size_t mapped; size_t retained; unsigned narenas; - ctl_arena_stats_t *arenas; /* (narenas + 1) elements. */ + ctl_arena_stats_t *arenas[1 << MALLOCX_ARENA_BITS]; }; #endif /* JEMALLOC_H_STRUCTS */ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 11a27366..991c541f 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -208,11 +208,18 @@ typedef unsigned szind_t; * * aaaaaaaa aaaatttt tttttttt 0znnnnnn */ -#define MALLOCX_ARENA_MASK ((int)~0xfffff) -#define MALLOCX_ARENA_MAX 0xffe -#define MALLOCX_TCACHE_MASK ((int)~0xfff000ffU) -#define MALLOCX_TCACHE_MAX 0xffd -#define MALLOCX_LG_ALIGN_MASK ((int)0x3f) +#define MALLOCX_ARENA_BITS 12 +#define MALLOCX_TCACHE_BITS 12 +#define MALLOCX_LG_ALIGN_BITS 6 +#define MALLOCX_ARENA_SHIFT 20 +#define MALLOCX_TCACHE_SHIFT 8 +#define MALLOCX_ARENA_MASK \ + (((1 << MALLOCX_ARENA_BITS) - 1) << MALLOCX_ARENA_SHIFT) +#define MALLOCX_ARENA_MAX ((1 << MALLOCX_ARENA_BITS) - 2) +#define MALLOCX_TCACHE_MASK \ + (((1 << MALLOCX_TCACHE_BITS) - 1) << MALLOCX_TCACHE_SHIFT) +#define MALLOCX_TCACHE_MAX ((1 << MALLOCX_TCACHE_BITS) - 3) +#define MALLOCX_LG_ALIGN_MASK ((1 << MALLOCX_LG_ALIGN_BITS) - 1) /* Use MALLOCX_ALIGN_GET() if alignment may not be specified in flags. */ #define MALLOCX_ALIGN_GET_SPECIFIED(flags) \ (ZU(1) << (flags & MALLOCX_LG_ALIGN_MASK)) @@ -222,9 +229,9 @@ typedef unsigned szind_t; ((bool)(flags & MALLOCX_ZERO)) #define MALLOCX_TCACHE_GET(flags) \ - (((unsigned)((flags & MALLOCX_TCACHE_MASK) >> 8)) - 2) + (((unsigned)((flags & MALLOCX_TCACHE_MASK) >> MALLOCX_TCACHE_SHIFT)) - 2) #define MALLOCX_ARENA_GET(flags) \ - (((unsigned)(((unsigned)flags) >> 20)) - 1) + (((unsigned)(((unsigned)flags) >> MALLOCX_ARENA_SHIFT)) - 1) /* Smallest size class to support. */ #define TINY_MIN (1U << LG_TINY_MIN) diff --git a/src/ctl.c b/src/ctl.c index 872da80f..d5b384c0 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -6,12 +6,12 @@ /* * ctl_mtx protects the following: - * - ctl_stats.* + * - ctl_stats->* */ static malloc_mutex_t ctl_mtx; static bool ctl_initialized; static uint64_t ctl_epoch; -static ctl_stats_t ctl_stats; +static ctl_stats_t *ctl_stats; /******************************************************************************/ /* Helpers for named and indexed nodes. */ @@ -455,7 +455,7 @@ stats_arenas_i2a_impl(size_t i, bool compat, bool validate) a = 0; break; default: - if (compat && i == ctl_stats.narenas) { + if (compat && i == ctl_stats->narenas) { /* * Provide deprecated backward compatibility for * accessing the merged stats at index narenas rather @@ -463,7 +463,7 @@ stats_arenas_i2a_impl(size_t i, bool compat, bool validate) * removal in 6.0.0. */ a = 0; - } else if (validate && i >= ctl_stats.narenas) + } else if (validate && i >= ctl_stats->narenas) a = UINT_MAX; else { /* @@ -471,8 +471,8 @@ stats_arenas_i2a_impl(size_t i, bool compat, bool validate) * more than one past the range of indices that have * initialized stats. */ - assert(i < ctl_stats.narenas || (!validate && i == - ctl_stats.narenas)); + assert(i < ctl_stats->narenas || (!validate && i == + ctl_stats->narenas)); a = (unsigned)i + 1; } break; @@ -482,10 +482,31 @@ stats_arenas_i2a_impl(size_t i, bool compat, bool validate) } static ctl_arena_stats_t * -stats_arenas_i(size_t i) +stats_arenas_i_impl(tsdn_t *tsdn, size_t i, bool compat, bool init) { + ctl_arena_stats_t *ret; + + assert(!compat || !init); + + ret = ctl_stats->arenas[stats_arenas_i2a_impl(i, compat, false)]; + if (init && ret == NULL) { + ret = (ctl_arena_stats_t *)base_alloc(tsdn, b0get(), + sizeof(ctl_arena_stats_t), QUANTUM); + if (ret == NULL) + return (NULL); + ctl_stats->arenas[stats_arenas_i2a_impl(i, compat, false)] = + ret; + } + + return (ret); +} - return (&ctl_stats.arenas[stats_arenas_i2a_impl(i, true, false)]); +static ctl_arena_stats_t * +stats_arenas_i(size_t i) +{ + ctl_arena_stats_t *ret = stats_arenas_i_impl(TSDN_NULL, i, true, false); + assert(ret != NULL); + return (ret); } static void @@ -609,25 +630,15 @@ ctl_arena_refresh(tsdn_t *tsdn, arena_t *arena, unsigned i) static bool ctl_grow(tsdn_t *tsdn, extent_hooks_t *extent_hooks) { - ctl_arena_stats_t *astats; - /* Initialize new arena. */ - if (arena_init(tsdn, ctl_stats.narenas, extent_hooks) == NULL) + /* Trigger stats allocation. */ + if (stats_arenas_i_impl(tsdn, ctl_stats->narenas, false, true) == NULL) return (true); - /* Allocate extended arena stats. */ - astats = (ctl_arena_stats_t *)a0malloc((ctl_stats.narenas + 2) * - sizeof(ctl_arena_stats_t)); - if (astats == NULL) + /* Initialize new arena. */ + if (arena_init(tsdn, ctl_stats->narenas, extent_hooks) == NULL) return (true); - - /* Initialize the new astats element. */ - memcpy(astats, ctl_stats.arenas, (ctl_stats.narenas + 1) * - sizeof(ctl_arena_stats_t)); - memset(&astats[ctl_stats.narenas + 1], 0, sizeof(ctl_arena_stats_t)); - a0dalloc(ctl_stats.arenas); - ctl_stats.arenas = astats; - ctl_stats.narenas++; + ctl_stats->narenas++; return (false); } @@ -637,7 +648,7 @@ ctl_refresh(tsdn_t *tsdn) { unsigned i; ctl_arena_stats_t *sstats = stats_arenas_i(MALLCTL_ARENAS_ALL); - VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas); + VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats->narenas); /* * Clear sum stats, since they will be merged into by @@ -645,10 +656,10 @@ ctl_refresh(tsdn_t *tsdn) */ ctl_arena_clear(sstats); - for (i = 0; i < ctl_stats.narenas; i++) + for (i = 0; i < ctl_stats->narenas; i++) tarenas[i] = arena_get(tsdn, i, false); - for (i = 0; i < ctl_stats.narenas; i++) { + for (i = 0; i < ctl_stats->narenas; i++) { ctl_arena_stats_t *astats = stats_arenas_i(i); bool initialized = (tarenas[i] != NULL); @@ -658,14 +669,14 @@ ctl_refresh(tsdn_t *tsdn) } if (config_stats) { - ctl_stats.allocated = sstats->allocated_small + + ctl_stats->allocated = sstats->allocated_small + sstats->astats.allocated_large; - ctl_stats.active = (sstats->pactive << LG_PAGE); - ctl_stats.metadata = sstats->astats.base + + ctl_stats->active = (sstats->pactive << LG_PAGE); + ctl_stats->metadata = sstats->astats.base + sstats->astats.internal; - ctl_stats.resident = sstats->astats.resident; - ctl_stats.mapped = sstats->astats.mapped; - ctl_stats.retained = sstats->astats.retained; + ctl_stats->resident = sstats->astats.resident; + ctl_stats->mapped = sstats->astats.mapped; + ctl_stats->retained = sstats->astats.retained; } ctl_epoch++; @@ -678,20 +689,41 @@ ctl_init(tsdn_t *tsdn) malloc_mutex_lock(tsdn, &ctl_mtx); if (!ctl_initialized) { + ctl_arena_stats_t *sstats; + unsigned i; + /* - * Allocate space for one extra arena stats element, which - * contains summed stats across all arenas. + * Allocate demand-zeroed space for pointers to the full range + * of supported arena indices. */ - ctl_stats.narenas = narenas_total_get(); - ctl_stats.arenas = (ctl_arena_stats_t *)a0malloc( - (ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t)); - if (ctl_stats.arenas == NULL) { + if (ctl_stats == NULL) { + ctl_stats = (ctl_stats_t *)base_alloc(tsdn, b0get(), + sizeof(ctl_stats_t), QUANTUM); + if (ctl_stats == NULL) { + ret = true; + goto label_return; + } + } + + /* + * Allocate space for the current full range of arenas here + * rather than doing it lazily elsewhere, in order to limit when + * OOM-caused errors can occur. + */ + if ((sstats = stats_arenas_i_impl(tsdn, MALLCTL_ARENAS_ALL, + false, true)) == NULL) { ret = true; goto label_return; } - memset(ctl_stats.arenas, 0, (ctl_stats.narenas + 1) * - sizeof(ctl_arena_stats_t)); - stats_arenas_i(MALLCTL_ARENAS_ALL)->initialized = true; + sstats->initialized = true; + + ctl_stats->narenas = narenas_total_get(); + for (i = 0; i < ctl_stats->narenas; i++) { + if (stats_arenas_i_impl(tsdn, i, false, true) == NULL) { + ret = true; + goto label_return; + } + } ctl_epoch = 0; ctl_refresh(tsdn); @@ -1428,7 +1460,7 @@ arena_i_purge(tsdn_t *tsdn, unsigned arena_ind, bool all) malloc_mutex_lock(tsdn, &ctl_mtx); { - unsigned narenas = ctl_stats.narenas; + unsigned narenas = ctl_stats->narenas; /* * Access via index narenas is deprecated, and scheduled for @@ -1511,7 +1543,7 @@ arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, arena_ind = (unsigned)mib[1]; if (config_debug) { malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); - assert(arena_ind < ctl_stats.narenas); + assert(arena_ind < ctl_stats->narenas); malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); } assert(arena_ind >= opt_narenas); @@ -1563,7 +1595,8 @@ arena_i_dss_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, * Access via index narenas is deprecated, and scheduled for removal in * 6.0.0. */ - if (arena_ind == MALLCTL_ARENAS_ALL || arena_ind == ctl_stats.narenas) { + if (arena_ind == MALLCTL_ARENAS_ALL || arena_ind == + ctl_stats->narenas) { if (dss_prec != dss_prec_limit && extent_dss_prec_set(dss_prec)) { ret = EFAULT; @@ -1664,7 +1697,7 @@ arena_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) const ctl_named_node_t *ret; malloc_mutex_lock(tsdn, &ctl_mtx); - if (i > ctl_stats.narenas && i != MALLCTL_ARENAS_ALL) { + if (i > ctl_stats->narenas && i != MALLCTL_ARENAS_ALL) { ret = NULL; goto label_return; } @@ -1690,7 +1723,7 @@ arenas_narenas_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = EINVAL; goto label_return; } - narenas = ctl_stats.narenas; + narenas = ctl_stats->narenas; READ(narenas, unsigned); ret = 0; @@ -1708,13 +1741,13 @@ arenas_initialized_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); READONLY(); - if (*oldlenp != ctl_stats.narenas * sizeof(bool)) { + if (*oldlenp != ctl_stats->narenas * sizeof(bool)) { ret = EINVAL; - nread = (*oldlenp < ctl_stats.narenas * sizeof(bool)) - ? (unsigned)(*oldlenp / sizeof(bool)) : ctl_stats.narenas; + nread = (*oldlenp < ctl_stats->narenas * sizeof(bool)) + ? (unsigned)(*oldlenp / sizeof(bool)) : ctl_stats->narenas; } else { ret = 0; - nread = ctl_stats.narenas; + nread = ctl_stats->narenas; } for (i = 0; i < nread; i++) @@ -1795,7 +1828,7 @@ arenas_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = EAGAIN; goto label_return; } - narenas = ctl_stats.narenas - 1; + narenas = ctl_stats->narenas - 1; READ(narenas, unsigned); ret = 0; @@ -1932,12 +1965,12 @@ CTL_RO_NL_CGEN(config_prof, lg_prof_sample, lg_prof_sample, size_t) /******************************************************************************/ -CTL_RO_CGEN(config_stats, stats_allocated, ctl_stats.allocated, size_t) -CTL_RO_CGEN(config_stats, stats_active, ctl_stats.active, size_t) -CTL_RO_CGEN(config_stats, stats_metadata, ctl_stats.metadata, size_t) -CTL_RO_CGEN(config_stats, stats_resident, ctl_stats.resident, size_t) -CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats.mapped, size_t) -CTL_RO_CGEN(config_stats, stats_retained, ctl_stats.retained, size_t) +CTL_RO_CGEN(config_stats, stats_allocated, ctl_stats->allocated, size_t) +CTL_RO_CGEN(config_stats, stats_active, ctl_stats->active, size_t) +CTL_RO_CGEN(config_stats, stats_metadata, ctl_stats->metadata, size_t) +CTL_RO_CGEN(config_stats, stats_resident, ctl_stats->resident, size_t) +CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats->mapped, size_t) +CTL_RO_CGEN(config_stats, stats_retained, ctl_stats->retained, size_t) CTL_RO_GEN(stats_arenas_i_dss, stats_arenas_i(mib[2])->dss, const char *) CTL_RO_GEN(stats_arenas_i_decay_time, stats_arenas_i(mib[2])->decay_time, @@ -2036,7 +2069,7 @@ stats_arenas_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) malloc_mutex_lock(tsdn, &ctl_mtx); a = stats_arenas_i2a_impl(i, true, true); - if (a == UINT_MAX || !ctl_stats.arenas[a].initialized) { + if (a == UINT_MAX || !ctl_stats->arenas[a]->initialized) { ret = NULL; goto label_return; } -- GitLab From c0a05e6abaca7d23c2cc225abb1b59a1160632a0 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 3 Jan 2017 15:09:50 -0800 Subject: [PATCH 217/544] Move static ctl_epoch variable into ctl_stats_t (as epoch). --- include/jemalloc/internal/ctl.h | 1 + src/ctl.c | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/jemalloc/internal/ctl.h b/include/jemalloc/internal/ctl.h index dfb1e8ef..8550bf10 100644 --- a/include/jemalloc/internal/ctl.h +++ b/include/jemalloc/internal/ctl.h @@ -54,6 +54,7 @@ struct ctl_arena_stats_s { }; struct ctl_stats_s { + uint64_t epoch; size_t allocated; size_t active; size_t metadata; diff --git a/src/ctl.c b/src/ctl.c index d5b384c0..d39edbf8 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -10,7 +10,6 @@ */ static malloc_mutex_t ctl_mtx; static bool ctl_initialized; -static uint64_t ctl_epoch; static ctl_stats_t *ctl_stats; /******************************************************************************/ @@ -679,7 +678,7 @@ ctl_refresh(tsdn_t *tsdn) ctl_stats->retained = sstats->astats.retained; } - ctl_epoch++; + ctl_stats->epoch++; } static bool @@ -725,7 +724,7 @@ ctl_init(tsdn_t *tsdn) } } - ctl_epoch = 0; + ctl_stats->epoch = 0; ctl_refresh(tsdn); ctl_initialized = true; } @@ -1169,7 +1168,7 @@ epoch_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, WRITE(newval, uint64_t); if (newp != NULL) ctl_refresh(tsd_tsdn(tsd)); - READ(ctl_epoch, uint64_t); + READ(ctl_stats->epoch, uint64_t); ret = 0; label_return: -- GitLab From 6edbedd9164d9b7682f7c3afb44e2b85c8eb52de Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 4 Jan 2017 07:51:49 -0800 Subject: [PATCH 218/544] Range-check mib[1] --> arena_ind casts. --- include/jemalloc/internal/ctl.h | 2 +- src/ctl.c | 29 ++++++++++++++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/include/jemalloc/internal/ctl.h b/include/jemalloc/internal/ctl.h index 8550bf10..0aa82541 100644 --- a/include/jemalloc/internal/ctl.h +++ b/include/jemalloc/internal/ctl.h @@ -19,7 +19,7 @@ struct ctl_named_node_s { struct ctl_node_s node; const char *name; /* If (nchildren == 0), this is a terminal node. */ - unsigned nchildren; + size_t nchildren; const ctl_node_t *children; int (*ctl)(tsd_t *, const size_t *, size_t, void *, size_t *, void *, size_t); diff --git a/src/ctl.c b/src/ctl.c index d39edbf8..0e7a09da 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -899,7 +899,7 @@ ctl_bymib(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, assert(node->nchildren > 0); if (ctl_named_node(node->children) != NULL) { /* Children are named. */ - if (node->nchildren <= (unsigned)mib[i]) { + if (node->nchildren <= mib[i]) { ret = ENOENT; goto label_return; } @@ -1010,6 +1010,14 @@ ctl_postfork_child(tsdn_t *tsdn) } \ } while (0) +#define MIB_UNSIGNED(v, i) do { \ + if (mib[i] > UINT_MAX) { \ + ret = EFAULT; \ + goto label_return; \ + } \ + v = (unsigned)mib[i]; \ +} while (0) + /* * There's a lot of code duplication in the following macros due to limitations * in how nested cpp macros are expanded. @@ -1503,10 +1511,12 @@ arena_i_purge_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; + unsigned arena_ind; READONLY(); WRITEONLY(); - arena_i_purge(tsd_tsdn(tsd), (unsigned)mib[1], true); + MIB_UNSIGNED(arena_ind, 1); + arena_i_purge(tsd_tsdn(tsd), arena_ind, true); ret = 0; label_return: @@ -1518,10 +1528,12 @@ arena_i_decay_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; + unsigned arena_ind; READONLY(); WRITEONLY(); - arena_i_purge(tsd_tsdn(tsd), (unsigned)mib[1], false); + MIB_UNSIGNED(arena_ind, 1); + arena_i_purge(tsd_tsdn(tsd), arena_ind, false); ret = 0; label_return: @@ -1538,8 +1550,8 @@ arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, READONLY(); WRITEONLY(); + MIB_UNSIGNED(arena_ind, 1); - arena_ind = (unsigned)mib[1]; if (config_debug) { malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); assert(arena_ind < ctl_stats->narenas); @@ -1566,12 +1578,13 @@ arena_i_dss_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, { int ret; const char *dss = NULL; - unsigned arena_ind = (unsigned)mib[1]; + unsigned arena_ind; dss_prec_t dss_prec_old = dss_prec_limit; dss_prec_t dss_prec = dss_prec_limit; malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); WRITE(dss, const char *); + MIB_UNSIGNED(arena_ind, 1); if (dss != NULL) { int i; bool match = false; @@ -1626,9 +1639,10 @@ arena_i_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; - unsigned arena_ind = (unsigned)mib[1]; + unsigned arena_ind; arena_t *arena; + MIB_UNSIGNED(arena_ind, 1); arena = arena_get(tsd_tsdn(tsd), arena_ind, false); if (arena == NULL) { ret = EFAULT; @@ -1661,10 +1675,11 @@ arena_i_extent_hooks_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; - unsigned arena_ind = (unsigned)mib[1]; + unsigned arena_ind; arena_t *arena; malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); + MIB_UNSIGNED(arena_ind, 1); if (arena_ind < narenas_total_get() && (arena = arena_get(tsd_tsdn(tsd), arena_ind, false)) != NULL) { if (newp != NULL) { -- GitLab From dc2125cf95cb1d9370ac7375185d6420c84388b9 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 4 Jan 2017 10:21:53 -0800 Subject: [PATCH 219/544] Replace the arenas.initialized mallctl with arena..initialized . --- doc/jemalloc.xml.in | 27 ++++++++++++----------- src/ctl.c | 54 +++++++++++++++++++++------------------------ src/stats.c | 12 ++++++---- test/unit/mallctl.c | 49 +++++++++++++++++++++++++--------------- 4 files changed, 78 insertions(+), 64 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 36aae37c..f213a2c8 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -1253,7 +1253,7 @@ malloc_conf = "xmalloc:true";]]> Get or set the arena associated with the calling thread. If the specified arena was not initialized beforehand (see the arenas.initialized + linkend="arena.i.initialized">arena.i.initialized mallctl), it will be automatically initialized as a side effect of calling this interface. @@ -1425,6 +1425,19 @@ malloc_conf = "xmalloc:true";]]> + + + arena.<i>.initialized + (bool) + r- + + Get whether the specified arena's statistics are + initialized (i.e. the arena was initialized prior to the current epoch). + This interface can also be nominally used to query whether the merged + statistics corresponding to MALLCTL_ARENAS_ALL are + initialized (always true). + + arena.<i>.purge @@ -1715,18 +1728,6 @@ struct extent_hooks_s { Current limit on number of arenas. - - - arenas.initialized - (bool *) - r- - - An array of arenas.narenas - booleans. Each boolean indicates whether the corresponding arena is - initialized. - - arenas.decay_time diff --git a/src/ctl.c b/src/ctl.c index 0e7a09da..45e397b8 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -109,7 +109,7 @@ CTL_PROTO(opt_prof_accum) CTL_PROTO(tcache_create) CTL_PROTO(tcache_flush) CTL_PROTO(tcache_destroy) -static void arena_i_purge(tsdn_t *tsdn, unsigned arena_ind, bool all); +CTL_PROTO(arena_i_initialized) CTL_PROTO(arena_i_purge) CTL_PROTO(arena_i_decay) CTL_PROTO(arena_i_reset) @@ -124,7 +124,6 @@ INDEX_PROTO(arenas_bin_i) CTL_PROTO(arenas_lextent_i_size) INDEX_PROTO(arenas_lextent_i) CTL_PROTO(arenas_narenas) -CTL_PROTO(arenas_initialized) CTL_PROTO(arenas_decay_time) CTL_PROTO(arenas_quantum) CTL_PROTO(arenas_page) @@ -271,6 +270,7 @@ static const ctl_named_node_t tcache_node[] = { }; static const ctl_named_node_t arena_i_node[] = { + {NAME("initialized"), CTL(arena_i_initialized)}, {NAME("purge"), CTL(arena_i_purge)}, {NAME("decay"), CTL(arena_i_decay)}, {NAME("reset"), CTL(arena_i_reset)}, @@ -312,7 +312,6 @@ static const ctl_indexed_node_t arenas_lextent_node[] = { static const ctl_named_node_t arenas_node[] = { {NAME("narenas"), CTL(arenas_narenas)}, - {NAME("initialized"), CTL(arenas_initialized)}, {NAME("decay_time"), CTL(arenas_decay_time)}, {NAME("quantum"), CTL(arenas_quantum)}, {NAME("page"), CTL(arenas_page)}, @@ -1461,6 +1460,29 @@ label_return: /******************************************************************************/ +static int +arena_i_initialized_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, + void *oldp, size_t *oldlenp, void *newp, size_t newlen) +{ + int ret; + tsdn_t *tsdn = tsd_tsdn(tsd); + unsigned arena_ind; + bool initialized; + + READONLY(); + MIB_UNSIGNED(arena_ind, 1); + + malloc_mutex_lock(tsdn, &ctl_mtx); + initialized = stats_arenas_i(arena_ind)->initialized; + malloc_mutex_unlock(tsdn, &ctl_mtx); + + READ(initialized, bool); + + ret = 0; +label_return: + return (ret); +} + static void arena_i_purge(tsdn_t *tsdn, unsigned arena_ind, bool all) { @@ -1746,32 +1768,6 @@ label_return: return (ret); } -static int -arenas_initialized_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ - int ret; - unsigned nread, i; - - malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); - READONLY(); - if (*oldlenp != ctl_stats->narenas * sizeof(bool)) { - ret = EINVAL; - nread = (*oldlenp < ctl_stats->narenas * sizeof(bool)) - ? (unsigned)(*oldlenp / sizeof(bool)) : ctl_stats->narenas; - } else { - ret = 0; - nread = ctl_stats->narenas; - } - - for (i = 0; i < nread; i++) - ((bool *)oldp)[i] = stats_arenas_i(i)->initialized; - -label_return: - malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); - return (ret); -} - static int arenas_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) diff --git a/src/stats.c b/src/stats.c index ad7d7ba4..4e09eb45 100644 --- a/src/stats.c +++ b/src/stats.c @@ -818,14 +818,18 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, CTL_GET("arenas.narenas", &narenas, unsigned); { + size_t mib[3]; + size_t miblen = sizeof(mib) / sizeof(size_t); + size_t sz; VARIABLE_ARRAY(bool, initialized, narenas); - size_t isz; unsigned i, j, ninitialized; - isz = sizeof(bool) * narenas; - xmallctl("arenas.initialized", (void *)initialized, - &isz, NULL, 0); + xmallctlnametomib("arena.0.initialized", mib, &miblen); for (i = ninitialized = 0; i < narenas; i++) { + mib[1] = i; + sz = sizeof(bool); + xmallctlbymib(mib, miblen, &initialized[i], &sz, + NULL, 0); if (initialized[i]) ninitialized++; } diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 95c27753..b3320788 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -354,6 +354,36 @@ TEST_BEGIN(test_thread_arena) } TEST_END +TEST_BEGIN(test_arena_i_initialized) +{ + unsigned narenas, i; + size_t sz; + size_t mib[3]; + size_t miblen = sizeof(mib) / sizeof(size_t); + bool initialized; + + sz = sizeof(narenas); + assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0), + 0, "Unexpected mallctl() failure"); + + assert_d_eq(mallctlnametomib("arena.0.initialized", mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + for (i = 0; i < narenas; i++) { + mib[1] = i; + sz = sizeof(initialized); + assert_d_eq(mallctlbymib(mib, miblen, &initialized, &sz, NULL, + 0), 0, "Unexpected mallctl() failure"); + } + + mib[1] = MALLCTL_ARENAS_ALL; + sz = sizeof(initialized); + assert_d_eq(mallctlbymib(mib, miblen, &initialized, &sz, NULL, 0), 0, + "Unexpected mallctl() failure"); + assert_true(initialized, + "Merged arena statistics should always be initialized"); +} +TEST_END + TEST_BEGIN(test_arena_i_decay_time) { ssize_t decay_time, orig_decay_time, prev_decay_time; @@ -479,23 +509,6 @@ TEST_BEGIN(test_arena_i_dss) } TEST_END -TEST_BEGIN(test_arenas_initialized) -{ - unsigned narenas; - size_t sz = sizeof(narenas); - - assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0), - 0, "Unexpected mallctl() failure"); - { - VARIABLE_ARRAY(bool, initialized, narenas); - - sz = narenas * sizeof(bool); - assert_d_eq(mallctl("arenas.initialized", (void *)initialized, - &sz, NULL, 0), 0, "Unexpected mallctl() failure"); - } -} -TEST_END - TEST_BEGIN(test_arenas_decay_time) { ssize_t decay_time, orig_decay_time, prev_decay_time; @@ -638,11 +651,11 @@ main(void) test_tcache_none, test_tcache, test_thread_arena, + test_arena_i_initialized, test_arena_i_decay_time, test_arena_i_purge, test_arena_i_decay, test_arena_i_dss, - test_arenas_initialized, test_arenas_decay_time, test_arenas_constants, test_arenas_bin_constants, -- GitLab From 3f291d59ada15f2be84c80dac71e0ddf03908d15 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 6 Jan 2017 11:22:08 -0800 Subject: [PATCH 220/544] Refactor test extent hook code to be reusable. Move test extent hook code from the extent integration test into a header, and normalize the out-of-band controls and introspection. Also refactor the base unit test to use the header. --- test/include/test/extent_hooks.h | 264 +++++++++++++++++++++++++++ test/integration/extent.c | 300 ++++++------------------------- test/unit/base.c | 150 +++++----------- 3 files changed, 366 insertions(+), 348 deletions(-) create mode 100644 test/include/test/extent_hooks.h diff --git a/test/include/test/extent_hooks.h b/test/include/test/extent_hooks.h new file mode 100644 index 00000000..f50747d0 --- /dev/null +++ b/test/include/test/extent_hooks.h @@ -0,0 +1,264 @@ +/* + * Boilerplate code used for testing extent hooks via interception and + * passthrough. + */ + +static void *extent_alloc_hook(extent_hooks_t *extent_hooks, void *new_addr, + size_t size, size_t alignment, bool *zero, bool *commit, + unsigned arena_ind); +static bool extent_dalloc_hook(extent_hooks_t *extent_hooks, void *addr, + size_t size, bool committed, unsigned arena_ind); +static bool extent_commit_hook(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t offset, size_t length, unsigned arena_ind); +static bool extent_decommit_hook(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t offset, size_t length, unsigned arena_ind); +static bool extent_purge_lazy_hook(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t offset, size_t length, unsigned arena_ind); +static bool extent_purge_forced_hook(extent_hooks_t *extent_hooks, + void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); +static bool extent_split_hook(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t size_a, size_t size_b, bool committed, + unsigned arena_ind); +static bool extent_merge_hook(extent_hooks_t *extent_hooks, void *addr_a, + size_t size_a, void *addr_b, size_t size_b, bool committed, + unsigned arena_ind); + +static extent_hooks_t *default_hooks; +static extent_hooks_t hooks = { + extent_alloc_hook, + extent_dalloc_hook, + extent_commit_hook, + extent_decommit_hook, + extent_purge_lazy_hook, + extent_purge_forced_hook, + extent_split_hook, + extent_merge_hook +}; + +/* Control whether hook functions pass calls through to default hooks. */ +static bool try_alloc = true; +static bool try_dalloc = true; +static bool try_commit = true; +static bool try_decommit = true; +static bool try_purge_lazy = true; +static bool try_purge_forced = true; +static bool try_split = true; +static bool try_merge = true; + +/* Set to false prior to operations, then introspect after operations. */ +static bool called_alloc; +static bool called_dalloc; +static bool called_commit; +static bool called_decommit; +static bool called_purge_lazy; +static bool called_purge_forced; +static bool called_split; +static bool called_merge; + +/* Set to false prior to operations, then introspect after operations. */ +static bool did_alloc; +static bool did_dalloc; +static bool did_commit; +static bool did_decommit; +static bool did_purge_lazy; +static bool did_purge_forced; +static bool did_split; +static bool did_merge; + +#if 0 +# define TRACE_HOOK(fmt, ...) malloc_printf(fmt, __VA_ARGS__) +#else +# define TRACE_HOOK(fmt, ...) +#endif + +static void * +extent_alloc_hook(extent_hooks_t *extent_hooks, void *new_addr, size_t size, + size_t alignment, bool *zero, bool *commit, unsigned arena_ind) +{ + void *ret; + + TRACE_HOOK("%s(extent_hooks=%p, new_addr=%p, size=%zu, alignment=%zu, " + "*zero=%s, *commit=%s, arena_ind=%u)\n", __func__, extent_hooks, + new_addr, size, alignment, *zero ? "true" : "false", *commit ? + "true" : "false", arena_ind); + assert_ptr_eq(extent_hooks, &hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->alloc, extent_alloc_hook, + "Wrong hook function"); + called_alloc = true; + if (!try_alloc) + return (NULL); + ret = default_hooks->alloc(default_hooks, new_addr, size, alignment, + zero, commit, 0); + did_alloc = (ret != NULL); + return (ret); +} + +static bool +extent_dalloc_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, + bool committed, unsigned arena_ind) +{ + bool err; + + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, " + "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ? + "true" : "false", arena_ind); + assert_ptr_eq(extent_hooks, &hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->dalloc, extent_dalloc_hook, + "Wrong hook function"); + called_dalloc = true; + if (!try_dalloc) + return (true); + err = default_hooks->dalloc(default_hooks, addr, size, committed, 0); + did_dalloc = !err; + return (err); +} + +static bool +extent_commit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t offset, size_t length, unsigned arena_ind) +{ + bool err; + + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " + "length=%zu, arena_ind=%u)\n", __func__, extent_hooks, addr, size, + offset, length, arena_ind); + assert_ptr_eq(extent_hooks, &hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->commit, extent_commit_hook, + "Wrong hook function"); + called_commit = true; + if (!try_commit) + return (true); + err = default_hooks->commit(default_hooks, addr, size, offset, length, + 0); + did_commit = !err; + return (err); +} + +static bool +extent_decommit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t offset, size_t length, unsigned arena_ind) +{ + bool err; + + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " + "length=%zu, arena_ind=%u)\n", __func__, extent_hooks, addr, size, + offset, length, arena_ind); + assert_ptr_eq(extent_hooks, &hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->decommit, extent_decommit_hook, + "Wrong hook function"); + called_decommit = true; + if (!try_decommit) + return (true); + err = default_hooks->decommit(default_hooks, addr, size, offset, length, + 0); + did_decommit = !err; + return (err); +} + +static bool +extent_purge_lazy_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t offset, size_t length, unsigned arena_ind) +{ + bool err; + + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " + "length=%zu arena_ind=%u)\n", __func__, extent_hooks, addr, size, + offset, length, arena_ind); + assert_ptr_eq(extent_hooks, &hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->purge_lazy, extent_purge_lazy_hook, + "Wrong hook function"); + called_purge_lazy = true; + if (!try_purge_lazy) + return (true); + err = default_hooks->purge_lazy == NULL || + default_hooks->purge_lazy(default_hooks, addr, size, offset, length, + 0); + did_purge_lazy = !err; + return (err); +} + +static bool +extent_purge_forced_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t offset, size_t length, unsigned arena_ind) +{ + bool err; + + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " + "length=%zu arena_ind=%u)\n", __func__, extent_hooks, addr, size, + offset, length, arena_ind); + assert_ptr_eq(extent_hooks, &hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->purge_forced, extent_purge_forced_hook, + "Wrong hook function"); + called_purge_forced = true; + if (!try_purge_forced) + return (true); + err = default_hooks->purge_forced == NULL || + default_hooks->purge_forced(default_hooks, addr, size, offset, + length, 0); + did_purge_forced = !err; + return (err); +} + +static bool +extent_split_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, + size_t size_a, size_t size_b, bool committed, unsigned arena_ind) +{ + bool err; + + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, size_a=%zu, " + "size_b=%zu, committed=%s, arena_ind=%u)\n", __func__, extent_hooks, + addr, size, size_a, size_b, committed ? "true" : "false", + arena_ind); + assert_ptr_eq(extent_hooks, &hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->split, extent_split_hook, + "Wrong hook function"); + called_split = true; + if (!try_split) + return (true); + err = (default_hooks->split == NULL || + default_hooks->split(default_hooks, addr, size, size_a, size_b, + committed, 0)); + did_split = !err; + return (err); +} + +static bool +extent_merge_hook(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, + void *addr_b, size_t size_b, bool committed, unsigned arena_ind) +{ + bool err; + + TRACE_HOOK("%s(extent_hooks=%p, addr_a=%p, size_a=%zu, addr_b=%p " + "size_b=%zu, committed=%s, arena_ind=%u)\n", __func__, extent_hooks, + addr_a, size_a, addr_b, size_b, committed ? "true" : "false", + arena_ind); + assert_ptr_eq(extent_hooks, &hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->merge, extent_merge_hook, + "Wrong hook function"); + called_merge = true; + if (!try_merge) + return (true); + err = (default_hooks->merge == NULL || + default_hooks->merge(default_hooks, addr_a, size_a, addr_b, size_b, + committed, 0)); + did_merge = !err; + return (err); +} + +static void +extent_hooks_prep(void) +{ + size_t sz; + + sz = sizeof(default_hooks); + assert_d_eq(mallctl("arena.0.extent_hooks", (void *)&default_hooks, &sz, + NULL, 0), 0, "Unexpected mallctl() error"); +} diff --git a/test/integration/extent.c b/test/integration/extent.c index 6be3b836..e347b66d 100644 --- a/test/integration/extent.c +++ b/test/integration/extent.c @@ -4,204 +4,7 @@ const char *malloc_conf = "junk:false"; #endif -static void *extent_alloc(extent_hooks_t *extent_hooks, void *new_addr, - size_t size, size_t alignment, bool *zero, bool *commit, - unsigned arena_ind); -static bool extent_dalloc(extent_hooks_t *extent_hooks, void *addr, - size_t size, bool committed, unsigned arena_ind); -static bool extent_commit(extent_hooks_t *extent_hooks, void *addr, - size_t size, size_t offset, size_t length, unsigned arena_ind); -static bool extent_decommit(extent_hooks_t *extent_hooks, void *addr, - size_t size, size_t offset, size_t length, unsigned arena_ind); -static bool extent_purge_lazy(extent_hooks_t *extent_hooks, void *addr, - size_t size, size_t offset, size_t length, unsigned arena_ind); -static bool extent_purge_forced(extent_hooks_t *extent_hooks, void *addr, - size_t size, size_t offset, size_t length, unsigned arena_ind); -static bool extent_split(extent_hooks_t *extent_hooks, void *addr, - size_t size, size_t size_a, size_t size_b, bool committed, - unsigned arena_ind); -static bool extent_merge(extent_hooks_t *extent_hooks, void *addr_a, - size_t size_a, void *addr_b, size_t size_b, bool committed, - unsigned arena_ind); - -static extent_hooks_t hooks = { - extent_alloc, - extent_dalloc, - extent_commit, - extent_decommit, - extent_purge_lazy, - extent_purge_forced, - extent_split, - extent_merge -}; -static extent_hooks_t *new_hooks = &hooks; -static extent_hooks_t *orig_hooks; -static extent_hooks_t *old_hooks; - -static bool do_dalloc = true; -static bool do_decommit; - -static bool did_alloc; -static bool did_dalloc; -static bool did_commit; -static bool did_decommit; -static bool did_purge_lazy; -static bool did_purge_forced; -static bool tried_split; -static bool did_split; -static bool did_merge; - -#if 0 -# define TRACE_HOOK(fmt, ...) malloc_printf(fmt, __VA_ARGS__) -#else -# define TRACE_HOOK(fmt, ...) -#endif - -static void * -extent_alloc(extent_hooks_t *extent_hooks, void *new_addr, size_t size, - size_t alignment, bool *zero, bool *commit, unsigned arena_ind) -{ - - TRACE_HOOK("%s(extent_hooks=%p, new_addr=%p, size=%zu, alignment=%zu, " - "*zero=%s, *commit=%s, arena_ind=%u)\n", __func__, extent_hooks, - new_addr, size, alignment, *zero ? "true" : "false", *commit ? - "true" : "false", arena_ind); - assert_ptr_eq(extent_hooks, new_hooks, - "extent_hooks should be same as pointer used to set hooks"); - assert_ptr_eq(extent_hooks->alloc, extent_alloc, "Wrong hook function"); - did_alloc = true; - return (old_hooks->alloc(old_hooks, new_addr, size, alignment, zero, - commit, 0)); -} - -static bool -extent_dalloc(extent_hooks_t *extent_hooks, void *addr, size_t size, - bool committed, unsigned arena_ind) -{ - - TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, " - "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ? - "true" : "false", arena_ind); - assert_ptr_eq(extent_hooks, new_hooks, - "extent_hooks should be same as pointer used to set hooks"); - assert_ptr_eq(extent_hooks->dalloc, extent_dalloc, - "Wrong hook function"); - did_dalloc = true; - if (!do_dalloc) - return (true); - return (old_hooks->dalloc(old_hooks, addr, size, committed, 0)); -} - -static bool -extent_commit(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t offset, size_t length, unsigned arena_ind) -{ - bool err; - - TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " - "length=%zu, arena_ind=%u)\n", __func__, extent_hooks, addr, size, - offset, length, arena_ind); - assert_ptr_eq(extent_hooks, new_hooks, - "extent_hooks should be same as pointer used to set hooks"); - assert_ptr_eq(extent_hooks->commit, extent_commit, - "Wrong hook function"); - err = old_hooks->commit(old_hooks, addr, size, offset, length, 0); - did_commit = !err; - return (err); -} - -static bool -extent_decommit(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t offset, size_t length, unsigned arena_ind) -{ - bool err; - - TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " - "length=%zu, arena_ind=%u)\n", __func__, extent_hooks, addr, size, - offset, length, arena_ind); - assert_ptr_eq(extent_hooks, new_hooks, - "extent_hooks should be same as pointer used to set hooks"); - assert_ptr_eq(extent_hooks->decommit, extent_decommit, - "Wrong hook function"); - if (!do_decommit) - return (true); - err = old_hooks->decommit(old_hooks, addr, size, offset, length, 0); - did_decommit = !err; - return (err); -} - -static bool -extent_purge_lazy(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t offset, size_t length, unsigned arena_ind) -{ - - TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " - "length=%zu arena_ind=%u)\n", __func__, extent_hooks, addr, size, - offset, length, arena_ind); - assert_ptr_eq(extent_hooks, new_hooks, - "extent_hooks should be same as pointer used to set hooks"); - assert_ptr_eq(extent_hooks->purge_lazy, extent_purge_lazy, - "Wrong hook function"); - did_purge_lazy = true; - return (old_hooks->purge_lazy == NULL || - old_hooks->purge_lazy(old_hooks, addr, size, offset, length, 0)); -} - -static bool -extent_purge_forced(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t offset, size_t length, unsigned arena_ind) -{ - - TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " - "length=%zu arena_ind=%u)\n", __func__, extent_hooks, addr, size, - offset, length, arena_ind); - assert_ptr_eq(extent_hooks, new_hooks, - "extent_hooks should be same as pointer used to set hooks"); - assert_ptr_eq(extent_hooks->purge_forced, extent_purge_forced, - "Wrong hook function"); - did_purge_forced = true; - return (old_hooks->purge_forced == NULL || - old_hooks->purge_forced(old_hooks, addr, size, offset, length, 0)); -} - -static bool -extent_split(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t size_a, size_t size_b, bool committed, unsigned arena_ind) -{ - bool err; - - TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, size_a=%zu, " - "size_b=%zu, committed=%s, arena_ind=%u)\n", __func__, extent_hooks, - addr, size, size_a, size_b, committed ? "true" : "false", - arena_ind); - assert_ptr_eq(extent_hooks, new_hooks, - "extent_hooks should be same as pointer used to set hooks"); - assert_ptr_eq(extent_hooks->split, extent_split, "Wrong hook function"); - tried_split = true; - err = (old_hooks->split == NULL || old_hooks->split(old_hooks, addr, - size, size_a, size_b, committed, 0)); - did_split = !err; - return (err); -} - -static bool -extent_merge(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, - void *addr_b, size_t size_b, bool committed, unsigned arena_ind) -{ - bool err; - - TRACE_HOOK("%s(extent_hooks=%p, addr_a=%p, size_a=%zu, addr_b=%p " - "size_b=%zu, committed=%s, arena_ind=%u)\n", __func__, extent_hooks, - addr_a, size_a, addr_b, size_b, committed ? "true" : "false", - arena_ind); - assert_ptr_eq(extent_hooks, new_hooks, - "extent_hooks should be same as pointer used to set hooks"); - assert_ptr_eq(extent_hooks->merge, extent_merge, "Wrong hook function"); - err = (old_hooks->merge == NULL || old_hooks->merge(old_hooks, addr_a, - size_a, addr_b, size_b, committed, 0)); - did_merge = !err; - return (err); -} +#include "test/extent_hooks.h" static void test_extent_body(unsigned arena_ind) @@ -229,37 +32,36 @@ test_extent_body(unsigned arena_ind) assert_d_eq(mallctlnametomib("arena.0.purge", purge_mib, &purge_miblen), 0, "Unexpected mallctlnametomib() failure"); purge_mib[1] = (size_t)arena_ind; - do_dalloc = false; - do_decommit = false; + try_dalloc = false; + try_decommit = false; p = mallocx(large0 * 2, flags); assert_ptr_not_null(p, "Unexpected mallocx() error"); - did_dalloc = false; - did_decommit = false; + called_dalloc = false; + called_decommit = false; did_purge_lazy = false; did_purge_forced = false; - tried_split = false; - did_split = false; + called_split = false; xallocx_success_a = (xallocx(p, large0, 0, flags) == large0); assert_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0), 0, "Unexpected arena.%u.purge error", arena_ind); if (xallocx_success_a) { - assert_true(did_dalloc, "Expected dalloc"); - assert_false(did_decommit, "Unexpected decommit"); + assert_true(called_dalloc, "Expected dalloc call"); + assert_true(called_decommit, "Expected decommit call"); assert_true(did_purge_lazy || did_purge_forced, "Expected purge"); } - assert_true(tried_split, "Expected split"); + assert_true(called_split, "Expected split call"); dallocx(p, flags); - do_dalloc = true; + try_dalloc = true; /* Test decommit/commit and observe split/merge. */ - do_dalloc = false; - do_decommit = true; + try_dalloc = false; + try_decommit = true; p = mallocx(large0 * 2, flags); assert_ptr_not_null(p, "Unexpected mallocx() error"); did_decommit = false; did_commit = false; - tried_split = false; + called_split = false; did_split = false; did_merge = false; xallocx_success_b = (xallocx(p, large0, 0, flags) == large0); @@ -275,8 +77,8 @@ test_extent_body(unsigned arena_ind) if (xallocx_success_b && xallocx_success_c) assert_true(did_merge, "Expected merge"); dallocx(p, flags); - do_dalloc = true; - do_decommit = false; + try_dalloc = true; + try_decommit = false; /* Make sure non-large allocation succeeds. */ p = mallocx(42, flags); @@ -290,6 +92,9 @@ TEST_BEGIN(test_extent_manual_hook) size_t old_size, new_size, sz; size_t hooks_mib[3]; size_t hooks_miblen; + extent_hooks_t *new_hooks, *old_hooks; + + extent_hooks_prep(); sz = sizeof(unsigned); assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), @@ -301,24 +106,27 @@ TEST_BEGIN(test_extent_manual_hook) &hooks_miblen), 0, "Unexpected mallctlnametomib() failure"); hooks_mib[1] = (size_t)arena_ind; old_size = sizeof(extent_hooks_t *); + new_hooks = &hooks; new_size = sizeof(extent_hooks_t *); assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks, &old_size, (void *)&new_hooks, new_size), 0, "Unexpected extent_hooks error"); - orig_hooks = old_hooks; - assert_ptr_ne(old_hooks->alloc, extent_alloc, "Unexpected alloc error"); - assert_ptr_ne(old_hooks->dalloc, extent_dalloc, - "Unexpected dalloc error"); - assert_ptr_ne(old_hooks->commit, extent_commit, - "Unexpected commit error"); - assert_ptr_ne(old_hooks->decommit, extent_decommit, - "Unexpected decommit error"); - assert_ptr_ne(old_hooks->purge_lazy, extent_purge_lazy, - "Unexpected purge_lazy error"); - assert_ptr_ne(old_hooks->purge_forced, extent_purge_forced, - "Unexpected purge_forced error"); - assert_ptr_ne(old_hooks->split, extent_split, "Unexpected split error"); - assert_ptr_ne(old_hooks->merge, extent_merge, "Unexpected merge error"); + assert_ptr_ne(old_hooks->alloc, extent_alloc_hook, + "Unexpected extent_hooks error"); + assert_ptr_ne(old_hooks->dalloc, extent_dalloc_hook, + "Unexpected extent_hooks error"); + assert_ptr_ne(old_hooks->commit, extent_commit_hook, + "Unexpected extent_hooks error"); + assert_ptr_ne(old_hooks->decommit, extent_decommit_hook, + "Unexpected extent_hooks error"); + assert_ptr_ne(old_hooks->purge_lazy, extent_purge_lazy_hook, + "Unexpected extent_hooks error"); + assert_ptr_ne(old_hooks->purge_forced, extent_purge_forced_hook, + "Unexpected extent_hooks error"); + assert_ptr_ne(old_hooks->split, extent_split_hook, + "Unexpected extent_hooks error"); + assert_ptr_ne(old_hooks->merge, extent_merge_hook, + "Unexpected extent_hooks error"); test_extent_body(arena_ind); @@ -327,23 +135,23 @@ TEST_BEGIN(test_extent_manual_hook) (void *)&old_hooks, new_size), 0, "Unexpected extent_hooks error"); assert_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks, &old_size, NULL, 0), 0, "Unexpected extent_hooks error"); - assert_ptr_eq(old_hooks, orig_hooks, "Unexpected hooks error"); - assert_ptr_eq(old_hooks->alloc, orig_hooks->alloc, - "Unexpected alloc error"); - assert_ptr_eq(old_hooks->dalloc, orig_hooks->dalloc, - "Unexpected dalloc error"); - assert_ptr_eq(old_hooks->commit, orig_hooks->commit, - "Unexpected commit error"); - assert_ptr_eq(old_hooks->decommit, orig_hooks->decommit, - "Unexpected decommit error"); - assert_ptr_eq(old_hooks->purge_lazy, orig_hooks->purge_lazy, - "Unexpected purge_lazy error"); - assert_ptr_eq(old_hooks->purge_forced, orig_hooks->purge_forced, - "Unexpected purge_forced error"); - assert_ptr_eq(old_hooks->split, orig_hooks->split, - "Unexpected split error"); - assert_ptr_eq(old_hooks->merge, orig_hooks->merge, - "Unexpected merge error"); + assert_ptr_eq(old_hooks, default_hooks, "Unexpected extent_hooks error"); + assert_ptr_eq(old_hooks->alloc, default_hooks->alloc, + "Unexpected extent_hooks error"); + assert_ptr_eq(old_hooks->dalloc, default_hooks->dalloc, + "Unexpected extent_hooks error"); + assert_ptr_eq(old_hooks->commit, default_hooks->commit, + "Unexpected extent_hooks error"); + assert_ptr_eq(old_hooks->decommit, default_hooks->decommit, + "Unexpected extent_hooks error"); + assert_ptr_eq(old_hooks->purge_lazy, default_hooks->purge_lazy, + "Unexpected extent_hooks error"); + assert_ptr_eq(old_hooks->purge_forced, default_hooks->purge_forced, + "Unexpected extent_hooks error"); + assert_ptr_eq(old_hooks->split, default_hooks->split, + "Unexpected extent_hooks error"); + assert_ptr_eq(old_hooks->merge, default_hooks->merge, + "Unexpected extent_hooks error"); } TEST_END @@ -351,8 +159,12 @@ TEST_BEGIN(test_extent_auto_hook) { unsigned arena_ind; size_t new_size, sz; + extent_hooks_t *new_hooks; + + extent_hooks_prep(); sz = sizeof(unsigned); + new_hooks = &hooks; new_size = sizeof(extent_hooks_t *); assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, (void *)&new_hooks, new_size), 0, "Unexpected mallctl() failure"); diff --git a/test/unit/base.c b/test/unit/base.c index 6a082a5e..8f97e8bf 100644 --- a/test/unit/base.c +++ b/test/unit/base.c @@ -1,27 +1,6 @@ #include "test/jemalloc_test.h" -static void *extent_alloc_hook(extent_hooks_t *extent_hooks, void *new_addr, - size_t size, size_t alignment, bool *zero, bool *commit, - unsigned arena_ind); -static bool extent_dalloc_hook(extent_hooks_t *extent_hooks, void *addr, - size_t size, bool committed, unsigned arena_ind); -static bool extent_decommit_hook(extent_hooks_t *extent_hooks, void *addr, - size_t size, size_t offset, size_t length, unsigned arena_ind); -static bool extent_purge_lazy_hook(extent_hooks_t *extent_hooks, void *addr, - size_t size, size_t offset, size_t length, unsigned arena_ind); -static bool extent_purge_forced_hook(extent_hooks_t *extent_hooks, - void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); - -static extent_hooks_t hooks_not_null = { - extent_alloc_hook, - extent_dalloc_hook, - NULL, /* commit */ - extent_decommit_hook, - extent_purge_lazy_hook, - extent_purge_forced_hook, - NULL, /* split */ - NULL /* merge */ -}; +#include "test/extent_hooks.h" static extent_hooks_t hooks_null = { extent_alloc_hook, @@ -34,80 +13,16 @@ static extent_hooks_t hooks_null = { NULL /* merge */ }; -static bool did_alloc; -static bool did_dalloc; -static bool did_decommit; -static bool did_purge_lazy; -static bool did_purge_forced; - -#if 0 -# define TRACE_HOOK(fmt, ...) malloc_printf(fmt, __VA_ARGS__) -#else -# define TRACE_HOOK(fmt, ...) -#endif - -static void * -extent_alloc_hook(extent_hooks_t *extent_hooks, void *new_addr, size_t size, - size_t alignment, bool *zero, bool *commit, unsigned arena_ind) -{ - - TRACE_HOOK("%s(extent_hooks=%p, new_addr=%p, size=%zu, alignment=%zu, " - "*zero=%s, *commit=%s, arena_ind=%u)\n", __func__, extent_hooks, - new_addr, size, alignment, *zero ? "true" : "false", *commit ? - "true" : "false", arena_ind); - did_alloc = true; - return (extent_hooks_default.alloc( - (extent_hooks_t *)&extent_hooks_default, new_addr, size, alignment, - zero, commit, 0)); -} - -static bool -extent_dalloc_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, - bool committed, unsigned arena_ind) -{ - - TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, " - "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ? - "true" : "false", arena_ind); - did_dalloc = true; - return (true); /* Cause cascade. */ -} - -static bool -extent_decommit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t offset, size_t length, unsigned arena_ind) -{ - - TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " - "length=%zu, arena_ind=%u)\n", __func__, extent_hooks, addr, size, - offset, length, arena_ind); - did_decommit = true; - return (true); /* Cause cascade. */ -} - -static bool -extent_purge_lazy_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t offset, size_t length, unsigned arena_ind) -{ - - TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " - "length=%zu arena_ind=%u)\n", __func__, extent_hooks, addr, size, - offset, length, arena_ind); - did_purge_lazy = true; - return (true); /* Cause cascade. */ -} - -static bool -extent_purge_forced_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t offset, size_t length, unsigned arena_ind) -{ - - TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " - "length=%zu arena_ind=%u)\n", __func__, extent_hooks, addr, size, - offset, length, arena_ind); - did_purge_forced = true; - return (true); /* Cause cascade. */ -} +static extent_hooks_t hooks_not_null = { + extent_alloc_hook, + extent_dalloc_hook, + NULL, /* commit */ + extent_decommit_hook, + extent_purge_lazy_hook, + extent_purge_forced_hook, + NULL, /* split */ + NULL /* merge */ +}; TEST_BEGIN(test_base_hooks_default) { @@ -135,12 +50,21 @@ TEST_END TEST_BEGIN(test_base_hooks_null) { + extent_hooks_t hooks_orig; tsdn_t *tsdn; base_t *base; size_t allocated0, allocated1, resident, mapped; + extent_hooks_prep(); + try_dalloc = false; + try_decommit = false; + try_purge_lazy = false; + try_purge_forced = false; + memcpy(&hooks_orig, &hooks, sizeof(extent_hooks_t)); + memcpy(&hooks, &hooks_null, sizeof(extent_hooks_t)); + tsdn = tsdn_fetch(); - base = base_new(tsdn, 0, (extent_hooks_t *)&hooks_null); + base = base_new(tsdn, 0, &hooks); assert_ptr_not_null(base, "Unexpected base_new() failure"); base_stats_get(tsdn, base, &allocated0, &resident, &mapped); @@ -155,20 +79,31 @@ TEST_BEGIN(test_base_hooks_null) "At least 42 bytes were allocated by base_alloc()"); base_delete(base); + + memcpy(&hooks, &hooks_orig, sizeof(extent_hooks_t)); } TEST_END TEST_BEGIN(test_base_hooks_not_null) { + extent_hooks_t hooks_orig; tsdn_t *tsdn; base_t *base; void *p, *q, *r, *r_exp; + extent_hooks_prep(); + try_dalloc = false; + try_decommit = false; + try_purge_lazy = false; + try_purge_forced = false; + memcpy(&hooks_orig, &hooks, sizeof(extent_hooks_t)); + memcpy(&hooks, &hooks_not_null, sizeof(extent_hooks_t)); + tsdn = tsdn_fetch(); did_alloc = false; - base = base_new(tsdn, 0, (extent_hooks_t *)&hooks_not_null); + base = base_new(tsdn, 0, &hooks); assert_ptr_not_null(base, "Unexpected base_new() failure"); - assert_true(did_alloc, "Expected alloc hook call"); + assert_true(did_alloc, "Expected alloc"); /* * Check for tight packing at specified alignment under simple @@ -254,12 +189,19 @@ TEST_BEGIN(test_base_hooks_not_null) } } - did_dalloc = did_decommit = did_purge_lazy = did_purge_forced = false; + called_dalloc = called_decommit = called_purge_lazy = + called_purge_forced = false; base_delete(base); - assert_true(did_dalloc, "Expected dalloc hook call"); - assert_true(did_decommit, "Expected decommit hook call"); - assert_true(did_purge_lazy, "Expected purge_lazy hook call"); - assert_true(did_purge_forced, "Expected purge_forced hook call"); + assert_true(called_dalloc, "Expected dalloc call"); + assert_true(called_decommit, "Expected decommit call"); + assert_true(called_purge_lazy, "Expected purge_lazy call"); + assert_true(called_purge_forced, "Expected purge_forced call"); + + try_dalloc = true; + try_decommit = true; + try_purge_lazy = true; + try_purge_forced = true; + memcpy(&hooks, &hooks_orig, sizeof(extent_hooks_t)); } TEST_END -- GitLab From edf1bafb2b36ef4e8a2ef1ac19a4f76e5bc42528 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 3 Jan 2017 17:21:59 -0800 Subject: [PATCH 221/544] Implement arena..destroy . Add MALLCTL_ARENAS_DESTROYED for accessing destroyed arena stats as an analogue to MALLCTL_ARENAS_ALL. This resolves #382. --- Makefile.in | 4 + doc/jemalloc.xml.in | 51 +++- include/jemalloc/internal/arena.h | 1 + include/jemalloc/internal/ctl.h | 12 +- include/jemalloc/internal/extent.h | 2 + .../jemalloc/internal/jemalloc_internal.h.in | 2 + include/jemalloc/internal/private_symbols.txt | 3 + include/jemalloc/jemalloc_macros.h.in | 5 + src/arena.c | 66 ++++ src/ctl.c | 285 ++++++++++++------ src/extent.c | 21 +- src/jemalloc.c | 2 +- src/stats.c | 37 ++- test/unit/arena_reset.c | 255 ++++++++++++++-- test/unit/arena_reset_prof.c | 5 + test/unit/mallctl.c | 9 + 16 files changed, 620 insertions(+), 140 deletions(-) create mode 100644 test/unit/arena_reset_prof.c diff --git a/Makefile.in b/Makefile.in index d8704923..edc50b4b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -195,6 +195,10 @@ TESTS_UNIT := \ $(srcroot)test/unit/util.c \ $(srcroot)test/unit/witness.c \ $(srcroot)test/unit/zero.c +ifeq (@enable_prof@, 1) +TESTS_UNIT += \ + $(srcroot)test/unit/arena_reset_prof.c +endif TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \ $(srcroot)test/integration/allocated.c \ $(srcroot)test/integration/extent.c \ diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index f213a2c8..36ec140b 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -426,13 +426,14 @@ for (i = 0; i < nbins; i++) { mallctl*() functions internally, so inconsistent statistics can be reported if multiple threads use these functions simultaneously. If is specified during - configuration, m and a can be specified to - omit merged arena and per arena statistics, respectively; b - and l can be specified to omit per size class statistics - for bins and large objects, respectively. Unrecognized characters are - silently ignored. Note that thread caching may prevent some statistics - from being completely up to date, since extra locking would be required to - merge counters that track thread cache operations. + configuration, m, d, and a + can be specified to omit merged arena, destroyed merged arena, and per + arena statistics, respectively; b and l can + be specified to omit per size class statistics for bins and large objects, + respectively. Unrecognized characters are silently ignored. Note that + thread caching may prevent some statistics from being completely up to + date, since extra locking would be required to merge counters that track + thread cache operations. The malloc_usable_size() function returns the usable size of the allocation pointed to by @@ -687,18 +688,21 @@ for (i = 0; i < nbins; i++) { MALLCTL NAMESPACE The following names are defined in the namespace accessible via the - mallctl*() functions. Value types are - specified in parentheses, their readable/writable statuses are encoded as + mallctl*() functions. Value types are specified in + parentheses, their readable/writable statuses are encoded as rw, r-, -w, or --, and required build configuration flags follow, if any. A name element encoded as <i> or <j> indicates an integer component, where the integer varies from 0 to some upper value that must be determined via introspection. In the case of stats.arenas.<i>.* - and arena.<i>.{purge,decay,dss}, + and arena.<i>.{initialized,purge,decay,dss}, <i> equal to MALLCTL_ARENAS_ALL can be used to operate on all arenas - or access the summation of statistics from all arenas. This constant can be + or access the summation of statistics from all arenas; similarly + <i> equal to + MALLCTL_ARENAS_DESTROYED can be used to access the + summation of statistics from all destroyed arenas. These constants can be utilized either via mallctlnametomib() followed by mallctlbymib(), or via code such as the following: - Take special note of the - epoch mallctl, which - controls refreshing of cached dynamic statistics. + Take special note of the epoch mallctl, which controls + refreshing of cached dynamic statistics. @@ -1478,6 +1482,25 @@ malloc_conf = "xmalloc:true";]]> beforehand. + + + arena.<i>.destroy + (void) + -- + + Destroy the arena. Discard all of the arena's extant + allocations using the same mechanism as for arena.<i>.reset + (with all the same constraints and side effects), merge the arena stats + into those accessible at arena index + MALLCTL_ARENAS_DESTROYED, and then completely + discard all metadata associated with the arena. Future calls to arenas.create may + recycle the arena index. Destruction will fail if any threads are + currently associated with the arena as a result of calls to thread.arena. + + arena.<i>.dss diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index 929adbe9..5e295509 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -290,6 +290,7 @@ bool arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time); void arena_purge(tsdn_t *tsdn, arena_t *arena, bool all); void arena_maybe_purge(tsdn_t *tsdn, arena_t *arena); void arena_reset(tsd_t *tsd, arena_t *arena); +void arena_destroy(tsd_t *tsd, arena_t *arena); void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_bin_t *tbin, szind_t binind, uint64_t prof_accumbytes); void arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, diff --git a/include/jemalloc/internal/ctl.h b/include/jemalloc/internal/ctl.h index 0aa82541..7dc3e5b5 100644 --- a/include/jemalloc/internal/ctl.h +++ b/include/jemalloc/internal/ctl.h @@ -32,7 +32,10 @@ struct ctl_indexed_node_s { }; struct ctl_arena_stats_s { + unsigned arena_ind; bool initialized; + ql_elm(ctl_arena_stats_t) destroyed_link; + unsigned nthreads; const char *dss; ssize_t decay_time; @@ -62,7 +65,14 @@ struct ctl_stats_s { size_t mapped; size_t retained; unsigned narenas; - ctl_arena_stats_t *arenas[1 << MALLOCX_ARENA_BITS]; + ql_head(ctl_arena_stats_t) destroyed; + /* + * Element 0 contains merged stats for extant arenas (accessed via + * MALLCTL_ARENAS_ALL), element 1 contains merged stats for destroyed + * arenas (accessed via MALLCTL_ARENAS_DESTROYED), and the remaining + * MALLOCX_ARENA_MAX+1 elements correspond to arenas. + */ + ctl_arena_stats_t *arenas[MALLOCX_ARENA_MAX + 3]; }; #endif /* JEMALLOC_H_STRUCTS */ diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent.h index 33b85145..70accffb 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent.h @@ -125,6 +125,8 @@ extent_t *extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, void extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent); void extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent); +bool extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent); void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent); bool extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 991c541f..6395d750 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -215,6 +215,7 @@ typedef unsigned szind_t; #define MALLOCX_TCACHE_SHIFT 8 #define MALLOCX_ARENA_MASK \ (((1 << MALLOCX_ARENA_BITS) - 1) << MALLOCX_ARENA_SHIFT) +/* NB: Arena index bias decreases the maximum number of arenas by 1. */ #define MALLOCX_ARENA_MAX ((1 << MALLOCX_ARENA_BITS) - 2) #define MALLOCX_TCACHE_MASK \ (((1 << MALLOCX_TCACHE_BITS) - 1) << MALLOCX_TCACHE_SHIFT) @@ -470,6 +471,7 @@ void a0dalloc(void *ptr); void *bootstrap_malloc(size_t size); void *bootstrap_calloc(size_t num, size_t size); void bootstrap_free(void *ptr); +void arena_set(unsigned ind, arena_t *arena); unsigned narenas_total_get(void); arena_t *arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); arena_tdata_t *arena_tdata_get_hard(tsd_t *tsd, unsigned ind); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 36960f08..c85219a9 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -21,6 +21,7 @@ arena_decay_time_default_get arena_decay_time_default_set arena_decay_time_get arena_decay_time_set +arena_destroy arena_dss_prec_get arena_dss_prec_set arena_extent_alloc_large @@ -67,6 +68,7 @@ arena_ralloc_no_move arena_reset arena_salloc arena_sdalloc +arena_set arena_slab_regind arena_stats_merge arena_tcache_fill_small @@ -164,6 +166,7 @@ extent_dalloc_cache extent_dalloc_gap extent_dalloc_mmap extent_dalloc_wrapper +extent_dalloc_wrapper_try extent_decommit_wrapper extent_dss_boot extent_dss_mergeable diff --git a/include/jemalloc/jemalloc_macros.h.in b/include/jemalloc/jemalloc_macros.h.in index ea41e2e8..05bcdd7b 100644 --- a/include/jemalloc/jemalloc_macros.h.in +++ b/include/jemalloc/jemalloc_macros.h.in @@ -44,6 +44,11 @@ * 0); */ #define MALLCTL_ARENAS_ALL 4096 +/* + * Use as arena index in "stats.arenas..*" mallctl interfaces to select + * destroyed arenas. + */ +#define MALLCTL_ARENAS_DESTROYED 4097 #if defined(__cplusplus) && defined(JEMALLOC_USE_CXX_THROW) # define JEMALLOC_CXX_THROW throw() diff --git a/src/arena.c b/src/arena.c index 3c31cc87..1f0c4df5 100644 --- a/src/arena.c +++ b/src/arena.c @@ -903,6 +903,72 @@ arena_reset(tsd_t *tsd, arena_t *arena) malloc_mutex_unlock(tsd_tsdn(tsd), &arena->lock); } +static void +arena_destroy_retained(tsdn_t *tsdn, arena_t *arena) +{ + extent_hooks_t *extent_hooks = extent_hooks_get(arena); + size_t i; + + /* + * Iterate over the retained extents and blindly attempt to deallocate + * them. This gives the extent allocator underlying the extent hooks an + * opportunity to unmap all retained memory without having to keep its + * own metadata structures, but if deallocation fails, that is the + * application's decision/problem. In practice, retained extents are + * leaked here if !config_munmap unless the application provided custom + * extent hooks, so best practice to either enable munmap (and avoid dss + * for arenas to be destroyed), or provide custom extent hooks that + * either unmap retained extents or track them for later use. + */ + for (i = 0; i < sizeof(arena->extents_retained)/sizeof(extent_heap_t); + i++) { + extent_heap_t *extents = &arena->extents_retained[i]; + extent_t *extent; + + while ((extent = extent_heap_remove_first(extents)) != NULL) { + extent_dalloc_wrapper_try(tsdn, arena, &extent_hooks, + extent); + } + } +} + +void +arena_destroy(tsd_t *tsd, arena_t *arena) +{ + + assert(base_ind_get(arena->base) >= narenas_auto); + assert(arena_nthreads_get(arena, false) == 0); + assert(arena_nthreads_get(arena, true) == 0); + + /* + * No allocations have occurred since arena_reset() was called. + * Furthermore, the caller (arena_i_destroy_ctl()) purged all cached + * extents, so only retained extents may remain. + */ + assert(arena->ndirty == 0); + + /* Attempt to deallocate retained memory. */ + arena_destroy_retained(tsd_tsdn(tsd), arena); + + /* + * Remove the arena pointer from the arenas array. We rely on the fact + * that there is no way for the application to get a dirty read from the + * arenas array unless there is an inherent race in the application + * involving access of an arena being concurrently destroyed. The + * application must synchronize knowledge of the arena's validity, so as + * long as we use an atomic write to update the arenas array, the + * application will get a clean read any time after it synchronizes + * knowledge that the arena is no longer valid. + */ + arena_set(base_ind_get(arena->base), NULL); + + /* + * Destroy the base allocator, which manages all metadata ever mapped by + * this arena. + */ + base_delete(arena->base); +} + static extent_t * arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, const arena_bin_info_t *bin_info) diff --git a/src/ctl.c b/src/ctl.c index 45e397b8..76fbce4b 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -48,18 +48,6 @@ static int n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \ static const ctl_named_node_t *n##_index(tsdn_t *tsdn, \ const size_t *mib, size_t miblen, size_t i); -static void ctl_arena_clear(ctl_arena_stats_t *astats); -static void ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_stats_t *cstats, - arena_t *arena); -static void ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, - ctl_arena_stats_t *astats); -static void ctl_arena_refresh(tsdn_t *tsdn, arena_t *arena, unsigned i); -static bool ctl_grow(tsdn_t *tsdn, extent_hooks_t *extent_hooks); -static void ctl_refresh(tsdn_t *tsdn); -static bool ctl_init(tsdn_t *tsdn); -static int ctl_lookup(tsdn_t *tsdn, const char *name, - ctl_node_t const **nodesp, size_t *mibp, size_t *depthp); - CTL_PROTO(version) CTL_PROTO(epoch) CTL_PROTO(thread_tcache_enabled) @@ -113,6 +101,7 @@ CTL_PROTO(arena_i_initialized) CTL_PROTO(arena_i_purge) CTL_PROTO(arena_i_decay) CTL_PROTO(arena_i_reset) +CTL_PROTO(arena_i_destroy) CTL_PROTO(arena_i_dss) CTL_PROTO(arena_i_decay_time) CTL_PROTO(arena_i_extent_hooks) @@ -274,6 +263,7 @@ static const ctl_named_node_t arena_i_node[] = { {NAME("purge"), CTL(arena_i_purge)}, {NAME("decay"), CTL(arena_i_decay)}, {NAME("reset"), CTL(arena_i_reset)}, + {NAME("destroy"), CTL(arena_i_destroy)}, {NAME("dss"), CTL(arena_i_dss)}, {NAME("decay_time"), CTL(arena_i_decay_time)}, {NAME("extent_hooks"), CTL(arena_i_extent_hooks)} @@ -452,6 +442,9 @@ stats_arenas_i2a_impl(size_t i, bool compat, bool validate) case MALLCTL_ARENAS_ALL: a = 0; break; + case MALLCTL_ARENAS_DESTROYED: + a = 1; + break; default: if (compat && i == ctl_stats->narenas) { /* @@ -471,7 +464,7 @@ stats_arenas_i2a_impl(size_t i, bool compat, bool validate) */ assert(i < ctl_stats->narenas || (!validate && i == ctl_stats->narenas)); - a = (unsigned)i + 1; + a = (unsigned)i + 2; } break; } @@ -479,6 +472,13 @@ stats_arenas_i2a_impl(size_t i, bool compat, bool validate) return (a); } +static unsigned +stats_arenas_i2a(size_t i) +{ + + return (stats_arenas_i2a_impl(i, true, false)); +} + static ctl_arena_stats_t * stats_arenas_i_impl(tsdn_t *tsdn, size_t i, bool compat, bool init) { @@ -492,10 +492,13 @@ stats_arenas_i_impl(tsdn_t *tsdn, size_t i, bool compat, bool init) sizeof(ctl_arena_stats_t), QUANTUM); if (ret == NULL) return (NULL); + ret->arena_ind = (unsigned)i; ctl_stats->arenas[stats_arenas_i2a_impl(i, compat, false)] = ret; } + assert(ret == NULL || stats_arenas_i2a(ret->arena_ind) == + stats_arenas_i2a(i)); return (ret); } @@ -553,92 +556,130 @@ ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_stats_t *cstats, arena_t *arena) } static void -ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats) +ctl_arena_stats_sdmerge(ctl_arena_stats_t *sdstats, ctl_arena_stats_t *astats, + bool destroyed) { unsigned i; - sstats->nthreads += astats->nthreads; - sstats->pactive += astats->pactive; - sstats->pdirty += astats->pdirty; + if (!destroyed) { + sdstats->nthreads += astats->nthreads; + sdstats->pactive += astats->pactive; + sdstats->pdirty += astats->pdirty; + } else { + assert(astats->nthreads == 0); + assert(astats->pactive == 0); + assert(astats->pdirty == 0); + } if (config_stats) { - sstats->astats.mapped += astats->astats.mapped; - sstats->astats.retained += astats->astats.retained; - sstats->astats.npurge += astats->astats.npurge; - sstats->astats.nmadvise += astats->astats.nmadvise; - sstats->astats.purged += astats->astats.purged; - - sstats->astats.base += astats->astats.base; - sstats->astats.internal += astats->astats.internal; - sstats->astats.resident += astats->astats.resident; - - sstats->allocated_small += astats->allocated_small; - sstats->nmalloc_small += astats->nmalloc_small; - sstats->ndalloc_small += astats->ndalloc_small; - sstats->nrequests_small += astats->nrequests_small; - - sstats->astats.allocated_large += - astats->astats.allocated_large; - sstats->astats.nmalloc_large += astats->astats.nmalloc_large; - sstats->astats.ndalloc_large += astats->astats.ndalloc_large; - sstats->astats.nrequests_large += + if (!destroyed) { + sdstats->astats.mapped += astats->astats.mapped; + sdstats->astats.retained += astats->astats.retained; + } + sdstats->astats.npurge += astats->astats.npurge; + sdstats->astats.nmadvise += astats->astats.nmadvise; + sdstats->astats.purged += astats->astats.purged; + + if (!destroyed) { + sdstats->astats.base += astats->astats.base; + sdstats->astats.internal += astats->astats.internal; + sdstats->astats.resident += astats->astats.resident; + } else + assert(astats->astats.internal == 0); + + if (!destroyed) + sdstats->allocated_small += astats->allocated_small; + else + assert(astats->allocated_small == 0); + sdstats->nmalloc_small += astats->nmalloc_small; + sdstats->ndalloc_small += astats->ndalloc_small; + sdstats->nrequests_small += astats->nrequests_small; + + if (!destroyed) { + sdstats->astats.allocated_large += + astats->astats.allocated_large; + } else + assert(astats->astats.allocated_large == 0); + sdstats->astats.nmalloc_large += astats->astats.nmalloc_large; + sdstats->astats.ndalloc_large += astats->astats.ndalloc_large; + sdstats->astats.nrequests_large += astats->astats.nrequests_large; for (i = 0; i < NBINS; i++) { - sstats->bstats[i].nmalloc += astats->bstats[i].nmalloc; - sstats->bstats[i].ndalloc += astats->bstats[i].ndalloc; - sstats->bstats[i].nrequests += + sdstats->bstats[i].nmalloc += astats->bstats[i].nmalloc; + sdstats->bstats[i].ndalloc += astats->bstats[i].ndalloc; + sdstats->bstats[i].nrequests += astats->bstats[i].nrequests; - sstats->bstats[i].curregs += astats->bstats[i].curregs; + if (!destroyed) { + sdstats->bstats[i].curregs += + astats->bstats[i].curregs; + } else + assert(astats->bstats[i].curregs == 0); if (config_tcache) { - sstats->bstats[i].nfills += + sdstats->bstats[i].nfills += astats->bstats[i].nfills; - sstats->bstats[i].nflushes += + sdstats->bstats[i].nflushes += astats->bstats[i].nflushes; } - sstats->bstats[i].nslabs += astats->bstats[i].nslabs; - sstats->bstats[i].reslabs += astats->bstats[i].reslabs; - sstats->bstats[i].curslabs += - astats->bstats[i].curslabs; + sdstats->bstats[i].nslabs += astats->bstats[i].nslabs; + sdstats->bstats[i].reslabs += astats->bstats[i].reslabs; + if (!destroyed) { + sdstats->bstats[i].curslabs += + astats->bstats[i].curslabs; + } else + assert(astats->bstats[i].curslabs == 0); } for (i = 0; i < NSIZES - NBINS; i++) { - sstats->lstats[i].nmalloc += astats->lstats[i].nmalloc; - sstats->lstats[i].ndalloc += astats->lstats[i].ndalloc; - sstats->lstats[i].nrequests += + sdstats->lstats[i].nmalloc += astats->lstats[i].nmalloc; + sdstats->lstats[i].ndalloc += astats->lstats[i].ndalloc; + sdstats->lstats[i].nrequests += astats->lstats[i].nrequests; - sstats->lstats[i].curlextents += - astats->lstats[i].curlextents; + if (!destroyed) { + sdstats->lstats[i].curlextents += + astats->lstats[i].curlextents; + } else + assert(astats->lstats[i].curlextents == 0); } } } static void -ctl_arena_refresh(tsdn_t *tsdn, arena_t *arena, unsigned i) +ctl_arena_refresh(tsdn_t *tsdn, arena_t *arena, ctl_arena_stats_t *sdstats, + unsigned i, bool destroyed) { ctl_arena_stats_t *astats = stats_arenas_i(i); - ctl_arena_stats_t *sstats = stats_arenas_i(MALLCTL_ARENAS_ALL); ctl_arena_clear(astats); ctl_arena_stats_amerge(tsdn, astats, arena); /* Merge into sum stats as well. */ - ctl_arena_stats_smerge(sstats, astats); + ctl_arena_stats_sdmerge(sdstats, astats, destroyed); } -static bool -ctl_grow(tsdn_t *tsdn, extent_hooks_t *extent_hooks) +static unsigned +ctl_arena_init(tsdn_t *tsdn, extent_hooks_t *extent_hooks) { + unsigned arena_ind; + ctl_arena_stats_t *astats; + + if ((astats = ql_last(&ctl_stats->destroyed, destroyed_link)) != NULL) { + ql_remove(&ctl_stats->destroyed, astats, destroyed_link); + arena_ind = astats->arena_ind; + } else + arena_ind = ctl_stats->narenas; /* Trigger stats allocation. */ - if (stats_arenas_i_impl(tsdn, ctl_stats->narenas, false, true) == NULL) - return (true); + if (stats_arenas_i_impl(tsdn, arena_ind, false, true) == NULL) + return (UINT_MAX); /* Initialize new arena. */ - if (arena_init(tsdn, ctl_stats->narenas, extent_hooks) == NULL) - return (true); - ctl_stats->narenas++; + if (arena_init(tsdn, arena_ind, extent_hooks) == NULL) + return (UINT_MAX); - return (false); + if (arena_ind == ctl_stats->narenas) + ctl_stats->narenas++; + + return (arena_ind); } static void @@ -663,7 +704,7 @@ ctl_refresh(tsdn_t *tsdn) astats->initialized = initialized; if (initialized) - ctl_arena_refresh(tsdn, tarenas[i], i); + ctl_arena_refresh(tsdn, tarenas[i], sstats, i, false); } if (config_stats) { @@ -687,7 +728,7 @@ ctl_init(tsdn_t *tsdn) malloc_mutex_lock(tsdn, &ctl_mtx); if (!ctl_initialized) { - ctl_arena_stats_t *sstats; + ctl_arena_stats_t *sstats, *dstats; unsigned i; /* @@ -715,6 +756,19 @@ ctl_init(tsdn_t *tsdn) } sstats->initialized = true; + if ((dstats = stats_arenas_i_impl(tsdn, + MALLCTL_ARENAS_DESTROYED, false, true)) == NULL) { + ret = true; + goto label_return; + } + ctl_arena_clear(dstats); + /* + * Don't toggle stats for MALLCTL_ARENAS_DESTROYED to + * initialized until an arena is actually destroyed, so that + * arena..initialized can be used to query whether the stats + * are relevant. + */ + ctl_stats->narenas = narenas_total_get(); for (i = 0; i < ctl_stats->narenas; i++) { if (stats_arenas_i_impl(tsdn, i, false, true) == NULL) { @@ -723,7 +777,7 @@ ctl_init(tsdn_t *tsdn) } } - ctl_stats->epoch = 0; + ql_new(&ctl_stats->destroyed); ctl_refresh(tsdn); ctl_initialized = true; } @@ -1563,33 +1617,85 @@ label_return: } static int -arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) +arena_i_reset_destroy_helper(tsd_t *tsd, const size_t *mib, size_t miblen, + void *oldp, size_t *oldlenp, void *newp, size_t newlen, unsigned *arena_ind, + arena_t **arena) { int ret; - unsigned arena_ind; - arena_t *arena; READONLY(); WRITEONLY(); - MIB_UNSIGNED(arena_ind, 1); + MIB_UNSIGNED(*arena_ind, 1); - if (config_debug) { - malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); - assert(arena_ind < ctl_stats->narenas); - malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); + if (*arena_ind < narenas_auto) { + ret = EFAULT; + goto label_return; } - assert(arena_ind >= opt_narenas); - arena = arena_get(tsd_tsdn(tsd), arena_ind, false); - if (arena == NULL) { + *arena = arena_get(tsd_tsdn(tsd), *arena_ind, false); + if (*arena == NULL) { ret = EFAULT; goto label_return; } + ret = 0; +label_return: + return (ret); +} + +static int +arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, + size_t *oldlenp, void *newp, size_t newlen) +{ + int ret; + unsigned arena_ind; + arena_t *arena; + + ret = arena_i_reset_destroy_helper(tsd, mib, miblen, oldp, oldlenp, + newp, newlen, &arena_ind, &arena); + if (ret != 0) + return (ret); + arena_reset(tsd, arena); - ret = 0; + return (ret); +} + +static int +arena_i_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, + size_t *oldlenp, void *newp, size_t newlen) +{ + int ret; + unsigned arena_ind; + arena_t *arena; + ctl_arena_stats_t *dstats, *astats; + + ret = arena_i_reset_destroy_helper(tsd, mib, miblen, oldp, oldlenp, + newp, newlen, &arena_ind, &arena); + if (ret != 0) + goto label_return; + + if (arena_nthreads_get(arena, false) != 0 || arena_nthreads_get(arena, + true) != 0) { + ret = EFAULT; + goto label_return; + } + + /* Merge stats after resetting and purging arena. */ + arena_reset(tsd, arena); + arena_purge(tsd_tsdn(tsd), arena, true); + dstats = stats_arenas_i(MALLCTL_ARENAS_DESTROYED); + dstats->initialized = true; + ctl_arena_refresh(tsd_tsdn(tsd), arena, dstats, arena_ind, true); + /* Destroy arena. */ + arena_destroy(tsd, arena); + astats = stats_arenas_i(arena_ind); + astats->initialized = false; + /* Record arena index for later recycling via arenas.create. */ + ql_elm_new(astats, destroyed_link); + ql_tail_insert(&ctl_stats->destroyed, astats, destroyed_link); + + assert(ret == 0); label_return: return (ret); } @@ -1733,9 +1839,16 @@ arena_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) const ctl_named_node_t *ret; malloc_mutex_lock(tsdn, &ctl_mtx); - if (i > ctl_stats->narenas && i != MALLCTL_ARENAS_ALL) { - ret = NULL; - goto label_return; + switch (i) { + case MALLCTL_ARENAS_ALL: + case MALLCTL_ARENAS_DESTROYED: + break; + default: + if (i > ctl_stats->narenas) { + ret = NULL; + goto label_return; + } + break; } ret = super_arena_i_node; @@ -1828,18 +1941,18 @@ arenas_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, { int ret; extent_hooks_t *extent_hooks; - unsigned narenas; + unsigned arena_ind; malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); extent_hooks = (extent_hooks_t *)&extent_hooks_default; WRITE(extent_hooks, extent_hooks_t *); - if (ctl_grow(tsd_tsdn(tsd), extent_hooks)) { + if ((arena_ind = ctl_arena_init(tsd_tsdn(tsd), extent_hooks)) == + UINT_MAX) { ret = EAGAIN; goto label_return; } - narenas = ctl_stats->narenas - 1; - READ(narenas, unsigned); + READ(arena_ind, unsigned); ret = 0; label_return: diff --git a/src/extent.c b/src/extent.c index 6eabde31..7eb49709 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1039,11 +1039,11 @@ extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, size_t size, return (extent_dalloc_default_impl(addr, size)); } -void -extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, +bool +extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { - bool err, zeroed; + bool err; assert(extent_base_get(extent) != NULL); assert(extent_size_get(extent) != 0); @@ -1067,10 +1067,21 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_committed_get(extent), arena_ind_get(arena))); } - if (!err) { + if (!err) extent_dalloc(tsdn, arena, extent); + + return (err); +} + +void +extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent) +{ + bool zeroed; + + if (!extent_dalloc_wrapper_try(tsdn, arena, r_extent_hooks, extent)) return; - } + extent_reregister(tsdn, extent); /* Try to decommit; purge if that fails. */ if (!extent_committed_get(extent)) diff --git a/src/jemalloc.c b/src/jemalloc.c index 2acab412..a053983f 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -375,7 +375,7 @@ bootstrap_free(void *ptr) a0idalloc(iealloc(NULL, ptr), ptr, false); } -static void +void arena_set(unsigned ind, arena_t *arena) { diff --git a/src/stats.c b/src/stats.c index 4e09eb45..ef349a50 100644 --- a/src/stats.c +++ b/src/stats.c @@ -772,7 +772,8 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, static void stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, - bool json, bool merged, bool unmerged, bool bins, bool large) + bool json, bool merged, bool destroyed, bool unmerged, bool bins, + bool large) { size_t allocated, active, metadata, resident, mapped, retained; @@ -808,7 +809,7 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, allocated, active, metadata, resident, mapped, retained); } - if (merged || unmerged) { + if (merged || destroyed || unmerged) { unsigned narenas; if (json) { @@ -822,6 +823,7 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, size_t miblen = sizeof(mib) / sizeof(size_t); size_t sz; VARIABLE_ARRAY(bool, initialized, narenas); + bool destroyed_initialized; unsigned i, j, ninitialized; xmallctlnametomib("arena.0.initialized", mib, &miblen); @@ -833,6 +835,10 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, if (initialized[i]) ninitialized++; } + mib[1] = MALLCTL_ARENAS_DESTROYED; + sz = sizeof(bool); + xmallctlbymib(mib, miblen, &destroyed_initialized, &sz, + NULL, 0); /* Merged stats. */ if (merged && (ninitialized > 1 || !unmerged)) { @@ -853,6 +859,25 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, } } + /* Destroyed stats. */ + if (destroyed_initialized && destroyed) { + /* Print destroyed arena stats. */ + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"destroyed\": {\n"); + } else { + malloc_cprintf(write_cb, cbopaque, + "\nDestroyed arenas stats:\n"); + } + stats_arena_print(write_cb, cbopaque, json, + MALLCTL_ARENAS_DESTROYED, bins, large); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t}%s\n", (ninitialized > 1) ? + "," : ""); + } + } + /* Unmerged stats. */ for (i = j = 0; i < narenas; i++) { if (initialized[i]) { @@ -895,6 +920,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, bool json = false; bool general = true; bool merged = config_stats; + bool destroyed = config_stats; bool unmerged = config_stats; bool bins = true; bool large = true; @@ -935,6 +961,9 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, case 'm': merged = false; break; + case 'd': + destroyed = false; + break; case 'a': unmerged = false; break; @@ -963,8 +992,8 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, stats_general_print(write_cb, cbopaque, json, more); } if (config_stats) { - stats_print_helper(write_cb, cbopaque, json, merged, unmerged, - bins, large); + stats_print_helper(write_cb, cbopaque, json, merged, destroyed, + unmerged, bins, large); } if (json) { diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 3a1b30f5..65ff1031 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -1,9 +1,9 @@ +#ifndef ARENA_RESET_PROF_C_ #include "test/jemalloc_test.h" - -#ifdef JEMALLOC_PROF -const char *malloc_conf = "prof:true,lg_prof_sample:0"; #endif +#include "test/extent_hooks.h" + static unsigned get_nsizes_impl(const char *cmd) { @@ -79,57 +79,64 @@ vsalloc(tsdn_t *tsdn, const void *ptr) return (isalloc(tsdn, extent, ptr)); } -TEST_BEGIN(test_arena_reset) +static unsigned +do_arena_create(extent_hooks_t *h) +{ + unsigned arena_ind; + size_t sz = sizeof(unsigned); + assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, + (void *)(h != NULL ? &h : NULL), (h != NULL ? sizeof(h) : 0)), 0, + "Unexpected mallctl() failure"); + return (arena_ind); +} + +static void +do_arena_reset_pre(unsigned arena_ind, void ***ptrs, unsigned *nptrs) { #define NLARGE 32 - unsigned arena_ind, nsmall, nlarge, nptrs, i; - size_t sz, miblen; - void **ptrs; + unsigned nsmall, nlarge, i; + size_t sz; int flags; - size_t mib[3]; tsdn_t *tsdn; - sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), - 0, "Unexpected mallctl() failure"); - flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; nsmall = get_nsmall(); nlarge = get_nlarge() > NLARGE ? NLARGE : get_nlarge(); - nptrs = nsmall + nlarge; - ptrs = (void **)malloc(nptrs * sizeof(void *)); - assert_ptr_not_null(ptrs, "Unexpected malloc() failure"); + *nptrs = nsmall + nlarge; + *ptrs = (void **)malloc(*nptrs * sizeof(void *)); + assert_ptr_not_null(*ptrs, "Unexpected malloc() failure"); /* Allocate objects with a wide range of sizes. */ for (i = 0; i < nsmall; i++) { sz = get_small_size(i); - ptrs[i] = mallocx(sz, flags); - assert_ptr_not_null(ptrs[i], + (*ptrs)[i] = mallocx(sz, flags); + assert_ptr_not_null((*ptrs)[i], "Unexpected mallocx(%zu, %#x) failure", sz, flags); } for (i = 0; i < nlarge; i++) { sz = get_large_size(i); - ptrs[nsmall + i] = mallocx(sz, flags); - assert_ptr_not_null(ptrs[i], + (*ptrs)[nsmall + i] = mallocx(sz, flags); + assert_ptr_not_null((*ptrs)[i], "Unexpected mallocx(%zu, %#x) failure", sz, flags); } tsdn = tsdn_fetch(); /* Verify allocations. */ - for (i = 0; i < nptrs; i++) { - assert_zu_gt(ivsalloc(tsdn, ptrs[i]), 0, + for (i = 0; i < *nptrs; i++) { + assert_zu_gt(ivsalloc(tsdn, (*ptrs)[i]), 0, "Allocation should have queryable size"); } +} - /* Reset. */ - miblen = sizeof(mib)/sizeof(size_t); - assert_d_eq(mallctlnametomib("arena.0.reset", mib, &miblen), 0, - "Unexpected mallctlnametomib() failure"); - mib[1] = (size_t)arena_ind; - assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, - "Unexpected mallctlbymib() failure"); +static void +do_arena_reset_post(void **ptrs, unsigned nptrs) +{ + tsdn_t *tsdn; + unsigned i; + + tsdn = tsdn_fetch(); /* Verify allocations no longer exist. */ for (i = 0; i < nptrs; i++) { @@ -139,6 +146,193 @@ TEST_BEGIN(test_arena_reset) free(ptrs); } + +static void +do_arena_reset_destroy(const char *name, unsigned arena_ind) +{ + size_t mib[3]; + size_t miblen; + + miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib(name, mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + mib[1] = (size_t)arena_ind; + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, + "Unexpected mallctlbymib() failure"); +} + +static void +do_arena_reset(unsigned arena_ind) +{ + + do_arena_reset_destroy("arena.0.reset", arena_ind); +} + +static void +do_arena_destroy(unsigned arena_ind) +{ + + do_arena_reset_destroy("arena.0.destroy", arena_ind); +} + +TEST_BEGIN(test_arena_reset) +{ + unsigned arena_ind; + void **ptrs; + unsigned nptrs; + + arena_ind = do_arena_create(NULL); + do_arena_reset_pre(arena_ind, &ptrs, &nptrs); + do_arena_reset(arena_ind); + do_arena_reset_post(ptrs, nptrs); +} +TEST_END + +static bool +arena_i_initialized(unsigned arena_ind, bool refresh) +{ + bool initialized; + size_t mib[3]; + size_t miblen, sz; + + if (refresh) { + uint64_t epoch = 1; + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, + sizeof(epoch)), 0, "Unexpected mallctl() failure"); + } + + miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("arena.0.initialized", mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + mib[1] = (size_t)arena_ind; + sz = sizeof(initialized); + assert_d_eq(mallctlbymib(mib, miblen, (void *)&initialized, &sz, NULL, + 0), 0, "Unexpected mallctlbymib() failure"); + + return (initialized); +} + +TEST_BEGIN(test_arena_destroy_initial) +{ + + assert_false(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false), + "Destroyed arena stats should not be initialized"); +} +TEST_END + +TEST_BEGIN(test_arena_destroy_hooks_default) +{ + unsigned arena_ind, arena_ind_another, arena_ind_prev; + void **ptrs; + unsigned nptrs; + + arena_ind = do_arena_create(NULL); + do_arena_reset_pre(arena_ind, &ptrs, &nptrs); + + assert_false(arena_i_initialized(arena_ind, false), + "Arena stats should not be initialized"); + assert_true(arena_i_initialized(arena_ind, true), + "Arena stats should be initialized"); + + /* + * Create another arena before destroying one, to better verify arena + * index reuse. + */ + arena_ind_another = do_arena_create(NULL); + + do_arena_destroy(arena_ind); + + assert_false(arena_i_initialized(arena_ind, true), + "Arena stats should not be initialized"); + assert_true(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false), + "Destroyed arena stats should be initialized"); + + do_arena_reset_post(ptrs, nptrs); + + arena_ind_prev = arena_ind; + arena_ind = do_arena_create(NULL); + do_arena_reset_pre(arena_ind, &ptrs, &nptrs); + assert_u_eq(arena_ind, arena_ind_prev, + "Arena index should have been recycled"); + do_arena_destroy(arena_ind); + do_arena_reset_post(ptrs, nptrs); + + do_arena_destroy(arena_ind_another); +} +TEST_END + +/* + * Actually unmap extents, regardless of config_munmap, so that attempts to + * access a destroyed arena's memory will segfault. + */ +static bool +extent_dalloc_unmap(extent_hooks_t *extent_hooks, void *addr, size_t size, + bool committed, unsigned arena_ind) +{ + + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, " + "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ? + "true" : "false", arena_ind); + assert_ptr_eq(extent_hooks, &hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->dalloc, extent_dalloc_unmap, + "Wrong hook function"); + called_dalloc = true; + if (!try_dalloc) + return (true); + pages_unmap(addr, size); + did_dalloc = true; + return (false); +} + +static extent_hooks_t hooks_orig; + +static extent_hooks_t hooks_unmap = { + extent_alloc_hook, + extent_dalloc_unmap, /* dalloc */ + extent_commit_hook, + extent_decommit_hook, + extent_purge_lazy_hook, + extent_purge_forced_hook, + extent_split_hook, + extent_merge_hook +}; + +TEST_BEGIN(test_arena_destroy_hooks_unmap) +{ + unsigned arena_ind; + void **ptrs; + unsigned nptrs; + + extent_hooks_prep(); + try_decommit = false; + memcpy(&hooks_orig, &hooks, sizeof(extent_hooks_t)); + memcpy(&hooks, &hooks_unmap, sizeof(extent_hooks_t)); + + did_alloc = false; + arena_ind = do_arena_create(&hooks); + do_arena_reset_pre(arena_ind, &ptrs, &nptrs); + + assert_true(did_alloc, "Expected alloc"); + + assert_false(arena_i_initialized(arena_ind, false), + "Arena stats should not be initialized"); + assert_true(arena_i_initialized(arena_ind, true), + "Arena stats should be initialized"); + + did_dalloc = false; + do_arena_destroy(arena_ind); + assert_true(did_dalloc, "Expected dalloc"); + + assert_false(arena_i_initialized(arena_ind, true), + "Arena stats should not be initialized"); + assert_true(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false), + "Destroyed arena stats should be initialized"); + + do_arena_reset_post(ptrs, nptrs); + + memcpy(&hooks, &hooks_orig, sizeof(extent_hooks_t)); +} TEST_END int @@ -146,5 +340,8 @@ main(void) { return (test( - test_arena_reset)); + test_arena_reset, + test_arena_destroy_initial, + test_arena_destroy_hooks_default, + test_arena_destroy_hooks_unmap)); } diff --git a/test/unit/arena_reset_prof.c b/test/unit/arena_reset_prof.c new file mode 100644 index 00000000..0fd362e9 --- /dev/null +++ b/test/unit/arena_reset_prof.c @@ -0,0 +1,5 @@ +#include "test/jemalloc_test.h" +#define ARENA_RESET_PROF_C_ + +const char *malloc_conf = "prof:true,lg_prof_sample:0"; +#include "arena_reset.c" diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index b3320788..fbe76cb4 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -381,6 +381,15 @@ TEST_BEGIN(test_arena_i_initialized) "Unexpected mallctl() failure"); assert_true(initialized, "Merged arena statistics should always be initialized"); + + /* Equivalent to the above but using mallctl() directly. */ + sz = sizeof(initialized); + assert_d_eq(mallctl( + "arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".initialized", + (void *)&initialized, &sz, NULL, 0), 0, + "Unexpected mallctl() failure"); + assert_true(initialized, + "Merged arena statistics should always be initialized"); } TEST_END -- GitLab From 77de5f27d848414a6d26e86e2812339ffe1062d3 Mon Sep 17 00:00:00 2001 From: John Paul Adrian Glaubitz Date: Wed, 21 Dec 2016 09:38:54 +0100 Subject: [PATCH 222/544] Use better pre-processor defines for sparc64 Currently, jemalloc detects sparc64 targets by checking whether __sparc64__ is defined. However, this definition is used on BSD targets only. Linux targets define both __sparc__ and __arch64__ for sparc64. Since this also works on BSD, rather use __sparc__ and __arch64__ instead of __sparc64__ to detect sparc64 targets. --- include/jemalloc/internal/mb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/jemalloc/internal/mb.h b/include/jemalloc/internal/mb.h index 5384728f..e58da5c3 100644 --- a/include/jemalloc/internal/mb.h +++ b/include/jemalloc/internal/mb.h @@ -76,7 +76,7 @@ mb_write(void) : "memory" /* Clobbers. */ ); } -#elif defined(__sparc64__) +#elif defined(__sparc__) && defined(__arch64__) JEMALLOC_INLINE void mb_write(void) { -- GitLab From 94c5d22a4da7844d0bdc5b370e47b1ba14268af2 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 11 Jan 2017 13:23:17 -0800 Subject: [PATCH 223/544] Remove mb.h, which is unused --- .../jemalloc/internal/jemalloc_internal.h.in | 4 - include/jemalloc/internal/mb.h | 115 ------------------ 2 files changed, 119 deletions(-) delete mode 100644 include/jemalloc/internal/mb.h diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 6395d750..a558012a 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -376,7 +376,6 @@ typedef unsigned szind_t; #include "jemalloc/internal/witness.h" #include "jemalloc/internal/mutex.h" #include "jemalloc/internal/tsd.h" -#include "jemalloc/internal/mb.h" #include "jemalloc/internal/extent.h" #include "jemalloc/internal/base.h" #include "jemalloc/internal/arena.h" @@ -405,7 +404,6 @@ typedef unsigned szind_t; #include "jemalloc/internal/ctl.h" #include "jemalloc/internal/witness.h" #include "jemalloc/internal/mutex.h" -#include "jemalloc/internal/mb.h" #include "jemalloc/internal/bitmap.h" #define JEMALLOC_ARENA_STRUCTS_A #include "jemalloc/internal/arena.h" @@ -497,7 +495,6 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/ctl.h" #include "jemalloc/internal/witness.h" #include "jemalloc/internal/mutex.h" -#include "jemalloc/internal/mb.h" #include "jemalloc/internal/bitmap.h" #include "jemalloc/internal/extent.h" #include "jemalloc/internal/base.h" @@ -528,7 +525,6 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/tsd.h" #include "jemalloc/internal/witness.h" #include "jemalloc/internal/mutex.h" -#include "jemalloc/internal/mb.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/extent.h" #include "jemalloc/internal/base.h" diff --git a/include/jemalloc/internal/mb.h b/include/jemalloc/internal/mb.h deleted file mode 100644 index e58da5c3..00000000 --- a/include/jemalloc/internal/mb.h +++ /dev/null @@ -1,115 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#ifndef JEMALLOC_ENABLE_INLINE -void mb_write(void); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MB_C_)) -#ifdef __i386__ -/* - * According to the Intel Architecture Software Developer's Manual, current - * processors execute instructions in order from the perspective of other - * processors in a multiprocessor system, but 1) Intel reserves the right to - * change that, and 2) the compiler's optimizer could re-order instructions if - * there weren't some form of barrier. Therefore, even if running on an - * architecture that does not need memory barriers (everything through at least - * i686), an "optimizer barrier" is necessary. - */ -JEMALLOC_INLINE void -mb_write(void) -{ - -# if 0 - /* This is a true memory barrier. */ - asm volatile ("pusha;" - "xor %%eax,%%eax;" - "cpuid;" - "popa;" - : /* Outputs. */ - : /* Inputs. */ - : "memory" /* Clobbers. */ - ); -# else - /* - * This is hopefully enough to keep the compiler from reordering - * instructions around this one. - */ - asm volatile ("nop;" - : /* Outputs. */ - : /* Inputs. */ - : "memory" /* Clobbers. */ - ); -# endif -} -#elif (defined(__amd64__) || defined(__x86_64__)) -JEMALLOC_INLINE void -mb_write(void) -{ - - asm volatile ("sfence" - : /* Outputs. */ - : /* Inputs. */ - : "memory" /* Clobbers. */ - ); -} -#elif defined(__powerpc__) -JEMALLOC_INLINE void -mb_write(void) -{ - - asm volatile ("eieio" - : /* Outputs. */ - : /* Inputs. */ - : "memory" /* Clobbers. */ - ); -} -#elif defined(__sparc__) && defined(__arch64__) -JEMALLOC_INLINE void -mb_write(void) -{ - - asm volatile ("membar #StoreStore" - : /* Outputs. */ - : /* Inputs. */ - : "memory" /* Clobbers. */ - ); -} -#elif defined(__tile__) -JEMALLOC_INLINE void -mb_write(void) -{ - - __sync_synchronize(); -} -#else -/* - * This is much slower than a simple memory barrier, but the semantics of mutex - * unlock make this work. - */ -JEMALLOC_INLINE void -mb_write(void) -{ - malloc_mutex_t mtx; - - malloc_mutex_init(&mtx, "mb", WITNESS_RANK_OMIT); - malloc_mutex_lock(TSDN_NULL, &mtx); - malloc_mutex_unlock(TSDN_NULL, &mtx); -} -#endif -#endif - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ -- GitLab From 77cccac8cde9fb1f1555331814c4e6440c16de43 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 10 Jan 2017 18:06:31 -0800 Subject: [PATCH 224/544] Break up headers into constituent parts This is part of a broader change to make header files better represent the dependencies between one another (see https://github.com/jemalloc/jemalloc/issues/533). It breaks up component headers into smaller parts that can be made to have a simpler dependency graph. For the autogenerated headers (smoothstep.h and size_classes.h), no splitting was necessary, so I didn't add support to emit multiple headers. --- include/jemalloc/internal/arena.h | 638 ------------------ include/jemalloc/internal/arena_externs.h | 92 +++ include/jemalloc/internal/arena_inlines_a.h | 91 +++ include/jemalloc/internal/arena_inlines_b.h | 209 ++++++ include/jemalloc/internal/arena_structs_a.h | 15 + include/jemalloc/internal/arena_structs_b.h | 214 ++++++ include/jemalloc/internal/arena_types.h | 22 + include/jemalloc/internal/atomic_externs.h | 12 + .../internal/{atomic.h => atomic_inlines.h} | 28 +- include/jemalloc/internal/base.h | 87 --- include/jemalloc/internal/base_externs.h | 18 + include/jemalloc/internal/base_inlines.h | 17 + include/jemalloc/internal/base_structs.h | 44 ++ include/jemalloc/internal/base_types.h | 7 + include/jemalloc/internal/bitmap.h | 322 --------- include/jemalloc/internal/bitmap_externs.h | 8 + include/jemalloc/internal/bitmap_inlines.h | 152 +++++ include/jemalloc/internal/bitmap_structs.h | 28 + include/jemalloc/internal/bitmap_types.h | 133 ++++ include/jemalloc/internal/ckh.h | 86 --- include/jemalloc/internal/ckh_externs.h | 18 + include/jemalloc/internal/ckh_structs.h | 41 ++ include/jemalloc/internal/ckh_types.h | 22 + include/jemalloc/internal/ctl.h | 127 ---- include/jemalloc/internal/ctl_externs.h | 43 ++ include/jemalloc/internal/ctl_structs.h | 68 ++ include/jemalloc/internal/ctl_types.h | 10 + include/jemalloc/internal/extent_dss.h | 39 -- .../jemalloc/internal/extent_dss_externs.h | 14 + .../jemalloc/internal/extent_dss_structs.h | 6 + include/jemalloc/internal/extent_dss_types.h | 14 + include/jemalloc/internal/extent_externs.h | 60 ++ .../internal/{extent.h => extent_inlines.h} | 162 +---- include/jemalloc/internal/extent_mmap.h | 21 - .../jemalloc/internal/extent_mmap_externs.h | 8 + include/jemalloc/internal/extent_structs.h | 84 +++ include/jemalloc/internal/extent_types.h | 8 + .../internal/{hash.h => hash_inlines.h} | 20 +- .../jemalloc/internal/jemalloc_internal.h.in | 237 +++---- .../internal/jemalloc_internal_macros.h | 5 + .../internal/{large.h => large_externs.h} | 19 +- include/jemalloc/internal/mutex.h | 150 ---- include/jemalloc/internal/mutex_externs.h | 18 + include/jemalloc/internal/mutex_inlines.h | 74 ++ include/jemalloc/internal/mutex_structs.h | 24 + include/jemalloc/internal/mutex_types.h | 33 + .../internal/{nstime.h => nstime_externs.h} | 28 +- include/jemalloc/internal/nstime_structs.h | 8 + include/jemalloc/internal/nstime_types.h | 9 + include/jemalloc/internal/pages_externs.h | 31 + .../internal/{pages.h => pages_types.h} | 47 +- .../internal/{prng.h => prng_inlines.h} | 44 +- include/jemalloc/internal/prng_types.h | 29 + include/jemalloc/internal/prof.h | 568 ---------------- include/jemalloc/internal/prof_externs.h | 83 +++ include/jemalloc/internal/prof_inlines.h | 242 +++++++ include/jemalloc/internal/prof_structs.h | 187 +++++ include/jemalloc/internal/prof_types.h | 55 ++ include/jemalloc/internal/ql.h | 5 + include/jemalloc/internal/qr.h | 5 + include/jemalloc/internal/rtree_externs.h | 23 + .../internal/{rtree.h => rtree_inlines.h} | 172 +---- include/jemalloc/internal/rtree_structs.h | 86 +++ include/jemalloc/internal/rtree_types.h | 58 ++ include/jemalloc/internal/size_classes.sh | 23 +- include/jemalloc/internal/smoothstep.h | 22 +- include/jemalloc/internal/smoothstep.sh | 22 +- include/jemalloc/internal/spin.h | 51 -- include/jemalloc/internal/spin_inlines.h | 31 + include/jemalloc/internal/spin_structs.h | 8 + include/jemalloc/internal/spin_types.h | 6 + include/jemalloc/internal/stats_externs.h | 9 + .../internal/{stats.h => stats_structs.h} | 29 +- include/jemalloc/internal/stats_types.h | 9 + include/jemalloc/internal/tcache_externs.h | 47 ++ .../internal/{tcache.h => tcache_inlines.h} | 159 +---- include/jemalloc/internal/tcache_structs.h | 55 ++ include/jemalloc/internal/tcache_types.h | 50 ++ .../internal/{ticker.h => ticker_inlines.h} | 26 +- include/jemalloc/internal/ticker_structs.h | 9 + include/jemalloc/internal/ticker_types.h | 6 + include/jemalloc/internal/tsd_externs.h | 18 + include/jemalloc/internal/tsd_inlines.h | 140 ++++ include/jemalloc/internal/tsd_structs.h | 73 ++ .../jemalloc/internal/{tsd.h => tsd_types.h} | 238 +------ include/jemalloc/internal/util_externs.h | 23 + .../internal/{util.h => util_inlines.h} | 128 +--- include/jemalloc/internal/util_types.h | 94 +++ include/jemalloc/internal/witness.h | 275 -------- include/jemalloc/internal/witness_externs.h | 37 + include/jemalloc/internal/witness_inlines.h | 163 +++++ include/jemalloc/internal/witness_structs.h | 28 + include/jemalloc/internal/witness_types.h | 46 ++ test/include/test/jemalloc_test.h.in | 16 +- 94 files changed, 3455 insertions(+), 3614 deletions(-) delete mode 100644 include/jemalloc/internal/arena.h create mode 100644 include/jemalloc/internal/arena_externs.h create mode 100644 include/jemalloc/internal/arena_inlines_a.h create mode 100644 include/jemalloc/internal/arena_inlines_b.h create mode 100644 include/jemalloc/internal/arena_structs_a.h create mode 100644 include/jemalloc/internal/arena_structs_b.h create mode 100644 include/jemalloc/internal/arena_types.h create mode 100644 include/jemalloc/internal/atomic_externs.h rename include/jemalloc/internal/{atomic.h => atomic_inlines.h} (93%) delete mode 100644 include/jemalloc/internal/base.h create mode 100644 include/jemalloc/internal/base_externs.h create mode 100644 include/jemalloc/internal/base_inlines.h create mode 100644 include/jemalloc/internal/base_structs.h create mode 100644 include/jemalloc/internal/base_types.h delete mode 100644 include/jemalloc/internal/bitmap.h create mode 100644 include/jemalloc/internal/bitmap_externs.h create mode 100644 include/jemalloc/internal/bitmap_inlines.h create mode 100644 include/jemalloc/internal/bitmap_structs.h create mode 100644 include/jemalloc/internal/bitmap_types.h delete mode 100644 include/jemalloc/internal/ckh.h create mode 100644 include/jemalloc/internal/ckh_externs.h create mode 100644 include/jemalloc/internal/ckh_structs.h create mode 100644 include/jemalloc/internal/ckh_types.h delete mode 100644 include/jemalloc/internal/ctl.h create mode 100644 include/jemalloc/internal/ctl_externs.h create mode 100644 include/jemalloc/internal/ctl_structs.h create mode 100644 include/jemalloc/internal/ctl_types.h delete mode 100644 include/jemalloc/internal/extent_dss.h create mode 100644 include/jemalloc/internal/extent_dss_externs.h create mode 100644 include/jemalloc/internal/extent_dss_structs.h create mode 100644 include/jemalloc/internal/extent_dss_types.h create mode 100644 include/jemalloc/internal/extent_externs.h rename include/jemalloc/internal/{extent.h => extent_inlines.h} (58%) delete mode 100644 include/jemalloc/internal/extent_mmap.h create mode 100644 include/jemalloc/internal/extent_mmap_externs.h create mode 100644 include/jemalloc/internal/extent_structs.h create mode 100644 include/jemalloc/internal/extent_types.h rename include/jemalloc/internal/{hash.h => hash_inlines.h} (92%) rename include/jemalloc/internal/{large.h => large_externs.h} (64%) delete mode 100644 include/jemalloc/internal/mutex.h create mode 100644 include/jemalloc/internal/mutex_externs.h create mode 100644 include/jemalloc/internal/mutex_inlines.h create mode 100644 include/jemalloc/internal/mutex_structs.h create mode 100644 include/jemalloc/internal/mutex_types.h rename include/jemalloc/internal/{nstime.h => nstime_externs.h} (53%) create mode 100644 include/jemalloc/internal/nstime_structs.h create mode 100644 include/jemalloc/internal/nstime_types.h create mode 100644 include/jemalloc/internal/pages_externs.h rename include/jemalloc/internal/{pages.h => pages_types.h} (54%) rename include/jemalloc/internal/{prng.h => prng_inlines.h} (71%) create mode 100644 include/jemalloc/internal/prng_types.h delete mode 100644 include/jemalloc/internal/prof.h create mode 100644 include/jemalloc/internal/prof_externs.h create mode 100644 include/jemalloc/internal/prof_inlines.h create mode 100644 include/jemalloc/internal/prof_structs.h create mode 100644 include/jemalloc/internal/prof_types.h create mode 100644 include/jemalloc/internal/rtree_externs.h rename include/jemalloc/internal/{rtree.h => rtree_inlines.h} (68%) create mode 100644 include/jemalloc/internal/rtree_structs.h create mode 100644 include/jemalloc/internal/rtree_types.h delete mode 100644 include/jemalloc/internal/spin.h create mode 100644 include/jemalloc/internal/spin_inlines.h create mode 100644 include/jemalloc/internal/spin_structs.h create mode 100644 include/jemalloc/internal/spin_types.h create mode 100644 include/jemalloc/internal/stats_externs.h rename include/jemalloc/internal/{stats.h => stats_structs.h} (72%) create mode 100644 include/jemalloc/internal/stats_types.h create mode 100644 include/jemalloc/internal/tcache_externs.h rename include/jemalloc/internal/{tcache.h => tcache_inlines.h} (57%) create mode 100644 include/jemalloc/internal/tcache_structs.h create mode 100644 include/jemalloc/internal/tcache_types.h rename include/jemalloc/internal/{ticker.h => ticker_inlines.h} (57%) create mode 100644 include/jemalloc/internal/ticker_structs.h create mode 100644 include/jemalloc/internal/ticker_types.h create mode 100644 include/jemalloc/internal/tsd_externs.h create mode 100644 include/jemalloc/internal/tsd_inlines.h create mode 100644 include/jemalloc/internal/tsd_structs.h rename include/jemalloc/internal/{tsd.h => tsd_types.h} (74%) create mode 100644 include/jemalloc/internal/util_externs.h rename include/jemalloc/internal/{util.h => util_inlines.h} (50%) create mode 100644 include/jemalloc/internal/util_types.h delete mode 100644 include/jemalloc/internal/witness.h create mode 100644 include/jemalloc/internal/witness_externs.h create mode 100644 include/jemalloc/internal/witness_inlines.h create mode 100644 include/jemalloc/internal/witness_structs.h create mode 100644 include/jemalloc/internal/witness_types.h diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h deleted file mode 100644 index 5e295509..00000000 --- a/include/jemalloc/internal/arena.h +++ /dev/null @@ -1,638 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -#define LARGE_MINCLASS (ZU(1) << LG_LARGE_MINCLASS) - -/* Maximum number of regions in one slab. */ -#define LG_SLAB_MAXREGS (LG_PAGE - LG_TINY_MIN) -#define SLAB_MAXREGS (1U << LG_SLAB_MAXREGS) - -/* Default decay time in seconds. */ -#define DECAY_TIME_DEFAULT 10 -/* Number of event ticks between time checks. */ -#define DECAY_NTICKS_PER_UPDATE 1000 - -typedef struct arena_slab_data_s arena_slab_data_t; -typedef struct arena_bin_info_s arena_bin_info_t; -typedef struct arena_decay_s arena_decay_t; -typedef struct arena_bin_s arena_bin_t; -typedef struct arena_s arena_t; -typedef struct arena_tdata_s arena_tdata_t; - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -#ifdef JEMALLOC_ARENA_STRUCTS_A -struct arena_slab_data_s { - /* Index of bin this slab is associated with. */ - szind_t binind; - - /* Number of free regions in slab. */ - unsigned nfree; - - /* Per region allocated/deallocated bitmap. */ - bitmap_t bitmap[BITMAP_GROUPS_MAX]; -}; -#endif /* JEMALLOC_ARENA_STRUCTS_A */ - -#ifdef JEMALLOC_ARENA_STRUCTS_B -/* - * Read-only information associated with each element of arena_t's bins array - * is stored separately, partly to reduce memory usage (only one copy, rather - * than one per arena), but mainly to avoid false cacheline sharing. - * - * Each slab has the following layout: - * - * /--------------------\ - * | region 0 | - * |--------------------| - * | region 1 | - * |--------------------| - * | ... | - * | ... | - * | ... | - * |--------------------| - * | region nregs-1 | - * \--------------------/ - */ -struct arena_bin_info_s { - /* Size of regions in a slab for this bin's size class. */ - size_t reg_size; - - /* Total size of a slab for this bin's size class. */ - size_t slab_size; - - /* Total number of regions in a slab for this bin's size class. */ - uint32_t nregs; - - /* - * Metadata used to manipulate bitmaps for slabs associated with this - * bin. - */ - bitmap_info_t bitmap_info; -}; - -struct arena_decay_s { - /* - * Approximate time in seconds from the creation of a set of unused - * dirty pages until an equivalent set of unused dirty pages is purged - * and/or reused. - */ - ssize_t time; - /* time / SMOOTHSTEP_NSTEPS. */ - nstime_t interval; - /* - * Time at which the current decay interval logically started. We do - * not actually advance to a new epoch until sometime after it starts - * because of scheduling and computation delays, and it is even possible - * to completely skip epochs. In all cases, during epoch advancement we - * merge all relevant activity into the most recently recorded epoch. - */ - nstime_t epoch; - /* Deadline randomness generator. */ - uint64_t jitter_state; - /* - * Deadline for current epoch. This is the sum of interval and per - * epoch jitter which is a uniform random variable in [0..interval). - * Epochs always advance by precise multiples of interval, but we - * randomize the deadline to reduce the likelihood of arenas purging in - * lockstep. - */ - nstime_t deadline; - /* - * Number of dirty pages at beginning of current epoch. During epoch - * advancement we use the delta between arena->decay.ndirty and - * arena->ndirty to determine how many dirty pages, if any, were - * generated. - */ - size_t nunpurged; - /* - * Trailing log of how many unused dirty pages were generated during - * each of the past SMOOTHSTEP_NSTEPS decay epochs, where the last - * element is the most recent epoch. Corresponding epoch times are - * relative to epoch. - */ - size_t backlog[SMOOTHSTEP_NSTEPS]; -}; - -struct arena_bin_s { - /* All operations on arena_bin_t fields require lock ownership. */ - malloc_mutex_t lock; - - /* - * Current slab being used to service allocations of this bin's size - * class. slabcur is independent of slabs_{nonfull,full}; whenever - * slabcur is reassigned, the previous slab must be deallocated or - * inserted into slabs_{nonfull,full}. - */ - extent_t *slabcur; - - /* - * Heap of non-full slabs. This heap is used to assure that new - * allocations come from the non-full slab that is oldest/lowest in - * memory. - */ - extent_heap_t slabs_nonfull; - - /* Ring sentinel used to track full slabs. */ - extent_t slabs_full; - - /* Bin statistics. */ - malloc_bin_stats_t stats; -}; - -struct arena_s { - /* - * Number of threads currently assigned to this arena, synchronized via - * atomic operations. Each thread has two distinct assignments, one for - * application-serving allocation, and the other for internal metadata - * allocation. Internal metadata must not be allocated from arenas - * explicitly created via the arenas.create mallctl, because the - * arena..reset mallctl indiscriminately discards all allocations for - * the affected arena. - * - * 0: Application allocation. - * 1: Internal metadata allocation. - */ - unsigned nthreads[2]; - - /* - * There are three classes of arena operations from a locking - * perspective: - * 1) Thread assignment (modifies nthreads) is synchronized via atomics. - * 2) Bin-related operations are protected by bin locks. - * 3) Extent-related operations are protected by this mutex. - */ - malloc_mutex_t lock; - - arena_stats_t stats; - /* - * List of tcaches for extant threads associated with this arena. - * Stats from these are merged incrementally, and at exit if - * opt_stats_print is enabled. - */ - ql_head(tcache_t) tcache_ql; - - uint64_t prof_accumbytes; - - /* - * PRNG state for cache index randomization of large allocation base - * pointers. - */ - size_t offset_state; - - /* Extent serial number generator state. */ - size_t extent_sn_next; - - dss_prec_t dss_prec; - - /* True if a thread is currently executing arena_purge_to_limit(). */ - bool purging; - - /* Number of pages in active extents. */ - size_t nactive; - - /* - * Current count of pages within unused extents that are potentially - * dirty, and for which pages_purge_*() has not been called. By - * tracking this, we can institute a limit on how much dirty unused - * memory is mapped for each arena. - */ - size_t ndirty; - - /* Decay-based purging state. */ - arena_decay_t decay; - - /* Extant large allocations. */ - ql_head(extent_t) large; - /* Synchronizes all large allocation/update/deallocation. */ - malloc_mutex_t large_mtx; - - /* - * Heaps of extents that were previously allocated. These are used when - * allocating extents, in an attempt to re-use address space. - */ - extent_heap_t extents_cached[NPSIZES+1]; - extent_heap_t extents_retained[NPSIZES+1]; - /* - * Ring sentinel used to track unused dirty memory. Dirty memory is - * managed as an LRU of cached extents. - */ - extent_t extents_dirty; - /* Protects extents_{cached,retained,dirty}. */ - malloc_mutex_t extents_mtx; - - /* - * Next extent size class in a growing series to use when satisfying a - * request via the extent hooks (only if !config_munmap). This limits - * the number of disjoint virtual memory ranges so that extent merging - * can be effective even if multiple arenas' extent allocation requests - * are highly interleaved. - */ - pszind_t extent_grow_next; - - /* Cache of extent structures that were allocated via base_alloc(). */ - ql_head(extent_t) extent_cache; - malloc_mutex_t extent_cache_mtx; - - /* bins is used to store heaps of free regions. */ - arena_bin_t bins[NBINS]; - - /* Base allocator, from which arena metadata are allocated. */ - base_t *base; -}; - -/* Used in conjunction with tsd for fast arena-related context lookup. */ -struct arena_tdata_s { - ticker_t decay_ticker; -}; -#endif /* JEMALLOC_ARENA_STRUCTS_B */ - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -static const size_t large_pad = -#ifdef JEMALLOC_CACHE_OBLIVIOUS - PAGE -#else - 0 -#endif - ; - -extern ssize_t opt_decay_time; - -extern const arena_bin_info_t arena_bin_info[NBINS]; - -extent_t *arena_extent_cache_alloc(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, - size_t alignment, bool *zero); -void arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent); -void arena_extent_cache_maybe_insert(tsdn_t *tsdn, arena_t *arena, - extent_t *extent, bool cache); -void arena_extent_cache_maybe_remove(tsdn_t *tsdn, arena_t *arena, - extent_t *extent, bool cache); -#ifdef JEMALLOC_JET -size_t arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr); -#endif -extent_t *arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, - size_t usize, size_t alignment, bool *zero); -void arena_extent_dalloc_large(tsdn_t *tsdn, arena_t *arena, - extent_t *extent, bool locked); -void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, - extent_t *extent, size_t oldsize); -void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, - extent_t *extent, size_t oldsize); -ssize_t arena_decay_time_get(tsdn_t *tsdn, arena_t *arena); -bool arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time); -void arena_purge(tsdn_t *tsdn, arena_t *arena, bool all); -void arena_maybe_purge(tsdn_t *tsdn, arena_t *arena); -void arena_reset(tsd_t *tsd, arena_t *arena); -void arena_destroy(tsd_t *tsd, arena_t *arena); -void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, - tcache_bin_t *tbin, szind_t binind, uint64_t prof_accumbytes); -void arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, - bool zero); -#ifdef JEMALLOC_JET -typedef void (arena_dalloc_junk_small_t)(void *, const arena_bin_info_t *); -extern arena_dalloc_junk_small_t *arena_dalloc_junk_small; -#else -void arena_dalloc_junk_small(void *ptr, const arena_bin_info_t *bin_info); -#endif -void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, - szind_t ind, bool zero); -void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, - size_t alignment, bool zero, tcache_t *tcache); -void arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize); -void arena_dalloc_promoted(tsdn_t *tsdn, extent_t *extent, void *ptr, - tcache_t *tcache, bool slow_path); -void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, - extent_t *extent, void *ptr); -void arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - void *ptr); -bool arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, - size_t oldsize, size_t size, size_t extra, bool zero); -void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, - size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache); -dss_prec_t arena_dss_prec_get(tsdn_t *tsdn, arena_t *arena); -bool arena_dss_prec_set(tsdn_t *tsdn, arena_t *arena, dss_prec_t dss_prec); -ssize_t arena_decay_time_default_get(void); -bool arena_decay_time_default_set(ssize_t decay_time); -void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, - unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, - size_t *ndirty); -void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty, - arena_stats_t *astats, malloc_bin_stats_t *bstats, - malloc_large_stats_t *lstats); -unsigned arena_nthreads_get(arena_t *arena, bool internal); -void arena_nthreads_inc(arena_t *arena, bool internal); -void arena_nthreads_dec(arena_t *arena, bool internal); -size_t arena_extent_sn_next(arena_t *arena); -arena_t *arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); -void arena_boot(void); -void arena_prefork0(tsdn_t *tsdn, arena_t *arena); -void arena_prefork1(tsdn_t *tsdn, arena_t *arena); -void arena_prefork2(tsdn_t *tsdn, arena_t *arena); -void arena_prefork3(tsdn_t *tsdn, arena_t *arena); -void arena_postfork_parent(tsdn_t *tsdn, arena_t *arena); -void arena_postfork_child(tsdn_t *tsdn, arena_t *arena); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#ifndef JEMALLOC_ENABLE_INLINE -unsigned arena_ind_get(const arena_t *arena); -void arena_internal_add(arena_t *arena, size_t size); -void arena_internal_sub(arena_t *arena, size_t size); -size_t arena_internal_get(arena_t *arena); -bool arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes); -bool arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes); -bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes); -szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin); -prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, - const void *ptr); -void arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize, prof_tctx_t *tctx); -void arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, - prof_tctx_t *tctx); -void arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks); -void arena_decay_tick(tsdn_t *tsdn, arena_t *arena); -void *arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, - bool zero, tcache_t *tcache, bool slow_path); -arena_t *arena_aalloc(tsdn_t *tsdn, const void *ptr); -size_t arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr); -void arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, - tcache_t *tcache, bool slow_path); -void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, - tcache_t *tcache, bool slow_path); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) -# ifdef JEMALLOC_ARENA_INLINE_A -JEMALLOC_INLINE unsigned -arena_ind_get(const arena_t *arena) -{ - - return (base_ind_get(arena->base)); -} - -JEMALLOC_INLINE void -arena_internal_add(arena_t *arena, size_t size) -{ - - atomic_add_zu(&arena->stats.internal, size); -} - -JEMALLOC_INLINE void -arena_internal_sub(arena_t *arena, size_t size) -{ - - atomic_sub_zu(&arena->stats.internal, size); -} - -JEMALLOC_INLINE size_t -arena_internal_get(arena_t *arena) -{ - - return (atomic_read_zu(&arena->stats.internal)); -} - -JEMALLOC_INLINE bool -arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes) -{ - - cassert(config_prof); - assert(prof_interval != 0); - - arena->prof_accumbytes += accumbytes; - if (arena->prof_accumbytes >= prof_interval) { - arena->prof_accumbytes %= prof_interval; - return (true); - } - return (false); -} - -JEMALLOC_INLINE bool -arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes) -{ - - cassert(config_prof); - - if (likely(prof_interval == 0)) - return (false); - return (arena_prof_accum_impl(arena, accumbytes)); -} - -JEMALLOC_INLINE bool -arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) -{ - - cassert(config_prof); - - if (likely(prof_interval == 0)) - return (false); - - { - bool ret; - - malloc_mutex_lock(tsdn, &arena->lock); - ret = arena_prof_accum_impl(arena, accumbytes); - malloc_mutex_unlock(tsdn, &arena->lock); - return (ret); - } -} -# endif /* JEMALLOC_ARENA_INLINE_A */ - -# ifdef JEMALLOC_ARENA_INLINE_B -JEMALLOC_INLINE szind_t -arena_bin_index(arena_t *arena, arena_bin_t *bin) -{ - szind_t binind = (szind_t)(bin - arena->bins); - assert(binind < NBINS); - return (binind); -} - -JEMALLOC_INLINE prof_tctx_t * -arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) -{ - - cassert(config_prof); - assert(ptr != NULL); - - if (unlikely(!extent_slab_get(extent))) - return (large_prof_tctx_get(tsdn, extent)); - return ((prof_tctx_t *)(uintptr_t)1U); -} - -JEMALLOC_INLINE void -arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize, prof_tctx_t *tctx) -{ - - cassert(config_prof); - assert(ptr != NULL); - - if (unlikely(!extent_slab_get(extent))) - large_prof_tctx_set(tsdn, extent, tctx); -} - -JEMALLOC_INLINE void -arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, - prof_tctx_t *tctx) -{ - - cassert(config_prof); - assert(ptr != NULL); - assert(!extent_slab_get(extent)); - - large_prof_tctx_reset(tsdn, extent); -} - -JEMALLOC_ALWAYS_INLINE void -arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) -{ - tsd_t *tsd; - ticker_t *decay_ticker; - - if (unlikely(tsdn_null(tsdn))) - return; - tsd = tsdn_tsd(tsdn); - decay_ticker = decay_ticker_get(tsd, arena_ind_get(arena)); - if (unlikely(decay_ticker == NULL)) - return; - if (unlikely(ticker_ticks(decay_ticker, nticks))) - arena_purge(tsdn, arena, false); -} - -JEMALLOC_ALWAYS_INLINE void -arena_decay_tick(tsdn_t *tsdn, arena_t *arena) -{ - - malloc_mutex_assert_not_owner(tsdn, &arena->lock); - - arena_decay_ticks(tsdn, arena, 1); -} - -JEMALLOC_ALWAYS_INLINE void * -arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, - tcache_t *tcache, bool slow_path) -{ - - assert(!tsdn_null(tsdn) || tcache == NULL); - assert(size != 0); - - if (likely(tcache != NULL)) { - if (likely(size <= SMALL_MAXCLASS)) { - return (tcache_alloc_small(tsdn_tsd(tsdn), arena, - tcache, size, ind, zero, slow_path)); - } - if (likely(size <= tcache_maxclass)) { - return (tcache_alloc_large(tsdn_tsd(tsdn), arena, - tcache, size, ind, zero, slow_path)); - } - /* (size > tcache_maxclass) case falls through. */ - assert(size > tcache_maxclass); - } - - return (arena_malloc_hard(tsdn, arena, size, ind, zero)); -} - -JEMALLOC_ALWAYS_INLINE arena_t * -arena_aalloc(tsdn_t *tsdn, const void *ptr) -{ - - return (extent_arena_get(iealloc(tsdn, ptr))); -} - -/* Return the size of the allocation pointed to by ptr. */ -JEMALLOC_ALWAYS_INLINE size_t -arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) -{ - size_t ret; - - assert(ptr != NULL); - - if (likely(extent_slab_get(extent))) - ret = index2size(extent_slab_data_get_const(extent)->binind); - else - ret = large_salloc(tsdn, extent); - - return (ret); -} - -JEMALLOC_ALWAYS_INLINE void -arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, - bool slow_path) -{ - - assert(!tsdn_null(tsdn) || tcache == NULL); - assert(ptr != NULL); - - if (likely(extent_slab_get(extent))) { - /* Small allocation. */ - if (likely(tcache != NULL)) { - szind_t binind = extent_slab_data_get(extent)->binind; - tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, binind, - slow_path); - } else { - arena_dalloc_small(tsdn, extent_arena_get(extent), - extent, ptr); - } - } else { - size_t usize = extent_usize_get(extent); - - if (likely(tcache != NULL) && usize <= tcache_maxclass) { - if (config_prof && unlikely(usize <= SMALL_MAXCLASS)) { - arena_dalloc_promoted(tsdn, extent, ptr, - tcache, slow_path); - } else { - tcache_dalloc_large(tsdn_tsd(tsdn), tcache, - ptr, usize, slow_path); - } - } else - large_dalloc(tsdn, extent); - } -} - -JEMALLOC_ALWAYS_INLINE void -arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, - tcache_t *tcache, bool slow_path) -{ - - assert(!tsdn_null(tsdn) || tcache == NULL); - assert(ptr != NULL); - - if (likely(extent_slab_get(extent))) { - /* Small allocation. */ - if (likely(tcache != NULL)) { - szind_t binind = size2index(size); - assert(binind == extent_slab_data_get(extent)->binind); - tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, binind, - slow_path); - } else { - arena_dalloc_small(tsdn, extent_arena_get(extent), - extent, ptr); - } - } else { - if (likely(tcache != NULL) && size <= tcache_maxclass) { - if (config_prof && unlikely(size <= SMALL_MAXCLASS)) { - arena_dalloc_promoted(tsdn, extent, ptr, - tcache, slow_path); - } else { - tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, - size, slow_path); - } - } else - large_dalloc(tsdn, extent); - } -} -# endif /* JEMALLOC_ARENA_INLINE_B */ -#endif - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h new file mode 100644 index 00000000..ecc82304 --- /dev/null +++ b/include/jemalloc/internal/arena_externs.h @@ -0,0 +1,92 @@ +#ifndef JEMALLOC_INTERNAL_ARENA_EXTERNS_H +#define JEMALLOC_INTERNAL_ARENA_EXTERNS_H + +static const size_t large_pad = +#ifdef JEMALLOC_CACHE_OBLIVIOUS + PAGE +#else + 0 +#endif + ; + +extern ssize_t opt_decay_time; + +extern const arena_bin_info_t arena_bin_info[NBINS]; + +extent_t *arena_extent_cache_alloc(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, + size_t alignment, bool *zero); +void arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent); +void arena_extent_cache_maybe_insert(tsdn_t *tsdn, arena_t *arena, + extent_t *extent, bool cache); +void arena_extent_cache_maybe_remove(tsdn_t *tsdn, arena_t *arena, + extent_t *extent, bool cache); +#ifdef JEMALLOC_JET +size_t arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr); +#endif +extent_t *arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, + size_t usize, size_t alignment, bool *zero); +void arena_extent_dalloc_large(tsdn_t *tsdn, arena_t *arena, + extent_t *extent, bool locked); +void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, + extent_t *extent, size_t oldsize); +void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, + extent_t *extent, size_t oldsize); +ssize_t arena_decay_time_get(tsdn_t *tsdn, arena_t *arena); +bool arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time); +void arena_purge(tsdn_t *tsdn, arena_t *arena, bool all); +void arena_maybe_purge(tsdn_t *tsdn, arena_t *arena); +void arena_reset(tsd_t *tsd, arena_t *arena); +void arena_destroy(tsd_t *tsd, arena_t *arena); +void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, + tcache_bin_t *tbin, szind_t binind, uint64_t prof_accumbytes); +void arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, + bool zero); +#ifdef JEMALLOC_JET +typedef void (arena_dalloc_junk_small_t)(void *, const arena_bin_info_t *); +extern arena_dalloc_junk_small_t *arena_dalloc_junk_small; +#else +void arena_dalloc_junk_small(void *ptr, const arena_bin_info_t *bin_info); +#endif +void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, + szind_t ind, bool zero); +void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, + size_t alignment, bool zero, tcache_t *tcache); +void arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize); +void arena_dalloc_promoted(tsdn_t *tsdn, extent_t *extent, void *ptr, + tcache_t *tcache, bool slow_path); +void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, + extent_t *extent, void *ptr); +void arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + void *ptr); +bool arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, + size_t oldsize, size_t size, size_t extra, bool zero); +void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, + size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache); +dss_prec_t arena_dss_prec_get(tsdn_t *tsdn, arena_t *arena); +bool arena_dss_prec_set(tsdn_t *tsdn, arena_t *arena, dss_prec_t dss_prec); +ssize_t arena_decay_time_default_get(void); +bool arena_decay_time_default_set(ssize_t decay_time); +void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, + unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, + size_t *ndirty); +void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, + const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty, + arena_stats_t *astats, malloc_bin_stats_t *bstats, + malloc_large_stats_t *lstats); +unsigned arena_nthreads_get(arena_t *arena, bool internal); +void arena_nthreads_inc(arena_t *arena, bool internal); +void arena_nthreads_dec(arena_t *arena, bool internal); +size_t arena_extent_sn_next(arena_t *arena); +arena_t *arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); +void arena_boot(void); +void arena_prefork0(tsdn_t *tsdn, arena_t *arena); +void arena_prefork1(tsdn_t *tsdn, arena_t *arena); +void arena_prefork2(tsdn_t *tsdn, arena_t *arena); +void arena_prefork3(tsdn_t *tsdn, arena_t *arena); +void arena_postfork_parent(tsdn_t *tsdn, arena_t *arena); +void arena_postfork_child(tsdn_t *tsdn, arena_t *arena); + +#endif /* JEMALLOC_INTERNAL_ARENA_EXTERNS_H */ diff --git a/include/jemalloc/internal/arena_inlines_a.h b/include/jemalloc/internal/arena_inlines_a.h new file mode 100644 index 00000000..743727b0 --- /dev/null +++ b/include/jemalloc/internal/arena_inlines_a.h @@ -0,0 +1,91 @@ +#ifndef JEMALLOC_INTERNAL_ARENA_INLINES_A_H +#define JEMALLOC_INTERNAL_ARENA_INLINES_A_H + +#ifndef JEMALLOC_ENABLE_INLINE +unsigned arena_ind_get(const arena_t *arena); +void arena_internal_add(arena_t *arena, size_t size); +void arena_internal_sub(arena_t *arena, size_t size); +size_t arena_internal_get(arena_t *arena); +bool arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes); +bool arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes); +bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes); +#endif /* JEMALLOC_ENABLE_INLINE */ + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) + +JEMALLOC_INLINE unsigned +arena_ind_get(const arena_t *arena) +{ + + return (base_ind_get(arena->base)); +} + +JEMALLOC_INLINE void +arena_internal_add(arena_t *arena, size_t size) +{ + + atomic_add_zu(&arena->stats.internal, size); +} + +JEMALLOC_INLINE void +arena_internal_sub(arena_t *arena, size_t size) +{ + + atomic_sub_zu(&arena->stats.internal, size); +} + +JEMALLOC_INLINE size_t +arena_internal_get(arena_t *arena) +{ + + return (atomic_read_zu(&arena->stats.internal)); +} + +JEMALLOC_INLINE bool +arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes) +{ + + cassert(config_prof); + assert(prof_interval != 0); + + arena->prof_accumbytes += accumbytes; + if (arena->prof_accumbytes >= prof_interval) { + arena->prof_accumbytes %= prof_interval; + return (true); + } + return (false); +} + +JEMALLOC_INLINE bool +arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes) +{ + + cassert(config_prof); + + if (likely(prof_interval == 0)) + return (false); + return (arena_prof_accum_impl(arena, accumbytes)); +} + +JEMALLOC_INLINE bool +arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) +{ + + cassert(config_prof); + + if (likely(prof_interval == 0)) + return (false); + + { + bool ret; + + malloc_mutex_lock(tsdn, &arena->lock); + ret = arena_prof_accum_impl(arena, accumbytes); + malloc_mutex_unlock(tsdn, &arena->lock); + return (ret); + } +} + +#endif /* (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) */ + +#endif /* JEMALLOC_INTERNAL_ARENA_INLINES_A_H */ diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h new file mode 100644 index 00000000..9068cf4c --- /dev/null +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -0,0 +1,209 @@ +#ifndef JEMALLOC_INTERNAL_ARENA_INLINES_B_H +#define JEMALLOC_INTERNAL_ARENA_INLINES_B_H + +#ifndef JEMALLOC_ENABLE_INLINE +szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin); +prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, + const void *ptr); +void arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize, prof_tctx_t *tctx); +void arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, + prof_tctx_t *tctx); +void arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks); +void arena_decay_tick(tsdn_t *tsdn, arena_t *arena); +void *arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, + bool zero, tcache_t *tcache, bool slow_path); +arena_t *arena_aalloc(tsdn_t *tsdn, const void *ptr); +size_t arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr); +void arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, + tcache_t *tcache, bool slow_path); +void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, + tcache_t *tcache, bool slow_path); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) +JEMALLOC_INLINE szind_t +arena_bin_index(arena_t *arena, arena_bin_t *bin) +{ + szind_t binind = (szind_t)(bin - arena->bins); + assert(binind < NBINS); + return (binind); +} + +JEMALLOC_INLINE prof_tctx_t * +arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) +{ + + cassert(config_prof); + assert(ptr != NULL); + + if (unlikely(!extent_slab_get(extent))) + return (large_prof_tctx_get(tsdn, extent)); + return ((prof_tctx_t *)(uintptr_t)1U); +} + +JEMALLOC_INLINE void +arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize, prof_tctx_t *tctx) +{ + + cassert(config_prof); + assert(ptr != NULL); + + if (unlikely(!extent_slab_get(extent))) + large_prof_tctx_set(tsdn, extent, tctx); +} + +JEMALLOC_INLINE void +arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, + prof_tctx_t *tctx) +{ + + cassert(config_prof); + assert(ptr != NULL); + assert(!extent_slab_get(extent)); + + large_prof_tctx_reset(tsdn, extent); +} + +JEMALLOC_ALWAYS_INLINE void +arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) +{ + tsd_t *tsd; + ticker_t *decay_ticker; + + if (unlikely(tsdn_null(tsdn))) + return; + tsd = tsdn_tsd(tsdn); + decay_ticker = decay_ticker_get(tsd, arena_ind_get(arena)); + if (unlikely(decay_ticker == NULL)) + return; + if (unlikely(ticker_ticks(decay_ticker, nticks))) + arena_purge(tsdn, arena, false); +} + +JEMALLOC_ALWAYS_INLINE void +arena_decay_tick(tsdn_t *tsdn, arena_t *arena) +{ + + malloc_mutex_assert_not_owner(tsdn, &arena->lock); + + arena_decay_ticks(tsdn, arena, 1); +} + +JEMALLOC_ALWAYS_INLINE void * +arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, + tcache_t *tcache, bool slow_path) +{ + + assert(!tsdn_null(tsdn) || tcache == NULL); + assert(size != 0); + + if (likely(tcache != NULL)) { + if (likely(size <= SMALL_MAXCLASS)) { + return (tcache_alloc_small(tsdn_tsd(tsdn), arena, + tcache, size, ind, zero, slow_path)); + } + if (likely(size <= tcache_maxclass)) { + return (tcache_alloc_large(tsdn_tsd(tsdn), arena, + tcache, size, ind, zero, slow_path)); + } + /* (size > tcache_maxclass) case falls through. */ + assert(size > tcache_maxclass); + } + + return (arena_malloc_hard(tsdn, arena, size, ind, zero)); +} + +JEMALLOC_ALWAYS_INLINE arena_t * +arena_aalloc(tsdn_t *tsdn, const void *ptr) +{ + + return (extent_arena_get(iealloc(tsdn, ptr))); +} + +/* Return the size of the allocation pointed to by ptr. */ +JEMALLOC_ALWAYS_INLINE size_t +arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) +{ + size_t ret; + + assert(ptr != NULL); + + if (likely(extent_slab_get(extent))) + ret = index2size(extent_slab_data_get_const(extent)->binind); + else + ret = large_salloc(tsdn, extent); + + return (ret); +} + +JEMALLOC_ALWAYS_INLINE void +arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, + bool slow_path) +{ + + assert(!tsdn_null(tsdn) || tcache == NULL); + assert(ptr != NULL); + + if (likely(extent_slab_get(extent))) { + /* Small allocation. */ + if (likely(tcache != NULL)) { + szind_t binind = extent_slab_data_get(extent)->binind; + tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, binind, + slow_path); + } else { + arena_dalloc_small(tsdn, extent_arena_get(extent), + extent, ptr); + } + } else { + size_t usize = extent_usize_get(extent); + + if (likely(tcache != NULL) && usize <= tcache_maxclass) { + if (config_prof && unlikely(usize <= SMALL_MAXCLASS)) { + arena_dalloc_promoted(tsdn, extent, ptr, + tcache, slow_path); + } else { + tcache_dalloc_large(tsdn_tsd(tsdn), tcache, + ptr, usize, slow_path); + } + } else + large_dalloc(tsdn, extent); + } +} + +JEMALLOC_ALWAYS_INLINE void +arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, + tcache_t *tcache, bool slow_path) +{ + + assert(!tsdn_null(tsdn) || tcache == NULL); + assert(ptr != NULL); + + if (likely(extent_slab_get(extent))) { + /* Small allocation. */ + if (likely(tcache != NULL)) { + szind_t binind = size2index(size); + assert(binind == extent_slab_data_get(extent)->binind); + tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, binind, + slow_path); + } else { + arena_dalloc_small(tsdn, extent_arena_get(extent), + extent, ptr); + } + } else { + if (likely(tcache != NULL) && size <= tcache_maxclass) { + if (config_prof && unlikely(size <= SMALL_MAXCLASS)) { + arena_dalloc_promoted(tsdn, extent, ptr, + tcache, slow_path); + } else { + tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, + size, slow_path); + } + } else + large_dalloc(tsdn, extent); + } +} + +#endif /* (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) */ +#endif /* JEMALLOC_INTERNAL_ARENA_INLINES_B_H */ diff --git a/include/jemalloc/internal/arena_structs_a.h b/include/jemalloc/internal/arena_structs_a.h new file mode 100644 index 00000000..ccb3b052 --- /dev/null +++ b/include/jemalloc/internal/arena_structs_a.h @@ -0,0 +1,15 @@ +#ifndef JEMALLOC_INTERNAL_ARENA_STRUCTS_A_H +#define JEMALLOC_INTERNAL_ARENA_STRUCTS_A_H + +struct arena_slab_data_s { + /* Index of bin this slab is associated with. */ + szind_t binind; + + /* Number of free regions in slab. */ + unsigned nfree; + + /* Per region allocated/deallocated bitmap. */ + bitmap_t bitmap[BITMAP_GROUPS_MAX]; +}; + +#endif /* JEMALLOC_INTERNAL_ARENA_STRUCTS_A_H */ diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h new file mode 100644 index 00000000..c1c20731 --- /dev/null +++ b/include/jemalloc/internal/arena_structs_b.h @@ -0,0 +1,214 @@ +#ifndef JEMALLOC_INTERNAL_ARENA_STRUCTS_B_H +#define JEMALLOC_INTERNAL_ARENA_STRUCTS_B_H +/* + * Read-only information associated with each element of arena_t's bins array + * is stored separately, partly to reduce memory usage (only one copy, rather + * than one per arena), but mainly to avoid false cacheline sharing. + * + * Each slab has the following layout: + * + * /--------------------\ + * | region 0 | + * |--------------------| + * | region 1 | + * |--------------------| + * | ... | + * | ... | + * | ... | + * |--------------------| + * | region nregs-1 | + * \--------------------/ + */ +struct arena_bin_info_s { + /* Size of regions in a slab for this bin's size class. */ + size_t reg_size; + + /* Total size of a slab for this bin's size class. */ + size_t slab_size; + + /* Total number of regions in a slab for this bin's size class. */ + uint32_t nregs; + + /* + * Metadata used to manipulate bitmaps for slabs associated with this + * bin. + */ + bitmap_info_t bitmap_info; +}; + +struct arena_decay_s { + /* + * Approximate time in seconds from the creation of a set of unused + * dirty pages until an equivalent set of unused dirty pages is purged + * and/or reused. + */ + ssize_t time; + /* time / SMOOTHSTEP_NSTEPS. */ + nstime_t interval; + /* + * Time at which the current decay interval logically started. We do + * not actually advance to a new epoch until sometime after it starts + * because of scheduling and computation delays, and it is even possible + * to completely skip epochs. In all cases, during epoch advancement we + * merge all relevant activity into the most recently recorded epoch. + */ + nstime_t epoch; + /* Deadline randomness generator. */ + uint64_t jitter_state; + /* + * Deadline for current epoch. This is the sum of interval and per + * epoch jitter which is a uniform random variable in [0..interval). + * Epochs always advance by precise multiples of interval, but we + * randomize the deadline to reduce the likelihood of arenas purging in + * lockstep. + */ + nstime_t deadline; + /* + * Number of dirty pages at beginning of current epoch. During epoch + * advancement we use the delta between arena->decay.ndirty and + * arena->ndirty to determine how many dirty pages, if any, were + * generated. + */ + size_t nunpurged; + /* + * Trailing log of how many unused dirty pages were generated during + * each of the past SMOOTHSTEP_NSTEPS decay epochs, where the last + * element is the most recent epoch. Corresponding epoch times are + * relative to epoch. + */ + size_t backlog[SMOOTHSTEP_NSTEPS]; +}; + +struct arena_bin_s { + /* All operations on arena_bin_t fields require lock ownership. */ + malloc_mutex_t lock; + + /* + * Current slab being used to service allocations of this bin's size + * class. slabcur is independent of slabs_{nonfull,full}; whenever + * slabcur is reassigned, the previous slab must be deallocated or + * inserted into slabs_{nonfull,full}. + */ + extent_t *slabcur; + + /* + * Heap of non-full slabs. This heap is used to assure that new + * allocations come from the non-full slab that is oldest/lowest in + * memory. + */ + extent_heap_t slabs_nonfull; + + /* Ring sentinel used to track full slabs. */ + extent_t slabs_full; + + /* Bin statistics. */ + malloc_bin_stats_t stats; +}; + +struct arena_s { + /* + * Number of threads currently assigned to this arena, synchronized via + * atomic operations. Each thread has two distinct assignments, one for + * application-serving allocation, and the other for internal metadata + * allocation. Internal metadata must not be allocated from arenas + * explicitly created via the arenas.create mallctl, because the + * arena..reset mallctl indiscriminately discards all allocations for + * the affected arena. + * + * 0: Application allocation. + * 1: Internal metadata allocation. + */ + unsigned nthreads[2]; + + /* + * There are three classes of arena operations from a locking + * perspective: + * 1) Thread assignment (modifies nthreads) is synchronized via atomics. + * 2) Bin-related operations are protected by bin locks. + * 3) Extent-related operations are protected by this mutex. + */ + malloc_mutex_t lock; + + arena_stats_t stats; + /* + * List of tcaches for extant threads associated with this arena. + * Stats from these are merged incrementally, and at exit if + * opt_stats_print is enabled. + */ + ql_head(tcache_t) tcache_ql; + + uint64_t prof_accumbytes; + + /* + * PRNG state for cache index randomization of large allocation base + * pointers. + */ + size_t offset_state; + + /* Extent serial number generator state. */ + size_t extent_sn_next; + + dss_prec_t dss_prec; + + /* True if a thread is currently executing arena_purge_to_limit(). */ + bool purging; + + /* Number of pages in active extents. */ + size_t nactive; + + /* + * Current count of pages within unused extents that are potentially + * dirty, and for which pages_purge_*() has not been called. By + * tracking this, we can institute a limit on how much dirty unused + * memory is mapped for each arena. + */ + size_t ndirty; + + /* Decay-based purging state. */ + arena_decay_t decay; + + /* Extant large allocations. */ + ql_head(extent_t) large; + /* Synchronizes all large allocation/update/deallocation. */ + malloc_mutex_t large_mtx; + + /* + * Heaps of extents that were previously allocated. These are used when + * allocating extents, in an attempt to re-use address space. + */ + extent_heap_t extents_cached[NPSIZES+1]; + extent_heap_t extents_retained[NPSIZES+1]; + /* + * Ring sentinel used to track unused dirty memory. Dirty memory is + * managed as an LRU of cached extents. + */ + extent_t extents_dirty; + /* Protects extents_{cached,retained,dirty}. */ + malloc_mutex_t extents_mtx; + + /* + * Next extent size class in a growing series to use when satisfying a + * request via the extent hooks (only if !config_munmap). This limits + * the number of disjoint virtual memory ranges so that extent merging + * can be effective even if multiple arenas' extent allocation requests + * are highly interleaved. + */ + pszind_t extent_grow_next; + + /* Cache of extent structures that were allocated via base_alloc(). */ + ql_head(extent_t) extent_cache; + malloc_mutex_t extent_cache_mtx; + + /* bins is used to store heaps of free regions. */ + arena_bin_t bins[NBINS]; + + /* Base allocator, from which arena metadata are allocated. */ + base_t *base; +}; + +/* Used in conjunction with tsd for fast arena-related context lookup. */ +struct arena_tdata_s { + ticker_t decay_ticker; +}; + +#endif /* JEMALLOC_INTERNAL_ARENA_STRUCTS_B_H */ diff --git a/include/jemalloc/internal/arena_types.h b/include/jemalloc/internal/arena_types.h new file mode 100644 index 00000000..a13a1b61 --- /dev/null +++ b/include/jemalloc/internal/arena_types.h @@ -0,0 +1,22 @@ +#ifndef JEMALLOC_INTERNAL_ARENA_TYPES_H +#define JEMALLOC_INTERNAL_ARENA_TYPES_H + +#define LARGE_MINCLASS (ZU(1) << LG_LARGE_MINCLASS) + +/* Maximum number of regions in one slab. */ +#define LG_SLAB_MAXREGS (LG_PAGE - LG_TINY_MIN) +#define SLAB_MAXREGS (1U << LG_SLAB_MAXREGS) + +/* Default decay time in seconds. */ +#define DECAY_TIME_DEFAULT 10 +/* Number of event ticks between time checks. */ +#define DECAY_NTICKS_PER_UPDATE 1000 + +typedef struct arena_slab_data_s arena_slab_data_t; +typedef struct arena_bin_info_s arena_bin_info_t; +typedef struct arena_decay_s arena_decay_t; +typedef struct arena_bin_s arena_bin_t; +typedef struct arena_s arena_t; +typedef struct arena_tdata_s arena_tdata_t; + +#endif /* JEMALLOC_INTERNAL_ARENA_TYPES_H */ diff --git a/include/jemalloc/internal/atomic_externs.h b/include/jemalloc/internal/atomic_externs.h new file mode 100644 index 00000000..002aebca --- /dev/null +++ b/include/jemalloc/internal/atomic_externs.h @@ -0,0 +1,12 @@ +#ifndef JEMALLOC_INTERNAL_ATOMIC_EXTERNS_H +#define JEMALLOC_INTERNAL_ATOMIC_EXTERNS_H + +#if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) +#define atomic_read_u64(p) atomic_add_u64(p, 0) +#endif +#define atomic_read_u32(p) atomic_add_u32(p, 0) +#define atomic_read_p(p) atomic_add_p(p, NULL) +#define atomic_read_zu(p) atomic_add_zu(p, 0) +#define atomic_read_u(p) atomic_add_u(p, 0) + +#endif /* JEMALLOC_INTERNAL_ATOMIC_EXTERNS_H */ diff --git a/include/jemalloc/internal/atomic.h b/include/jemalloc/internal/atomic_inlines.h similarity index 93% rename from include/jemalloc/internal/atomic.h rename to include/jemalloc/internal/atomic_inlines.h index 4b5b4ea9..de0ac6ac 100644 --- a/include/jemalloc/internal/atomic.h +++ b/include/jemalloc/internal/atomic_inlines.h @@ -1,25 +1,5 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -#if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) -#define atomic_read_u64(p) atomic_add_u64(p, 0) -#endif -#define atomic_read_u32(p) atomic_add_u32(p, 0) -#define atomic_read_p(p) atomic_add_p(p, NULL) -#define atomic_read_zu(p) atomic_add_zu(p, 0) -#define atomic_read_u(p) atomic_add_u(p, 0) - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES +#ifndef JEMALLOC_INTERNAL_ATOMIC_INLINES_H +#define JEMALLOC_INTERNAL_ATOMIC_INLINES_H /* * All arithmetic functions return the arithmetic result of the atomic @@ -646,6 +626,4 @@ atomic_write_u(unsigned *p, unsigned x) /******************************************************************************/ #endif - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ +#endif /* JEMALLOC_INTERNAL_ATOMIC_INLINES_H */ diff --git a/include/jemalloc/internal/base.h b/include/jemalloc/internal/base.h deleted file mode 100644 index a54a5502..00000000 --- a/include/jemalloc/internal/base.h +++ /dev/null @@ -1,87 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -typedef struct base_block_s base_block_t; -typedef struct base_s base_t; - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -/* Embedded at the beginning of every block of base-managed virtual memory. */ -struct base_block_s { - /* Total size of block's virtual memory mapping. */ - size_t size; - - /* Next block in list of base's blocks. */ - base_block_t *next; - - /* Tracks unused trailing space. */ - extent_t extent; -}; - -struct base_s { - /* Associated arena's index within the arenas array. */ - unsigned ind; - - /* User-configurable extent hook functions. */ - union { - extent_hooks_t *extent_hooks; - void *extent_hooks_pun; - }; - - /* Protects base_alloc() and base_stats_get() operations. */ - malloc_mutex_t mtx; - - /* Serial number generation state. */ - size_t extent_sn_next; - - /* Chain of all blocks associated with base. */ - base_block_t *blocks; - - /* Heap of extents that track unused trailing space within blocks. */ - extent_heap_t avail[NSIZES]; - - /* Stats, only maintained if config_stats. */ - size_t allocated; - size_t resident; - size_t mapped; -}; - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -base_t *b0get(void); -base_t *base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); -void base_delete(base_t *base); -extent_hooks_t *base_extent_hooks_get(base_t *base); -extent_hooks_t *base_extent_hooks_set(base_t *base, - extent_hooks_t *extent_hooks); -void *base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment); -void base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated, - size_t *resident, size_t *mapped); -void base_prefork(tsdn_t *tsdn, base_t *base); -void base_postfork_parent(tsdn_t *tsdn, base_t *base); -void base_postfork_child(tsdn_t *tsdn, base_t *base); -bool base_boot(tsdn_t *tsdn); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#ifndef JEMALLOC_ENABLE_INLINE -unsigned base_ind_get(const base_t *base); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BASE_C_)) -JEMALLOC_INLINE unsigned -base_ind_get(const base_t *base) -{ - - return (base->ind); -} -#endif - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ diff --git a/include/jemalloc/internal/base_externs.h b/include/jemalloc/internal/base_externs.h new file mode 100644 index 00000000..2c555cff --- /dev/null +++ b/include/jemalloc/internal/base_externs.h @@ -0,0 +1,18 @@ +#ifndef JEMALLOC_INTERNAL_BASE_EXTERNS_H +#define JEMALLOC_INTERNAL_BASE_EXTERNS_H + +base_t *b0get(void); +base_t *base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); +void base_delete(base_t *base); +extent_hooks_t *base_extent_hooks_get(base_t *base); +extent_hooks_t *base_extent_hooks_set(base_t *base, + extent_hooks_t *extent_hooks); +void *base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment); +void base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated, + size_t *resident, size_t *mapped); +void base_prefork(tsdn_t *tsdn, base_t *base); +void base_postfork_parent(tsdn_t *tsdn, base_t *base); +void base_postfork_child(tsdn_t *tsdn, base_t *base); +bool base_boot(tsdn_t *tsdn); + +#endif /* JEMALLOC_INTERNAL_BASE_EXTERNS_H */ diff --git a/include/jemalloc/internal/base_inlines.h b/include/jemalloc/internal/base_inlines.h new file mode 100644 index 00000000..f882bcde --- /dev/null +++ b/include/jemalloc/internal/base_inlines.h @@ -0,0 +1,17 @@ +#ifndef JEMALLOC_INTERNAL_BASE_INLINES_H +#define JEMALLOC_INTERNAL_BASE_INLINES_H + +#ifndef JEMALLOC_ENABLE_INLINE +unsigned base_ind_get(const base_t *base); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BASE_C_)) +JEMALLOC_INLINE unsigned +base_ind_get(const base_t *base) +{ + + return (base->ind); +} +#endif + +#endif /* JEMALLOC_INTERNAL_BASE_INLINES_H */ diff --git a/include/jemalloc/internal/base_structs.h b/include/jemalloc/internal/base_structs.h new file mode 100644 index 00000000..bad37c06 --- /dev/null +++ b/include/jemalloc/internal/base_structs.h @@ -0,0 +1,44 @@ +#ifndef JEMALLOC_INTERNAL_BASE_STRUCTS_H +#define JEMALLOC_INTERNAL_BASE_STRUCTS_H + +/* Embedded at the beginning of every block of base-managed virtual memory. */ +struct base_block_s { + /* Total size of block's virtual memory mapping. */ + size_t size; + + /* Next block in list of base's blocks. */ + base_block_t *next; + + /* Tracks unused trailing space. */ + extent_t extent; +}; + +struct base_s { + /* Associated arena's index within the arenas array. */ + unsigned ind; + + /* User-configurable extent hook functions. */ + union { + extent_hooks_t *extent_hooks; + void *extent_hooks_pun; + }; + + /* Protects base_alloc() and base_stats_get() operations. */ + malloc_mutex_t mtx; + + /* Serial number generation state. */ + size_t extent_sn_next; + + /* Chain of all blocks associated with base. */ + base_block_t *blocks; + + /* Heap of extents that track unused trailing space within blocks. */ + extent_heap_t avail[NSIZES]; + + /* Stats, only maintained if config_stats. */ + size_t allocated; + size_t resident; + size_t mapped; +}; + +#endif /* JEMALLOC_INTERNAL_BASE_STRUCTS_H */ diff --git a/include/jemalloc/internal/base_types.h b/include/jemalloc/internal/base_types.h new file mode 100644 index 00000000..be7ee825 --- /dev/null +++ b/include/jemalloc/internal/base_types.h @@ -0,0 +1,7 @@ +#ifndef JEMALLOC_INTERNAL_BASE_TYPES_H +#define JEMALLOC_INTERNAL_BASE_TYPES_H + +typedef struct base_block_s base_block_t; +typedef struct base_s base_t; + +#endif /* JEMALLOC_INTERNAL_BASE_TYPES_H */ diff --git a/include/jemalloc/internal/bitmap.h b/include/jemalloc/internal/bitmap.h deleted file mode 100644 index c2e34554..00000000 --- a/include/jemalloc/internal/bitmap.h +++ /dev/null @@ -1,322 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -/* Maximum bitmap bit count is 2^LG_BITMAP_MAXBITS. */ -#define LG_BITMAP_MAXBITS LG_SLAB_MAXREGS -#define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS) - -typedef struct bitmap_level_s bitmap_level_t; -typedef struct bitmap_info_s bitmap_info_t; -typedef unsigned long bitmap_t; -#define LG_SIZEOF_BITMAP LG_SIZEOF_LONG - -/* Number of bits per group. */ -#define LG_BITMAP_GROUP_NBITS (LG_SIZEOF_BITMAP + 3) -#define BITMAP_GROUP_NBITS (1U << LG_BITMAP_GROUP_NBITS) -#define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1) - -/* - * Do some analysis on how big the bitmap is before we use a tree. For a brute - * force linear search, if we would have to call ffs_lu() more than 2^3 times, - * use a tree instead. - */ -#if LG_BITMAP_MAXBITS - LG_BITMAP_GROUP_NBITS > 3 -# define BITMAP_USE_TREE -#endif - -/* Number of groups required to store a given number of bits. */ -#define BITMAP_BITS2GROUPS(nbits) \ - (((nbits) + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS) - -/* - * Number of groups required at a particular level for a given number of bits. - */ -#define BITMAP_GROUPS_L0(nbits) \ - BITMAP_BITS2GROUPS(nbits) -#define BITMAP_GROUPS_L1(nbits) \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits)) -#define BITMAP_GROUPS_L2(nbits) \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))) -#define BITMAP_GROUPS_L3(nbits) \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ - BITMAP_BITS2GROUPS((nbits))))) -#define BITMAP_GROUPS_L4(nbits) \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))))) - -/* - * Assuming the number of levels, number of groups required for a given number - * of bits. - */ -#define BITMAP_GROUPS_1_LEVEL(nbits) \ - BITMAP_GROUPS_L0(nbits) -#define BITMAP_GROUPS_2_LEVEL(nbits) \ - (BITMAP_GROUPS_1_LEVEL(nbits) + BITMAP_GROUPS_L1(nbits)) -#define BITMAP_GROUPS_3_LEVEL(nbits) \ - (BITMAP_GROUPS_2_LEVEL(nbits) + BITMAP_GROUPS_L2(nbits)) -#define BITMAP_GROUPS_4_LEVEL(nbits) \ - (BITMAP_GROUPS_3_LEVEL(nbits) + BITMAP_GROUPS_L3(nbits)) -#define BITMAP_GROUPS_5_LEVEL(nbits) \ - (BITMAP_GROUPS_4_LEVEL(nbits) + BITMAP_GROUPS_L4(nbits)) - -/* - * Maximum number of groups required to support LG_BITMAP_MAXBITS. - */ -#ifdef BITMAP_USE_TREE - -#if LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_1_LEVEL(BITMAP_MAXBITS) -#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 2 -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_2_LEVEL(BITMAP_MAXBITS) -#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 3 -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_3_LEVEL(BITMAP_MAXBITS) -#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 4 -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_4_LEVEL(BITMAP_MAXBITS) -#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 5 -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_5_LEVEL(BITMAP_MAXBITS) -#else -# error "Unsupported bitmap size" -#endif - -/* - * Maximum number of levels possible. This could be statically computed based - * on LG_BITMAP_MAXBITS: - * - * #define BITMAP_MAX_LEVELS \ - * (LG_BITMAP_MAXBITS / LG_SIZEOF_BITMAP) \ - * + !!(LG_BITMAP_MAXBITS % LG_SIZEOF_BITMAP) - * - * However, that would not allow the generic BITMAP_INFO_INITIALIZER() macro, so - * instead hardcode BITMAP_MAX_LEVELS to the largest number supported by the - * various cascading macros. The only additional cost this incurs is some - * unused trailing entries in bitmap_info_t structures; the bitmaps themselves - * are not impacted. - */ -#define BITMAP_MAX_LEVELS 5 - -#define BITMAP_INFO_INITIALIZER(nbits) { \ - /* nbits. */ \ - nbits, \ - /* nlevels. */ \ - (BITMAP_GROUPS_L0(nbits) > BITMAP_GROUPS_L1(nbits)) + \ - (BITMAP_GROUPS_L1(nbits) > BITMAP_GROUPS_L2(nbits)) + \ - (BITMAP_GROUPS_L2(nbits) > BITMAP_GROUPS_L3(nbits)) + \ - (BITMAP_GROUPS_L3(nbits) > BITMAP_GROUPS_L4(nbits)) + 1, \ - /* levels. */ \ - { \ - {0}, \ - {BITMAP_GROUPS_L0(nbits)}, \ - {BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \ - {BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) + \ - BITMAP_GROUPS_L0(nbits)}, \ - {BITMAP_GROUPS_L3(nbits) + BITMAP_GROUPS_L2(nbits) + \ - BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \ - {BITMAP_GROUPS_L4(nbits) + BITMAP_GROUPS_L3(nbits) + \ - BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) \ - + BITMAP_GROUPS_L0(nbits)} \ - } \ -} - -#else /* BITMAP_USE_TREE */ - -#define BITMAP_GROUPS_MAX BITMAP_BITS2GROUPS(BITMAP_MAXBITS) - -#define BITMAP_INFO_INITIALIZER(nbits) { \ - /* nbits. */ \ - nbits, \ - /* ngroups. */ \ - BITMAP_BITS2GROUPS(nbits) \ -} - -#endif /* BITMAP_USE_TREE */ - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -struct bitmap_level_s { - /* Offset of this level's groups within the array of groups. */ - size_t group_offset; -}; - -struct bitmap_info_s { - /* Logical number of bits in bitmap (stored at bottom level). */ - size_t nbits; - -#ifdef BITMAP_USE_TREE - /* Number of levels necessary for nbits. */ - unsigned nlevels; - - /* - * Only the first (nlevels+1) elements are used, and levels are ordered - * bottom to top (e.g. the bottom level is stored in levels[0]). - */ - bitmap_level_t levels[BITMAP_MAX_LEVELS+1]; -#else /* BITMAP_USE_TREE */ - /* Number of groups necessary for nbits. */ - size_t ngroups; -#endif /* BITMAP_USE_TREE */ -}; - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -void bitmap_info_init(bitmap_info_t *binfo, size_t nbits); -void bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo); -size_t bitmap_size(const bitmap_info_t *binfo); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#ifndef JEMALLOC_ENABLE_INLINE -bool bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo); -bool bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); -void bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); -size_t bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo); -void bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BITMAP_C_)) -JEMALLOC_INLINE bool -bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) -{ -#ifdef BITMAP_USE_TREE - size_t rgoff = binfo->levels[binfo->nlevels].group_offset - 1; - bitmap_t rg = bitmap[rgoff]; - /* The bitmap is full iff the root group is 0. */ - return (rg == 0); -#else - size_t i; - - for (i = 0; i < binfo->ngroups; i++) { - if (bitmap[i] != 0) - return (false); - } - return (true); -#endif -} - -JEMALLOC_INLINE bool -bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) -{ - size_t goff; - bitmap_t g; - - assert(bit < binfo->nbits); - goff = bit >> LG_BITMAP_GROUP_NBITS; - g = bitmap[goff]; - return (!(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK)))); -} - -JEMALLOC_INLINE void -bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) -{ - size_t goff; - bitmap_t *gp; - bitmap_t g; - - assert(bit < binfo->nbits); - assert(!bitmap_get(bitmap, binfo, bit)); - goff = bit >> LG_BITMAP_GROUP_NBITS; - gp = &bitmap[goff]; - g = *gp; - assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); - g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); - *gp = g; - assert(bitmap_get(bitmap, binfo, bit)); -#ifdef BITMAP_USE_TREE - /* Propagate group state transitions up the tree. */ - if (g == 0) { - unsigned i; - for (i = 1; i < binfo->nlevels; i++) { - bit = goff; - goff = bit >> LG_BITMAP_GROUP_NBITS; - gp = &bitmap[binfo->levels[i].group_offset + goff]; - g = *gp; - assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); - g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); - *gp = g; - if (g != 0) - break; - } - } -#endif -} - -/* sfu: set first unset. */ -JEMALLOC_INLINE size_t -bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) -{ - size_t bit; - bitmap_t g; - unsigned i; - - assert(!bitmap_full(bitmap, binfo)); - -#ifdef BITMAP_USE_TREE - i = binfo->nlevels - 1; - g = bitmap[binfo->levels[i].group_offset]; - bit = ffs_lu(g) - 1; - while (i > 0) { - i--; - g = bitmap[binfo->levels[i].group_offset + bit]; - bit = (bit << LG_BITMAP_GROUP_NBITS) + (ffs_lu(g) - 1); - } -#else - i = 0; - g = bitmap[0]; - while ((bit = ffs_lu(g)) == 0) { - i++; - g = bitmap[i]; - } - bit = (i << LG_BITMAP_GROUP_NBITS) + (bit - 1); -#endif - bitmap_set(bitmap, binfo, bit); - return (bit); -} - -JEMALLOC_INLINE void -bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) -{ - size_t goff; - bitmap_t *gp; - bitmap_t g; - UNUSED bool propagate; - - assert(bit < binfo->nbits); - assert(bitmap_get(bitmap, binfo, bit)); - goff = bit >> LG_BITMAP_GROUP_NBITS; - gp = &bitmap[goff]; - g = *gp; - propagate = (g == 0); - assert((g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))) == 0); - g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); - *gp = g; - assert(!bitmap_get(bitmap, binfo, bit)); -#ifdef BITMAP_USE_TREE - /* Propagate group state transitions up the tree. */ - if (propagate) { - unsigned i; - for (i = 1; i < binfo->nlevels; i++) { - bit = goff; - goff = bit >> LG_BITMAP_GROUP_NBITS; - gp = &bitmap[binfo->levels[i].group_offset + goff]; - g = *gp; - propagate = (g == 0); - assert((g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))) - == 0); - g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); - *gp = g; - if (!propagate) - break; - } - } -#endif /* BITMAP_USE_TREE */ -} - -#endif - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ diff --git a/include/jemalloc/internal/bitmap_externs.h b/include/jemalloc/internal/bitmap_externs.h new file mode 100644 index 00000000..4df63eba --- /dev/null +++ b/include/jemalloc/internal/bitmap_externs.h @@ -0,0 +1,8 @@ +#ifndef JEMALLOC_INTERNAL_BITMAP_EXTERNS_H +#define JEMALLOC_INTERNAL_BITMAP_EXTERNS_H + +void bitmap_info_init(bitmap_info_t *binfo, size_t nbits); +void bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo); +size_t bitmap_size(const bitmap_info_t *binfo); + +#endif /* JEMALLOC_INTERNAL_BITMAP_EXTERNS_H */ diff --git a/include/jemalloc/internal/bitmap_inlines.h b/include/jemalloc/internal/bitmap_inlines.h new file mode 100644 index 00000000..5400f9d1 --- /dev/null +++ b/include/jemalloc/internal/bitmap_inlines.h @@ -0,0 +1,152 @@ +#ifndef JEMALLOC_INTERNAL_BITMAP_INLINES_H +#define JEMALLOC_INTERNAL_BITMAP_INLINES_H + +#ifndef JEMALLOC_ENABLE_INLINE +bool bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo); +bool bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); +void bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); +size_t bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo); +void bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BITMAP_C_)) +JEMALLOC_INLINE bool +bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) +{ +#ifdef BITMAP_USE_TREE + size_t rgoff = binfo->levels[binfo->nlevels].group_offset - 1; + bitmap_t rg = bitmap[rgoff]; + /* The bitmap is full iff the root group is 0. */ + return (rg == 0); +#else + size_t i; + + for (i = 0; i < binfo->ngroups; i++) { + if (bitmap[i] != 0) + return (false); + } + return (true); +#endif +} + +JEMALLOC_INLINE bool +bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) +{ + size_t goff; + bitmap_t g; + + assert(bit < binfo->nbits); + goff = bit >> LG_BITMAP_GROUP_NBITS; + g = bitmap[goff]; + return (!(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK)))); +} + +JEMALLOC_INLINE void +bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) +{ + size_t goff; + bitmap_t *gp; + bitmap_t g; + + assert(bit < binfo->nbits); + assert(!bitmap_get(bitmap, binfo, bit)); + goff = bit >> LG_BITMAP_GROUP_NBITS; + gp = &bitmap[goff]; + g = *gp; + assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); + g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); + *gp = g; + assert(bitmap_get(bitmap, binfo, bit)); +#ifdef BITMAP_USE_TREE + /* Propagate group state transitions up the tree. */ + if (g == 0) { + unsigned i; + for (i = 1; i < binfo->nlevels; i++) { + bit = goff; + goff = bit >> LG_BITMAP_GROUP_NBITS; + gp = &bitmap[binfo->levels[i].group_offset + goff]; + g = *gp; + assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); + g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); + *gp = g; + if (g != 0) + break; + } + } +#endif +} + +/* sfu: set first unset. */ +JEMALLOC_INLINE size_t +bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) +{ + size_t bit; + bitmap_t g; + unsigned i; + + assert(!bitmap_full(bitmap, binfo)); + +#ifdef BITMAP_USE_TREE + i = binfo->nlevels - 1; + g = bitmap[binfo->levels[i].group_offset]; + bit = ffs_lu(g) - 1; + while (i > 0) { + i--; + g = bitmap[binfo->levels[i].group_offset + bit]; + bit = (bit << LG_BITMAP_GROUP_NBITS) + (ffs_lu(g) - 1); + } +#else + i = 0; + g = bitmap[0]; + while ((bit = ffs_lu(g)) == 0) { + i++; + g = bitmap[i]; + } + bit = (i << LG_BITMAP_GROUP_NBITS) + (bit - 1); +#endif + bitmap_set(bitmap, binfo, bit); + return (bit); +} + +JEMALLOC_INLINE void +bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) +{ + size_t goff; + bitmap_t *gp; + bitmap_t g; + UNUSED bool propagate; + + assert(bit < binfo->nbits); + assert(bitmap_get(bitmap, binfo, bit)); + goff = bit >> LG_BITMAP_GROUP_NBITS; + gp = &bitmap[goff]; + g = *gp; + propagate = (g == 0); + assert((g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))) == 0); + g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); + *gp = g; + assert(!bitmap_get(bitmap, binfo, bit)); +#ifdef BITMAP_USE_TREE + /* Propagate group state transitions up the tree. */ + if (propagate) { + unsigned i; + for (i = 1; i < binfo->nlevels; i++) { + bit = goff; + goff = bit >> LG_BITMAP_GROUP_NBITS; + gp = &bitmap[binfo->levels[i].group_offset + goff]; + g = *gp; + propagate = (g == 0); + assert((g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))) + == 0); + g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); + *gp = g; + if (!propagate) + break; + } + } +#endif /* BITMAP_USE_TREE */ +} + +#endif + +#endif /* JEMALLOC_INTERNAL_BITMAP_INLINES_H */ diff --git a/include/jemalloc/internal/bitmap_structs.h b/include/jemalloc/internal/bitmap_structs.h new file mode 100644 index 00000000..297ae669 --- /dev/null +++ b/include/jemalloc/internal/bitmap_structs.h @@ -0,0 +1,28 @@ +#ifndef JEMALLOC_INTERNAL_BITMAP_STRUCTS_H +#define JEMALLOC_INTERNAL_BITMAP_STRUCTS_H + +struct bitmap_level_s { + /* Offset of this level's groups within the array of groups. */ + size_t group_offset; +}; + +struct bitmap_info_s { + /* Logical number of bits in bitmap (stored at bottom level). */ + size_t nbits; + +#ifdef BITMAP_USE_TREE + /* Number of levels necessary for nbits. */ + unsigned nlevels; + + /* + * Only the first (nlevels+1) elements are used, and levels are ordered + * bottom to top (e.g. the bottom level is stored in levels[0]). + */ + bitmap_level_t levels[BITMAP_MAX_LEVELS+1]; +#else /* BITMAP_USE_TREE */ + /* Number of groups necessary for nbits. */ + size_t ngroups; +#endif /* BITMAP_USE_TREE */ +}; + +#endif /* JEMALLOC_INTERNAL_BITMAP_STRUCTS_H */ diff --git a/include/jemalloc/internal/bitmap_types.h b/include/jemalloc/internal/bitmap_types.h new file mode 100644 index 00000000..d823186f --- /dev/null +++ b/include/jemalloc/internal/bitmap_types.h @@ -0,0 +1,133 @@ +#ifndef JEMALLOC_INTERNAL_BITMAP_TYPES_H +#define JEMALLOC_INTERNAL_BITMAP_TYPES_H + +/* Maximum bitmap bit count is 2^LG_BITMAP_MAXBITS. */ +#define LG_BITMAP_MAXBITS LG_SLAB_MAXREGS +#define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS) + +typedef struct bitmap_level_s bitmap_level_t; +typedef struct bitmap_info_s bitmap_info_t; +typedef unsigned long bitmap_t; +#define LG_SIZEOF_BITMAP LG_SIZEOF_LONG + +/* Number of bits per group. */ +#define LG_BITMAP_GROUP_NBITS (LG_SIZEOF_BITMAP + 3) +#define BITMAP_GROUP_NBITS (1U << LG_BITMAP_GROUP_NBITS) +#define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1) + +/* + * Do some analysis on how big the bitmap is before we use a tree. For a brute + * force linear search, if we would have to call ffs_lu() more than 2^3 times, + * use a tree instead. + */ +#if LG_BITMAP_MAXBITS - LG_BITMAP_GROUP_NBITS > 3 +# define BITMAP_USE_TREE +#endif + +/* Number of groups required to store a given number of bits. */ +#define BITMAP_BITS2GROUPS(nbits) \ + (((nbits) + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS) + +/* + * Number of groups required at a particular level for a given number of bits. + */ +#define BITMAP_GROUPS_L0(nbits) \ + BITMAP_BITS2GROUPS(nbits) +#define BITMAP_GROUPS_L1(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits)) +#define BITMAP_GROUPS_L2(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))) +#define BITMAP_GROUPS_L3(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ + BITMAP_BITS2GROUPS((nbits))))) +#define BITMAP_GROUPS_L4(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))))) + +/* + * Assuming the number of levels, number of groups required for a given number + * of bits. + */ +#define BITMAP_GROUPS_1_LEVEL(nbits) \ + BITMAP_GROUPS_L0(nbits) +#define BITMAP_GROUPS_2_LEVEL(nbits) \ + (BITMAP_GROUPS_1_LEVEL(nbits) + BITMAP_GROUPS_L1(nbits)) +#define BITMAP_GROUPS_3_LEVEL(nbits) \ + (BITMAP_GROUPS_2_LEVEL(nbits) + BITMAP_GROUPS_L2(nbits)) +#define BITMAP_GROUPS_4_LEVEL(nbits) \ + (BITMAP_GROUPS_3_LEVEL(nbits) + BITMAP_GROUPS_L3(nbits)) +#define BITMAP_GROUPS_5_LEVEL(nbits) \ + (BITMAP_GROUPS_4_LEVEL(nbits) + BITMAP_GROUPS_L4(nbits)) + +/* + * Maximum number of groups required to support LG_BITMAP_MAXBITS. + */ +#ifdef BITMAP_USE_TREE + +#if LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_1_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 2 +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_2_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 3 +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_3_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 4 +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_4_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 5 +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_5_LEVEL(BITMAP_MAXBITS) +#else +# error "Unsupported bitmap size" +#endif + +/* + * Maximum number of levels possible. This could be statically computed based + * on LG_BITMAP_MAXBITS: + * + * #define BITMAP_MAX_LEVELS \ + * (LG_BITMAP_MAXBITS / LG_SIZEOF_BITMAP) \ + * + !!(LG_BITMAP_MAXBITS % LG_SIZEOF_BITMAP) + * + * However, that would not allow the generic BITMAP_INFO_INITIALIZER() macro, so + * instead hardcode BITMAP_MAX_LEVELS to the largest number supported by the + * various cascading macros. The only additional cost this incurs is some + * unused trailing entries in bitmap_info_t structures; the bitmaps themselves + * are not impacted. + */ +#define BITMAP_MAX_LEVELS 5 + +#define BITMAP_INFO_INITIALIZER(nbits) { \ + /* nbits. */ \ + nbits, \ + /* nlevels. */ \ + (BITMAP_GROUPS_L0(nbits) > BITMAP_GROUPS_L1(nbits)) + \ + (BITMAP_GROUPS_L1(nbits) > BITMAP_GROUPS_L2(nbits)) + \ + (BITMAP_GROUPS_L2(nbits) > BITMAP_GROUPS_L3(nbits)) + \ + (BITMAP_GROUPS_L3(nbits) > BITMAP_GROUPS_L4(nbits)) + 1, \ + /* levels. */ \ + { \ + {0}, \ + {BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) + \ + BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L3(nbits) + BITMAP_GROUPS_L2(nbits) + \ + BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L4(nbits) + BITMAP_GROUPS_L3(nbits) + \ + BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) \ + + BITMAP_GROUPS_L0(nbits)} \ + } \ +} + +#else /* BITMAP_USE_TREE */ + +#define BITMAP_GROUPS_MAX BITMAP_BITS2GROUPS(BITMAP_MAXBITS) + +#define BITMAP_INFO_INITIALIZER(nbits) { \ + /* nbits. */ \ + nbits, \ + /* ngroups. */ \ + BITMAP_BITS2GROUPS(nbits) \ +} + +#endif /* BITMAP_USE_TREE */ + +#endif /* JEMALLOC_INTERNAL_BITMAP_TYPES_H */ diff --git a/include/jemalloc/internal/ckh.h b/include/jemalloc/internal/ckh.h deleted file mode 100644 index f75ad90b..00000000 --- a/include/jemalloc/internal/ckh.h +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -typedef struct ckh_s ckh_t; -typedef struct ckhc_s ckhc_t; - -/* Typedefs to allow easy function pointer passing. */ -typedef void ckh_hash_t (const void *, size_t[2]); -typedef bool ckh_keycomp_t (const void *, const void *); - -/* Maintain counters used to get an idea of performance. */ -/* #define CKH_COUNT */ -/* Print counter values in ckh_delete() (requires CKH_COUNT). */ -/* #define CKH_VERBOSE */ - -/* - * There are 2^LG_CKH_BUCKET_CELLS cells in each hash table bucket. Try to fit - * one bucket per L1 cache line. - */ -#define LG_CKH_BUCKET_CELLS (LG_CACHELINE - LG_SIZEOF_PTR - 1) - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -/* Hash table cell. */ -struct ckhc_s { - const void *key; - const void *data; -}; - -struct ckh_s { -#ifdef CKH_COUNT - /* Counters used to get an idea of performance. */ - uint64_t ngrows; - uint64_t nshrinks; - uint64_t nshrinkfails; - uint64_t ninserts; - uint64_t nrelocs; -#endif - - /* Used for pseudo-random number generation. */ - uint64_t prng_state; - - /* Total number of items. */ - size_t count; - - /* - * Minimum and current number of hash table buckets. There are - * 2^LG_CKH_BUCKET_CELLS cells per bucket. - */ - unsigned lg_minbuckets; - unsigned lg_curbuckets; - - /* Hash and comparison functions. */ - ckh_hash_t *hash; - ckh_keycomp_t *keycomp; - - /* Hash table with 2^lg_curbuckets buckets. */ - ckhc_t *tab; -}; - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -bool ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, - ckh_keycomp_t *keycomp); -void ckh_delete(tsd_t *tsd, ckh_t *ckh); -size_t ckh_count(ckh_t *ckh); -bool ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data); -bool ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data); -bool ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key, - void **data); -bool ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data); -void ckh_string_hash(const void *key, size_t r_hash[2]); -bool ckh_string_keycomp(const void *k1, const void *k2); -void ckh_pointer_hash(const void *key, size_t r_hash[2]); -bool ckh_pointer_keycomp(const void *k1, const void *k2); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ diff --git a/include/jemalloc/internal/ckh_externs.h b/include/jemalloc/internal/ckh_externs.h new file mode 100644 index 00000000..c912f72b --- /dev/null +++ b/include/jemalloc/internal/ckh_externs.h @@ -0,0 +1,18 @@ +#ifndef JEMALLOC_INTERNAL_CKH_EXTERNS_H +#define JEMALLOC_INTERNAL_CKH_EXTERNS_H + +bool ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, + ckh_keycomp_t *keycomp); +void ckh_delete(tsd_t *tsd, ckh_t *ckh); +size_t ckh_count(ckh_t *ckh); +bool ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data); +bool ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data); +bool ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key, + void **data); +bool ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data); +void ckh_string_hash(const void *key, size_t r_hash[2]); +bool ckh_string_keycomp(const void *k1, const void *k2); +void ckh_pointer_hash(const void *key, size_t r_hash[2]); +bool ckh_pointer_keycomp(const void *k1, const void *k2); + +#endif /* JEMALLOC_INTERNAL_CKH_EXTERNS_H */ diff --git a/include/jemalloc/internal/ckh_structs.h b/include/jemalloc/internal/ckh_structs.h new file mode 100644 index 00000000..a800cbc2 --- /dev/null +++ b/include/jemalloc/internal/ckh_structs.h @@ -0,0 +1,41 @@ +#ifndef JEMALLOC_INTERNAL_CKH_STRUCTS_H +#define JEMALLOC_INTERNAL_CKH_STRUCTS_H + +/* Hash table cell. */ +struct ckhc_s { + const void *key; + const void *data; +}; + +struct ckh_s { +#ifdef CKH_COUNT + /* Counters used to get an idea of performance. */ + uint64_t ngrows; + uint64_t nshrinks; + uint64_t nshrinkfails; + uint64_t ninserts; + uint64_t nrelocs; +#endif + + /* Used for pseudo-random number generation. */ + uint64_t prng_state; + + /* Total number of items. */ + size_t count; + + /* + * Minimum and current number of hash table buckets. There are + * 2^LG_CKH_BUCKET_CELLS cells per bucket. + */ + unsigned lg_minbuckets; + unsigned lg_curbuckets; + + /* Hash and comparison functions. */ + ckh_hash_t *hash; + ckh_keycomp_t *keycomp; + + /* Hash table with 2^lg_curbuckets buckets. */ + ckhc_t *tab; +}; + +#endif /* JEMALLOC_INTERNAL_CKH_STRUCTS_H */ diff --git a/include/jemalloc/internal/ckh_types.h b/include/jemalloc/internal/ckh_types.h new file mode 100644 index 00000000..9a1d8d49 --- /dev/null +++ b/include/jemalloc/internal/ckh_types.h @@ -0,0 +1,22 @@ +#ifndef JEMALLOC_INTERNAL_CKH_TYPES_H +#define JEMALLOC_INTERNAL_CKH_TYPES_H + +typedef struct ckh_s ckh_t; +typedef struct ckhc_s ckhc_t; + +/* Typedefs to allow easy function pointer passing. */ +typedef void ckh_hash_t (const void *, size_t[2]); +typedef bool ckh_keycomp_t (const void *, const void *); + +/* Maintain counters used to get an idea of performance. */ +/* #define CKH_COUNT */ +/* Print counter values in ckh_delete() (requires CKH_COUNT). */ +/* #define CKH_VERBOSE */ + +/* + * There are 2^LG_CKH_BUCKET_CELLS cells in each hash table bucket. Try to fit + * one bucket per L1 cache line. + */ +#define LG_CKH_BUCKET_CELLS (LG_CACHELINE - LG_SIZEOF_PTR - 1) + +#endif /* JEMALLOC_INTERNAL_CKH_TYPES_H */ diff --git a/include/jemalloc/internal/ctl.h b/include/jemalloc/internal/ctl.h deleted file mode 100644 index 7dc3e5b5..00000000 --- a/include/jemalloc/internal/ctl.h +++ /dev/null @@ -1,127 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -typedef struct ctl_node_s ctl_node_t; -typedef struct ctl_named_node_s ctl_named_node_t; -typedef struct ctl_indexed_node_s ctl_indexed_node_t; -typedef struct ctl_arena_stats_s ctl_arena_stats_t; -typedef struct ctl_stats_s ctl_stats_t; - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -struct ctl_node_s { - bool named; -}; - -struct ctl_named_node_s { - struct ctl_node_s node; - const char *name; - /* If (nchildren == 0), this is a terminal node. */ - size_t nchildren; - const ctl_node_t *children; - int (*ctl)(tsd_t *, const size_t *, size_t, void *, - size_t *, void *, size_t); -}; - -struct ctl_indexed_node_s { - struct ctl_node_s node; - const ctl_named_node_t *(*index)(tsdn_t *, const size_t *, size_t, - size_t); -}; - -struct ctl_arena_stats_s { - unsigned arena_ind; - bool initialized; - ql_elm(ctl_arena_stats_t) destroyed_link; - - unsigned nthreads; - const char *dss; - ssize_t decay_time; - size_t pactive; - size_t pdirty; - - /* The remainder are only populated if config_stats is true. */ - - arena_stats_t astats; - - /* Aggregate stats for small size classes, based on bin stats. */ - size_t allocated_small; - uint64_t nmalloc_small; - uint64_t ndalloc_small; - uint64_t nrequests_small; - - malloc_bin_stats_t bstats[NBINS]; - malloc_large_stats_t lstats[NSIZES - NBINS]; -}; - -struct ctl_stats_s { - uint64_t epoch; - size_t allocated; - size_t active; - size_t metadata; - size_t resident; - size_t mapped; - size_t retained; - unsigned narenas; - ql_head(ctl_arena_stats_t) destroyed; - /* - * Element 0 contains merged stats for extant arenas (accessed via - * MALLCTL_ARENAS_ALL), element 1 contains merged stats for destroyed - * arenas (accessed via MALLCTL_ARENAS_DESTROYED), and the remaining - * MALLOCX_ARENA_MAX+1 elements correspond to arenas. - */ - ctl_arena_stats_t *arenas[MALLOCX_ARENA_MAX + 3]; -}; - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -int ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp, - void *newp, size_t newlen); -int ctl_nametomib(tsdn_t *tsdn, const char *name, size_t *mibp, - size_t *miblenp); - -int ctl_bymib(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen); -bool ctl_boot(void); -void ctl_prefork(tsdn_t *tsdn); -void ctl_postfork_parent(tsdn_t *tsdn); -void ctl_postfork_child(tsdn_t *tsdn); - -#define xmallctl(name, oldp, oldlenp, newp, newlen) do { \ - if (je_mallctl(name, oldp, oldlenp, newp, newlen) \ - != 0) { \ - malloc_printf( \ - ": Failure in xmallctl(\"%s\", ...)\n", \ - name); \ - abort(); \ - } \ -} while (0) - -#define xmallctlnametomib(name, mibp, miblenp) do { \ - if (je_mallctlnametomib(name, mibp, miblenp) != 0) { \ - malloc_printf(": Failure in " \ - "xmallctlnametomib(\"%s\", ...)\n", name); \ - abort(); \ - } \ -} while (0) - -#define xmallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) do { \ - if (je_mallctlbymib(mib, miblen, oldp, oldlenp, newp, \ - newlen) != 0) { \ - malloc_write( \ - ": Failure in xmallctlbymib()\n"); \ - abort(); \ - } \ -} while (0) - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ - diff --git a/include/jemalloc/internal/ctl_externs.h b/include/jemalloc/internal/ctl_externs.h new file mode 100644 index 00000000..11f77cfb --- /dev/null +++ b/include/jemalloc/internal/ctl_externs.h @@ -0,0 +1,43 @@ +#ifndef JEMALLOC_INTERNAL_CTL_EXTERNS_H +#define JEMALLOC_INTERNAL_CTL_EXTERNS_H + +int ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp, + void *newp, size_t newlen); +int ctl_nametomib(tsdn_t *tsdn, const char *name, size_t *mibp, + size_t *miblenp); + +int ctl_bymib(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, + size_t *oldlenp, void *newp, size_t newlen); +bool ctl_boot(void); +void ctl_prefork(tsdn_t *tsdn); +void ctl_postfork_parent(tsdn_t *tsdn); +void ctl_postfork_child(tsdn_t *tsdn); + +#define xmallctl(name, oldp, oldlenp, newp, newlen) do { \ + if (je_mallctl(name, oldp, oldlenp, newp, newlen) \ + != 0) { \ + malloc_printf( \ + ": Failure in xmallctl(\"%s\", ...)\n", \ + name); \ + abort(); \ + } \ +} while (0) + +#define xmallctlnametomib(name, mibp, miblenp) do { \ + if (je_mallctlnametomib(name, mibp, miblenp) != 0) { \ + malloc_printf(": Failure in " \ + "xmallctlnametomib(\"%s\", ...)\n", name); \ + abort(); \ + } \ +} while (0) + +#define xmallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) do { \ + if (je_mallctlbymib(mib, miblen, oldp, oldlenp, newp, \ + newlen) != 0) { \ + malloc_write( \ + ": Failure in xmallctlbymib()\n"); \ + abort(); \ + } \ +} while (0) + +#endif /* JEMALLOC_INTERNAL_CTL_EXTERNS_H */ diff --git a/include/jemalloc/internal/ctl_structs.h b/include/jemalloc/internal/ctl_structs.h new file mode 100644 index 00000000..8f94c6c4 --- /dev/null +++ b/include/jemalloc/internal/ctl_structs.h @@ -0,0 +1,68 @@ +#ifndef JEMALLOC_INTERNAL_CTL_STRUCTS_H +#define JEMALLOC_INTERNAL_CTL_STRUCTS_H + +struct ctl_node_s { + bool named; +}; + +struct ctl_named_node_s { + struct ctl_node_s node; + const char *name; + /* If (nchildren == 0), this is a terminal node. */ + size_t nchildren; + const ctl_node_t *children; + int (*ctl)(tsd_t *, const size_t *, size_t, void *, + size_t *, void *, size_t); +}; + +struct ctl_indexed_node_s { + struct ctl_node_s node; + const ctl_named_node_t *(*index)(tsdn_t *, const size_t *, size_t, + size_t); +}; + +struct ctl_arena_stats_s { + unsigned arena_ind; + bool initialized; + ql_elm(ctl_arena_stats_t) destroyed_link; + + unsigned nthreads; + const char *dss; + ssize_t decay_time; + size_t pactive; + size_t pdirty; + + /* The remainder are only populated if config_stats is true. */ + + arena_stats_t astats; + + /* Aggregate stats for small size classes, based on bin stats. */ + size_t allocated_small; + uint64_t nmalloc_small; + uint64_t ndalloc_small; + uint64_t nrequests_small; + + malloc_bin_stats_t bstats[NBINS]; + malloc_large_stats_t lstats[NSIZES - NBINS]; +}; + +struct ctl_stats_s { + uint64_t epoch; + size_t allocated; + size_t active; + size_t metadata; + size_t resident; + size_t mapped; + size_t retained; + unsigned narenas; + ql_head(ctl_arena_stats_t) destroyed; + /* + * Element 0 contains merged stats for extant arenas (accessed via + * MALLCTL_ARENAS_ALL), element 1 contains merged stats for destroyed + * arenas (accessed via MALLCTL_ARENAS_DESTROYED), and the remaining + * MALLOCX_ARENA_MAX+1 elements correspond to arenas. + */ + ctl_arena_stats_t *arenas[MALLOCX_ARENA_MAX + 3]; +}; + +#endif /* JEMALLOC_INTERNAL_CTL_STRUCTS_H */ diff --git a/include/jemalloc/internal/ctl_types.h b/include/jemalloc/internal/ctl_types.h new file mode 100644 index 00000000..848c4f10 --- /dev/null +++ b/include/jemalloc/internal/ctl_types.h @@ -0,0 +1,10 @@ +#ifndef JEMALLOC_INTERNAL_CTL_TYPES_H +#define JEMALLOC_INTERNAL_CTL_TYPES_H + +typedef struct ctl_node_s ctl_node_t; +typedef struct ctl_named_node_s ctl_named_node_t; +typedef struct ctl_indexed_node_s ctl_indexed_node_t; +typedef struct ctl_arena_stats_s ctl_arena_stats_t; +typedef struct ctl_stats_s ctl_stats_t; + +#endif /* JEMALLOC_INTERNAL_CTL_TYPES_H */ diff --git a/include/jemalloc/internal/extent_dss.h b/include/jemalloc/internal/extent_dss.h deleted file mode 100644 index f2dac52e..00000000 --- a/include/jemalloc/internal/extent_dss.h +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -typedef enum { - dss_prec_disabled = 0, - dss_prec_primary = 1, - dss_prec_secondary = 2, - - dss_prec_limit = 3 -} dss_prec_t; -#define DSS_PREC_DEFAULT dss_prec_secondary -#define DSS_DEFAULT "secondary" - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -extern const char *dss_prec_names[]; - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -extern const char *opt_dss; - -dss_prec_t extent_dss_prec_get(void); -bool extent_dss_prec_set(dss_prec_t dss_prec); -void *extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, - size_t size, size_t alignment, bool *zero, bool *commit); -bool extent_in_dss(void *addr); -bool extent_dss_mergeable(void *addr_a, void *addr_b); -void extent_dss_boot(void); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ diff --git a/include/jemalloc/internal/extent_dss_externs.h b/include/jemalloc/internal/extent_dss_externs.h new file mode 100644 index 00000000..d376fa74 --- /dev/null +++ b/include/jemalloc/internal/extent_dss_externs.h @@ -0,0 +1,14 @@ +#ifndef JEMALLOC_INTERNAL_EXTENT_DSS_EXTERNS_H +#define JEMALLOC_INTERNAL_EXTENT_DSS_EXTERNS_H + +extern const char *opt_dss; + +dss_prec_t extent_dss_prec_get(void); +bool extent_dss_prec_set(dss_prec_t dss_prec); +void *extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, + size_t size, size_t alignment, bool *zero, bool *commit); +bool extent_in_dss(void *addr); +bool extent_dss_mergeable(void *addr_a, void *addr_b); +void extent_dss_boot(void); + +#endif /* JEMALLOC_INTERNAL_EXTENT_DSS_EXTERNS_H */ diff --git a/include/jemalloc/internal/extent_dss_structs.h b/include/jemalloc/internal/extent_dss_structs.h new file mode 100644 index 00000000..2d8c6f05 --- /dev/null +++ b/include/jemalloc/internal/extent_dss_structs.h @@ -0,0 +1,6 @@ +#ifndef JEMALLOC_INTERNAL_EXTENT_DSS_STRUCTS_H +#define JEMALLOC_INTERNAL_EXTENT_DSS_STRUCTS_H + +extern const char *dss_prec_names[]; + +#endif /* JEMALLOC_INTERNAL_EXTENT_DSS_STRUCTS_H */ diff --git a/include/jemalloc/internal/extent_dss_types.h b/include/jemalloc/internal/extent_dss_types.h new file mode 100644 index 00000000..2839757c --- /dev/null +++ b/include/jemalloc/internal/extent_dss_types.h @@ -0,0 +1,14 @@ +#ifndef JEMALLOC_INTERNAL_EXTENT_DSS_TYPES_H +#define JEMALLOC_INTERNAL_EXTENT_DSS_TYPES_H + +typedef enum { + dss_prec_disabled = 0, + dss_prec_primary = 1, + dss_prec_secondary = 2, + + dss_prec_limit = 3 +} dss_prec_t; +#define DSS_PREC_DEFAULT dss_prec_secondary +#define DSS_DEFAULT "secondary" + +#endif /* JEMALLOC_INTERNAL_EXTENT_DSS_TYPES_H */ diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h new file mode 100644 index 00000000..59f3c7ca --- /dev/null +++ b/include/jemalloc/internal/extent_externs.h @@ -0,0 +1,60 @@ +#ifndef JEMALLOC_INTERNAL_EXTENT_EXTERNS_H +#define JEMALLOC_INTERNAL_EXTENT_EXTERNS_H + +extern rtree_t extents_rtree; +extern const extent_hooks_t extent_hooks_default; + +extent_t *extent_alloc(tsdn_t *tsdn, arena_t *arena); +void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent); + +extent_hooks_t *extent_hooks_get(arena_t *arena); +extent_hooks_t *extent_hooks_set(arena_t *arena, extent_hooks_t *extent_hooks); + +#ifdef JEMALLOC_JET +typedef size_t (extent_size_quantize_t)(size_t); +extern extent_size_quantize_t *extent_size_quantize_floor; +extern extent_size_quantize_t *extent_size_quantize_ceil; +#else +size_t extent_size_quantize_floor(size_t size); +size_t extent_size_quantize_ceil(size_t size); +#endif + +ph_proto(, extent_heap_, extent_heap_t, extent_t) + +extent_t *extent_alloc_cache_locked(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool *commit, bool slab); +extent_t *extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool *commit, bool slab); +extent_t *extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool *commit, bool slab); +void extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent); +void extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent); +bool extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent); +void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent); +bool extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, + size_t length); +bool extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, + size_t length); +bool extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, + size_t length); +bool extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, + size_t length); +extent_t *extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a, + size_t usize_a, size_t size_b, size_t usize_b); +bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b); + +bool extent_boot(void); + +#endif /* JEMALLOC_INTERNAL_EXTENT_EXTERNS_H */ diff --git a/include/jemalloc/internal/extent.h b/include/jemalloc/internal/extent_inlines.h similarity index 58% rename from include/jemalloc/internal/extent.h rename to include/jemalloc/internal/extent_inlines.h index 70accffb..e48af92f 100644 --- a/include/jemalloc/internal/extent.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -1,157 +1,5 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -typedef struct extent_s extent_t; - -#define EXTENT_HOOKS_INITIALIZER NULL - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -/* Extent (span of pages). Use accessor functions for e_* fields. */ -struct extent_s { - /* Arena from which this extent came, if any. */ - arena_t *e_arena; - - /* Pointer to the extent that this structure is responsible for. */ - void *e_addr; - - /* Extent size. */ - size_t e_size; - - /* - * Usable size, typically smaller than extent size due to large_pad or - * promotion of sampled small regions. - */ - size_t e_usize; - - /* - * Serial number (potentially non-unique). - * - * In principle serial numbers can wrap around on 32-bit systems if - * JEMALLOC_MUNMAP is defined, but as long as comparison functions fall - * back on address comparison for equal serial numbers, stable (if - * imperfect) ordering is maintained. - * - * Serial numbers may not be unique even in the absence of wrap-around, - * e.g. when splitting an extent and assigning the same serial number to - * both resulting adjacent extents. - */ - size_t e_sn; - - /* True if extent is active (in use). */ - bool e_active; - - /* - * The zeroed flag is used by extent recycling code to track whether - * memory is zero-filled. - */ - bool e_zeroed; - - /* - * True if physical memory is committed to the extent, whether - * explicitly or implicitly as on a system that overcommits and - * satisfies physical memory needs on demand via soft page faults. - */ - bool e_committed; - - /* - * The slab flag indicates whether the extent is used for a slab of - * small regions. This helps differentiate small size classes, and it - * indicates whether interior pointers can be looked up via iealloc(). - */ - bool e_slab; - - union { - /* Small region slab metadata. */ - arena_slab_data_t e_slab_data; - - /* Profile counters, used for large objects. */ - union { - void *e_prof_tctx_pun; - prof_tctx_t *e_prof_tctx; - }; - }; - - /* - * Linkage for arena's extents_dirty and arena_bin_t's slabs_full rings. - */ - qr(extent_t) qr_link; - - union { - /* Linkage for per size class sn/address-ordered heaps. */ - phn(extent_t) ph_link; - - /* Linkage for arena's large and extent_cache lists. */ - ql_elm(extent_t) ql_link; - }; -}; -typedef ph(extent_t) extent_heap_t; - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -extern rtree_t extents_rtree; -extern const extent_hooks_t extent_hooks_default; - -extent_t *extent_alloc(tsdn_t *tsdn, arena_t *arena); -void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent); - -extent_hooks_t *extent_hooks_get(arena_t *arena); -extent_hooks_t *extent_hooks_set(arena_t *arena, extent_hooks_t *extent_hooks); - -#ifdef JEMALLOC_JET -typedef size_t (extent_size_quantize_t)(size_t); -extern extent_size_quantize_t *extent_size_quantize_floor; -extern extent_size_quantize_t *extent_size_quantize_ceil; -#else -size_t extent_size_quantize_floor(size_t size); -size_t extent_size_quantize_ceil(size_t size); -#endif - -ph_proto(, extent_heap_, extent_heap_t, extent_t) - -extent_t *extent_alloc_cache_locked(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab); -extent_t *extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab); -extent_t *extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab); -void extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent); -void extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent); -bool extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent); -void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent); -bool extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, - size_t length); -bool extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, - size_t length); -bool extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, - size_t length); -bool extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, - size_t length); -extent_t *extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a, - size_t usize_a, size_t size_b, size_t usize_b); -bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b); - -bool extent_boot(void); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES +#ifndef JEMALLOC_INTERNAL_EXTENT_INLINES_H +#define JEMALLOC_INTERNAL_EXTENT_INLINES_H #ifndef JEMALLOC_ENABLE_INLINE extent_t *extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent); @@ -492,8 +340,4 @@ extent_snad_comp(const extent_t *a, const extent_t *b) } #endif -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ - -#include "jemalloc/internal/extent_dss.h" -#include "jemalloc/internal/extent_mmap.h" +#endif /* JEMALLOC_INTERNAL_EXTENT_INLINES_H */ diff --git a/include/jemalloc/internal/extent_mmap.h b/include/jemalloc/internal/extent_mmap.h deleted file mode 100644 index 3c1a7884..00000000 --- a/include/jemalloc/internal/extent_mmap.h +++ /dev/null @@ -1,21 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -void *extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, - bool *zero, bool *commit); -bool extent_dalloc_mmap(void *addr, size_t size); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ diff --git a/include/jemalloc/internal/extent_mmap_externs.h b/include/jemalloc/internal/extent_mmap_externs.h new file mode 100644 index 00000000..5917b53d --- /dev/null +++ b/include/jemalloc/internal/extent_mmap_externs.h @@ -0,0 +1,8 @@ +#ifndef JEMALLOC_INTERNAL_EXTENT_MMAP_EXTERNS_H +#define JEMALLOC_INTERNAL_EXTENT_MMAP_EXTERNS_H + +void *extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, + bool *zero, bool *commit); +bool extent_dalloc_mmap(void *addr, size_t size); + +#endif /* JEMALLOC_INTERNAL_EXTENT_MMAP_EXTERNS_H */ diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h new file mode 100644 index 00000000..de31317c --- /dev/null +++ b/include/jemalloc/internal/extent_structs.h @@ -0,0 +1,84 @@ +#ifndef JEMALLOC_INTERNAL_EXTENT_STRUCTS_H +#define JEMALLOC_INTERNAL_EXTENT_STRUCTS_H + +/* Extent (span of pages). Use accessor functions for e_* fields. */ +struct extent_s { + /* Arena from which this extent came, if any. */ + arena_t *e_arena; + + /* Pointer to the extent that this structure is responsible for. */ + void *e_addr; + + /* Extent size. */ + size_t e_size; + + /* + * Usable size, typically smaller than extent size due to large_pad or + * promotion of sampled small regions. + */ + size_t e_usize; + + /* + * Serial number (potentially non-unique). + * + * In principle serial numbers can wrap around on 32-bit systems if + * JEMALLOC_MUNMAP is defined, but as long as comparison functions fall + * back on address comparison for equal serial numbers, stable (if + * imperfect) ordering is maintained. + * + * Serial numbers may not be unique even in the absence of wrap-around, + * e.g. when splitting an extent and assigning the same serial number to + * both resulting adjacent extents. + */ + size_t e_sn; + + /* True if extent is active (in use). */ + bool e_active; + + /* + * The zeroed flag is used by extent recycling code to track whether + * memory is zero-filled. + */ + bool e_zeroed; + + /* + * True if physical memory is committed to the extent, whether + * explicitly or implicitly as on a system that overcommits and + * satisfies physical memory needs on demand via soft page faults. + */ + bool e_committed; + + /* + * The slab flag indicates whether the extent is used for a slab of + * small regions. This helps differentiate small size classes, and it + * indicates whether interior pointers can be looked up via iealloc(). + */ + bool e_slab; + + union { + /* Small region slab metadata. */ + arena_slab_data_t e_slab_data; + + /* Profile counters, used for large objects. */ + union { + void *e_prof_tctx_pun; + prof_tctx_t *e_prof_tctx; + }; + }; + + /* + * Linkage for arena's extents_dirty and arena_bin_t's slabs_full rings. + */ + qr(extent_t) qr_link; + + union { + /* Linkage for per size class sn/address-ordered heaps. */ + phn(extent_t) ph_link; + + /* Linkage for arena's large and extent_cache lists. */ + ql_elm(extent_t) ql_link; + }; +}; +typedef ph(extent_t) extent_heap_t; + +#endif /* JEMALLOC_INTERNAL_EXTENT_STRUCTS_H */ diff --git a/include/jemalloc/internal/extent_types.h b/include/jemalloc/internal/extent_types.h new file mode 100644 index 00000000..4873dc54 --- /dev/null +++ b/include/jemalloc/internal/extent_types.h @@ -0,0 +1,8 @@ +#ifndef JEMALLOC_INTERNAL_EXTENT_TYPES_H +#define JEMALLOC_INTERNAL_EXTENT_TYPES_H + +typedef struct extent_s extent_t; + +#define EXTENT_HOOKS_INITIALIZER NULL + +#endif /* JEMALLOC_INTERNAL_EXTENT_TYPES_H */ diff --git a/include/jemalloc/internal/hash.h b/include/jemalloc/internal/hash_inlines.h similarity index 92% rename from include/jemalloc/internal/hash.h rename to include/jemalloc/internal/hash_inlines.h index 1ff2d9a0..0340418e 100644 --- a/include/jemalloc/internal/hash.h +++ b/include/jemalloc/internal/hash_inlines.h @@ -1,22 +1,11 @@ +#ifndef JEMALLOC_INTERNAL_HASH_INLINES_H +#define JEMALLOC_INTERNAL_HASH_INLINES_H + /* * The following hash function is based on MurmurHash3, placed into the public * domain by Austin Appleby. See https://github.com/aappleby/smhasher for * details. */ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES #ifndef JEMALLOC_ENABLE_INLINE uint32_t hash_x86_32(const void *key, int len, uint32_t seed); @@ -353,5 +342,4 @@ hash(const void *key, size_t len, const uint32_t seed, size_t r_hash[2]) } #endif -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ +#endif /* JEMALLOC_INTERNAL_HASH_INLINES_H */ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index a558012a..dfbb4b6d 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -176,21 +176,38 @@ static const bool have_thp = /* * jemalloc can conceptually be broken into components (arena, tcache, etc.), * but there are circular dependencies that cannot be broken without - * substantial performance degradation. In order to reduce the effect on - * visual code flow, read the header files in multiple passes, with one of the - * following cpp variables defined during each pass: + * substantial performance degradation. * + * Historically, we dealt with this by each header into four sections (types, + * structs, externs, and inlines), and included each header file multiple times + * in this file, picking out the portion we want on each pass using the + * following #defines: * JEMALLOC_H_TYPES : Preprocessor-defined constants and psuedo-opaque data * types. * JEMALLOC_H_STRUCTS : Data structures. * JEMALLOC_H_EXTERNS : Extern data declarations and function prototypes. * JEMALLOC_H_INLINES : Inline functions. + * + * We're moving toward a world in which the dependencies are explicit; each file + * will #include the headers it depends on (rather than relying on them being + * implicitly available via this file including every header file in the + * project). + * + * We're now in an intermediate state: we've broken up the header files to avoid + * having to include each one multiple times, but have not yet moved the + * dependency information into the header files (i.e. we still rely on the + * ordering in this file to ensure all a header's dependencies are available in + * its translation unit). Each component is now broken up into multiple header + * files, corresponding to the sections above (e.g. instead of "tsd.h", we now + * have "tsd_types.h", "tsd_structs.h", "tsd_externs.h", "tsd_inlines.h"). */ -/******************************************************************************/ -#define JEMALLOC_H_TYPES #include "jemalloc/internal/jemalloc_internal_macros.h" +/******************************************************************************/ +/* TYPES */ +/******************************************************************************/ + /* Page size index type. */ typedef unsigned pszind_t; @@ -362,69 +379,57 @@ typedef unsigned szind_t; # define VARIABLE_ARRAY(type, name, count) type name[(count)] #endif -#include "jemalloc/internal/nstime.h" -#include "jemalloc/internal/util.h" -#include "jemalloc/internal/atomic.h" -#include "jemalloc/internal/spin.h" -#include "jemalloc/internal/prng.h" -#include "jemalloc/internal/ticker.h" -#include "jemalloc/internal/ckh.h" +#include "jemalloc/internal/nstime_types.h" +#include "jemalloc/internal/util_types.h" +#include "jemalloc/internal/spin_types.h" +#include "jemalloc/internal/prng_types.h" +#include "jemalloc/internal/ticker_types.h" +#include "jemalloc/internal/ckh_types.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/smoothstep.h" -#include "jemalloc/internal/stats.h" -#include "jemalloc/internal/ctl.h" -#include "jemalloc/internal/witness.h" -#include "jemalloc/internal/mutex.h" -#include "jemalloc/internal/tsd.h" -#include "jemalloc/internal/extent.h" -#include "jemalloc/internal/base.h" -#include "jemalloc/internal/arena.h" -#include "jemalloc/internal/bitmap.h" -#include "jemalloc/internal/rtree.h" -#include "jemalloc/internal/pages.h" -#include "jemalloc/internal/large.h" -#include "jemalloc/internal/tcache.h" -#include "jemalloc/internal/hash.h" -#include "jemalloc/internal/prof.h" - -#undef JEMALLOC_H_TYPES +#include "jemalloc/internal/stats_types.h" +#include "jemalloc/internal/ctl_types.h" +#include "jemalloc/internal/witness_types.h" +#include "jemalloc/internal/mutex_types.h" +#include "jemalloc/internal/tsd_types.h" +#include "jemalloc/internal/extent_types.h" +#include "jemalloc/internal/extent_dss_types.h" +#include "jemalloc/internal/base_types.h" +#include "jemalloc/internal/arena_types.h" +#include "jemalloc/internal/bitmap_types.h" +#include "jemalloc/internal/rtree_types.h" +#include "jemalloc/internal/pages_types.h" +#include "jemalloc/internal/tcache_types.h" +#include "jemalloc/internal/prof_types.h" + + /******************************************************************************/ -#define JEMALLOC_H_STRUCTS - -#include "jemalloc/internal/nstime.h" -#include "jemalloc/internal/util.h" -#include "jemalloc/internal/atomic.h" -#include "jemalloc/internal/spin.h" -#include "jemalloc/internal/prng.h" -#include "jemalloc/internal/ticker.h" -#include "jemalloc/internal/ckh.h" -#include "jemalloc/internal/size_classes.h" -#include "jemalloc/internal/smoothstep.h" -#include "jemalloc/internal/stats.h" -#include "jemalloc/internal/ctl.h" -#include "jemalloc/internal/witness.h" -#include "jemalloc/internal/mutex.h" -#include "jemalloc/internal/bitmap.h" -#define JEMALLOC_ARENA_STRUCTS_A -#include "jemalloc/internal/arena.h" -#undef JEMALLOC_ARENA_STRUCTS_A -#include "jemalloc/internal/extent.h" -#include "jemalloc/internal/base.h" -#define JEMALLOC_ARENA_STRUCTS_B -#include "jemalloc/internal/arena.h" -#undef JEMALLOC_ARENA_STRUCTS_B -#include "jemalloc/internal/rtree.h" -#include "jemalloc/internal/pages.h" -#include "jemalloc/internal/large.h" -#include "jemalloc/internal/tcache.h" -#include "jemalloc/internal/hash.h" -#include "jemalloc/internal/prof.h" - -#include "jemalloc/internal/tsd.h" - -#undef JEMALLOC_H_STRUCTS +/* STRUCTS */ +/******************************************************************************/ + +#include "jemalloc/internal/nstime_structs.h" +#include "jemalloc/internal/spin_structs.h" +#include "jemalloc/internal/ticker_structs.h" +#include "jemalloc/internal/ckh_structs.h" +#include "jemalloc/internal/stats_structs.h" +#include "jemalloc/internal/ctl_structs.h" +#include "jemalloc/internal/witness_structs.h" +#include "jemalloc/internal/mutex_structs.h" +#include "jemalloc/internal/bitmap_structs.h" +#include "jemalloc/internal/arena_structs_a.h" +#include "jemalloc/internal/extent_structs.h" +#include "jemalloc/internal/extent_dss_structs.h" +#include "jemalloc/internal/base_structs.h" +#include "jemalloc/internal/arena_structs_b.h" +#include "jemalloc/internal/rtree_structs.h" +#include "jemalloc/internal/tcache_structs.h" +#include "jemalloc/internal/prof_structs.h" +#include "jemalloc/internal/tsd_structs.h" + + +/******************************************************************************/ +/* EXTERNS */ /******************************************************************************/ -#define JEMALLOC_H_EXTERNS extern bool opt_abort; extern const char *opt_junk; @@ -482,54 +487,42 @@ void jemalloc_prefork(void); void jemalloc_postfork_parent(void); void jemalloc_postfork_child(void); -#include "jemalloc/internal/nstime.h" -#include "jemalloc/internal/util.h" -#include "jemalloc/internal/atomic.h" -#include "jemalloc/internal/spin.h" -#include "jemalloc/internal/prng.h" -#include "jemalloc/internal/ticker.h" -#include "jemalloc/internal/ckh.h" -#include "jemalloc/internal/size_classes.h" -#include "jemalloc/internal/smoothstep.h" -#include "jemalloc/internal/stats.h" -#include "jemalloc/internal/ctl.h" -#include "jemalloc/internal/witness.h" -#include "jemalloc/internal/mutex.h" -#include "jemalloc/internal/bitmap.h" -#include "jemalloc/internal/extent.h" -#include "jemalloc/internal/base.h" -#include "jemalloc/internal/arena.h" -#include "jemalloc/internal/rtree.h" -#include "jemalloc/internal/pages.h" -#include "jemalloc/internal/large.h" -#include "jemalloc/internal/tcache.h" -#include "jemalloc/internal/hash.h" -#include "jemalloc/internal/prof.h" -#include "jemalloc/internal/tsd.h" - -#undef JEMALLOC_H_EXTERNS +#include "jemalloc/internal/nstime_externs.h" +#include "jemalloc/internal/util_externs.h" +#include "jemalloc/internal/atomic_externs.h" +#include "jemalloc/internal/ckh_externs.h" +#include "jemalloc/internal/stats_externs.h" +#include "jemalloc/internal/ctl_externs.h" +#include "jemalloc/internal/witness_externs.h" +#include "jemalloc/internal/mutex_externs.h" +#include "jemalloc/internal/bitmap_externs.h" +#include "jemalloc/internal/extent_externs.h" +#include "jemalloc/internal/extent_dss_externs.h" +#include "jemalloc/internal/extent_mmap_externs.h" +#include "jemalloc/internal/base_externs.h" +#include "jemalloc/internal/arena_externs.h" +#include "jemalloc/internal/rtree_externs.h" +#include "jemalloc/internal/pages_externs.h" +#include "jemalloc/internal/large_externs.h" +#include "jemalloc/internal/tcache_externs.h" +#include "jemalloc/internal/prof_externs.h" +#include "jemalloc/internal/tsd_externs.h" + +/******************************************************************************/ +/* INLINES */ /******************************************************************************/ -#define JEMALLOC_H_INLINES - -#include "jemalloc/internal/nstime.h" -#include "jemalloc/internal/util.h" -#include "jemalloc/internal/atomic.h" -#include "jemalloc/internal/spin.h" -#include "jemalloc/internal/prng.h" -#include "jemalloc/internal/ticker.h" -#include "jemalloc/internal/ckh.h" -#include "jemalloc/internal/size_classes.h" -#include "jemalloc/internal/smoothstep.h" -#include "jemalloc/internal/stats.h" -#include "jemalloc/internal/ctl.h" -#include "jemalloc/internal/tsd.h" -#include "jemalloc/internal/witness.h" -#include "jemalloc/internal/mutex.h" -#include "jemalloc/internal/rtree.h" -#include "jemalloc/internal/extent.h" -#include "jemalloc/internal/base.h" -#include "jemalloc/internal/pages.h" -#include "jemalloc/internal/large.h" + +#include "jemalloc/internal/util_inlines.h" +#include "jemalloc/internal/atomic_inlines.h" +#include "jemalloc/internal/spin_inlines.h" +#include "jemalloc/internal/prng_inlines.h" +#include "jemalloc/internal/ticker_inlines.h" +#include "jemalloc/internal/tsd_inlines.h" +#include "jemalloc/internal/witness_inlines.h" +#include "jemalloc/internal/mutex_inlines.h" +#include "jemalloc/internal/rtree_inlines.h" +#include "jemalloc/internal/extent_inlines.h" +#include "jemalloc/internal/base_inlines.h" #ifndef JEMALLOC_ENABLE_INLINE pszind_t psz2ind(size_t psz); @@ -925,14 +918,12 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) } #endif -#include "jemalloc/internal/bitmap.h" +#include "jemalloc/internal/bitmap_inlines.h" /* - * Include portions of arena.h interleaved with tcache.h in order to resolve - * circular dependencies. + * Include portions of arena code interleaved with tcache code in order to + * resolve circular dependencies. */ -#define JEMALLOC_ARENA_INLINE_A -#include "jemalloc/internal/arena.h" -#undef JEMALLOC_ARENA_INLINE_A +#include "jemalloc/internal/arena_inlines_a.h" #ifndef JEMALLOC_ENABLE_INLINE extent_t *iealloc(tsdn_t *tsdn, const void *ptr); @@ -947,11 +938,9 @@ iealloc(tsdn_t *tsdn, const void *ptr) } #endif -#include "jemalloc/internal/tcache.h" -#define JEMALLOC_ARENA_INLINE_B -#include "jemalloc/internal/arena.h" -#undef JEMALLOC_ARENA_INLINE_B -#include "jemalloc/internal/hash.h" +#include "jemalloc/internal/tcache_inlines.h" +#include "jemalloc/internal/arena_inlines_b.h" +#include "jemalloc/internal/hash_inlines.h" #ifndef JEMALLOC_ENABLE_INLINE arena_t *iaalloc(tsdn_t *tsdn, const void *ptr); @@ -1211,10 +1200,8 @@ ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, } #endif -#include "jemalloc/internal/prof.h" +#include "jemalloc/internal/prof_inlines.h" -#undef JEMALLOC_H_INLINES -/******************************************************************************/ #ifdef __cplusplus } diff --git a/include/jemalloc/internal/jemalloc_internal_macros.h b/include/jemalloc/internal/jemalloc_internal_macros.h index 57492049..80820f87 100644 --- a/include/jemalloc/internal/jemalloc_internal_macros.h +++ b/include/jemalloc/internal/jemalloc_internal_macros.h @@ -1,3 +1,6 @@ +#ifndef JEMALLOC_INTERNAL_MACROS_H +#define JEMALLOC_INTERNAL_MACROS_H + /* * JEMALLOC_ALWAYS_INLINE and JEMALLOC_INLINE are used within header files for * functions that are static inline functions if inlining is enabled, and @@ -55,3 +58,5 @@ #if !defined(JEMALLOC_HAS_RESTRICT) || defined(__cplusplus) # define restrict #endif + +#endif /* JEMALLOC_INTERNAL_MACROS_H */ diff --git a/include/jemalloc/internal/large.h b/include/jemalloc/internal/large_externs.h similarity index 64% rename from include/jemalloc/internal/large.h rename to include/jemalloc/internal/large_externs.h index f3d382b5..f0a03399 100644 --- a/include/jemalloc/internal/large.h +++ b/include/jemalloc/internal/large_externs.h @@ -1,13 +1,5 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS +#ifndef JEMALLOC_INTERNAL_LARGE_EXTERNS_H +#define JEMALLOC_INTERNAL_LARGE_EXTERNS_H void *large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero); void *large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, @@ -32,9 +24,4 @@ prof_tctx_t *large_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent); void large_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx); void large_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent); -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ +#endif /* JEMALLOC_INTERNAL_LARGE_EXTERNS_H */ diff --git a/include/jemalloc/internal/mutex.h b/include/jemalloc/internal/mutex.h deleted file mode 100644 index d5b3693c..00000000 --- a/include/jemalloc/internal/mutex.h +++ /dev/null @@ -1,150 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -typedef struct malloc_mutex_s malloc_mutex_t; - -#ifdef _WIN32 -# define MALLOC_MUTEX_INITIALIZER -#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) -# define MALLOC_MUTEX_INITIALIZER \ - {OS_UNFAIR_LOCK_INIT, WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} -#elif (defined(JEMALLOC_OSSPIN)) -# define MALLOC_MUTEX_INITIALIZER \ - {0, WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} -#elif (defined(JEMALLOC_MUTEX_INIT_CB)) -# define MALLOC_MUTEX_INITIALIZER \ - {PTHREAD_MUTEX_INITIALIZER, NULL, \ - WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} -#else -# if (defined(JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP) && \ - defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP)) -# define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_ADAPTIVE_NP -# define MALLOC_MUTEX_INITIALIZER \ - {PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP, \ - WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} -# else -# define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT -# define MALLOC_MUTEX_INITIALIZER \ - {PTHREAD_MUTEX_INITIALIZER, \ - WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} -# endif -#endif - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -struct malloc_mutex_s { -#ifdef _WIN32 -# if _WIN32_WINNT >= 0x0600 - SRWLOCK lock; -# else - CRITICAL_SECTION lock; -# endif -#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) - os_unfair_lock lock; -#elif (defined(JEMALLOC_OSSPIN)) - OSSpinLock lock; -#elif (defined(JEMALLOC_MUTEX_INIT_CB)) - pthread_mutex_t lock; - malloc_mutex_t *postponed_next; -#else - pthread_mutex_t lock; -#endif - witness_t witness; -}; - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -#ifdef JEMALLOC_LAZY_LOCK -extern bool isthreaded; -#else -# undef isthreaded /* Undo private_namespace.h definition. */ -# define isthreaded true -#endif - -bool malloc_mutex_init(malloc_mutex_t *mutex, const char *name, - witness_rank_t rank); -void malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex); -void malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex); -void malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex); -bool malloc_mutex_boot(void); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#ifndef JEMALLOC_ENABLE_INLINE -void malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex); -void malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex); -void malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); -void malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) -JEMALLOC_INLINE void -malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) -{ - - if (isthreaded) { - witness_assert_not_owner(tsdn, &mutex->witness); -#ifdef _WIN32 -# if _WIN32_WINNT >= 0x0600 - AcquireSRWLockExclusive(&mutex->lock); -# else - EnterCriticalSection(&mutex->lock); -# endif -#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) - os_unfair_lock_lock(&mutex->lock); -#elif (defined(JEMALLOC_OSSPIN)) - OSSpinLockLock(&mutex->lock); -#else - pthread_mutex_lock(&mutex->lock); -#endif - witness_lock(tsdn, &mutex->witness); - } -} - -JEMALLOC_INLINE void -malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) -{ - - if (isthreaded) { - witness_unlock(tsdn, &mutex->witness); -#ifdef _WIN32 -# if _WIN32_WINNT >= 0x0600 - ReleaseSRWLockExclusive(&mutex->lock); -# else - LeaveCriticalSection(&mutex->lock); -# endif -#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) - os_unfair_lock_unlock(&mutex->lock); -#elif (defined(JEMALLOC_OSSPIN)) - OSSpinLockUnlock(&mutex->lock); -#else - pthread_mutex_unlock(&mutex->lock); -#endif - } -} - -JEMALLOC_INLINE void -malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) -{ - - if (isthreaded) - witness_assert_owner(tsdn, &mutex->witness); -} - -JEMALLOC_INLINE void -malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) -{ - - if (isthreaded) - witness_assert_not_owner(tsdn, &mutex->witness); -} -#endif - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ diff --git a/include/jemalloc/internal/mutex_externs.h b/include/jemalloc/internal/mutex_externs.h new file mode 100644 index 00000000..ba6418ef --- /dev/null +++ b/include/jemalloc/internal/mutex_externs.h @@ -0,0 +1,18 @@ +#ifndef JEMALLOC_INTERNAL_MUTEX_EXTERNS_H +#define JEMALLOC_INTERNAL_MUTEX_EXTERNS_H + +#ifdef JEMALLOC_LAZY_LOCK +extern bool isthreaded; +#else +# undef isthreaded /* Undo private_namespace.h definition. */ +# define isthreaded true +#endif + +bool malloc_mutex_init(malloc_mutex_t *mutex, const char *name, + witness_rank_t rank); +void malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex); +void malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex); +void malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex); +bool malloc_mutex_boot(void); + +#endif /* JEMALLOC_INTERNAL_MUTEX_EXTERNS_H */ diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h new file mode 100644 index 00000000..b769f0ca --- /dev/null +++ b/include/jemalloc/internal/mutex_inlines.h @@ -0,0 +1,74 @@ +#ifndef JEMALLOC_INTERNAL_MUTEX_INLINES_H +#define JEMALLOC_INTERNAL_MUTEX_INLINES_H + +#ifndef JEMALLOC_ENABLE_INLINE +void malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex); +void malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex); +void malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); +void malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) +JEMALLOC_INLINE void +malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) +{ + + if (isthreaded) { + witness_assert_not_owner(tsdn, &mutex->witness); +#ifdef _WIN32 +# if _WIN32_WINNT >= 0x0600 + AcquireSRWLockExclusive(&mutex->lock); +# else + EnterCriticalSection(&mutex->lock); +# endif +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) + os_unfair_lock_lock(&mutex->lock); +#elif (defined(JEMALLOC_OSSPIN)) + OSSpinLockLock(&mutex->lock); +#else + pthread_mutex_lock(&mutex->lock); +#endif + witness_lock(tsdn, &mutex->witness); + } +} + +JEMALLOC_INLINE void +malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) +{ + + if (isthreaded) { + witness_unlock(tsdn, &mutex->witness); +#ifdef _WIN32 +# if _WIN32_WINNT >= 0x0600 + ReleaseSRWLockExclusive(&mutex->lock); +# else + LeaveCriticalSection(&mutex->lock); +# endif +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) + os_unfair_lock_unlock(&mutex->lock); +#elif (defined(JEMALLOC_OSSPIN)) + OSSpinLockUnlock(&mutex->lock); +#else + pthread_mutex_unlock(&mutex->lock); +#endif + } +} + +JEMALLOC_INLINE void +malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) +{ + + if (isthreaded) + witness_assert_owner(tsdn, &mutex->witness); +} + +JEMALLOC_INLINE void +malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) +{ + + if (isthreaded) + witness_assert_not_owner(tsdn, &mutex->witness); +} +#endif + +#endif /* JEMALLOC_INTERNAL_MUTEX_INLINES_H */ diff --git a/include/jemalloc/internal/mutex_structs.h b/include/jemalloc/internal/mutex_structs.h new file mode 100644 index 00000000..4a18a075 --- /dev/null +++ b/include/jemalloc/internal/mutex_structs.h @@ -0,0 +1,24 @@ +#ifndef JEMALLOC_INTERNAL_MUTEX_STRUCTS_H +#define JEMALLOC_INTERNAL_MUTEX_STRUCTS_H + +struct malloc_mutex_s { +#ifdef _WIN32 +# if _WIN32_WINNT >= 0x0600 + SRWLOCK lock; +# else + CRITICAL_SECTION lock; +# endif +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) + os_unfair_lock lock; +#elif (defined(JEMALLOC_OSSPIN)) + OSSpinLock lock; +#elif (defined(JEMALLOC_MUTEX_INIT_CB)) + pthread_mutex_t lock; + malloc_mutex_t *postponed_next; +#else + pthread_mutex_t lock; +#endif + witness_t witness; +}; + +#endif /* JEMALLOC_INTERNAL_MUTEX_STRUCTS_H */ diff --git a/include/jemalloc/internal/mutex_types.h b/include/jemalloc/internal/mutex_types.h new file mode 100644 index 00000000..8c9f249d --- /dev/null +++ b/include/jemalloc/internal/mutex_types.h @@ -0,0 +1,33 @@ +#ifndef JEMALLOC_INTERNAL_MUTEX_TYPES_H +#define JEMALLOC_INTERNAL_MUTEX_TYPES_H + +typedef struct malloc_mutex_s malloc_mutex_t; + +#ifdef _WIN32 +# define MALLOC_MUTEX_INITIALIZER +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) +# define MALLOC_MUTEX_INITIALIZER \ + {OS_UNFAIR_LOCK_INIT, WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} +#elif (defined(JEMALLOC_OSSPIN)) +# define MALLOC_MUTEX_INITIALIZER \ + {0, WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} +#elif (defined(JEMALLOC_MUTEX_INIT_CB)) +# define MALLOC_MUTEX_INITIALIZER \ + {PTHREAD_MUTEX_INITIALIZER, NULL, \ + WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} +#else +# if (defined(JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP) && \ + defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP)) +# define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_ADAPTIVE_NP +# define MALLOC_MUTEX_INITIALIZER \ + {PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP, \ + WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} +# else +# define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT +# define MALLOC_MUTEX_INITIALIZER \ + {PTHREAD_MUTEX_INITIALIZER, \ + WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} +# endif +#endif + +#endif /* JEMALLOC_INTERNAL_MUTEX_TYPES_H */ diff --git a/include/jemalloc/internal/nstime.h b/include/jemalloc/internal/nstime_externs.h similarity index 53% rename from include/jemalloc/internal/nstime.h rename to include/jemalloc/internal/nstime_externs.h index 93b27dc8..cf14ae0c 100644 --- a/include/jemalloc/internal/nstime.h +++ b/include/jemalloc/internal/nstime_externs.h @@ -1,22 +1,5 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -typedef struct nstime_s nstime_t; - -/* Maximum supported number of seconds (~584 years). */ -#define NSTIME_SEC_MAX KQU(18446744072) - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -struct nstime_s { - uint64_t ns; -}; - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS +#ifndef JEMALLOC_INTERNAL_NSTIME_EXTERNS_H +#define JEMALLOC_INTERNAL_NSTIME_EXTERNS_H void nstime_init(nstime_t *time, uint64_t ns); void nstime_init2(nstime_t *time, uint64_t sec, uint64_t nsec); @@ -40,9 +23,4 @@ bool nstime_monotonic(void); bool nstime_update(nstime_t *time); #endif -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ +#endif /* JEMALLOC_INTERNAL_NSTIME_EXTERNS_H */ diff --git a/include/jemalloc/internal/nstime_structs.h b/include/jemalloc/internal/nstime_structs.h new file mode 100644 index 00000000..a637f616 --- /dev/null +++ b/include/jemalloc/internal/nstime_structs.h @@ -0,0 +1,8 @@ +#ifndef JEMALLOC_INTERNAL_NSTIME_STRUCTS_H +#define JEMALLOC_INTERNAL_NSTIME_STRUCTS_H + +struct nstime_s { + uint64_t ns; +}; + +#endif /* JEMALLOC_INTERNAL_NSTIME_STRUCTS_H */ diff --git a/include/jemalloc/internal/nstime_types.h b/include/jemalloc/internal/nstime_types.h new file mode 100644 index 00000000..861c5a8a --- /dev/null +++ b/include/jemalloc/internal/nstime_types.h @@ -0,0 +1,9 @@ +#ifndef JEMALLOC_INTERNAL_NSTIME_TYPES_H +#define JEMALLOC_INTERNAL_NSTIME_TYPES_H + +typedef struct nstime_s nstime_t; + +/* Maximum supported number of seconds (~584 years). */ +#define NSTIME_SEC_MAX KQU(18446744072) + +#endif /* JEMALLOC_INTERNAL_NSTIME_TYPES_H */ diff --git a/include/jemalloc/internal/pages_externs.h b/include/jemalloc/internal/pages_externs.h new file mode 100644 index 00000000..7e34efb3 --- /dev/null +++ b/include/jemalloc/internal/pages_externs.h @@ -0,0 +1,31 @@ +#ifndef JEMALLOC_INTERNAL_PAGES_EXTERNS_H +#define JEMALLOC_INTERNAL_PAGES_EXTERNS_H + +static const bool pages_can_purge_lazy = +#ifdef PAGES_CAN_PURGE_LAZY + true +#else + false +#endif + ; +static const bool pages_can_purge_forced = +#ifdef PAGES_CAN_PURGE_FORCED + true +#else + false +#endif + ; + +void *pages_map(void *addr, size_t size, bool *commit); +void pages_unmap(void *addr, size_t size); +void *pages_trim(void *addr, size_t alloc_size, size_t leadsize, + size_t size, bool *commit); +bool pages_commit(void *addr, size_t size); +bool pages_decommit(void *addr, size_t size); +bool pages_purge_lazy(void *addr, size_t size); +bool pages_purge_forced(void *addr, size_t size); +bool pages_huge(void *addr, size_t size); +bool pages_nohuge(void *addr, size_t size); +void pages_boot(void); + +#endif /* JEMALLOC_INTERNAL_PAGES_EXTERNS_H */ diff --git a/include/jemalloc/internal/pages.h b/include/jemalloc/internal/pages_types.h similarity index 54% rename from include/jemalloc/internal/pages.h rename to include/jemalloc/internal/pages_types.h index 98e4f38a..be1e245f 100644 --- a/include/jemalloc/internal/pages.h +++ b/include/jemalloc/internal/pages_types.h @@ -1,5 +1,5 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES +#ifndef JEMALLOC_INTERNAL_PAGES_TYPES_H +#define JEMALLOC_INTERNAL_PAGES_TYPES_H /* Page size. LG_PAGE is determined by the configure script. */ #ifdef PAGE_MASK @@ -41,45 +41,4 @@ # define PAGES_CAN_PURGE_FORCED #endif -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -static const bool pages_can_purge_lazy = -#ifdef PAGES_CAN_PURGE_LAZY - true -#else - false -#endif - ; -static const bool pages_can_purge_forced = -#ifdef PAGES_CAN_PURGE_FORCED - true -#else - false -#endif - ; - -void *pages_map(void *addr, size_t size, bool *commit); -void pages_unmap(void *addr, size_t size); -void *pages_trim(void *addr, size_t alloc_size, size_t leadsize, - size_t size, bool *commit); -bool pages_commit(void *addr, size_t size); -bool pages_decommit(void *addr, size_t size); -bool pages_purge_lazy(void *addr, size_t size); -bool pages_purge_forced(void *addr, size_t size); -bool pages_huge(void *addr, size_t size); -bool pages_nohuge(void *addr, size_t size); -void pages_boot(void); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ - +#endif /* JEMALLOC_INTERNAL_PAGES_TYPES_H */ diff --git a/include/jemalloc/internal/prng.h b/include/jemalloc/internal/prng_inlines.h similarity index 71% rename from include/jemalloc/internal/prng.h rename to include/jemalloc/internal/prng_inlines.h index 94fd55a7..b82a6620 100644 --- a/include/jemalloc/internal/prng.h +++ b/include/jemalloc/internal/prng_inlines.h @@ -1,42 +1,5 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -/* - * Simple linear congruential pseudo-random number generator: - * - * prng(y) = (a*x + c) % m - * - * where the following constants ensure maximal period: - * - * a == Odd number (relatively prime to 2^n), and (a-1) is a multiple of 4. - * c == Odd number (relatively prime to 2^n). - * m == 2^32 - * - * See Knuth's TAOCP 3rd Ed., Vol. 2, pg. 17 for details on these constraints. - * - * This choice of m has the disadvantage that the quality of the bits is - * proportional to bit position. For example, the lowest bit has a cycle of 2, - * the next has a cycle of 4, etc. For this reason, we prefer to use the upper - * bits. - */ - -#define PRNG_A_32 UINT32_C(1103515241) -#define PRNG_C_32 UINT32_C(12347) - -#define PRNG_A_64 UINT64_C(6364136223846793005) -#define PRNG_C_64 UINT64_C(1442695040888963407) - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES +#ifndef JEMALLOC_INTERNAL_PRNG_INLINES_H +#define JEMALLOC_INTERNAL_PRNG_INLINES_H #ifndef JEMALLOC_ENABLE_INLINE uint32_t prng_state_next_u32(uint32_t state); @@ -203,5 +166,4 @@ prng_range_zu(size_t *state, size_t range, bool atomic) } #endif -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ +#endif /* JEMALLOC_INTERNAL_PRNG_INLINES_H */ diff --git a/include/jemalloc/internal/prng_types.h b/include/jemalloc/internal/prng_types.h new file mode 100644 index 00000000..dec44c09 --- /dev/null +++ b/include/jemalloc/internal/prng_types.h @@ -0,0 +1,29 @@ +#ifndef JEMALLOC_INTERNAL_PRNG_TYPES_H +#define JEMALLOC_INTERNAL_PRNG_TYPES_H + +/* + * Simple linear congruential pseudo-random number generator: + * + * prng(y) = (a*x + c) % m + * + * where the following constants ensure maximal period: + * + * a == Odd number (relatively prime to 2^n), and (a-1) is a multiple of 4. + * c == Odd number (relatively prime to 2^n). + * m == 2^32 + * + * See Knuth's TAOCP 3rd Ed., Vol. 2, pg. 17 for details on these constraints. + * + * This choice of m has the disadvantage that the quality of the bits is + * proportional to bit position. For example, the lowest bit has a cycle of 2, + * the next has a cycle of 4, etc. For this reason, we prefer to use the upper + * bits. + */ + +#define PRNG_A_32 UINT32_C(1103515241) +#define PRNG_C_32 UINT32_C(12347) + +#define PRNG_A_64 UINT64_C(6364136223846793005) +#define PRNG_C_64 UINT64_C(1442695040888963407) + +#endif /* JEMALLOC_INTERNAL_PRNG_TYPES_H */ diff --git a/include/jemalloc/internal/prof.h b/include/jemalloc/internal/prof.h deleted file mode 100644 index 2d1791b9..00000000 --- a/include/jemalloc/internal/prof.h +++ /dev/null @@ -1,568 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -typedef struct prof_bt_s prof_bt_t; -typedef struct prof_cnt_s prof_cnt_t; -typedef struct prof_tctx_s prof_tctx_t; -typedef struct prof_gctx_s prof_gctx_t; -typedef struct prof_tdata_s prof_tdata_t; - -/* Option defaults. */ -#ifdef JEMALLOC_PROF -# define PROF_PREFIX_DEFAULT "jeprof" -#else -# define PROF_PREFIX_DEFAULT "" -#endif -#define LG_PROF_SAMPLE_DEFAULT 19 -#define LG_PROF_INTERVAL_DEFAULT -1 - -/* - * Hard limit on stack backtrace depth. The version of prof_backtrace() that - * is based on __builtin_return_address() necessarily has a hard-coded number - * of backtrace frame handlers, and should be kept in sync with this setting. - */ -#define PROF_BT_MAX 128 - -/* Initial hash table size. */ -#define PROF_CKH_MINITEMS 64 - -/* Size of memory buffer to use when writing dump files. */ -#define PROF_DUMP_BUFSIZE 65536 - -/* Size of stack-allocated buffer used by prof_printf(). */ -#define PROF_PRINTF_BUFSIZE 128 - -/* - * Number of mutexes shared among all gctx's. No space is allocated for these - * unless profiling is enabled, so it's okay to over-provision. - */ -#define PROF_NCTX_LOCKS 1024 - -/* - * Number of mutexes shared among all tdata's. No space is allocated for these - * unless profiling is enabled, so it's okay to over-provision. - */ -#define PROF_NTDATA_LOCKS 256 - -/* - * prof_tdata pointers close to NULL are used to encode state information that - * is used for cleaning up during thread shutdown. - */ -#define PROF_TDATA_STATE_REINCARNATED ((prof_tdata_t *)(uintptr_t)1) -#define PROF_TDATA_STATE_PURGATORY ((prof_tdata_t *)(uintptr_t)2) -#define PROF_TDATA_STATE_MAX PROF_TDATA_STATE_PURGATORY - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -struct prof_bt_s { - /* Backtrace, stored as len program counters. */ - void **vec; - unsigned len; -}; - -#ifdef JEMALLOC_PROF_LIBGCC -/* Data structure passed to libgcc _Unwind_Backtrace() callback functions. */ -typedef struct { - prof_bt_t *bt; - unsigned max; -} prof_unwind_data_t; -#endif - -struct prof_cnt_s { - /* Profiling counters. */ - uint64_t curobjs; - uint64_t curbytes; - uint64_t accumobjs; - uint64_t accumbytes; -}; - -typedef enum { - prof_tctx_state_initializing, - prof_tctx_state_nominal, - prof_tctx_state_dumping, - prof_tctx_state_purgatory /* Dumper must finish destroying. */ -} prof_tctx_state_t; - -struct prof_tctx_s { - /* Thread data for thread that performed the allocation. */ - prof_tdata_t *tdata; - - /* - * Copy of tdata->thr_{uid,discrim}, necessary because tdata may be - * defunct during teardown. - */ - uint64_t thr_uid; - uint64_t thr_discrim; - - /* Profiling counters, protected by tdata->lock. */ - prof_cnt_t cnts; - - /* Associated global context. */ - prof_gctx_t *gctx; - - /* - * UID that distinguishes multiple tctx's created by the same thread, - * but coexisting in gctx->tctxs. There are two ways that such - * coexistence can occur: - * - A dumper thread can cause a tctx to be retained in the purgatory - * state. - * - Although a single "producer" thread must create all tctx's which - * share the same thr_uid, multiple "consumers" can each concurrently - * execute portions of prof_tctx_destroy(). prof_tctx_destroy() only - * gets called once each time cnts.cur{objs,bytes} drop to 0, but this - * threshold can be hit again before the first consumer finishes - * executing prof_tctx_destroy(). - */ - uint64_t tctx_uid; - - /* Linkage into gctx's tctxs. */ - rb_node(prof_tctx_t) tctx_link; - - /* - * True during prof_alloc_prep()..prof_malloc_sample_object(), prevents - * sample vs destroy race. - */ - bool prepared; - - /* Current dump-related state, protected by gctx->lock. */ - prof_tctx_state_t state; - - /* - * Copy of cnts snapshotted during early dump phase, protected by - * dump_mtx. - */ - prof_cnt_t dump_cnts; -}; -typedef rb_tree(prof_tctx_t) prof_tctx_tree_t; - -struct prof_gctx_s { - /* Protects nlimbo, cnt_summed, and tctxs. */ - malloc_mutex_t *lock; - - /* - * Number of threads that currently cause this gctx to be in a state of - * limbo due to one of: - * - Initializing this gctx. - * - Initializing per thread counters associated with this gctx. - * - Preparing to destroy this gctx. - * - Dumping a heap profile that includes this gctx. - * nlimbo must be 1 (single destroyer) in order to safely destroy the - * gctx. - */ - unsigned nlimbo; - - /* - * Tree of profile counters, one for each thread that has allocated in - * this context. - */ - prof_tctx_tree_t tctxs; - - /* Linkage for tree of contexts to be dumped. */ - rb_node(prof_gctx_t) dump_link; - - /* Temporary storage for summation during dump. */ - prof_cnt_t cnt_summed; - - /* Associated backtrace. */ - prof_bt_t bt; - - /* Backtrace vector, variable size, referred to by bt. */ - void *vec[1]; -}; -typedef rb_tree(prof_gctx_t) prof_gctx_tree_t; - -struct prof_tdata_s { - malloc_mutex_t *lock; - - /* Monotonically increasing unique thread identifier. */ - uint64_t thr_uid; - - /* - * Monotonically increasing discriminator among tdata structures - * associated with the same thr_uid. - */ - uint64_t thr_discrim; - - /* Included in heap profile dumps if non-NULL. */ - char *thread_name; - - bool attached; - bool expired; - - rb_node(prof_tdata_t) tdata_link; - - /* - * Counter used to initialize prof_tctx_t's tctx_uid. No locking is - * necessary when incrementing this field, because only one thread ever - * does so. - */ - uint64_t tctx_uid_next; - - /* - * Hash of (prof_bt_t *)-->(prof_tctx_t *). Each thread tracks - * backtraces for which it has non-zero allocation/deallocation counters - * associated with thread-specific prof_tctx_t objects. Other threads - * may write to prof_tctx_t contents when freeing associated objects. - */ - ckh_t bt2tctx; - - /* Sampling state. */ - uint64_t prng_state; - uint64_t bytes_until_sample; - - /* State used to avoid dumping while operating on prof internals. */ - bool enq; - bool enq_idump; - bool enq_gdump; - - /* - * Set to true during an early dump phase for tdata's which are - * currently being dumped. New threads' tdata's have this initialized - * to false so that they aren't accidentally included in later dump - * phases. - */ - bool dumping; - - /* - * True if profiling is active for this tdata's thread - * (thread.prof.active mallctl). - */ - bool active; - - /* Temporary storage for summation during dump. */ - prof_cnt_t cnt_summed; - - /* Backtrace vector, used for calls to prof_backtrace(). */ - void *vec[PROF_BT_MAX]; -}; -typedef rb_tree(prof_tdata_t) prof_tdata_tree_t; - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -extern bool opt_prof; -extern bool opt_prof_active; -extern bool opt_prof_thread_active_init; -extern size_t opt_lg_prof_sample; /* Mean bytes between samples. */ -extern ssize_t opt_lg_prof_interval; /* lg(prof_interval). */ -extern bool opt_prof_gdump; /* High-water memory dumping. */ -extern bool opt_prof_final; /* Final profile dumping. */ -extern bool opt_prof_leak; /* Dump leak summary at exit. */ -extern bool opt_prof_accum; /* Report cumulative bytes. */ -extern char opt_prof_prefix[ - /* Minimize memory bloat for non-prof builds. */ -#ifdef JEMALLOC_PROF - PATH_MAX + -#endif - 1]; - -/* Accessed via prof_active_[gs]et{_unlocked,}(). */ -extern bool prof_active; - -/* Accessed via prof_gdump_[gs]et{_unlocked,}(). */ -extern bool prof_gdump_val; - -/* - * Profile dump interval, measured in bytes allocated. Each arena triggers a - * profile dump when it reaches this threshold. The effect is that the - * interval between profile dumps averages prof_interval, though the actual - * interval between dumps will tend to be sporadic, and the interval will be a - * maximum of approximately (prof_interval * narenas). - */ -extern uint64_t prof_interval; - -/* - * Initialized as opt_lg_prof_sample, and potentially modified during profiling - * resets. - */ -extern size_t lg_prof_sample; - -void prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated); -void prof_malloc_sample_object(tsdn_t *tsdn, extent_t *extent, - const void *ptr, size_t usize, prof_tctx_t *tctx); -void prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_tctx_t *tctx); -void bt_init(prof_bt_t *bt, void **vec); -void prof_backtrace(prof_bt_t *bt); -prof_tctx_t *prof_lookup(tsd_t *tsd, prof_bt_t *bt); -#ifdef JEMALLOC_JET -size_t prof_tdata_count(void); -size_t prof_bt_count(void); -const prof_cnt_t *prof_cnt_all(void); -typedef int (prof_dump_open_t)(bool, const char *); -extern prof_dump_open_t *prof_dump_open; -typedef bool (prof_dump_header_t)(tsdn_t *, bool, const prof_cnt_t *); -extern prof_dump_header_t *prof_dump_header; -#endif -void prof_idump(tsdn_t *tsdn); -bool prof_mdump(tsd_t *tsd, const char *filename); -void prof_gdump(tsdn_t *tsdn); -prof_tdata_t *prof_tdata_init(tsd_t *tsd); -prof_tdata_t *prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata); -void prof_reset(tsd_t *tsd, size_t lg_sample); -void prof_tdata_cleanup(tsd_t *tsd); -bool prof_active_get(tsdn_t *tsdn); -bool prof_active_set(tsdn_t *tsdn, bool active); -const char *prof_thread_name_get(tsd_t *tsd); -int prof_thread_name_set(tsd_t *tsd, const char *thread_name); -bool prof_thread_active_get(tsd_t *tsd); -bool prof_thread_active_set(tsd_t *tsd, bool active); -bool prof_thread_active_init_get(tsdn_t *tsdn); -bool prof_thread_active_init_set(tsdn_t *tsdn, bool active_init); -bool prof_gdump_get(tsdn_t *tsdn); -bool prof_gdump_set(tsdn_t *tsdn, bool active); -void prof_boot0(void); -void prof_boot1(void); -bool prof_boot2(tsd_t *tsd); -void prof_prefork0(tsdn_t *tsdn); -void prof_prefork1(tsdn_t *tsdn); -void prof_postfork_parent(tsdn_t *tsdn); -void prof_postfork_child(tsdn_t *tsdn); -void prof_sample_threshold_update(prof_tdata_t *tdata); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#ifndef JEMALLOC_ENABLE_INLINE -bool prof_active_get_unlocked(void); -bool prof_gdump_get_unlocked(void); -prof_tdata_t *prof_tdata_get(tsd_t *tsd, bool create); -prof_tctx_t *prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, - const void *ptr); -void prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize, prof_tctx_t *tctx); -void prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, - prof_tctx_t *tctx); -bool prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update, - prof_tdata_t **tdata_out); -prof_tctx_t *prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, - bool update); -void prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize, prof_tctx_t *tctx); -void prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, - size_t usize, prof_tctx_t *tctx, bool prof_active, bool updated, - extent_t *old_extent, const void *old_ptr, size_t old_usize, - prof_tctx_t *old_tctx); -void prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, - size_t usize); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PROF_C_)) -JEMALLOC_ALWAYS_INLINE bool -prof_active_get_unlocked(void) -{ - - /* - * Even if opt_prof is true, sampling can be temporarily disabled by - * setting prof_active to false. No locking is used when reading - * prof_active in the fast path, so there are no guarantees regarding - * how long it will take for all threads to notice state changes. - */ - return (prof_active); -} - -JEMALLOC_ALWAYS_INLINE bool -prof_gdump_get_unlocked(void) -{ - - /* - * No locking is used when reading prof_gdump_val in the fast path, so - * there are no guarantees regarding how long it will take for all - * threads to notice state changes. - */ - return (prof_gdump_val); -} - -JEMALLOC_ALWAYS_INLINE prof_tdata_t * -prof_tdata_get(tsd_t *tsd, bool create) -{ - prof_tdata_t *tdata; - - cassert(config_prof); - - tdata = tsd_prof_tdata_get(tsd); - if (create) { - if (unlikely(tdata == NULL)) { - if (tsd_nominal(tsd)) { - tdata = prof_tdata_init(tsd); - tsd_prof_tdata_set(tsd, tdata); - } - } else if (unlikely(tdata->expired)) { - tdata = prof_tdata_reinit(tsd, tdata); - tsd_prof_tdata_set(tsd, tdata); - } - assert(tdata == NULL || tdata->attached); - } - - return (tdata); -} - -JEMALLOC_ALWAYS_INLINE prof_tctx_t * -prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) -{ - - cassert(config_prof); - assert(ptr != NULL); - - return (arena_prof_tctx_get(tsdn, extent, ptr)); -} - -JEMALLOC_ALWAYS_INLINE void -prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, - prof_tctx_t *tctx) -{ - - cassert(config_prof); - assert(ptr != NULL); - - arena_prof_tctx_set(tsdn, extent, ptr, usize, tctx); -} - -JEMALLOC_ALWAYS_INLINE void -prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, - prof_tctx_t *tctx) -{ - - cassert(config_prof); - assert(ptr != NULL); - - arena_prof_tctx_reset(tsdn, extent, ptr, tctx); -} - -JEMALLOC_ALWAYS_INLINE bool -prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update, - prof_tdata_t **tdata_out) -{ - prof_tdata_t *tdata; - - cassert(config_prof); - - tdata = prof_tdata_get(tsd, true); - if (unlikely((uintptr_t)tdata <= (uintptr_t)PROF_TDATA_STATE_MAX)) - tdata = NULL; - - if (tdata_out != NULL) - *tdata_out = tdata; - - if (unlikely(tdata == NULL)) - return (true); - - if (likely(tdata->bytes_until_sample >= usize)) { - if (update) - tdata->bytes_until_sample -= usize; - return (true); - } else { - /* Compute new sample threshold. */ - if (update) - prof_sample_threshold_update(tdata); - return (!tdata->active); - } -} - -JEMALLOC_ALWAYS_INLINE prof_tctx_t * -prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update) -{ - prof_tctx_t *ret; - prof_tdata_t *tdata; - prof_bt_t bt; - - assert(usize == s2u(usize)); - - if (!prof_active || likely(prof_sample_accum_update(tsd, usize, update, - &tdata))) - ret = (prof_tctx_t *)(uintptr_t)1U; - else { - bt_init(&bt, tdata->vec); - prof_backtrace(&bt); - ret = prof_lookup(tsd, &bt); - } - - return (ret); -} - -JEMALLOC_ALWAYS_INLINE void -prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, - prof_tctx_t *tctx) -{ - - cassert(config_prof); - assert(ptr != NULL); - assert(usize == isalloc(tsdn, extent, ptr)); - - if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) - prof_malloc_sample_object(tsdn, extent, ptr, usize, tctx); - else { - prof_tctx_set(tsdn, extent, ptr, usize, - (prof_tctx_t *)(uintptr_t)1U); - } -} - -JEMALLOC_ALWAYS_INLINE void -prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, - prof_tctx_t *tctx, bool prof_active, bool updated, extent_t *old_extent, - const void *old_ptr, size_t old_usize, prof_tctx_t *old_tctx) -{ - bool sampled, old_sampled, moved; - - cassert(config_prof); - assert(ptr != NULL || (uintptr_t)tctx <= (uintptr_t)1U); - - if (prof_active && !updated && ptr != NULL) { - assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr)); - if (prof_sample_accum_update(tsd, usize, true, NULL)) { - /* - * Don't sample. The usize passed to prof_alloc_prep() - * was larger than what actually got allocated, so a - * backtrace was captured for this allocation, even - * though its actual usize was insufficient to cross the - * sample threshold. - */ - prof_alloc_rollback(tsd, tctx, true); - tctx = (prof_tctx_t *)(uintptr_t)1U; - } - } - - /* - * The following code must differentiate among eight possible cases, - * based on three boolean conditions. - */ - sampled = ((uintptr_t)tctx > (uintptr_t)1U); - old_sampled = ((uintptr_t)old_tctx > (uintptr_t)1U); - moved = (ptr != old_ptr); - - /* - * The following block must only execute if this is a non-moving - * reallocation, because for moving reallocation the old allocation will - * be deallocated via a separate call. - */ - if (unlikely(old_sampled) && !moved) - prof_free_sampled_object(tsd, old_usize, old_tctx); - - if (unlikely(sampled)) { - prof_malloc_sample_object(tsd_tsdn(tsd), extent, ptr, usize, - tctx); - } else if (moved) { - prof_tctx_set(tsd_tsdn(tsd), extent, ptr, usize, - (prof_tctx_t *)(uintptr_t)1U); - } else if (unlikely(old_sampled)) - prof_tctx_reset(tsd_tsdn(tsd), extent, ptr, tctx); -} - -JEMALLOC_ALWAYS_INLINE void -prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, size_t usize) -{ - prof_tctx_t *tctx = prof_tctx_get(tsd_tsdn(tsd), extent, ptr); - - cassert(config_prof); - assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr)); - - if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) - prof_free_sampled_object(tsd, usize, tctx); -} -#endif - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ diff --git a/include/jemalloc/internal/prof_externs.h b/include/jemalloc/internal/prof_externs.h new file mode 100644 index 00000000..3f857145 --- /dev/null +++ b/include/jemalloc/internal/prof_externs.h @@ -0,0 +1,83 @@ +#ifndef JEMALLOC_INTERNAL_PROF_EXTERNS_H +#define JEMALLOC_INTERNAL_PROF_EXTERNS_H + +extern bool opt_prof; +extern bool opt_prof_active; +extern bool opt_prof_thread_active_init; +extern size_t opt_lg_prof_sample; /* Mean bytes between samples. */ +extern ssize_t opt_lg_prof_interval; /* lg(prof_interval). */ +extern bool opt_prof_gdump; /* High-water memory dumping. */ +extern bool opt_prof_final; /* Final profile dumping. */ +extern bool opt_prof_leak; /* Dump leak summary at exit. */ +extern bool opt_prof_accum; /* Report cumulative bytes. */ +extern char opt_prof_prefix[ + /* Minimize memory bloat for non-prof builds. */ +#ifdef JEMALLOC_PROF + PATH_MAX + +#endif + 1]; + +/* Accessed via prof_active_[gs]et{_unlocked,}(). */ +extern bool prof_active; + +/* Accessed via prof_gdump_[gs]et{_unlocked,}(). */ +extern bool prof_gdump_val; + +/* + * Profile dump interval, measured in bytes allocated. Each arena triggers a + * profile dump when it reaches this threshold. The effect is that the + * interval between profile dumps averages prof_interval, though the actual + * interval between dumps will tend to be sporadic, and the interval will be a + * maximum of approximately (prof_interval * narenas). + */ +extern uint64_t prof_interval; + +/* + * Initialized as opt_lg_prof_sample, and potentially modified during profiling + * resets. + */ +extern size_t lg_prof_sample; + +void prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated); +void prof_malloc_sample_object(tsdn_t *tsdn, extent_t *extent, + const void *ptr, size_t usize, prof_tctx_t *tctx); +void prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_tctx_t *tctx); +void bt_init(prof_bt_t *bt, void **vec); +void prof_backtrace(prof_bt_t *bt); +prof_tctx_t *prof_lookup(tsd_t *tsd, prof_bt_t *bt); +#ifdef JEMALLOC_JET +size_t prof_tdata_count(void); +size_t prof_bt_count(void); +const prof_cnt_t *prof_cnt_all(void); +typedef int (prof_dump_open_t)(bool, const char *); +extern prof_dump_open_t *prof_dump_open; +typedef bool (prof_dump_header_t)(tsdn_t *, bool, const prof_cnt_t *); +extern prof_dump_header_t *prof_dump_header; +#endif +void prof_idump(tsdn_t *tsdn); +bool prof_mdump(tsd_t *tsd, const char *filename); +void prof_gdump(tsdn_t *tsdn); +prof_tdata_t *prof_tdata_init(tsd_t *tsd); +prof_tdata_t *prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata); +void prof_reset(tsd_t *tsd, size_t lg_sample); +void prof_tdata_cleanup(tsd_t *tsd); +bool prof_active_get(tsdn_t *tsdn); +bool prof_active_set(tsdn_t *tsdn, bool active); +const char *prof_thread_name_get(tsd_t *tsd); +int prof_thread_name_set(tsd_t *tsd, const char *thread_name); +bool prof_thread_active_get(tsd_t *tsd); +bool prof_thread_active_set(tsd_t *tsd, bool active); +bool prof_thread_active_init_get(tsdn_t *tsdn); +bool prof_thread_active_init_set(tsdn_t *tsdn, bool active_init); +bool prof_gdump_get(tsdn_t *tsdn); +bool prof_gdump_set(tsdn_t *tsdn, bool active); +void prof_boot0(void); +void prof_boot1(void); +bool prof_boot2(tsd_t *tsd); +void prof_prefork0(tsdn_t *tsdn); +void prof_prefork1(tsdn_t *tsdn); +void prof_postfork_parent(tsdn_t *tsdn); +void prof_postfork_child(tsdn_t *tsdn); +void prof_sample_threshold_update(prof_tdata_t *tdata); + +#endif /* JEMALLOC_INTERNAL_PROF_EXTERNS_H */ diff --git a/include/jemalloc/internal/prof_inlines.h b/include/jemalloc/internal/prof_inlines.h new file mode 100644 index 00000000..0b580425 --- /dev/null +++ b/include/jemalloc/internal/prof_inlines.h @@ -0,0 +1,242 @@ +#ifndef JEMALLOC_INTERNAL_PROF_INLINES_H +#define JEMALLOC_INTERNAL_PROF_INLINES_H + +#ifndef JEMALLOC_ENABLE_INLINE +bool prof_active_get_unlocked(void); +bool prof_gdump_get_unlocked(void); +prof_tdata_t *prof_tdata_get(tsd_t *tsd, bool create); +prof_tctx_t *prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, + const void *ptr); +void prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize, prof_tctx_t *tctx); +void prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, + prof_tctx_t *tctx); +bool prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update, + prof_tdata_t **tdata_out); +prof_tctx_t *prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, + bool update); +void prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, + size_t usize, prof_tctx_t *tctx); +void prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, + size_t usize, prof_tctx_t *tctx, bool prof_active, bool updated, + extent_t *old_extent, const void *old_ptr, size_t old_usize, + prof_tctx_t *old_tctx); +void prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, + size_t usize); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PROF_C_)) +JEMALLOC_ALWAYS_INLINE bool +prof_active_get_unlocked(void) +{ + + /* + * Even if opt_prof is true, sampling can be temporarily disabled by + * setting prof_active to false. No locking is used when reading + * prof_active in the fast path, so there are no guarantees regarding + * how long it will take for all threads to notice state changes. + */ + return (prof_active); +} + +JEMALLOC_ALWAYS_INLINE bool +prof_gdump_get_unlocked(void) +{ + + /* + * No locking is used when reading prof_gdump_val in the fast path, so + * there are no guarantees regarding how long it will take for all + * threads to notice state changes. + */ + return (prof_gdump_val); +} + +JEMALLOC_ALWAYS_INLINE prof_tdata_t * +prof_tdata_get(tsd_t *tsd, bool create) +{ + prof_tdata_t *tdata; + + cassert(config_prof); + + tdata = tsd_prof_tdata_get(tsd); + if (create) { + if (unlikely(tdata == NULL)) { + if (tsd_nominal(tsd)) { + tdata = prof_tdata_init(tsd); + tsd_prof_tdata_set(tsd, tdata); + } + } else if (unlikely(tdata->expired)) { + tdata = prof_tdata_reinit(tsd, tdata); + tsd_prof_tdata_set(tsd, tdata); + } + assert(tdata == NULL || tdata->attached); + } + + return (tdata); +} + +JEMALLOC_ALWAYS_INLINE prof_tctx_t * +prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) +{ + + cassert(config_prof); + assert(ptr != NULL); + + return (arena_prof_tctx_get(tsdn, extent, ptr)); +} + +JEMALLOC_ALWAYS_INLINE void +prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, + prof_tctx_t *tctx) +{ + + cassert(config_prof); + assert(ptr != NULL); + + arena_prof_tctx_set(tsdn, extent, ptr, usize, tctx); +} + +JEMALLOC_ALWAYS_INLINE void +prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, + prof_tctx_t *tctx) +{ + + cassert(config_prof); + assert(ptr != NULL); + + arena_prof_tctx_reset(tsdn, extent, ptr, tctx); +} + +JEMALLOC_ALWAYS_INLINE bool +prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update, + prof_tdata_t **tdata_out) +{ + prof_tdata_t *tdata; + + cassert(config_prof); + + tdata = prof_tdata_get(tsd, true); + if (unlikely((uintptr_t)tdata <= (uintptr_t)PROF_TDATA_STATE_MAX)) + tdata = NULL; + + if (tdata_out != NULL) + *tdata_out = tdata; + + if (unlikely(tdata == NULL)) + return (true); + + if (likely(tdata->bytes_until_sample >= usize)) { + if (update) + tdata->bytes_until_sample -= usize; + return (true); + } else { + /* Compute new sample threshold. */ + if (update) + prof_sample_threshold_update(tdata); + return (!tdata->active); + } +} + +JEMALLOC_ALWAYS_INLINE prof_tctx_t * +prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update) +{ + prof_tctx_t *ret; + prof_tdata_t *tdata; + prof_bt_t bt; + + assert(usize == s2u(usize)); + + if (!prof_active || likely(prof_sample_accum_update(tsd, usize, update, + &tdata))) + ret = (prof_tctx_t *)(uintptr_t)1U; + else { + bt_init(&bt, tdata->vec); + prof_backtrace(&bt); + ret = prof_lookup(tsd, &bt); + } + + return (ret); +} + +JEMALLOC_ALWAYS_INLINE void +prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, + prof_tctx_t *tctx) +{ + + cassert(config_prof); + assert(ptr != NULL); + assert(usize == isalloc(tsdn, extent, ptr)); + + if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) + prof_malloc_sample_object(tsdn, extent, ptr, usize, tctx); + else { + prof_tctx_set(tsdn, extent, ptr, usize, + (prof_tctx_t *)(uintptr_t)1U); + } +} + +JEMALLOC_ALWAYS_INLINE void +prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, + prof_tctx_t *tctx, bool prof_active, bool updated, extent_t *old_extent, + const void *old_ptr, size_t old_usize, prof_tctx_t *old_tctx) +{ + bool sampled, old_sampled, moved; + + cassert(config_prof); + assert(ptr != NULL || (uintptr_t)tctx <= (uintptr_t)1U); + + if (prof_active && !updated && ptr != NULL) { + assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr)); + if (prof_sample_accum_update(tsd, usize, true, NULL)) { + /* + * Don't sample. The usize passed to prof_alloc_prep() + * was larger than what actually got allocated, so a + * backtrace was captured for this allocation, even + * though its actual usize was insufficient to cross the + * sample threshold. + */ + prof_alloc_rollback(tsd, tctx, true); + tctx = (prof_tctx_t *)(uintptr_t)1U; + } + } + + /* + * The following code must differentiate among eight possible cases, + * based on three boolean conditions. + */ + sampled = ((uintptr_t)tctx > (uintptr_t)1U); + old_sampled = ((uintptr_t)old_tctx > (uintptr_t)1U); + moved = (ptr != old_ptr); + + /* + * The following block must only execute if this is a non-moving + * reallocation, because for moving reallocation the old allocation will + * be deallocated via a separate call. + */ + if (unlikely(old_sampled) && !moved) + prof_free_sampled_object(tsd, old_usize, old_tctx); + + if (unlikely(sampled)) { + prof_malloc_sample_object(tsd_tsdn(tsd), extent, ptr, usize, + tctx); + } else if (moved) { + prof_tctx_set(tsd_tsdn(tsd), extent, ptr, usize, + (prof_tctx_t *)(uintptr_t)1U); + } else if (unlikely(old_sampled)) + prof_tctx_reset(tsd_tsdn(tsd), extent, ptr, tctx); +} + +JEMALLOC_ALWAYS_INLINE void +prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, size_t usize) +{ + prof_tctx_t *tctx = prof_tctx_get(tsd_tsdn(tsd), extent, ptr); + + cassert(config_prof); + assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr)); + + if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) + prof_free_sampled_object(tsd, usize, tctx); +} +#endif + +#endif /* JEMALLOC_INTERNAL_PROF_INLINES_H */ diff --git a/include/jemalloc/internal/prof_structs.h b/include/jemalloc/internal/prof_structs.h new file mode 100644 index 00000000..caae1257 --- /dev/null +++ b/include/jemalloc/internal/prof_structs.h @@ -0,0 +1,187 @@ +#ifndef JEMALLOC_INTERNAL_PROF_STRUCTS_H +#define JEMALLOC_INTERNAL_PROF_STRUCTS_H + +struct prof_bt_s { + /* Backtrace, stored as len program counters. */ + void **vec; + unsigned len; +}; + +#ifdef JEMALLOC_PROF_LIBGCC +/* Data structure passed to libgcc _Unwind_Backtrace() callback functions. */ +typedef struct { + prof_bt_t *bt; + unsigned max; +} prof_unwind_data_t; +#endif + +struct prof_cnt_s { + /* Profiling counters. */ + uint64_t curobjs; + uint64_t curbytes; + uint64_t accumobjs; + uint64_t accumbytes; +}; + +typedef enum { + prof_tctx_state_initializing, + prof_tctx_state_nominal, + prof_tctx_state_dumping, + prof_tctx_state_purgatory /* Dumper must finish destroying. */ +} prof_tctx_state_t; + +struct prof_tctx_s { + /* Thread data for thread that performed the allocation. */ + prof_tdata_t *tdata; + + /* + * Copy of tdata->thr_{uid,discrim}, necessary because tdata may be + * defunct during teardown. + */ + uint64_t thr_uid; + uint64_t thr_discrim; + + /* Profiling counters, protected by tdata->lock. */ + prof_cnt_t cnts; + + /* Associated global context. */ + prof_gctx_t *gctx; + + /* + * UID that distinguishes multiple tctx's created by the same thread, + * but coexisting in gctx->tctxs. There are two ways that such + * coexistence can occur: + * - A dumper thread can cause a tctx to be retained in the purgatory + * state. + * - Although a single "producer" thread must create all tctx's which + * share the same thr_uid, multiple "consumers" can each concurrently + * execute portions of prof_tctx_destroy(). prof_tctx_destroy() only + * gets called once each time cnts.cur{objs,bytes} drop to 0, but this + * threshold can be hit again before the first consumer finishes + * executing prof_tctx_destroy(). + */ + uint64_t tctx_uid; + + /* Linkage into gctx's tctxs. */ + rb_node(prof_tctx_t) tctx_link; + + /* + * True during prof_alloc_prep()..prof_malloc_sample_object(), prevents + * sample vs destroy race. + */ + bool prepared; + + /* Current dump-related state, protected by gctx->lock. */ + prof_tctx_state_t state; + + /* + * Copy of cnts snapshotted during early dump phase, protected by + * dump_mtx. + */ + prof_cnt_t dump_cnts; +}; +typedef rb_tree(prof_tctx_t) prof_tctx_tree_t; + +struct prof_gctx_s { + /* Protects nlimbo, cnt_summed, and tctxs. */ + malloc_mutex_t *lock; + + /* + * Number of threads that currently cause this gctx to be in a state of + * limbo due to one of: + * - Initializing this gctx. + * - Initializing per thread counters associated with this gctx. + * - Preparing to destroy this gctx. + * - Dumping a heap profile that includes this gctx. + * nlimbo must be 1 (single destroyer) in order to safely destroy the + * gctx. + */ + unsigned nlimbo; + + /* + * Tree of profile counters, one for each thread that has allocated in + * this context. + */ + prof_tctx_tree_t tctxs; + + /* Linkage for tree of contexts to be dumped. */ + rb_node(prof_gctx_t) dump_link; + + /* Temporary storage for summation during dump. */ + prof_cnt_t cnt_summed; + + /* Associated backtrace. */ + prof_bt_t bt; + + /* Backtrace vector, variable size, referred to by bt. */ + void *vec[1]; +}; +typedef rb_tree(prof_gctx_t) prof_gctx_tree_t; + +struct prof_tdata_s { + malloc_mutex_t *lock; + + /* Monotonically increasing unique thread identifier. */ + uint64_t thr_uid; + + /* + * Monotonically increasing discriminator among tdata structures + * associated with the same thr_uid. + */ + uint64_t thr_discrim; + + /* Included in heap profile dumps if non-NULL. */ + char *thread_name; + + bool attached; + bool expired; + + rb_node(prof_tdata_t) tdata_link; + + /* + * Counter used to initialize prof_tctx_t's tctx_uid. No locking is + * necessary when incrementing this field, because only one thread ever + * does so. + */ + uint64_t tctx_uid_next; + + /* + * Hash of (prof_bt_t *)-->(prof_tctx_t *). Each thread tracks + * backtraces for which it has non-zero allocation/deallocation counters + * associated with thread-specific prof_tctx_t objects. Other threads + * may write to prof_tctx_t contents when freeing associated objects. + */ + ckh_t bt2tctx; + + /* Sampling state. */ + uint64_t prng_state; + uint64_t bytes_until_sample; + + /* State used to avoid dumping while operating on prof internals. */ + bool enq; + bool enq_idump; + bool enq_gdump; + + /* + * Set to true during an early dump phase for tdata's which are + * currently being dumped. New threads' tdata's have this initialized + * to false so that they aren't accidentally included in later dump + * phases. + */ + bool dumping; + + /* + * True if profiling is active for this tdata's thread + * (thread.prof.active mallctl). + */ + bool active; + + /* Temporary storage for summation during dump. */ + prof_cnt_t cnt_summed; + + /* Backtrace vector, used for calls to prof_backtrace(). */ + void *vec[PROF_BT_MAX]; +}; +typedef rb_tree(prof_tdata_t) prof_tdata_tree_t; + +#endif /* JEMALLOC_INTERNAL_PROF_STRUCTS_H */ diff --git a/include/jemalloc/internal/prof_types.h b/include/jemalloc/internal/prof_types.h new file mode 100644 index 00000000..e1eb7fb1 --- /dev/null +++ b/include/jemalloc/internal/prof_types.h @@ -0,0 +1,55 @@ +#ifndef JEMALLOC_INTERNAL_PROF_TYPES_H +#define JEMALLOC_INTERNAL_PROF_TYPES_H + +typedef struct prof_bt_s prof_bt_t; +typedef struct prof_cnt_s prof_cnt_t; +typedef struct prof_tctx_s prof_tctx_t; +typedef struct prof_gctx_s prof_gctx_t; +typedef struct prof_tdata_s prof_tdata_t; + +/* Option defaults. */ +#ifdef JEMALLOC_PROF +# define PROF_PREFIX_DEFAULT "jeprof" +#else +# define PROF_PREFIX_DEFAULT "" +#endif +#define LG_PROF_SAMPLE_DEFAULT 19 +#define LG_PROF_INTERVAL_DEFAULT -1 + +/* + * Hard limit on stack backtrace depth. The version of prof_backtrace() that + * is based on __builtin_return_address() necessarily has a hard-coded number + * of backtrace frame handlers, and should be kept in sync with this setting. + */ +#define PROF_BT_MAX 128 + +/* Initial hash table size. */ +#define PROF_CKH_MINITEMS 64 + +/* Size of memory buffer to use when writing dump files. */ +#define PROF_DUMP_BUFSIZE 65536 + +/* Size of stack-allocated buffer used by prof_printf(). */ +#define PROF_PRINTF_BUFSIZE 128 + +/* + * Number of mutexes shared among all gctx's. No space is allocated for these + * unless profiling is enabled, so it's okay to over-provision. + */ +#define PROF_NCTX_LOCKS 1024 + +/* + * Number of mutexes shared among all tdata's. No space is allocated for these + * unless profiling is enabled, so it's okay to over-provision. + */ +#define PROF_NTDATA_LOCKS 256 + +/* + * prof_tdata pointers close to NULL are used to encode state information that + * is used for cleaning up during thread shutdown. + */ +#define PROF_TDATA_STATE_REINCARNATED ((prof_tdata_t *)(uintptr_t)1) +#define PROF_TDATA_STATE_PURGATORY ((prof_tdata_t *)(uintptr_t)2) +#define PROF_TDATA_STATE_MAX PROF_TDATA_STATE_PURGATORY + +#endif /* JEMALLOC_INTERNAL_PROF_TYPES_H */ diff --git a/include/jemalloc/internal/ql.h b/include/jemalloc/internal/ql.h index 1834bb85..424485c4 100644 --- a/include/jemalloc/internal/ql.h +++ b/include/jemalloc/internal/ql.h @@ -1,3 +1,6 @@ +#ifndef JEMALLOC_INTERNAL_QL_H +#define JEMALLOC_INTERNAL_QL_H + /* List definitions. */ #define ql_head(a_type) \ struct { \ @@ -79,3 +82,5 @@ struct { \ #define ql_reverse_foreach(a_var, a_head, a_field) \ qr_reverse_foreach((a_var), ql_first(a_head), a_field) + +#endif /* JEMALLOC_INTERNAL_QL_H */ diff --git a/include/jemalloc/internal/qr.h b/include/jemalloc/internal/qr.h index 3b5d0276..06dfdafd 100644 --- a/include/jemalloc/internal/qr.h +++ b/include/jemalloc/internal/qr.h @@ -1,3 +1,6 @@ +#ifndef JEMALLOC_INTERNAL_QR_H +#define JEMALLOC_INTERNAL_QR_H + /* Ring definitions. */ #define qr(a_type) \ struct { \ @@ -67,3 +70,5 @@ struct { \ (var) != NULL; \ (var) = (((var) != (a_qr)) \ ? (var)->a_field.qre_prev : NULL)) + +#endif /* JEMALLOC_INTERNAL_QR_H */ diff --git a/include/jemalloc/internal/rtree_externs.h b/include/jemalloc/internal/rtree_externs.h new file mode 100644 index 00000000..db8e8b12 --- /dev/null +++ b/include/jemalloc/internal/rtree_externs.h @@ -0,0 +1,23 @@ +#ifndef JEMALLOC_INTERNAL_RTREE_EXTERNS_H +#define JEMALLOC_INTERNAL_RTREE_EXTERNS_H + +bool rtree_new(rtree_t *rtree, unsigned bits); +#ifdef JEMALLOC_JET +typedef rtree_elm_t *(rtree_node_alloc_t)(tsdn_t *, rtree_t *, size_t); +extern rtree_node_alloc_t *rtree_node_alloc; +typedef void (rtree_node_dalloc_t)(tsdn_t *, rtree_t *, rtree_elm_t *); +extern rtree_node_dalloc_t *rtree_node_dalloc; +void rtree_delete(tsdn_t *tsdn, rtree_t *rtree); +#endif +rtree_elm_t *rtree_subtree_read_hard(tsdn_t *tsdn, rtree_t *rtree, + unsigned level); +rtree_elm_t *rtree_child_read_hard(tsdn_t *tsdn, rtree_t *rtree, + rtree_elm_t *elm, unsigned level); +void rtree_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, + uintptr_t key, const rtree_elm_t *elm); +void rtree_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, + const rtree_elm_t *elm); +void rtree_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, + const rtree_elm_t *elm); + +#endif /* JEMALLOC_INTERNAL_RTREE_EXTERNS_H */ diff --git a/include/jemalloc/internal/rtree.h b/include/jemalloc/internal/rtree_inlines.h similarity index 68% rename from include/jemalloc/internal/rtree.h rename to include/jemalloc/internal/rtree_inlines.h index b2a2800e..7efba54d 100644 --- a/include/jemalloc/internal/rtree.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -1,170 +1,5 @@ -/* - * This radix tree implementation is tailored to the singular purpose of - * associating metadata with extents that are currently owned by jemalloc. - * - ******************************************************************************* - */ -#ifdef JEMALLOC_H_TYPES - -typedef struct rtree_elm_s rtree_elm_t; -typedef struct rtree_elm_witness_s rtree_elm_witness_t; -typedef struct rtree_elm_witness_tsd_s rtree_elm_witness_tsd_t; -typedef struct rtree_level_s rtree_level_t; -typedef struct rtree_ctx_s rtree_ctx_t; -typedef struct rtree_s rtree_t; - -/* - * RTREE_BITS_PER_LEVEL must be a power of two that is no larger than the - * machine address width. - */ -#define LG_RTREE_BITS_PER_LEVEL 4 -#define RTREE_BITS_PER_LEVEL (1U << LG_RTREE_BITS_PER_LEVEL) -/* Maximum rtree height. */ -#define RTREE_HEIGHT_MAX \ - ((1U << (LG_SIZEOF_PTR+3)) / RTREE_BITS_PER_LEVEL) - -#define RTREE_CTX_INITIALIZER { \ - false, \ - 0, \ - 0, \ - {NULL /* C initializes all trailing elements to NULL. */} \ -} - -/* - * Maximum number of concurrently acquired elements per thread. This controls - * how many witness_t structures are embedded in tsd. Ideally rtree_elm_t would - * have a witness_t directly embedded, but that would dramatically bloat the - * tree. This must contain enough entries to e.g. coalesce two extents. - */ -#define RTREE_ELM_ACQUIRE_MAX 4 - -/* Initializers for rtree_elm_witness_tsd_t. */ -#define RTREE_ELM_WITNESS_INITIALIZER { \ - NULL, \ - WITNESS_INITIALIZER("rtree_elm", WITNESS_RANK_RTREE_ELM) \ -} - -#define RTREE_ELM_WITNESS_TSD_INITIALIZER { \ - { \ - RTREE_ELM_WITNESS_INITIALIZER, \ - RTREE_ELM_WITNESS_INITIALIZER, \ - RTREE_ELM_WITNESS_INITIALIZER, \ - RTREE_ELM_WITNESS_INITIALIZER \ - } \ -} - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -struct rtree_elm_s { - union { - void *pun; - rtree_elm_t *child; - extent_t *extent; - }; -}; - -struct rtree_elm_witness_s { - const rtree_elm_t *elm; - witness_t witness; -}; - -struct rtree_elm_witness_tsd_s { - rtree_elm_witness_t witnesses[RTREE_ELM_ACQUIRE_MAX]; -}; - -struct rtree_level_s { - /* - * A non-NULL subtree points to a subtree rooted along the hypothetical - * path to the leaf node corresponding to key 0. Depending on what keys - * have been used to store to the tree, an arbitrary combination of - * subtree pointers may remain NULL. - * - * Suppose keys comprise 48 bits, and LG_RTREE_BITS_PER_LEVEL is 4. - * This results in a 3-level tree, and the leftmost leaf can be directly - * accessed via levels[2], the subtree prefixed by 0x0000 (excluding - * 0x00000000) can be accessed via levels[1], and the remainder of the - * tree can be accessed via levels[0]. - * - * levels[0] : [ | 0x0001******** | 0x0002******** | ...] - * - * levels[1] : [ | 0x00000001**** | 0x00000002**** | ... ] - * - * levels[2] : [extent(0x000000000000) | extent(0x000000000001) | ...] - * - * This has practical implications on x64, which currently uses only the - * lower 47 bits of virtual address space in userland, thus leaving - * levels[0] unused and avoiding a level of tree traversal. - */ - union { - void *subtree_pun; - rtree_elm_t *subtree; - }; - /* Number of key bits distinguished by this level. */ - unsigned bits; - /* - * Cumulative number of key bits distinguished by traversing to - * corresponding tree level. - */ - unsigned cumbits; -}; - -struct rtree_ctx_s { - /* If false, key/elms have not yet been initialized by a lookup. */ - bool valid; - /* Key that corresponds to the tree path recorded in elms. */ - uintptr_t key; - /* Memoized rtree_start_level(key). */ - unsigned start_level; - /* - * A path through rtree, driven by key. Only elements that could - * actually be used for subsequent lookups are initialized, i.e. if - * start_level = rtree_start_level(key) is non-zero, the first - * start_level elements are uninitialized. The last element contains a - * pointer to the leaf node element that corresponds to key, so that - * exact matches require no tree node offset computation. - */ - rtree_elm_t *elms[RTREE_HEIGHT_MAX + 1]; -}; - -struct rtree_s { - unsigned height; - /* - * Precomputed table used to convert from the number of leading 0 key - * bits to which subtree level to start at. - */ - unsigned start_level[RTREE_HEIGHT_MAX + 1]; - rtree_level_t levels[RTREE_HEIGHT_MAX]; - malloc_mutex_t init_lock; -}; - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -bool rtree_new(rtree_t *rtree, unsigned bits); -#ifdef JEMALLOC_JET -typedef rtree_elm_t *(rtree_node_alloc_t)(tsdn_t *, rtree_t *, size_t); -extern rtree_node_alloc_t *rtree_node_alloc; -typedef void (rtree_node_dalloc_t)(tsdn_t *, rtree_t *, rtree_elm_t *); -extern rtree_node_dalloc_t *rtree_node_dalloc; -void rtree_delete(tsdn_t *tsdn, rtree_t *rtree); -#endif -rtree_elm_t *rtree_subtree_read_hard(tsdn_t *tsdn, rtree_t *rtree, - unsigned level); -rtree_elm_t *rtree_child_read_hard(tsdn_t *tsdn, rtree_t *rtree, - rtree_elm_t *elm, unsigned level); -void rtree_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, - uintptr_t key, const rtree_elm_t *elm); -void rtree_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, - const rtree_elm_t *elm); -void rtree_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, - const rtree_elm_t *elm); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES +#ifndef JEMALLOC_INTERNAL_RTREE_INLINES_H +#define JEMALLOC_INTERNAL_RTREE_INLINES_H #ifndef JEMALLOC_ENABLE_INLINE unsigned rtree_start_level(const rtree_t *rtree, uintptr_t key); @@ -604,5 +439,4 @@ rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key) } #endif -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ +#endif /* JEMALLOC_INTERNAL_RTREE_INLINES_H */ diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h new file mode 100644 index 00000000..5a7a23c7 --- /dev/null +++ b/include/jemalloc/internal/rtree_structs.h @@ -0,0 +1,86 @@ +#ifndef JEMALLOC_INTERNAL_RTREE_STRUCTS_H +#define JEMALLOC_INTERNAL_RTREE_STRUCTS_H + +struct rtree_elm_s { + union { + void *pun; + rtree_elm_t *child; + extent_t *extent; + }; +}; + +struct rtree_elm_witness_s { + const rtree_elm_t *elm; + witness_t witness; +}; + +struct rtree_elm_witness_tsd_s { + rtree_elm_witness_t witnesses[RTREE_ELM_ACQUIRE_MAX]; +}; + +struct rtree_level_s { + /* + * A non-NULL subtree points to a subtree rooted along the hypothetical + * path to the leaf node corresponding to key 0. Depending on what keys + * have been used to store to the tree, an arbitrary combination of + * subtree pointers may remain NULL. + * + * Suppose keys comprise 48 bits, and LG_RTREE_BITS_PER_LEVEL is 4. + * This results in a 3-level tree, and the leftmost leaf can be directly + * accessed via levels[2], the subtree prefixed by 0x0000 (excluding + * 0x00000000) can be accessed via levels[1], and the remainder of the + * tree can be accessed via levels[0]. + * + * levels[0] : [ | 0x0001******** | 0x0002******** | ...] + * + * levels[1] : [ | 0x00000001**** | 0x00000002**** | ... ] + * + * levels[2] : [extent(0x000000000000) | extent(0x000000000001) | ...] + * + * This has practical implications on x64, which currently uses only the + * lower 47 bits of virtual address space in userland, thus leaving + * levels[0] unused and avoiding a level of tree traversal. + */ + union { + void *subtree_pun; + rtree_elm_t *subtree; + }; + /* Number of key bits distinguished by this level. */ + unsigned bits; + /* + * Cumulative number of key bits distinguished by traversing to + * corresponding tree level. + */ + unsigned cumbits; +}; + +struct rtree_ctx_s { + /* If false, key/elms have not yet been initialized by a lookup. */ + bool valid; + /* Key that corresponds to the tree path recorded in elms. */ + uintptr_t key; + /* Memoized rtree_start_level(key). */ + unsigned start_level; + /* + * A path through rtree, driven by key. Only elements that could + * actually be used for subsequent lookups are initialized, i.e. if + * start_level = rtree_start_level(key) is non-zero, the first + * start_level elements are uninitialized. The last element contains a + * pointer to the leaf node element that corresponds to key, so that + * exact matches require no tree node offset computation. + */ + rtree_elm_t *elms[RTREE_HEIGHT_MAX + 1]; +}; + +struct rtree_s { + unsigned height; + /* + * Precomputed table used to convert from the number of leading 0 key + * bits to which subtree level to start at. + */ + unsigned start_level[RTREE_HEIGHT_MAX + 1]; + rtree_level_t levels[RTREE_HEIGHT_MAX]; + malloc_mutex_t init_lock; +}; + +#endif /* JEMALLOC_INTERNAL_RTREE_STRUCTS_H */ diff --git a/include/jemalloc/internal/rtree_types.h b/include/jemalloc/internal/rtree_types.h new file mode 100644 index 00000000..c02ab7a1 --- /dev/null +++ b/include/jemalloc/internal/rtree_types.h @@ -0,0 +1,58 @@ +#ifndef JEMALLOC_INTERNAL_RTREE_TYPES_H +#define JEMALLOC_INTERNAL_RTREE_TYPES_H + +/* + * This radix tree implementation is tailored to the singular purpose of + * associating metadata with extents that are currently owned by jemalloc. + * + ******************************************************************************* + */ + +typedef struct rtree_elm_s rtree_elm_t; +typedef struct rtree_elm_witness_s rtree_elm_witness_t; +typedef struct rtree_elm_witness_tsd_s rtree_elm_witness_tsd_t; +typedef struct rtree_level_s rtree_level_t; +typedef struct rtree_ctx_s rtree_ctx_t; +typedef struct rtree_s rtree_t; + +/* + * RTREE_BITS_PER_LEVEL must be a power of two that is no larger than the + * machine address width. + */ +#define LG_RTREE_BITS_PER_LEVEL 4 +#define RTREE_BITS_PER_LEVEL (1U << LG_RTREE_BITS_PER_LEVEL) +/* Maximum rtree height. */ +#define RTREE_HEIGHT_MAX \ + ((1U << (LG_SIZEOF_PTR+3)) / RTREE_BITS_PER_LEVEL) + +#define RTREE_CTX_INITIALIZER { \ + false, \ + 0, \ + 0, \ + {NULL /* C initializes all trailing elements to NULL. */} \ +} + +/* + * Maximum number of concurrently acquired elements per thread. This controls + * how many witness_t structures are embedded in tsd. Ideally rtree_elm_t would + * have a witness_t directly embedded, but that would dramatically bloat the + * tree. This must contain enough entries to e.g. coalesce two extents. + */ +#define RTREE_ELM_ACQUIRE_MAX 4 + +/* Initializers for rtree_elm_witness_tsd_t. */ +#define RTREE_ELM_WITNESS_INITIALIZER { \ + NULL, \ + WITNESS_INITIALIZER("rtree_elm", WITNESS_RANK_RTREE_ELM) \ +} + +#define RTREE_ELM_WITNESS_TSD_INITIALIZER { \ + { \ + RTREE_ELM_WITNESS_INITIALIZER, \ + RTREE_ELM_WITNESS_INITIALIZER, \ + RTREE_ELM_WITNESS_INITIALIZER, \ + RTREE_ELM_WITNESS_INITIALIZER \ + } \ +} + +#endif /* JEMALLOC_INTERNAL_RTREE_TYPES_H */ diff --git a/include/jemalloc/internal/size_classes.sh b/include/jemalloc/internal/size_classes.sh index 5a57f87d..3680b653 100755 --- a/include/jemalloc/internal/size_classes.sh +++ b/include/jemalloc/internal/size_classes.sh @@ -261,9 +261,10 @@ size_classes() { } cat <iteration = 0; -} - -JEMALLOC_INLINE void -spin_adaptive(spin_t *spin) -{ - volatile uint64_t i; - - for (i = 0; i < (KQU(1) << spin->iteration); i++) - CPU_SPINWAIT; - - if (spin->iteration < 63) - spin->iteration++; -} - -#endif - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ - diff --git a/include/jemalloc/internal/spin_inlines.h b/include/jemalloc/internal/spin_inlines.h new file mode 100644 index 00000000..b10f67e7 --- /dev/null +++ b/include/jemalloc/internal/spin_inlines.h @@ -0,0 +1,31 @@ +#ifndef JEMALLOC_INTERNAL_SPIN_INLINES_H +#define JEMALLOC_INTERNAL_SPIN_INLINES_H + +#ifndef JEMALLOC_ENABLE_INLINE +void spin_init(spin_t *spin); +void spin_adaptive(spin_t *spin); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_SPIN_C_)) +JEMALLOC_INLINE void +spin_init(spin_t *spin) +{ + + spin->iteration = 0; +} + +JEMALLOC_INLINE void +spin_adaptive(spin_t *spin) +{ + volatile uint64_t i; + + for (i = 0; i < (KQU(1) << spin->iteration); i++) + CPU_SPINWAIT; + + if (spin->iteration < 63) + spin->iteration++; +} + +#endif + +#endif /* JEMALLOC_INTERNAL_SPIN_INLINES_H */ diff --git a/include/jemalloc/internal/spin_structs.h b/include/jemalloc/internal/spin_structs.h new file mode 100644 index 00000000..ef71a765 --- /dev/null +++ b/include/jemalloc/internal/spin_structs.h @@ -0,0 +1,8 @@ +#ifndef JEMALLOC_INTERNAL_SPIN_STRUCTS_H +#define JEMALLOC_INTERNAL_SPIN_STRUCTS_H + +struct spin_s { + unsigned iteration; +}; + +#endif /* JEMALLOC_INTERNAL_SPIN_STRUCTS_H */ diff --git a/include/jemalloc/internal/spin_types.h b/include/jemalloc/internal/spin_types.h new file mode 100644 index 00000000..52ee4cc1 --- /dev/null +++ b/include/jemalloc/internal/spin_types.h @@ -0,0 +1,6 @@ +#ifndef JEMALLOC_INTERNAL_SPIN_TYPES_H +#define JEMALLOC_INTERNAL_SPIN_TYPES_H + +typedef struct spin_s spin_t; + +#endif /* JEMALLOC_INTERNAL_SPIN_TYPES_H */ diff --git a/include/jemalloc/internal/stats_externs.h b/include/jemalloc/internal/stats_externs.h new file mode 100644 index 00000000..a0a1ab6c --- /dev/null +++ b/include/jemalloc/internal/stats_externs.h @@ -0,0 +1,9 @@ +#ifndef JEMALLOC_INTERNAL_STATS_EXTERNS_H +#define JEMALLOC_INTERNAL_STATS_EXTERNS_H + +extern bool opt_stats_print; + +void stats_print(void (*write)(void *, const char *), void *cbopaque, + const char *opts); + +#endif /* JEMALLOC_INTERNAL_STATS_EXTERNS_H */ diff --git a/include/jemalloc/internal/stats.h b/include/jemalloc/internal/stats_structs.h similarity index 72% rename from include/jemalloc/internal/stats.h rename to include/jemalloc/internal/stats_structs.h index bea4e3e7..aaa0bf4f 100644 --- a/include/jemalloc/internal/stats.h +++ b/include/jemalloc/internal/stats_structs.h @@ -1,14 +1,5 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -typedef struct tcache_bin_stats_s tcache_bin_stats_t; -typedef struct malloc_bin_stats_s malloc_bin_stats_t; -typedef struct malloc_large_stats_s malloc_large_stats_t; -typedef struct arena_stats_s arena_stats_t; - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS +#ifndef JEMALLOC_INTERNAL_STATS_STRUCTS_H +#define JEMALLOC_INTERNAL_STATS_STRUCTS_H struct tcache_bin_stats_s { /* @@ -113,18 +104,4 @@ struct arena_stats_s { malloc_large_stats_t lstats[NSIZES - NBINS]; }; -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -extern bool opt_stats_print; - -void stats_print(void (*write)(void *, const char *), void *cbopaque, - const char *opts); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ +#endif /* JEMALLOC_INTERNAL_STATS_STRUCTS_H */ diff --git a/include/jemalloc/internal/stats_types.h b/include/jemalloc/internal/stats_types.h new file mode 100644 index 00000000..f202b231 --- /dev/null +++ b/include/jemalloc/internal/stats_types.h @@ -0,0 +1,9 @@ +#ifndef JEMALLOC_INTERNAL_STATS_TYPES_H +#define JEMALLOC_INTERNAL_STATS_TYPES_H + +typedef struct tcache_bin_stats_s tcache_bin_stats_t; +typedef struct malloc_bin_stats_s malloc_bin_stats_t; +typedef struct malloc_large_stats_s malloc_large_stats_t; +typedef struct arena_stats_s arena_stats_t; + +#endif /* JEMALLOC_INTERNAL_STATS_TYPES_H */ diff --git a/include/jemalloc/internal/tcache_externs.h b/include/jemalloc/internal/tcache_externs.h new file mode 100644 index 00000000..ead90afc --- /dev/null +++ b/include/jemalloc/internal/tcache_externs.h @@ -0,0 +1,47 @@ +#ifndef JEMALLOC_INTERNAL_TCACHE_EXTERNS_H +#define JEMALLOC_INTERNAL_TCACHE_EXTERNS_H + +extern bool opt_tcache; +extern ssize_t opt_lg_tcache_max; + +extern tcache_bin_info_t *tcache_bin_info; + +/* + * Number of tcache bins. There are NBINS small-object bins, plus 0 or more + * large-object bins. + */ +extern unsigned nhbins; + +/* Maximum cached size class. */ +extern size_t tcache_maxclass; + +/* + * Explicit tcaches, managed via the tcache.{create,flush,destroy} mallctls and + * usable via the MALLOCX_TCACHE() flag. The automatic per thread tcaches are + * completely disjoint from this data structure. tcaches starts off as a sparse + * array, so it has no physical memory footprint until individual pages are + * touched. This allows the entire array to be allocated the first time an + * explicit tcache is created without a disproportionate impact on memory usage. + */ +extern tcaches_t *tcaches; + +size_t tcache_salloc(tsdn_t *tsdn, const void *ptr); +void tcache_event_hard(tsd_t *tsd, tcache_t *tcache); +void *tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, + tcache_bin_t *tbin, szind_t binind, bool *tcache_success); +void tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, + szind_t binind, unsigned rem); +void tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, + unsigned rem, tcache_t *tcache); +void tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, + arena_t *oldarena, arena_t *newarena); +tcache_t *tcache_get_hard(tsd_t *tsd); +tcache_t *tcache_create(tsdn_t *tsdn, arena_t *arena); +void tcache_cleanup(tsd_t *tsd); +void tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); +bool tcaches_create(tsd_t *tsd, unsigned *r_ind); +void tcaches_flush(tsd_t *tsd, unsigned ind); +void tcaches_destroy(tsd_t *tsd, unsigned ind); +bool tcache_boot(tsdn_t *tsdn); + +#endif /* JEMALLOC_INTERNAL_TCACHE_EXTERNS_H */ diff --git a/include/jemalloc/internal/tcache.h b/include/jemalloc/internal/tcache_inlines.h similarity index 57% rename from include/jemalloc/internal/tcache.h rename to include/jemalloc/internal/tcache_inlines.h index 25a1ad02..e522d9e6 100644 --- a/include/jemalloc/internal/tcache.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -1,157 +1,5 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -typedef struct tcache_bin_info_s tcache_bin_info_t; -typedef struct tcache_bin_s tcache_bin_t; -typedef struct tcache_s tcache_t; -typedef struct tcaches_s tcaches_t; - -/* - * tcache pointers close to NULL are used to encode state information that is - * used for two purposes: preventing thread caching on a per thread basis and - * cleaning up during thread shutdown. - */ -#define TCACHE_STATE_DISABLED ((tcache_t *)(uintptr_t)1) -#define TCACHE_STATE_REINCARNATED ((tcache_t *)(uintptr_t)2) -#define TCACHE_STATE_PURGATORY ((tcache_t *)(uintptr_t)3) -#define TCACHE_STATE_MAX TCACHE_STATE_PURGATORY - -/* - * Absolute minimum number of cache slots for each small bin. - */ -#define TCACHE_NSLOTS_SMALL_MIN 20 - -/* - * Absolute maximum number of cache slots for each small bin in the thread - * cache. This is an additional constraint beyond that imposed as: twice the - * number of regions per slab for this size class. - * - * This constant must be an even number. - */ -#define TCACHE_NSLOTS_SMALL_MAX 200 - -/* Number of cache slots for large size classes. */ -#define TCACHE_NSLOTS_LARGE 20 - -/* (1U << opt_lg_tcache_max) is used to compute tcache_maxclass. */ -#define LG_TCACHE_MAXCLASS_DEFAULT 15 - -/* - * TCACHE_GC_SWEEP is the approximate number of allocation events between - * full GC sweeps. Integer rounding may cause the actual number to be - * slightly higher, since GC is performed incrementally. - */ -#define TCACHE_GC_SWEEP 8192 - -/* Number of tcache allocation/deallocation events between incremental GCs. */ -#define TCACHE_GC_INCR \ - ((TCACHE_GC_SWEEP / NBINS) + ((TCACHE_GC_SWEEP / NBINS == 0) ? 0 : 1)) - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -typedef enum { - tcache_enabled_false = 0, /* Enable cast to/from bool. */ - tcache_enabled_true = 1, - tcache_enabled_default = 2 -} tcache_enabled_t; - -/* - * Read-only information associated with each element of tcache_t's tbins array - * is stored separately, mainly to reduce memory usage. - */ -struct tcache_bin_info_s { - unsigned ncached_max; /* Upper limit on ncached. */ -}; - -struct tcache_bin_s { - tcache_bin_stats_t tstats; - int low_water; /* Min # cached since last GC. */ - unsigned lg_fill_div; /* Fill (ncached_max >> lg_fill_div). */ - unsigned ncached; /* # of cached objects. */ - /* - * To make use of adjacent cacheline prefetch, the items in the avail - * stack goes to higher address for newer allocations. avail points - * just above the available space, which means that - * avail[-ncached, ... -1] are available items and the lowest item will - * be allocated first. - */ - void **avail; /* Stack of available objects. */ -}; - -struct tcache_s { - ql_elm(tcache_t) link; /* Used for aggregating stats. */ - uint64_t prof_accumbytes;/* Cleared after arena_prof_accum(). */ - ticker_t gc_ticker; /* Drives incremental GC. */ - szind_t next_gc_bin; /* Next bin to GC. */ - tcache_bin_t tbins[1]; /* Dynamically sized. */ - /* - * The pointer stacks associated with tbins follow as a contiguous - * array. During tcache initialization, the avail pointer in each - * element of tbins is initialized to point to the proper offset within - * this array. - */ -}; - -/* Linkage for list of available (previously used) explicit tcache IDs. */ -struct tcaches_s { - union { - tcache_t *tcache; - tcaches_t *next; - }; -}; - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -extern bool opt_tcache; -extern ssize_t opt_lg_tcache_max; - -extern tcache_bin_info_t *tcache_bin_info; - -/* - * Number of tcache bins. There are NBINS small-object bins, plus 0 or more - * large-object bins. - */ -extern unsigned nhbins; - -/* Maximum cached size class. */ -extern size_t tcache_maxclass; - -/* - * Explicit tcaches, managed via the tcache.{create,flush,destroy} mallctls and - * usable via the MALLOCX_TCACHE() flag. The automatic per thread tcaches are - * completely disjoint from this data structure. tcaches starts off as a sparse - * array, so it has no physical memory footprint until individual pages are - * touched. This allows the entire array to be allocated the first time an - * explicit tcache is created without a disproportionate impact on memory usage. - */ -extern tcaches_t *tcaches; - -size_t tcache_salloc(tsdn_t *tsdn, const void *ptr); -void tcache_event_hard(tsd_t *tsd, tcache_t *tcache); -void *tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, - tcache_bin_t *tbin, szind_t binind, bool *tcache_success); -void tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, - szind_t binind, unsigned rem); -void tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, - unsigned rem, tcache_t *tcache); -void tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, - arena_t *oldarena, arena_t *newarena); -tcache_t *tcache_get_hard(tsd_t *tsd); -tcache_t *tcache_create(tsdn_t *tsdn, arena_t *arena); -void tcache_cleanup(tsd_t *tsd); -void tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); -bool tcaches_create(tsd_t *tsd, unsigned *r_ind); -void tcaches_flush(tsd_t *tsd, unsigned ind); -void tcaches_destroy(tsd_t *tsd, unsigned ind); -bool tcache_boot(tsdn_t *tsdn); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES +#ifndef JEMALLOC_INTERNAL_TCACHE_INLINES_H +#define JEMALLOC_INTERNAL_TCACHE_INLINES_H #ifndef JEMALLOC_ENABLE_INLINE void tcache_event(tsd_t *tsd, tcache_t *tcache); @@ -455,5 +303,4 @@ tcaches_get(tsd_t *tsd, unsigned ind) } #endif -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ +#endif /* JEMALLOC_INTERNAL_TCACHE_INLINES_H */ diff --git a/include/jemalloc/internal/tcache_structs.h b/include/jemalloc/internal/tcache_structs.h new file mode 100644 index 00000000..a2b28afd --- /dev/null +++ b/include/jemalloc/internal/tcache_structs.h @@ -0,0 +1,55 @@ +#ifndef JEMALLOC_INTERNAL_TCACHE_STRUCTS_H +#define JEMALLOC_INTERNAL_TCACHE_STRUCTS_H + +typedef enum { + tcache_enabled_false = 0, /* Enable cast to/from bool. */ + tcache_enabled_true = 1, + tcache_enabled_default = 2 +} tcache_enabled_t; + +/* + * Read-only information associated with each element of tcache_t's tbins array + * is stored separately, mainly to reduce memory usage. + */ +struct tcache_bin_info_s { + unsigned ncached_max; /* Upper limit on ncached. */ +}; + +struct tcache_bin_s { + tcache_bin_stats_t tstats; + int low_water; /* Min # cached since last GC. */ + unsigned lg_fill_div; /* Fill (ncached_max >> lg_fill_div). */ + unsigned ncached; /* # of cached objects. */ + /* + * To make use of adjacent cacheline prefetch, the items in the avail + * stack goes to higher address for newer allocations. avail points + * just above the available space, which means that + * avail[-ncached, ... -1] are available items and the lowest item will + * be allocated first. + */ + void **avail; /* Stack of available objects. */ +}; + +struct tcache_s { + ql_elm(tcache_t) link; /* Used for aggregating stats. */ + uint64_t prof_accumbytes;/* Cleared after arena_prof_accum(). */ + ticker_t gc_ticker; /* Drives incremental GC. */ + szind_t next_gc_bin; /* Next bin to GC. */ + tcache_bin_t tbins[1]; /* Dynamically sized. */ + /* + * The pointer stacks associated with tbins follow as a contiguous + * array. During tcache initialization, the avail pointer in each + * element of tbins is initialized to point to the proper offset within + * this array. + */ +}; + +/* Linkage for list of available (previously used) explicit tcache IDs. */ +struct tcaches_s { + union { + tcache_t *tcache; + tcaches_t *next; + }; +}; + +#endif /* JEMALLOC_INTERNAL_TCACHE_STRUCTS_H */ diff --git a/include/jemalloc/internal/tcache_types.h b/include/jemalloc/internal/tcache_types.h new file mode 100644 index 00000000..c6ac7670 --- /dev/null +++ b/include/jemalloc/internal/tcache_types.h @@ -0,0 +1,50 @@ +#ifndef JEMALLOC_INTERNAL_TCACHE_TYPES_H +#define JEMALLOC_INTERNAL_TCACHE_TYPES_H + +typedef struct tcache_bin_info_s tcache_bin_info_t; +typedef struct tcache_bin_s tcache_bin_t; +typedef struct tcache_s tcache_t; +typedef struct tcaches_s tcaches_t; + +/* + * tcache pointers close to NULL are used to encode state information that is + * used for two purposes: preventing thread caching on a per thread basis and + * cleaning up during thread shutdown. + */ +#define TCACHE_STATE_DISABLED ((tcache_t *)(uintptr_t)1) +#define TCACHE_STATE_REINCARNATED ((tcache_t *)(uintptr_t)2) +#define TCACHE_STATE_PURGATORY ((tcache_t *)(uintptr_t)3) +#define TCACHE_STATE_MAX TCACHE_STATE_PURGATORY + +/* + * Absolute minimum number of cache slots for each small bin. + */ +#define TCACHE_NSLOTS_SMALL_MIN 20 + +/* + * Absolute maximum number of cache slots for each small bin in the thread + * cache. This is an additional constraint beyond that imposed as: twice the + * number of regions per slab for this size class. + * + * This constant must be an even number. + */ +#define TCACHE_NSLOTS_SMALL_MAX 200 + +/* Number of cache slots for large size classes. */ +#define TCACHE_NSLOTS_LARGE 20 + +/* (1U << opt_lg_tcache_max) is used to compute tcache_maxclass. */ +#define LG_TCACHE_MAXCLASS_DEFAULT 15 + +/* + * TCACHE_GC_SWEEP is the approximate number of allocation events between + * full GC sweeps. Integer rounding may cause the actual number to be + * slightly higher, since GC is performed incrementally. + */ +#define TCACHE_GC_SWEEP 8192 + +/* Number of tcache allocation/deallocation events between incremental GCs. */ +#define TCACHE_GC_INCR \ + ((TCACHE_GC_SWEEP / NBINS) + ((TCACHE_GC_SWEEP / NBINS == 0) ? 0 : 1)) + +#endif /* JEMALLOC_INTERNAL_TCACHE_TYPES_H */ diff --git a/include/jemalloc/internal/ticker.h b/include/jemalloc/internal/ticker_inlines.h similarity index 57% rename from include/jemalloc/internal/ticker.h rename to include/jemalloc/internal/ticker_inlines.h index 4696e56d..42f37eb2 100644 --- a/include/jemalloc/internal/ticker.h +++ b/include/jemalloc/internal/ticker_inlines.h @@ -1,24 +1,5 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -typedef struct ticker_s ticker_t; - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -struct ticker_s { - int32_t tick; - int32_t nticks; -}; - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES +#ifndef JEMALLOC_INTERNAL_TICKER_INLINES_H +#define JEMALLOC_INTERNAL_TICKER_INLINES_H #ifndef JEMALLOC_ENABLE_INLINE void ticker_init(ticker_t *ticker, int32_t nticks); @@ -71,5 +52,4 @@ ticker_tick(ticker_t *ticker) } #endif -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ +#endif /* JEMALLOC_INTERNAL_TICKER_INLINES_H */ diff --git a/include/jemalloc/internal/ticker_structs.h b/include/jemalloc/internal/ticker_structs.h new file mode 100644 index 00000000..e30c4e21 --- /dev/null +++ b/include/jemalloc/internal/ticker_structs.h @@ -0,0 +1,9 @@ +#ifndef JEMALLOC_INTERNAL_TICKER_STRUCTS_H +#define JEMALLOC_INTERNAL_TICKER_STRUCTS_H + +struct ticker_s { + int32_t tick; + int32_t nticks; +}; + +#endif /* JEMALLOC_INTERNAL_TICKER_STRUCTS_H */ diff --git a/include/jemalloc/internal/ticker_types.h b/include/jemalloc/internal/ticker_types.h new file mode 100644 index 00000000..62d67f3d --- /dev/null +++ b/include/jemalloc/internal/ticker_types.h @@ -0,0 +1,6 @@ +#ifndef JEMALLOC_INTERNAL_TICKER_TYPES_H +#define JEMALLOC_INTERNAL_TICKER_TYPES_H + +typedef struct ticker_s ticker_t; + +#endif /* JEMALLOC_INTERNAL_TICKER_TYPES_H */ diff --git a/include/jemalloc/internal/tsd_externs.h b/include/jemalloc/internal/tsd_externs.h new file mode 100644 index 00000000..87ebaf2d --- /dev/null +++ b/include/jemalloc/internal/tsd_externs.h @@ -0,0 +1,18 @@ +#ifndef JEMALLOC_INTERNAL_TSD_EXTERNS_H +#define JEMALLOC_INTERNAL_TSD_EXTERNS_H + +void *malloc_tsd_malloc(size_t size); +void malloc_tsd_dalloc(void *wrapper); +void malloc_tsd_no_cleanup(void *arg); +void malloc_tsd_cleanup_register(bool (*f)(void)); +tsd_t *malloc_tsd_boot0(void); +void malloc_tsd_boot1(void); +#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ + !defined(_WIN32)) +void *tsd_init_check_recursion(tsd_init_head_t *head, + tsd_init_block_t *block); +void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block); +#endif +void tsd_cleanup(void *arg); + +#endif /* JEMALLOC_INTERNAL_TSD_EXTERNS_H */ diff --git a/include/jemalloc/internal/tsd_inlines.h b/include/jemalloc/internal/tsd_inlines.h new file mode 100644 index 00000000..ad915d1a --- /dev/null +++ b/include/jemalloc/internal/tsd_inlines.h @@ -0,0 +1,140 @@ +#ifndef JEMALLOC_INTERNAL_TSD_INLINES_H +#define JEMALLOC_INTERNAL_TSD_INLINES_H + +#ifndef JEMALLOC_ENABLE_INLINE +malloc_tsd_protos(JEMALLOC_ATTR(unused), , tsd_t) + +tsd_t *tsd_fetch_impl(bool init); +tsd_t *tsd_fetch(void); +tsdn_t *tsd_tsdn(tsd_t *tsd); +bool tsd_nominal(tsd_t *tsd); +#define O(n, t, c) \ +t *tsd_##n##p_get(tsd_t *tsd); \ +t tsd_##n##_get(tsd_t *tsd); \ +void tsd_##n##_set(tsd_t *tsd, t n); +MALLOC_TSD +#undef O +tsdn_t *tsdn_fetch(void); +bool tsdn_null(const tsdn_t *tsdn); +tsd_t *tsdn_tsd(tsdn_t *tsdn); +rtree_ctx_t *tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TSD_C_)) +malloc_tsd_externs(, tsd_t) +malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, , tsd_t, tsd_initializer, tsd_cleanup) + +JEMALLOC_ALWAYS_INLINE tsd_t * +tsd_fetch_impl(bool init) +{ + tsd_t *tsd = tsd_get(init); + + if (!init && tsd_get_allocates() && tsd == NULL) + return (NULL); + assert(tsd != NULL); + + if (unlikely(tsd->state != tsd_state_nominal)) { + if (tsd->state == tsd_state_uninitialized) { + tsd->state = tsd_state_nominal; + /* Trigger cleanup handler registration. */ + tsd_set(tsd); + } else if (tsd->state == tsd_state_purgatory) { + tsd->state = tsd_state_reincarnated; + tsd_set(tsd); + } else + assert(tsd->state == tsd_state_reincarnated); + } + + return (tsd); +} + +JEMALLOC_ALWAYS_INLINE tsd_t * +tsd_fetch(void) +{ + + return (tsd_fetch_impl(true)); +} + +JEMALLOC_ALWAYS_INLINE tsdn_t * +tsd_tsdn(tsd_t *tsd) +{ + + return ((tsdn_t *)tsd); +} + +JEMALLOC_INLINE bool +tsd_nominal(tsd_t *tsd) +{ + + return (tsd->state == tsd_state_nominal); +} + +#define O(n, t, c) \ +JEMALLOC_ALWAYS_INLINE t * \ +tsd_##n##p_get(tsd_t *tsd) \ +{ \ + \ + return (&tsd->n); \ +} \ + \ +JEMALLOC_ALWAYS_INLINE t \ +tsd_##n##_get(tsd_t *tsd) \ +{ \ + \ + return (*tsd_##n##p_get(tsd)); \ +} \ + \ +JEMALLOC_ALWAYS_INLINE void \ +tsd_##n##_set(tsd_t *tsd, t n) \ +{ \ + \ + assert(tsd->state == tsd_state_nominal); \ + tsd->n = n; \ +} +MALLOC_TSD +#undef O + +JEMALLOC_ALWAYS_INLINE tsdn_t * +tsdn_fetch(void) +{ + + if (!tsd_booted_get()) + return (NULL); + + return (tsd_tsdn(tsd_fetch_impl(false))); +} + +JEMALLOC_ALWAYS_INLINE bool +tsdn_null(const tsdn_t *tsdn) +{ + + return (tsdn == NULL); +} + +JEMALLOC_ALWAYS_INLINE tsd_t * +tsdn_tsd(tsdn_t *tsdn) +{ + + assert(!tsdn_null(tsdn)); + + return (&tsdn->tsd); +} + +JEMALLOC_ALWAYS_INLINE rtree_ctx_t * +tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback) +{ + + /* + * If tsd cannot be accessed, initialize the fallback rtree_ctx and + * return a pointer to it. + */ + if (unlikely(tsdn_null(tsdn))) { + static const rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; + memcpy(fallback, &rtree_ctx, sizeof(rtree_ctx_t)); + return (fallback); + } + return (tsd_rtree_ctxp_get(tsdn_tsd(tsdn))); +} +#endif + +#endif /* JEMALLOC_INTERNAL_TSD_INLINES_H */ diff --git a/include/jemalloc/internal/tsd_structs.h b/include/jemalloc/internal/tsd_structs.h new file mode 100644 index 00000000..8d94c5be --- /dev/null +++ b/include/jemalloc/internal/tsd_structs.h @@ -0,0 +1,73 @@ +#ifndef JEMALLOC_INTERNAL_TSD_STRUCTS_H +#define JEMALLOC_INTERNAL_TSD_STRUCTS_H + +#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ + !defined(_WIN32)) +struct tsd_init_block_s { + ql_elm(tsd_init_block_t) link; + pthread_t thread; + void *data; +}; +struct tsd_init_head_s { + ql_head(tsd_init_block_t) blocks; + malloc_mutex_t lock; +}; +#endif + +#define MALLOC_TSD \ +/* O(name, type, cleanup) */ \ + O(tcache, tcache_t *, yes) \ + O(thread_allocated, uint64_t, no) \ + O(thread_deallocated, uint64_t, no) \ + O(prof_tdata, prof_tdata_t *, yes) \ + O(iarena, arena_t *, yes) \ + O(arena, arena_t *, yes) \ + O(arenas_tdata, arena_tdata_t *, yes) \ + O(narenas_tdata, unsigned, no) \ + O(arenas_tdata_bypass, bool, no) \ + O(tcache_enabled, tcache_enabled_t, no) \ + O(rtree_ctx, rtree_ctx_t, no) \ + O(witnesses, witness_list_t, yes) \ + O(rtree_elm_witnesses, rtree_elm_witness_tsd_t,no) \ + O(witness_fork, bool, no) \ + +#define TSD_INITIALIZER { \ + tsd_state_uninitialized, \ + NULL, \ + 0, \ + 0, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + 0, \ + false, \ + tcache_enabled_default, \ + RTREE_CTX_INITIALIZER, \ + ql_head_initializer(witnesses), \ + RTREE_ELM_WITNESS_TSD_INITIALIZER, \ + false \ +} + +struct tsd_s { + tsd_state_t state; +#define O(n, t, c) \ + t n; +MALLOC_TSD +#undef O +}; + +/* + * Wrapper around tsd_t that makes it possible to avoid implicit conversion + * between tsd_t and tsdn_t, where tsdn_t is "nullable" and has to be + * explicitly converted to tsd_t, which is non-nullable. + */ +struct tsdn_s { + tsd_t tsd; +}; + +static const tsd_t tsd_initializer = TSD_INITIALIZER; + +malloc_tsd_types(, tsd_t) + +#endif /* JEMALLOC_INTERNAL_TSD_STRUCTS_H */ diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd_types.h similarity index 74% rename from include/jemalloc/internal/tsd.h rename to include/jemalloc/internal/tsd_types.h index c4f010ae..b48eaeca 100644 --- a/include/jemalloc/internal/tsd.h +++ b/include/jemalloc/internal/tsd_types.h @@ -1,5 +1,5 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES +#ifndef JEMALLOC_INTERNAL_TSD_TYPES_H +#define JEMALLOC_INTERNAL_TSD_TYPES_H /* Maximum number of malloc_tsd users with cleanup functions. */ #define MALLOC_TSD_CLEANUPS_MAX 2 @@ -576,236 +576,4 @@ a_name##tsd_set(a_type *val) \ } #endif -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ - !defined(_WIN32)) -struct tsd_init_block_s { - ql_elm(tsd_init_block_t) link; - pthread_t thread; - void *data; -}; -struct tsd_init_head_s { - ql_head(tsd_init_block_t) blocks; - malloc_mutex_t lock; -}; -#endif - -#define MALLOC_TSD \ -/* O(name, type, cleanup) */ \ - O(tcache, tcache_t *, yes) \ - O(thread_allocated, uint64_t, no) \ - O(thread_deallocated, uint64_t, no) \ - O(prof_tdata, prof_tdata_t *, yes) \ - O(iarena, arena_t *, yes) \ - O(arena, arena_t *, yes) \ - O(arenas_tdata, arena_tdata_t *, yes) \ - O(narenas_tdata, unsigned, no) \ - O(arenas_tdata_bypass, bool, no) \ - O(tcache_enabled, tcache_enabled_t, no) \ - O(rtree_ctx, rtree_ctx_t, no) \ - O(witnesses, witness_list_t, yes) \ - O(rtree_elm_witnesses, rtree_elm_witness_tsd_t,no) \ - O(witness_fork, bool, no) \ - -#define TSD_INITIALIZER { \ - tsd_state_uninitialized, \ - NULL, \ - 0, \ - 0, \ - NULL, \ - NULL, \ - NULL, \ - NULL, \ - 0, \ - false, \ - tcache_enabled_default, \ - RTREE_CTX_INITIALIZER, \ - ql_head_initializer(witnesses), \ - RTREE_ELM_WITNESS_TSD_INITIALIZER, \ - false \ -} - -struct tsd_s { - tsd_state_t state; -#define O(n, t, c) \ - t n; -MALLOC_TSD -#undef O -}; - -/* - * Wrapper around tsd_t that makes it possible to avoid implicit conversion - * between tsd_t and tsdn_t, where tsdn_t is "nullable" and has to be - * explicitly converted to tsd_t, which is non-nullable. - */ -struct tsdn_s { - tsd_t tsd; -}; - -static const tsd_t tsd_initializer = TSD_INITIALIZER; - -malloc_tsd_types(, tsd_t) - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -void *malloc_tsd_malloc(size_t size); -void malloc_tsd_dalloc(void *wrapper); -void malloc_tsd_no_cleanup(void *arg); -void malloc_tsd_cleanup_register(bool (*f)(void)); -tsd_t *malloc_tsd_boot0(void); -void malloc_tsd_boot1(void); -#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ - !defined(_WIN32)) -void *tsd_init_check_recursion(tsd_init_head_t *head, - tsd_init_block_t *block); -void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block); -#endif -void tsd_cleanup(void *arg); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#ifndef JEMALLOC_ENABLE_INLINE -malloc_tsd_protos(JEMALLOC_ATTR(unused), , tsd_t) - -tsd_t *tsd_fetch_impl(bool init); -tsd_t *tsd_fetch(void); -tsdn_t *tsd_tsdn(tsd_t *tsd); -bool tsd_nominal(tsd_t *tsd); -#define O(n, t, c) \ -t *tsd_##n##p_get(tsd_t *tsd); \ -t tsd_##n##_get(tsd_t *tsd); \ -void tsd_##n##_set(tsd_t *tsd, t n); -MALLOC_TSD -#undef O -tsdn_t *tsdn_fetch(void); -bool tsdn_null(const tsdn_t *tsdn); -tsd_t *tsdn_tsd(tsdn_t *tsdn); -rtree_ctx_t *tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TSD_C_)) -malloc_tsd_externs(, tsd_t) -malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, , tsd_t, tsd_initializer, tsd_cleanup) - -JEMALLOC_ALWAYS_INLINE tsd_t * -tsd_fetch_impl(bool init) -{ - tsd_t *tsd = tsd_get(init); - - if (!init && tsd_get_allocates() && tsd == NULL) - return (NULL); - assert(tsd != NULL); - - if (unlikely(tsd->state != tsd_state_nominal)) { - if (tsd->state == tsd_state_uninitialized) { - tsd->state = tsd_state_nominal; - /* Trigger cleanup handler registration. */ - tsd_set(tsd); - } else if (tsd->state == tsd_state_purgatory) { - tsd->state = tsd_state_reincarnated; - tsd_set(tsd); - } else - assert(tsd->state == tsd_state_reincarnated); - } - - return (tsd); -} - -JEMALLOC_ALWAYS_INLINE tsd_t * -tsd_fetch(void) -{ - - return (tsd_fetch_impl(true)); -} - -JEMALLOC_ALWAYS_INLINE tsdn_t * -tsd_tsdn(tsd_t *tsd) -{ - - return ((tsdn_t *)tsd); -} - -JEMALLOC_INLINE bool -tsd_nominal(tsd_t *tsd) -{ - - return (tsd->state == tsd_state_nominal); -} - -#define O(n, t, c) \ -JEMALLOC_ALWAYS_INLINE t * \ -tsd_##n##p_get(tsd_t *tsd) \ -{ \ - \ - return (&tsd->n); \ -} \ - \ -JEMALLOC_ALWAYS_INLINE t \ -tsd_##n##_get(tsd_t *tsd) \ -{ \ - \ - return (*tsd_##n##p_get(tsd)); \ -} \ - \ -JEMALLOC_ALWAYS_INLINE void \ -tsd_##n##_set(tsd_t *tsd, t n) \ -{ \ - \ - assert(tsd->state == tsd_state_nominal); \ - tsd->n = n; \ -} -MALLOC_TSD -#undef O - -JEMALLOC_ALWAYS_INLINE tsdn_t * -tsdn_fetch(void) -{ - - if (!tsd_booted_get()) - return (NULL); - - return (tsd_tsdn(tsd_fetch_impl(false))); -} - -JEMALLOC_ALWAYS_INLINE bool -tsdn_null(const tsdn_t *tsdn) -{ - - return (tsdn == NULL); -} - -JEMALLOC_ALWAYS_INLINE tsd_t * -tsdn_tsd(tsdn_t *tsdn) -{ - - assert(!tsdn_null(tsdn)); - - return (&tsdn->tsd); -} - -JEMALLOC_ALWAYS_INLINE rtree_ctx_t * -tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback) -{ - - /* - * If tsd cannot be accessed, initialize the fallback rtree_ctx and - * return a pointer to it. - */ - if (unlikely(tsdn_null(tsdn))) { - static const rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; - memcpy(fallback, &rtree_ctx, sizeof(rtree_ctx_t)); - return (fallback); - } - return (tsd_rtree_ctxp_get(tsdn_tsd(tsdn))); -} -#endif - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ +#endif /* JEMALLOC_INTERNAL_TSD_TYPES_H */ diff --git a/include/jemalloc/internal/util_externs.h b/include/jemalloc/internal/util_externs.h new file mode 100644 index 00000000..b203b773 --- /dev/null +++ b/include/jemalloc/internal/util_externs.h @@ -0,0 +1,23 @@ +#ifndef JEMALLOC_INTERNAL_UTIL_EXTERNS_H +#define JEMALLOC_INTERNAL_UTIL_EXTERNS_H + +int buferror(int err, char *buf, size_t buflen); +uintmax_t malloc_strtoumax(const char *restrict nptr, + char **restrict endptr, int base); +void malloc_write(const char *s); + +/* + * malloc_vsnprintf() supports a subset of snprintf(3) that avoids floating + * point math. + */ +size_t malloc_vsnprintf(char *str, size_t size, const char *format, + va_list ap); +size_t malloc_snprintf(char *str, size_t size, const char *format, ...) + JEMALLOC_FORMAT_PRINTF(3, 4); +void malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque, + const char *format, va_list ap); +void malloc_cprintf(void (*write)(void *, const char *), void *cbopaque, + const char *format, ...) JEMALLOC_FORMAT_PRINTF(3, 4); +void malloc_printf(const char *format, ...) JEMALLOC_FORMAT_PRINTF(1, 2); + +#endif /* JEMALLOC_INTERNAL_UTIL_EXTERNS_H */ diff --git a/include/jemalloc/internal/util.h b/include/jemalloc/internal/util_inlines.h similarity index 50% rename from include/jemalloc/internal/util.h rename to include/jemalloc/internal/util_inlines.h index 592806dc..93f5b1de 100644 --- a/include/jemalloc/internal/util.h +++ b/include/jemalloc/internal/util_inlines.h @@ -1,126 +1,5 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -#ifdef _WIN32 -# ifdef _WIN64 -# define FMT64_PREFIX "ll" -# define FMTPTR_PREFIX "ll" -# else -# define FMT64_PREFIX "ll" -# define FMTPTR_PREFIX "" -# endif -# define FMTd32 "d" -# define FMTu32 "u" -# define FMTx32 "x" -# define FMTd64 FMT64_PREFIX "d" -# define FMTu64 FMT64_PREFIX "u" -# define FMTx64 FMT64_PREFIX "x" -# define FMTdPTR FMTPTR_PREFIX "d" -# define FMTuPTR FMTPTR_PREFIX "u" -# define FMTxPTR FMTPTR_PREFIX "x" -#else -# include -# define FMTd32 PRId32 -# define FMTu32 PRIu32 -# define FMTx32 PRIx32 -# define FMTd64 PRId64 -# define FMTu64 PRIu64 -# define FMTx64 PRIx64 -# define FMTdPTR PRIdPTR -# define FMTuPTR PRIuPTR -# define FMTxPTR PRIxPTR -#endif - -/* Size of stack-allocated buffer passed to buferror(). */ -#define BUFERROR_BUF 64 - -/* - * Size of stack-allocated buffer used by malloc_{,v,vc}printf(). This must be - * large enough for all possible uses within jemalloc. - */ -#define MALLOC_PRINTF_BUFSIZE 4096 - -/* Junk fill patterns. */ -#ifndef JEMALLOC_ALLOC_JUNK -# define JEMALLOC_ALLOC_JUNK ((uint8_t)0xa5) -#endif -#ifndef JEMALLOC_FREE_JUNK -# define JEMALLOC_FREE_JUNK ((uint8_t)0x5a) -#endif - -/* - * Wrap a cpp argument that contains commas such that it isn't broken up into - * multiple arguments. - */ -#define JEMALLOC_ARG_CONCAT(...) __VA_ARGS__ - -/* cpp macro definition stringification. */ -#define STRINGIFY_HELPER(x) #x -#define STRINGIFY(x) STRINGIFY_HELPER(x) - -/* - * Silence compiler warnings due to uninitialized values. This is used - * wherever the compiler fails to recognize that the variable is never used - * uninitialized. - */ -#ifdef JEMALLOC_CC_SILENCE -# define JEMALLOC_CC_SILENCE_INIT(v) = v -#else -# define JEMALLOC_CC_SILENCE_INIT(v) -#endif - -#ifdef __GNUC__ -# define likely(x) __builtin_expect(!!(x), 1) -# define unlikely(x) __builtin_expect(!!(x), 0) -#else -# define likely(x) !!(x) -# define unlikely(x) !!(x) -#endif - -#if !defined(JEMALLOC_INTERNAL_UNREACHABLE) -# error JEMALLOC_INTERNAL_UNREACHABLE should have been defined by configure -#endif - -#define unreachable() JEMALLOC_INTERNAL_UNREACHABLE() - -#include "jemalloc/internal/assert.h" - -/* Use to assert a particular configuration, e.g., cassert(config_debug). */ -#define cassert(c) do { \ - if (unlikely(!(c))) \ - not_reached(); \ -} while (0) - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -int buferror(int err, char *buf, size_t buflen); -uintmax_t malloc_strtoumax(const char *restrict nptr, - char **restrict endptr, int base); -void malloc_write(const char *s); - -/* - * malloc_vsnprintf() supports a subset of snprintf(3) that avoids floating - * point math. - */ -size_t malloc_vsnprintf(char *str, size_t size, const char *format, - va_list ap); -size_t malloc_snprintf(char *str, size_t size, const char *format, ...) - JEMALLOC_FORMAT_PRINTF(3, 4); -void malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque, - const char *format, va_list ap); -void malloc_cprintf(void (*write)(void *, const char *), void *cbopaque, - const char *format, ...) JEMALLOC_FORMAT_PRINTF(3, 4); -void malloc_printf(const char *format, ...) JEMALLOC_FORMAT_PRINTF(1, 2); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES +#ifndef JEMALLOC_INTERNAL_UTIL_INLINES_H +#define JEMALLOC_INTERNAL_UTIL_INLINES_H #ifndef JEMALLOC_ENABLE_INLINE unsigned ffs_llu(unsigned long long bitmap); @@ -342,5 +221,4 @@ get_errno(void) } #endif -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ +#endif /* JEMALLOC_INTERNAL_UTIL_INLINES_H */ diff --git a/include/jemalloc/internal/util_types.h b/include/jemalloc/internal/util_types.h new file mode 100644 index 00000000..7f727993 --- /dev/null +++ b/include/jemalloc/internal/util_types.h @@ -0,0 +1,94 @@ +#ifndef JEMALLOC_INTERNAL_UTIL_TYPES_H +#define JEMALLOC_INTERNAL_UTIL_TYPES_H + +#ifdef _WIN32 +# ifdef _WIN64 +# define FMT64_PREFIX "ll" +# define FMTPTR_PREFIX "ll" +# else +# define FMT64_PREFIX "ll" +# define FMTPTR_PREFIX "" +# endif +# define FMTd32 "d" +# define FMTu32 "u" +# define FMTx32 "x" +# define FMTd64 FMT64_PREFIX "d" +# define FMTu64 FMT64_PREFIX "u" +# define FMTx64 FMT64_PREFIX "x" +# define FMTdPTR FMTPTR_PREFIX "d" +# define FMTuPTR FMTPTR_PREFIX "u" +# define FMTxPTR FMTPTR_PREFIX "x" +#else +# include +# define FMTd32 PRId32 +# define FMTu32 PRIu32 +# define FMTx32 PRIx32 +# define FMTd64 PRId64 +# define FMTu64 PRIu64 +# define FMTx64 PRIx64 +# define FMTdPTR PRIdPTR +# define FMTuPTR PRIuPTR +# define FMTxPTR PRIxPTR +#endif + +/* Size of stack-allocated buffer passed to buferror(). */ +#define BUFERROR_BUF 64 + +/* + * Size of stack-allocated buffer used by malloc_{,v,vc}printf(). This must be + * large enough for all possible uses within jemalloc. + */ +#define MALLOC_PRINTF_BUFSIZE 4096 + +/* Junk fill patterns. */ +#ifndef JEMALLOC_ALLOC_JUNK +# define JEMALLOC_ALLOC_JUNK ((uint8_t)0xa5) +#endif +#ifndef JEMALLOC_FREE_JUNK +# define JEMALLOC_FREE_JUNK ((uint8_t)0x5a) +#endif + +/* + * Wrap a cpp argument that contains commas such that it isn't broken up into + * multiple arguments. + */ +#define JEMALLOC_ARG_CONCAT(...) __VA_ARGS__ + +/* cpp macro definition stringification. */ +#define STRINGIFY_HELPER(x) #x +#define STRINGIFY(x) STRINGIFY_HELPER(x) + +/* + * Silence compiler warnings due to uninitialized values. This is used + * wherever the compiler fails to recognize that the variable is never used + * uninitialized. + */ +#ifdef JEMALLOC_CC_SILENCE +# define JEMALLOC_CC_SILENCE_INIT(v) = v +#else +# define JEMALLOC_CC_SILENCE_INIT(v) +#endif + +#ifdef __GNUC__ +# define likely(x) __builtin_expect(!!(x), 1) +# define unlikely(x) __builtin_expect(!!(x), 0) +#else +# define likely(x) !!(x) +# define unlikely(x) !!(x) +#endif + +#if !defined(JEMALLOC_INTERNAL_UNREACHABLE) +# error JEMALLOC_INTERNAL_UNREACHABLE should have been defined by configure +#endif + +#define unreachable() JEMALLOC_INTERNAL_UNREACHABLE() + +#include "jemalloc/internal/assert.h" + +/* Use to assert a particular configuration, e.g., cassert(config_debug). */ +#define cassert(c) do { \ + if (unlikely(!(c))) \ + not_reached(); \ +} while (0) + +#endif /* JEMALLOC_INTERNAL_UTIL_TYPES_H */ diff --git a/include/jemalloc/internal/witness.h b/include/jemalloc/internal/witness.h deleted file mode 100644 index 86ddb64a..00000000 --- a/include/jemalloc/internal/witness.h +++ /dev/null @@ -1,275 +0,0 @@ -/******************************************************************************/ -#ifdef JEMALLOC_H_TYPES - -typedef struct witness_s witness_t; -typedef unsigned witness_rank_t; -typedef ql_head(witness_t) witness_list_t; -typedef int witness_comp_t (const witness_t *, void *, const witness_t *, - void *); - -/* - * Lock ranks. Witnesses with rank WITNESS_RANK_OMIT are completely ignored by - * the witness machinery. - */ -#define WITNESS_RANK_OMIT 0U - -#define WITNESS_RANK_INIT 1U -#define WITNESS_RANK_CTL 1U -#define WITNESS_RANK_ARENAS 2U - -#define WITNESS_RANK_PROF_DUMP 3U -#define WITNESS_RANK_PROF_BT2GCTX 4U -#define WITNESS_RANK_PROF_TDATAS 5U -#define WITNESS_RANK_PROF_TDATA 6U -#define WITNESS_RANK_PROF_GCTX 7U - -#define WITNESS_RANK_ARENA 8U -#define WITNESS_RANK_ARENA_EXTENTS 9U -#define WITNESS_RANK_ARENA_EXTENT_CACHE 10 - -#define WITNESS_RANK_RTREE_ELM 11U -#define WITNESS_RANK_RTREE 12U -#define WITNESS_RANK_BASE 13U - -#define WITNESS_RANK_LEAF 0xffffffffU -#define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF -#define WITNESS_RANK_ARENA_LARGE WITNESS_RANK_LEAF -#define WITNESS_RANK_DSS WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_ACTIVE WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_DUMP_SEQ WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_GDUMP WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_NEXT_THR_UID WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_THREAD_ACTIVE_INIT WITNESS_RANK_LEAF - -#define WITNESS_INITIALIZER(name, rank) {name, rank, NULL, NULL, {NULL, NULL}} - -#endif /* JEMALLOC_H_TYPES */ -/******************************************************************************/ -#ifdef JEMALLOC_H_STRUCTS - -struct witness_s { - /* Name, used for printing lock order reversal messages. */ - const char *name; - - /* - * Witness rank, where 0 is lowest and UINT_MAX is highest. Witnesses - * must be acquired in order of increasing rank. - */ - witness_rank_t rank; - - /* - * If two witnesses are of equal rank and they have the samp comp - * function pointer, it is called as a last attempt to differentiate - * between witnesses of equal rank. - */ - witness_comp_t *comp; - - /* Opaque data, passed to comp(). */ - void *opaque; - - /* Linkage for thread's currently owned locks. */ - ql_elm(witness_t) link; -}; - -#endif /* JEMALLOC_H_STRUCTS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_EXTERNS - -void witness_init(witness_t *witness, const char *name, witness_rank_t rank, - witness_comp_t *comp, void *opaque); -#ifdef JEMALLOC_JET -typedef void (witness_lock_error_t)(const witness_list_t *, const witness_t *); -extern witness_lock_error_t *witness_lock_error; -#else -void witness_lock_error(const witness_list_t *witnesses, - const witness_t *witness); -#endif -#ifdef JEMALLOC_JET -typedef void (witness_owner_error_t)(const witness_t *); -extern witness_owner_error_t *witness_owner_error; -#else -void witness_owner_error(const witness_t *witness); -#endif -#ifdef JEMALLOC_JET -typedef void (witness_not_owner_error_t)(const witness_t *); -extern witness_not_owner_error_t *witness_not_owner_error; -#else -void witness_not_owner_error(const witness_t *witness); -#endif -#ifdef JEMALLOC_JET -typedef void (witness_lockless_error_t)(const witness_list_t *); -extern witness_lockless_error_t *witness_lockless_error; -#else -void witness_lockless_error(const witness_list_t *witnesses); -#endif - -void witnesses_cleanup(tsd_t *tsd); -void witness_prefork(tsd_t *tsd); -void witness_postfork_parent(tsd_t *tsd); -void witness_postfork_child(tsd_t *tsd); - -#endif /* JEMALLOC_H_EXTERNS */ -/******************************************************************************/ -#ifdef JEMALLOC_H_INLINES - -#ifndef JEMALLOC_ENABLE_INLINE -bool witness_owner(tsd_t *tsd, const witness_t *witness); -void witness_assert_owner(tsdn_t *tsdn, const witness_t *witness); -void witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness); -void witness_assert_lockless(tsdn_t *tsdn); -void witness_lock(tsdn_t *tsdn, witness_t *witness); -void witness_unlock(tsdn_t *tsdn, witness_t *witness); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) -/* Helper, not intended for direct use. */ -JEMALLOC_INLINE bool -witness_owner(tsd_t *tsd, const witness_t *witness) -{ - witness_list_t *witnesses; - witness_t *w; - - cassert(config_debug); - - witnesses = tsd_witnessesp_get(tsd); - ql_foreach(w, witnesses, link) { - if (w == witness) - return (true); - } - - return (false); -} - -JEMALLOC_INLINE void -witness_assert_owner(tsdn_t *tsdn, const witness_t *witness) -{ - tsd_t *tsd; - - if (!config_debug) - return; - - if (tsdn_null(tsdn)) - return; - tsd = tsdn_tsd(tsdn); - if (witness->rank == WITNESS_RANK_OMIT) - return; - - if (witness_owner(tsd, witness)) - return; - witness_owner_error(witness); -} - -JEMALLOC_INLINE void -witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness) -{ - tsd_t *tsd; - witness_list_t *witnesses; - witness_t *w; - - if (!config_debug) - return; - - if (tsdn_null(tsdn)) - return; - tsd = tsdn_tsd(tsdn); - if (witness->rank == WITNESS_RANK_OMIT) - return; - - witnesses = tsd_witnessesp_get(tsd); - ql_foreach(w, witnesses, link) { - if (w == witness) - witness_not_owner_error(witness); - } -} - -JEMALLOC_INLINE void -witness_assert_lockless(tsdn_t *tsdn) -{ - tsd_t *tsd; - witness_list_t *witnesses; - witness_t *w; - - if (!config_debug) - return; - - if (tsdn_null(tsdn)) - return; - tsd = tsdn_tsd(tsdn); - - witnesses = tsd_witnessesp_get(tsd); - w = ql_last(witnesses, link); - if (w != NULL) - witness_lockless_error(witnesses); -} - -JEMALLOC_INLINE void -witness_lock(tsdn_t *tsdn, witness_t *witness) -{ - tsd_t *tsd; - witness_list_t *witnesses; - witness_t *w; - - if (!config_debug) - return; - - if (tsdn_null(tsdn)) - return; - tsd = tsdn_tsd(tsdn); - if (witness->rank == WITNESS_RANK_OMIT) - return; - - witness_assert_not_owner(tsdn, witness); - - witnesses = tsd_witnessesp_get(tsd); - w = ql_last(witnesses, link); - if (w == NULL) { - /* No other locks; do nothing. */ - } else if (tsd_witness_fork_get(tsd) && w->rank <= witness->rank) { - /* Forking, and relaxed ranking satisfied. */ - } else if (w->rank > witness->rank) { - /* Not forking, rank order reversal. */ - witness_lock_error(witnesses, witness); - } else if (w->rank == witness->rank && (w->comp == NULL || w->comp != - witness->comp || w->comp(w, w->opaque, witness, witness->opaque) > - 0)) { - /* - * Missing/incompatible comparison function, or comparison - * function indicates rank order reversal. - */ - witness_lock_error(witnesses, witness); - } - - ql_elm_new(witness, link); - ql_tail_insert(witnesses, witness, link); -} - -JEMALLOC_INLINE void -witness_unlock(tsdn_t *tsdn, witness_t *witness) -{ - tsd_t *tsd; - witness_list_t *witnesses; - - if (!config_debug) - return; - - if (tsdn_null(tsdn)) - return; - tsd = tsdn_tsd(tsdn); - if (witness->rank == WITNESS_RANK_OMIT) - return; - - /* - * Check whether owner before removal, rather than relying on - * witness_assert_owner() to abort, so that unit tests can test this - * function's failure mode without causing undefined behavior. - */ - if (witness_owner(tsd, witness)) { - witnesses = tsd_witnessesp_get(tsd); - ql_remove(witnesses, witness, link); - } else - witness_assert_owner(tsdn, witness); -} -#endif - -#endif /* JEMALLOC_H_INLINES */ -/******************************************************************************/ diff --git a/include/jemalloc/internal/witness_externs.h b/include/jemalloc/internal/witness_externs.h new file mode 100644 index 00000000..dcd987cc --- /dev/null +++ b/include/jemalloc/internal/witness_externs.h @@ -0,0 +1,37 @@ +#ifndef JEMALLOC_INTERNAL_WITNESS_EXTERNS_H +#define JEMALLOC_INTERNAL_WITNESS_EXTERNS_H + +void witness_init(witness_t *witness, const char *name, witness_rank_t rank, + witness_comp_t *comp, void *opaque); +#ifdef JEMALLOC_JET +typedef void (witness_lock_error_t)(const witness_list_t *, const witness_t *); +extern witness_lock_error_t *witness_lock_error; +#else +void witness_lock_error(const witness_list_t *witnesses, + const witness_t *witness); +#endif +#ifdef JEMALLOC_JET +typedef void (witness_owner_error_t)(const witness_t *); +extern witness_owner_error_t *witness_owner_error; +#else +void witness_owner_error(const witness_t *witness); +#endif +#ifdef JEMALLOC_JET +typedef void (witness_not_owner_error_t)(const witness_t *); +extern witness_not_owner_error_t *witness_not_owner_error; +#else +void witness_not_owner_error(const witness_t *witness); +#endif +#ifdef JEMALLOC_JET +typedef void (witness_lockless_error_t)(const witness_list_t *); +extern witness_lockless_error_t *witness_lockless_error; +#else +void witness_lockless_error(const witness_list_t *witnesses); +#endif + +void witnesses_cleanup(tsd_t *tsd); +void witness_prefork(tsd_t *tsd); +void witness_postfork_parent(tsd_t *tsd); +void witness_postfork_child(tsd_t *tsd); + +#endif /* JEMALLOC_INTERNAL_WITNESS_EXTERNS_H */ diff --git a/include/jemalloc/internal/witness_inlines.h b/include/jemalloc/internal/witness_inlines.h new file mode 100644 index 00000000..259aa2e5 --- /dev/null +++ b/include/jemalloc/internal/witness_inlines.h @@ -0,0 +1,163 @@ +#ifndef JEMALLOC_INTERNAL_WITNESS_INLINES_H +#define JEMALLOC_INTERNAL_WITNESS_INLINES_H + +#ifndef JEMALLOC_ENABLE_INLINE +bool witness_owner(tsd_t *tsd, const witness_t *witness); +void witness_assert_owner(tsdn_t *tsdn, const witness_t *witness); +void witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness); +void witness_assert_lockless(tsdn_t *tsdn); +void witness_lock(tsdn_t *tsdn, witness_t *witness); +void witness_unlock(tsdn_t *tsdn, witness_t *witness); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) +/* Helper, not intended for direct use. */ +JEMALLOC_INLINE bool +witness_owner(tsd_t *tsd, const witness_t *witness) +{ + witness_list_t *witnesses; + witness_t *w; + + cassert(config_debug); + + witnesses = tsd_witnessesp_get(tsd); + ql_foreach(w, witnesses, link) { + if (w == witness) + return (true); + } + + return (false); +} + +JEMALLOC_INLINE void +witness_assert_owner(tsdn_t *tsdn, const witness_t *witness) +{ + tsd_t *tsd; + + if (!config_debug) + return; + + if (tsdn_null(tsdn)) + return; + tsd = tsdn_tsd(tsdn); + if (witness->rank == WITNESS_RANK_OMIT) + return; + + if (witness_owner(tsd, witness)) + return; + witness_owner_error(witness); +} + +JEMALLOC_INLINE void +witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness) +{ + tsd_t *tsd; + witness_list_t *witnesses; + witness_t *w; + + if (!config_debug) + return; + + if (tsdn_null(tsdn)) + return; + tsd = tsdn_tsd(tsdn); + if (witness->rank == WITNESS_RANK_OMIT) + return; + + witnesses = tsd_witnessesp_get(tsd); + ql_foreach(w, witnesses, link) { + if (w == witness) + witness_not_owner_error(witness); + } +} + +JEMALLOC_INLINE void +witness_assert_lockless(tsdn_t *tsdn) +{ + tsd_t *tsd; + witness_list_t *witnesses; + witness_t *w; + + if (!config_debug) + return; + + if (tsdn_null(tsdn)) + return; + tsd = tsdn_tsd(tsdn); + + witnesses = tsd_witnessesp_get(tsd); + w = ql_last(witnesses, link); + if (w != NULL) + witness_lockless_error(witnesses); +} + +JEMALLOC_INLINE void +witness_lock(tsdn_t *tsdn, witness_t *witness) +{ + tsd_t *tsd; + witness_list_t *witnesses; + witness_t *w; + + if (!config_debug) + return; + + if (tsdn_null(tsdn)) + return; + tsd = tsdn_tsd(tsdn); + if (witness->rank == WITNESS_RANK_OMIT) + return; + + witness_assert_not_owner(tsdn, witness); + + witnesses = tsd_witnessesp_get(tsd); + w = ql_last(witnesses, link); + if (w == NULL) { + /* No other locks; do nothing. */ + } else if (tsd_witness_fork_get(tsd) && w->rank <= witness->rank) { + /* Forking, and relaxed ranking satisfied. */ + } else if (w->rank > witness->rank) { + /* Not forking, rank order reversal. */ + witness_lock_error(witnesses, witness); + } else if (w->rank == witness->rank && (w->comp == NULL || w->comp != + witness->comp || w->comp(w, w->opaque, witness, witness->opaque) > + 0)) { + /* + * Missing/incompatible comparison function, or comparison + * function indicates rank order reversal. + */ + witness_lock_error(witnesses, witness); + } + + ql_elm_new(witness, link); + ql_tail_insert(witnesses, witness, link); +} + +JEMALLOC_INLINE void +witness_unlock(tsdn_t *tsdn, witness_t *witness) +{ + tsd_t *tsd; + witness_list_t *witnesses; + + if (!config_debug) + return; + + if (tsdn_null(tsdn)) + return; + tsd = tsdn_tsd(tsdn); + if (witness->rank == WITNESS_RANK_OMIT) + return; + + /* + * Check whether owner before removal, rather than relying on + * witness_assert_owner() to abort, so that unit tests can test this + * function's failure mode without causing undefined behavior. + */ + if (witness_owner(tsd, witness)) { + witnesses = tsd_witnessesp_get(tsd); + ql_remove(witnesses, witness, link); + } else + witness_assert_owner(tsdn, witness); +} +#endif + +#endif /* JEMALLOC_INTERNAL_WITNESS_INLINES_H */ diff --git a/include/jemalloc/internal/witness_structs.h b/include/jemalloc/internal/witness_structs.h new file mode 100644 index 00000000..95d19706 --- /dev/null +++ b/include/jemalloc/internal/witness_structs.h @@ -0,0 +1,28 @@ +#ifndef JEMALLOC_INTERNAL_WITNESS_STRUCTS_H +#define JEMALLOC_INTERNAL_WITNESS_STRUCTS_H + +struct witness_s { + /* Name, used for printing lock order reversal messages. */ + const char *name; + + /* + * Witness rank, where 0 is lowest and UINT_MAX is highest. Witnesses + * must be acquired in order of increasing rank. + */ + witness_rank_t rank; + + /* + * If two witnesses are of equal rank and they have the samp comp + * function pointer, it is called as a last attempt to differentiate + * between witnesses of equal rank. + */ + witness_comp_t *comp; + + /* Opaque data, passed to comp(). */ + void *opaque; + + /* Linkage for thread's currently owned locks. */ + ql_elm(witness_t) link; +}; + +#endif /* JEMALLOC_INTERNAL_WITNESS_STRUCTS_H */ diff --git a/include/jemalloc/internal/witness_types.h b/include/jemalloc/internal/witness_types.h new file mode 100644 index 00000000..ef962824 --- /dev/null +++ b/include/jemalloc/internal/witness_types.h @@ -0,0 +1,46 @@ +#ifndef JEMALLOC_INTERNAL_WITNESS_TYPES_H +#define JEMALLOC_INTERNAL_WITNESS_TYPES_H + +typedef struct witness_s witness_t; +typedef unsigned witness_rank_t; +typedef ql_head(witness_t) witness_list_t; +typedef int witness_comp_t (const witness_t *, void *, const witness_t *, + void *); + +/* + * Lock ranks. Witnesses with rank WITNESS_RANK_OMIT are completely ignored by + * the witness machinery. + */ +#define WITNESS_RANK_OMIT 0U + +#define WITNESS_RANK_INIT 1U +#define WITNESS_RANK_CTL 1U +#define WITNESS_RANK_ARENAS 2U + +#define WITNESS_RANK_PROF_DUMP 3U +#define WITNESS_RANK_PROF_BT2GCTX 4U +#define WITNESS_RANK_PROF_TDATAS 5U +#define WITNESS_RANK_PROF_TDATA 6U +#define WITNESS_RANK_PROF_GCTX 7U + +#define WITNESS_RANK_ARENA 8U +#define WITNESS_RANK_ARENA_EXTENTS 9U +#define WITNESS_RANK_ARENA_EXTENT_CACHE 10 + +#define WITNESS_RANK_RTREE_ELM 11U +#define WITNESS_RANK_RTREE 12U +#define WITNESS_RANK_BASE 13U + +#define WITNESS_RANK_LEAF 0xffffffffU +#define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF +#define WITNESS_RANK_ARENA_LARGE WITNESS_RANK_LEAF +#define WITNESS_RANK_DSS WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_ACTIVE WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_DUMP_SEQ WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_GDUMP WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_NEXT_THR_UID WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_THREAD_ACTIVE_INIT WITNESS_RANK_LEAF + +#define WITNESS_INITIALIZER(name, rank) {name, rank, NULL, NULL, {NULL, NULL}} + +#endif /* JEMALLOC_INTERNAL_WITNESS_TYPES_H */ diff --git a/test/include/test/jemalloc_test.h.in b/test/include/test/jemalloc_test.h.in index 66485c0e..2dd0cdea 100644 --- a/test/include/test/jemalloc_test.h.in +++ b/test/include/test/jemalloc_test.h.in @@ -69,18 +69,14 @@ static const bool config_debug = # define JEMALLOC_N(n) @private_namespace@##n # include "jemalloc/internal/private_namespace.h" -# define JEMALLOC_H_TYPES -# define JEMALLOC_H_STRUCTS -# define JEMALLOC_H_EXTERNS -# define JEMALLOC_H_INLINES -# include "jemalloc/internal/nstime.h" -# include "jemalloc/internal/util.h" +# include "jemalloc/internal/nstime_types.h" +# include "jemalloc/internal/nstime_structs.h" +# include "jemalloc/internal/nstime_externs.h" +# include "jemalloc/internal/util_types.h" +# include "jemalloc/internal/util_externs.h" +# include "jemalloc/internal/util_inlines.h" # include "jemalloc/internal/qr.h" # include "jemalloc/internal/ql.h" -# undef JEMALLOC_H_TYPES -# undef JEMALLOC_H_STRUCTS -# undef JEMALLOC_H_EXTERNS -# undef JEMALLOC_H_INLINES /******************************************************************************/ /* -- GitLab From 87e81e609b5d1bd8821d7256208091c546e62c5a Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 13 Jan 2017 10:34:50 -0800 Subject: [PATCH 225/544] Fix indentation. --- src/ckh.c | 6 +++--- src/jemalloc_cpp.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ckh.c b/src/ckh.c index 6f16565f..6f0f1e4d 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -547,10 +547,10 @@ bool ckh_string_keycomp(const void *k1, const void *k2) { - assert(k1 != NULL); - assert(k2 != NULL); + assert(k1 != NULL); + assert(k2 != NULL); - return (strcmp((char *)k1, (char *)k2) ? false : true); + return (strcmp((char *)k1, (char *)k2) ? false : true); } void diff --git a/src/jemalloc_cpp.cpp b/src/jemalloc_cpp.cpp index 4c5756b3..4d88f993 100644 --- a/src/jemalloc_cpp.cpp +++ b/src/jemalloc_cpp.cpp @@ -92,7 +92,7 @@ void * operator new[](std::size_t size, const std::nothrow_t&) noexcept { - return (newImpl(size)); + return (newImpl(size)); } void -- GitLab From ffbb7dac3d669697ab8b39367994a58e0c1fa42d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 13 Jan 2017 10:35:35 -0800 Subject: [PATCH 226/544] Remove leading blank lines from function bodies. This resolves #535. --- include/jemalloc/internal/arena_inlines_a.h | 7 --- include/jemalloc/internal/arena_inlines_b.h | 8 ---- include/jemalloc/internal/atomic_inlines.h | 42 ----------------- include/jemalloc/internal/base_inlines.h | 1 - include/jemalloc/internal/extent_inlines.h | 31 ------------- include/jemalloc/internal/hash_inlines.h | 7 --- .../jemalloc/internal/jemalloc_internal.h.in | 25 ----------- .../internal/jemalloc_internal_decls.h | 1 - include/jemalloc/internal/mutex_inlines.h | 4 -- include/jemalloc/internal/ph.h | 4 -- include/jemalloc/internal/prng_inlines.h | 3 -- include/jemalloc/internal/prof_inlines.h | 6 --- include/jemalloc/internal/rtree_inlines.h | 5 --- include/jemalloc/internal/spin_inlines.h | 1 - include/jemalloc/internal/tcache_inlines.h | 1 - include/jemalloc/internal/ticker_inlines.h | 5 --- include/jemalloc/internal/tsd_inlines.h | 10 ----- include/jemalloc/internal/tsd_types.h | 25 ----------- include/jemalloc/internal/util_inlines.h | 13 ------ include/msvc_compat/strings.h | 1 - src/arena.c | 45 ------------------- src/base.c | 9 ---- src/bitmap.c | 4 -- src/ckh.c | 5 --- src/ctl.c | 13 ------ src/extent.c | 28 ------------ src/extent_dss.c | 5 --- src/extent_mmap.c | 1 - src/jemalloc.c | 27 ----------- src/jemalloc_cpp.cpp | 10 ----- src/large.c | 11 ----- src/mutex.c | 6 --- src/nstime.c | 14 ------ src/pages.c | 9 ---- src/prof.c | 29 ------------ src/rtree.c | 6 --- src/tcache.c | 6 --- src/tsd.c | 7 --- src/util.c | 5 --- src/witness.c | 6 --- src/zone.c | 11 ----- test/include/test/math.h | 1 - test/include/test/mq.h | 1 - test/integration/MALLOCX_ARENA.c | 1 - test/integration/aligned_alloc.c | 2 - test/integration/allocated.c | 2 - test/integration/cpp/basic.cpp | 1 - test/integration/extent.c | 1 - test/integration/mallocx.c | 4 -- test/integration/overflow.c | 1 - test/integration/posix_memalign.c | 2 - test/integration/rallocx.c | 3 -- test/integration/sdallocx.c | 1 - test/integration/thread_arena.c | 1 - test/integration/thread_tcache_enabled.c | 2 - test/integration/xallocx.c | 5 --- test/src/btalloc.c | 1 - test/src/mq.c | 1 - test/src/mtx.c | 4 -- test/src/test.c | 4 -- test/src/thd.c | 3 -- test/src/timer.c | 2 - test/stress/microbench.c | 6 --- test/unit/SFMT.c | 1 - test/unit/a0.c | 1 - test/unit/arena_reset.c | 9 ---- test/unit/atomic.c | 6 --- test/unit/base.c | 1 - test/unit/bitmap.c | 2 - test/unit/ckh.c | 1 - test/unit/decay.c | 3 -- test/unit/extent_quantize.c | 1 - test/unit/fork.c | 1 - test/unit/hash.c | 6 --- test/unit/junk.c | 5 --- test/unit/mallctl.c | 6 --- test/unit/math.c | 1 - test/unit/mq.c | 1 - test/unit/mtx.c | 1 - test/unit/nstime.c | 2 - test/unit/pack.c | 1 - test/unit/pages.c | 1 - test/unit/ph.c | 2 - test/unit/prng.c | 11 ----- test/unit/prof_accum.c | 2 - test/unit/prof_active.c | 6 --- test/unit/prof_gdump.c | 1 - test/unit/prof_idump.c | 1 - test/unit/prof_reset.c | 3 -- test/unit/prof_thread_name.c | 2 - test/unit/ql.c | 1 - test/unit/qr.c | 1 - test/unit/rb.c | 1 - test/unit/rtree.c | 2 - test/unit/size_classes.c | 1 - test/unit/slab.c | 1 - test/unit/smoothstep.c | 1 - test/unit/stats.c | 2 - test/unit/ticker.c | 1 - test/unit/tsd.c | 2 - test/unit/util.c | 4 -- test/unit/witness.c | 7 --- test/unit/zero.c | 3 -- 103 files changed, 611 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_a.h b/include/jemalloc/internal/arena_inlines_a.h index 743727b0..d241b8a1 100644 --- a/include/jemalloc/internal/arena_inlines_a.h +++ b/include/jemalloc/internal/arena_inlines_a.h @@ -16,35 +16,30 @@ bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes); JEMALLOC_INLINE unsigned arena_ind_get(const arena_t *arena) { - return (base_ind_get(arena->base)); } JEMALLOC_INLINE void arena_internal_add(arena_t *arena, size_t size) { - atomic_add_zu(&arena->stats.internal, size); } JEMALLOC_INLINE void arena_internal_sub(arena_t *arena, size_t size) { - atomic_sub_zu(&arena->stats.internal, size); } JEMALLOC_INLINE size_t arena_internal_get(arena_t *arena) { - return (atomic_read_zu(&arena->stats.internal)); } JEMALLOC_INLINE bool arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes) { - cassert(config_prof); assert(prof_interval != 0); @@ -59,7 +54,6 @@ arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes) JEMALLOC_INLINE bool arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes) { - cassert(config_prof); if (likely(prof_interval == 0)) @@ -70,7 +64,6 @@ arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes) JEMALLOC_INLINE bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) { - cassert(config_prof); if (likely(prof_interval == 0)) diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 9068cf4c..94614668 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -33,7 +33,6 @@ arena_bin_index(arena_t *arena, arena_bin_t *bin) JEMALLOC_INLINE prof_tctx_t * arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { - cassert(config_prof); assert(ptr != NULL); @@ -46,7 +45,6 @@ JEMALLOC_INLINE void arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, prof_tctx_t *tctx) { - cassert(config_prof); assert(ptr != NULL); @@ -58,7 +56,6 @@ JEMALLOC_INLINE void arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, prof_tctx_t *tctx) { - cassert(config_prof); assert(ptr != NULL); assert(!extent_slab_get(extent)); @@ -85,7 +82,6 @@ arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) JEMALLOC_ALWAYS_INLINE void arena_decay_tick(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_assert_not_owner(tsdn, &arena->lock); arena_decay_ticks(tsdn, arena, 1); @@ -95,7 +91,6 @@ JEMALLOC_ALWAYS_INLINE void * arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, tcache_t *tcache, bool slow_path) { - assert(!tsdn_null(tsdn) || tcache == NULL); assert(size != 0); @@ -118,7 +113,6 @@ arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, JEMALLOC_ALWAYS_INLINE arena_t * arena_aalloc(tsdn_t *tsdn, const void *ptr) { - return (extent_arena_get(iealloc(tsdn, ptr))); } @@ -142,7 +136,6 @@ JEMALLOC_ALWAYS_INLINE void arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, bool slow_path) { - assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); @@ -176,7 +169,6 @@ JEMALLOC_ALWAYS_INLINE void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, tcache_t *tcache, bool slow_path) { - assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); diff --git a/include/jemalloc/internal/atomic_inlines.h b/include/jemalloc/internal/atomic_inlines.h index de0ac6ac..89d1b354 100644 --- a/include/jemalloc/internal/atomic_inlines.h +++ b/include/jemalloc/internal/atomic_inlines.h @@ -101,7 +101,6 @@ atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) JEMALLOC_INLINE void atomic_write_u64(uint64_t *p, uint64_t x) { - asm volatile ( "xchgq %1, %0;" /* Lock is implied by xchgq. */ : "=m" (*p), "+r" (x) /* Outputs. */ @@ -141,7 +140,6 @@ atomic_write_u64(uint64_t *p, uint64_t x) JEMALLOC_INLINE uint64_t atomic_add_u64(uint64_t *p, uint64_t x) { - /* * atomic_fetchadd_64() doesn't exist, but we only ever use this * function on LP64 systems, so atomic_fetchadd_long() will do. @@ -154,7 +152,6 @@ atomic_add_u64(uint64_t *p, uint64_t x) JEMALLOC_INLINE uint64_t atomic_sub_u64(uint64_t *p, uint64_t x) { - assert(sizeof(uint64_t) == sizeof(unsigned long)); return (atomic_fetchadd_long(p, (unsigned long)(-(long)x)) - x); @@ -163,7 +160,6 @@ atomic_sub_u64(uint64_t *p, uint64_t x) JEMALLOC_INLINE bool atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { - assert(sizeof(uint64_t) == sizeof(unsigned long)); return (!atomic_cmpset_long(p, (unsigned long)c, (unsigned long)s)); @@ -172,7 +168,6 @@ atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) JEMALLOC_INLINE void atomic_write_u64(uint64_t *p, uint64_t x) { - assert(sizeof(uint64_t) == sizeof(unsigned long)); atomic_store_rel_long(p, x); @@ -181,21 +176,18 @@ atomic_write_u64(uint64_t *p, uint64_t x) JEMALLOC_INLINE uint64_t atomic_add_u64(uint64_t *p, uint64_t x) { - return (OSAtomicAdd64((int64_t)x, (int64_t *)p)); } JEMALLOC_INLINE uint64_t atomic_sub_u64(uint64_t *p, uint64_t x) { - return (OSAtomicAdd64(-((int64_t)x), (int64_t *)p)); } JEMALLOC_INLINE bool atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { - return (!OSAtomicCompareAndSwap64(c, s, (int64_t *)p)); } @@ -213,14 +205,12 @@ atomic_write_u64(uint64_t *p, uint64_t x) JEMALLOC_INLINE uint64_t atomic_add_u64(uint64_t *p, uint64_t x) { - return (InterlockedExchangeAdd64(p, x) + x); } JEMALLOC_INLINE uint64_t atomic_sub_u64(uint64_t *p, uint64_t x) { - return (InterlockedExchangeAdd64(p, -((int64_t)x)) - x); } @@ -236,7 +226,6 @@ atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) JEMALLOC_INLINE void atomic_write_u64(uint64_t *p, uint64_t x) { - InterlockedExchange64(p, x); } # elif (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || \ @@ -244,28 +233,24 @@ atomic_write_u64(uint64_t *p, uint64_t x) JEMALLOC_INLINE uint64_t atomic_add_u64(uint64_t *p, uint64_t x) { - return (__sync_add_and_fetch(p, x)); } JEMALLOC_INLINE uint64_t atomic_sub_u64(uint64_t *p, uint64_t x) { - return (__sync_sub_and_fetch(p, x)); } JEMALLOC_INLINE bool atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { - return (!__sync_bool_compare_and_swap(p, c, s)); } JEMALLOC_INLINE void atomic_write_u64(uint64_t *p, uint64_t x) { - __sync_lock_test_and_set(p, x); } # else @@ -325,7 +310,6 @@ atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) JEMALLOC_INLINE void atomic_write_u32(uint32_t *p, uint32_t x) { - asm volatile ( "xchgl %1, %0;" /* Lock is implied by xchgl. */ : "=m" (*p), "+r" (x) /* Outputs. */ @@ -365,49 +349,42 @@ atomic_write_u32(uint32_t *p, uint32_t x) JEMALLOC_INLINE uint32_t atomic_add_u32(uint32_t *p, uint32_t x) { - return (atomic_fetchadd_32(p, x) + x); } JEMALLOC_INLINE uint32_t atomic_sub_u32(uint32_t *p, uint32_t x) { - return (atomic_fetchadd_32(p, (uint32_t)(-(int32_t)x)) - x); } JEMALLOC_INLINE bool atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { - return (!atomic_cmpset_32(p, c, s)); } JEMALLOC_INLINE void atomic_write_u32(uint32_t *p, uint32_t x) { - atomic_store_rel_32(p, x); } #elif (defined(JEMALLOC_OSATOMIC)) JEMALLOC_INLINE uint32_t atomic_add_u32(uint32_t *p, uint32_t x) { - return (OSAtomicAdd32((int32_t)x, (int32_t *)p)); } JEMALLOC_INLINE uint32_t atomic_sub_u32(uint32_t *p, uint32_t x) { - return (OSAtomicAdd32(-((int32_t)x), (int32_t *)p)); } JEMALLOC_INLINE bool atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { - return (!OSAtomicCompareAndSwap32(c, s, (int32_t *)p)); } @@ -425,14 +402,12 @@ atomic_write_u32(uint32_t *p, uint32_t x) JEMALLOC_INLINE uint32_t atomic_add_u32(uint32_t *p, uint32_t x) { - return (InterlockedExchangeAdd(p, x) + x); } JEMALLOC_INLINE uint32_t atomic_sub_u32(uint32_t *p, uint32_t x) { - return (InterlockedExchangeAdd(p, -((int32_t)x)) - x); } @@ -448,7 +423,6 @@ atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) JEMALLOC_INLINE void atomic_write_u32(uint32_t *p, uint32_t x) { - InterlockedExchange(p, x); } #elif (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || \ @@ -456,28 +430,24 @@ atomic_write_u32(uint32_t *p, uint32_t x) JEMALLOC_INLINE uint32_t atomic_add_u32(uint32_t *p, uint32_t x) { - return (__sync_add_and_fetch(p, x)); } JEMALLOC_INLINE uint32_t atomic_sub_u32(uint32_t *p, uint32_t x) { - return (__sync_sub_and_fetch(p, x)); } JEMALLOC_INLINE bool atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { - return (!__sync_bool_compare_and_swap(p, c, s)); } JEMALLOC_INLINE void atomic_write_u32(uint32_t *p, uint32_t x) { - __sync_lock_test_and_set(p, x); } #else @@ -489,7 +459,6 @@ atomic_write_u32(uint32_t *p, uint32_t x) JEMALLOC_INLINE void * atomic_add_p(void **p, void *x) { - #if (LG_SIZEOF_PTR == 3) return ((void *)atomic_add_u64((uint64_t *)p, (uint64_t)x)); #elif (LG_SIZEOF_PTR == 2) @@ -500,7 +469,6 @@ atomic_add_p(void **p, void *x) JEMALLOC_INLINE void * atomic_sub_p(void **p, void *x) { - #if (LG_SIZEOF_PTR == 3) return ((void *)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x))); #elif (LG_SIZEOF_PTR == 2) @@ -511,7 +479,6 @@ atomic_sub_p(void **p, void *x) JEMALLOC_INLINE bool atomic_cas_p(void **p, void *c, void *s) { - #if (LG_SIZEOF_PTR == 3) return (atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); #elif (LG_SIZEOF_PTR == 2) @@ -522,7 +489,6 @@ atomic_cas_p(void **p, void *c, void *s) JEMALLOC_INLINE void atomic_write_p(void **p, const void *x) { - #if (LG_SIZEOF_PTR == 3) atomic_write_u64((uint64_t *)p, (uint64_t)x); #elif (LG_SIZEOF_PTR == 2) @@ -535,7 +501,6 @@ atomic_write_p(void **p, const void *x) JEMALLOC_INLINE size_t atomic_add_zu(size_t *p, size_t x) { - #if (LG_SIZEOF_PTR == 3) return ((size_t)atomic_add_u64((uint64_t *)p, (uint64_t)x)); #elif (LG_SIZEOF_PTR == 2) @@ -546,7 +511,6 @@ atomic_add_zu(size_t *p, size_t x) JEMALLOC_INLINE size_t atomic_sub_zu(size_t *p, size_t x) { - #if (LG_SIZEOF_PTR == 3) return ((size_t)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x))); #elif (LG_SIZEOF_PTR == 2) @@ -557,7 +521,6 @@ atomic_sub_zu(size_t *p, size_t x) JEMALLOC_INLINE bool atomic_cas_zu(size_t *p, size_t c, size_t s) { - #if (LG_SIZEOF_PTR == 3) return (atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); #elif (LG_SIZEOF_PTR == 2) @@ -568,7 +531,6 @@ atomic_cas_zu(size_t *p, size_t c, size_t s) JEMALLOC_INLINE void atomic_write_zu(size_t *p, size_t x) { - #if (LG_SIZEOF_PTR == 3) atomic_write_u64((uint64_t *)p, (uint64_t)x); #elif (LG_SIZEOF_PTR == 2) @@ -581,7 +543,6 @@ atomic_write_zu(size_t *p, size_t x) JEMALLOC_INLINE unsigned atomic_add_u(unsigned *p, unsigned x) { - #if (LG_SIZEOF_INT == 3) return ((unsigned)atomic_add_u64((uint64_t *)p, (uint64_t)x)); #elif (LG_SIZEOF_INT == 2) @@ -592,7 +553,6 @@ atomic_add_u(unsigned *p, unsigned x) JEMALLOC_INLINE unsigned atomic_sub_u(unsigned *p, unsigned x) { - #if (LG_SIZEOF_INT == 3) return ((unsigned)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x))); @@ -605,7 +565,6 @@ atomic_sub_u(unsigned *p, unsigned x) JEMALLOC_INLINE bool atomic_cas_u(unsigned *p, unsigned c, unsigned s) { - #if (LG_SIZEOF_INT == 3) return (atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); #elif (LG_SIZEOF_INT == 2) @@ -616,7 +575,6 @@ atomic_cas_u(unsigned *p, unsigned c, unsigned s) JEMALLOC_INLINE void atomic_write_u(unsigned *p, unsigned x) { - #if (LG_SIZEOF_INT == 3) atomic_write_u64((uint64_t *)p, (uint64_t)x); #elif (LG_SIZEOF_INT == 2) diff --git a/include/jemalloc/internal/base_inlines.h b/include/jemalloc/internal/base_inlines.h index f882bcde..63547d65 100644 --- a/include/jemalloc/internal/base_inlines.h +++ b/include/jemalloc/internal/base_inlines.h @@ -9,7 +9,6 @@ unsigned base_ind_get(const base_t *base); JEMALLOC_INLINE unsigned base_ind_get(const base_t *base) { - return (base->ind); } #endif diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index e48af92f..87e0bcd0 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -55,14 +55,12 @@ extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent) JEMALLOC_INLINE arena_t * extent_arena_get(const extent_t *extent) { - return (extent->e_arena); } JEMALLOC_INLINE void * extent_base_get(const extent_t *extent) { - assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || !extent->e_slab); return (PAGE_ADDR2BASE(extent->e_addr)); @@ -71,7 +69,6 @@ extent_base_get(const extent_t *extent) JEMALLOC_INLINE void * extent_addr_get(const extent_t *extent) { - assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || !extent->e_slab); return (extent->e_addr); @@ -80,14 +77,12 @@ extent_addr_get(const extent_t *extent) JEMALLOC_INLINE size_t extent_size_get(const extent_t *extent) { - return (extent->e_size); } JEMALLOC_INLINE size_t extent_usize_get(const extent_t *extent) { - assert(!extent->e_slab); return (extent->e_usize); } @@ -95,14 +90,12 @@ extent_usize_get(const extent_t *extent) JEMALLOC_INLINE void * extent_before_get(const extent_t *extent) { - return ((void *)((uintptr_t)extent_base_get(extent) - PAGE)); } JEMALLOC_INLINE void * extent_last_get(const extent_t *extent) { - return ((void *)((uintptr_t)extent_base_get(extent) + extent_size_get(extent) - PAGE)); } @@ -110,7 +103,6 @@ extent_last_get(const extent_t *extent) JEMALLOC_INLINE void * extent_past_get(const extent_t *extent) { - return ((void *)((uintptr_t)extent_base_get(extent) + extent_size_get(extent))); } @@ -118,49 +110,42 @@ extent_past_get(const extent_t *extent) JEMALLOC_INLINE size_t extent_sn_get(const extent_t *extent) { - return (extent->e_sn); } JEMALLOC_INLINE bool extent_active_get(const extent_t *extent) { - return (extent->e_active); } JEMALLOC_INLINE bool extent_retained_get(const extent_t *extent) { - return (qr_next(extent, qr_link) == extent); } JEMALLOC_INLINE bool extent_zeroed_get(const extent_t *extent) { - return (extent->e_zeroed); } JEMALLOC_INLINE bool extent_committed_get(const extent_t *extent) { - return (extent->e_committed); } JEMALLOC_INLINE bool extent_slab_get(const extent_t *extent) { - return (extent->e_slab); } JEMALLOC_INLINE arena_slab_data_t * extent_slab_data_get(extent_t *extent) { - assert(extent->e_slab); return (&extent->e_slab_data); } @@ -168,7 +153,6 @@ extent_slab_data_get(extent_t *extent) JEMALLOC_INLINE const arena_slab_data_t * extent_slab_data_get_const(const extent_t *extent) { - assert(extent->e_slab); return (&extent->e_slab_data); } @@ -176,7 +160,6 @@ extent_slab_data_get_const(const extent_t *extent) JEMALLOC_INLINE prof_tctx_t * extent_prof_tctx_get(const extent_t *extent) { - return ((prof_tctx_t *)atomic_read_p( &((extent_t *)extent)->e_prof_tctx_pun)); } @@ -184,21 +167,18 @@ extent_prof_tctx_get(const extent_t *extent) JEMALLOC_INLINE void extent_arena_set(extent_t *extent, arena_t *arena) { - extent->e_arena = arena; } JEMALLOC_INLINE void extent_addr_set(extent_t *extent, void *addr) { - extent->e_addr = addr; } JEMALLOC_INLINE void extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment) { - assert(extent_base_get(extent) == extent_addr_get(extent)); if (alignment < PAGE) { @@ -219,56 +199,48 @@ extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment) JEMALLOC_INLINE void extent_size_set(extent_t *extent, size_t size) { - extent->e_size = size; } JEMALLOC_INLINE void extent_usize_set(extent_t *extent, size_t usize) { - extent->e_usize = usize; } JEMALLOC_INLINE void extent_sn_set(extent_t *extent, size_t sn) { - extent->e_sn = sn; } JEMALLOC_INLINE void extent_active_set(extent_t *extent, bool active) { - extent->e_active = active; } JEMALLOC_INLINE void extent_zeroed_set(extent_t *extent, bool zeroed) { - extent->e_zeroed = zeroed; } JEMALLOC_INLINE void extent_committed_set(extent_t *extent, bool committed) { - extent->e_committed = committed; } JEMALLOC_INLINE void extent_slab_set(extent_t *extent, bool slab) { - extent->e_slab = slab; } JEMALLOC_INLINE void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) { - atomic_write_p(&extent->e_prof_tctx_pun, tctx); } @@ -277,7 +249,6 @@ extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, size_t usize, size_t sn, bool active, bool zeroed, bool committed, bool slab) { - assert(addr == PAGE_ADDR2BASE(addr) || !slab); extent_arena_set(extent, arena); @@ -297,14 +268,12 @@ extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, JEMALLOC_INLINE void extent_ring_insert(extent_t *sentinel, extent_t *extent) { - qr_meld(sentinel, extent, extent_t, qr_link); } JEMALLOC_INLINE void extent_ring_remove(extent_t *extent) { - qr_remove(extent, qr_link); } diff --git a/include/jemalloc/internal/hash_inlines.h b/include/jemalloc/internal/hash_inlines.h index 0340418e..4bb78505 100644 --- a/include/jemalloc/internal/hash_inlines.h +++ b/include/jemalloc/internal/hash_inlines.h @@ -23,21 +23,18 @@ void hash(const void *key, size_t len, const uint32_t seed, JEMALLOC_INLINE uint32_t hash_rotl_32(uint32_t x, int8_t r) { - return ((x << r) | (x >> (32 - r))); } JEMALLOC_INLINE uint64_t hash_rotl_64(uint64_t x, int8_t r) { - return ((x << r) | (x >> (64 - r))); } JEMALLOC_INLINE uint32_t hash_get_block_32(const uint32_t *p, int i) { - /* Handle unaligned read. */ if (unlikely((uintptr_t)p & (sizeof(uint32_t)-1)) != 0) { uint32_t ret; @@ -52,7 +49,6 @@ hash_get_block_32(const uint32_t *p, int i) JEMALLOC_INLINE uint64_t hash_get_block_64(const uint64_t *p, int i) { - /* Handle unaligned read. */ if (unlikely((uintptr_t)p & (sizeof(uint64_t)-1)) != 0) { uint64_t ret; @@ -67,7 +63,6 @@ hash_get_block_64(const uint64_t *p, int i) JEMALLOC_INLINE uint32_t hash_fmix_32(uint32_t h) { - h ^= h >> 16; h *= 0x85ebca6b; h ^= h >> 13; @@ -80,7 +75,6 @@ hash_fmix_32(uint32_t h) JEMALLOC_INLINE uint64_t hash_fmix_64(uint64_t k) { - k ^= k >> 33; k *= KQU(0xff51afd7ed558ccd); k ^= k >> 33; @@ -326,7 +320,6 @@ hash_x64_128(const void *key, const int len, const uint32_t seed, JEMALLOC_INLINE void hash(const void *key, size_t len, const uint32_t seed, size_t r_hash[2]) { - assert(len <= INT_MAX); /* Unfortunate implementation limitation. */ #if (LG_SIZEOF_PTR == 3 && !defined(JEMALLOC_BIG_ENDIAN)) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index dfbb4b6d..00dce68d 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -553,7 +553,6 @@ ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind); JEMALLOC_ALWAYS_INLINE pszind_t psz2ind(size_t psz) { - if (unlikely(psz > LARGE_MAXCLASS)) return (NPSIZES); { @@ -577,7 +576,6 @@ psz2ind(size_t psz) JEMALLOC_INLINE size_t pind2sz_compute(pszind_t pind) { - if (unlikely(pind == NPSIZES)) return (LARGE_MAXCLASS + PAGE); { @@ -608,7 +606,6 @@ pind2sz_lookup(pszind_t pind) JEMALLOC_INLINE size_t pind2sz(pszind_t pind) { - assert(pind < NPSIZES+1); return (pind2sz_lookup(pind)); } @@ -616,7 +613,6 @@ pind2sz(pszind_t pind) JEMALLOC_INLINE size_t psz2u(size_t psz) { - if (unlikely(psz > LARGE_MAXCLASS)) return (LARGE_MAXCLASS + PAGE); { @@ -633,7 +629,6 @@ psz2u(size_t psz) JEMALLOC_INLINE szind_t size2index_compute(size_t size) { - if (unlikely(size > LARGE_MAXCLASS)) return (NSIZES); #if (NTBINS != 0) @@ -664,7 +659,6 @@ size2index_compute(size_t size) JEMALLOC_ALWAYS_INLINE szind_t size2index_lookup(size_t size) { - assert(size <= LOOKUP_MAXCLASS); { szind_t ret = (size2index_tab[(size-1) >> LG_TINY_MIN]); @@ -676,7 +670,6 @@ size2index_lookup(size_t size) JEMALLOC_ALWAYS_INLINE szind_t size2index(size_t size) { - assert(size > 0); if (likely(size <= LOOKUP_MAXCLASS)) return (size2index_lookup(size)); @@ -686,7 +679,6 @@ size2index(size_t size) JEMALLOC_INLINE size_t index2size_compute(szind_t index) { - #if (NTBINS > 0) if (index < NTBINS) return (ZU(1) << (LG_TINY_MAXCLASS - NTBINS + 1 + index)); @@ -721,7 +713,6 @@ index2size_lookup(szind_t index) JEMALLOC_ALWAYS_INLINE size_t index2size(szind_t index) { - assert(index < NSIZES); return (index2size_lookup(index)); } @@ -729,7 +720,6 @@ index2size(szind_t index) JEMALLOC_ALWAYS_INLINE size_t s2u_compute(size_t size) { - if (unlikely(size > LARGE_MAXCLASS)) return (0); #if (NTBINS > 0) @@ -767,7 +757,6 @@ s2u_lookup(size_t size) JEMALLOC_ALWAYS_INLINE size_t s2u(size_t size) { - assert(size > 0); if (likely(size <= LOOKUP_MAXCLASS)) return (s2u_lookup(size)); @@ -852,14 +841,12 @@ arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) JEMALLOC_INLINE arena_t * arena_choose(tsd_t *tsd, arena_t *arena) { - return (arena_choose_impl(tsd, arena, false)); } JEMALLOC_INLINE arena_t * arena_ichoose(tsd_t *tsd, arena_t *arena) { - return (arena_choose_impl(tsd, arena, true)); } @@ -933,7 +920,6 @@ extent_t *iealloc(tsdn_t *tsdn, const void *ptr); JEMALLOC_ALWAYS_INLINE extent_t * iealloc(tsdn_t *tsdn, const void *ptr) { - return (extent_lookup(tsdn, ptr, true)); } #endif @@ -975,7 +961,6 @@ bool ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, JEMALLOC_ALWAYS_INLINE arena_t * iaalloc(tsdn_t *tsdn, const void *ptr) { - assert(ptr != NULL); return (arena_aalloc(tsdn, ptr)); @@ -991,7 +976,6 @@ iaalloc(tsdn_t *tsdn, const void *ptr) JEMALLOC_ALWAYS_INLINE size_t isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { - assert(ptr != NULL); return (arena_salloc(tsdn, extent, ptr)); @@ -1019,7 +1003,6 @@ iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, JEMALLOC_ALWAYS_INLINE void * ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, bool slow_path) { - return (iallocztm(tsd_tsdn(tsd), size, ind, zero, tcache_get(tsd, true), false, NULL, slow_path)); } @@ -1049,14 +1032,12 @@ JEMALLOC_ALWAYS_INLINE void * ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) { - return (ipallocztm(tsdn, usize, alignment, zero, tcache, false, arena)); } JEMALLOC_ALWAYS_INLINE void * ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero) { - return (ipallocztm(tsd_tsdn(tsd), usize, alignment, zero, tcache_get(tsd, true), false, NULL)); } @@ -1088,7 +1069,6 @@ JEMALLOC_ALWAYS_INLINE void idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, bool is_internal, bool slow_path) { - assert(ptr != NULL); assert(!is_internal || tcache == NULL); assert(!is_internal || arena_ind_get(iaalloc(tsdn, ptr)) < @@ -1104,7 +1084,6 @@ idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, JEMALLOC_ALWAYS_INLINE void idalloc(tsd_t *tsd, extent_t *extent, void *ptr) { - idalloctm(tsd_tsdn(tsd), extent, ptr, tcache_get(tsd, false), false, true); } @@ -1113,7 +1092,6 @@ JEMALLOC_ALWAYS_INLINE void isdalloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, tcache_t *tcache, bool slow_path) { - arena_sdalloc(tsdn, extent, ptr, size, tcache, slow_path); } @@ -1154,7 +1132,6 @@ JEMALLOC_ALWAYS_INLINE void * iralloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) { - assert(ptr != NULL); assert(size != 0); @@ -1176,7 +1153,6 @@ JEMALLOC_ALWAYS_INLINE void * iralloc(tsd_t *tsd, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero) { - return (iralloct(tsd_tsdn(tsd), extent, ptr, oldsize, size, alignment, zero, tcache_get(tsd, true), NULL)); } @@ -1185,7 +1161,6 @@ JEMALLOC_ALWAYS_INLINE bool ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t extra, size_t alignment, bool zero) { - assert(ptr != NULL); assert(size != 0); diff --git a/include/jemalloc/internal/jemalloc_internal_decls.h b/include/jemalloc/internal/jemalloc_internal_decls.h index c907d910..277027f0 100644 --- a/include/jemalloc/internal/jemalloc_internal_decls.h +++ b/include/jemalloc/internal/jemalloc_internal_decls.h @@ -63,7 +63,6 @@ typedef intptr_t ssize_t; static int isblank(int c) { - return (c == '\t' || c == ' '); } #endif diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index b769f0ca..d65fa13c 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -12,7 +12,6 @@ void malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); JEMALLOC_INLINE void malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) { - if (isthreaded) { witness_assert_not_owner(tsdn, &mutex->witness); #ifdef _WIN32 @@ -35,7 +34,6 @@ malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) JEMALLOC_INLINE void malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) { - if (isthreaded) { witness_unlock(tsdn, &mutex->witness); #ifdef _WIN32 @@ -57,7 +55,6 @@ malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) JEMALLOC_INLINE void malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { - if (isthreaded) witness_assert_owner(tsdn, &mutex->witness); } @@ -65,7 +62,6 @@ malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) JEMALLOC_INLINE void malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { - if (isthreaded) witness_assert_not_owner(tsdn, &mutex->witness); } diff --git a/include/jemalloc/internal/ph.h b/include/jemalloc/internal/ph.h index 4f91c333..9efb7b74 100644 --- a/include/jemalloc/internal/ph.h +++ b/include/jemalloc/internal/ph.h @@ -207,19 +207,16 @@ a_attr void a_prefix##remove(a_ph_type *ph, a_type *phn); a_attr void \ a_prefix##new(a_ph_type *ph) \ { \ - \ memset(ph, 0, sizeof(ph(a_type))); \ } \ a_attr bool \ a_prefix##empty(a_ph_type *ph) \ { \ - \ return (ph->ph_root == NULL); \ } \ a_attr a_type * \ a_prefix##first(a_ph_type *ph) \ { \ - \ if (ph->ph_root == NULL) \ return (NULL); \ ph_merge_aux(a_type, a_field, ph, a_cmp); \ @@ -228,7 +225,6 @@ a_prefix##first(a_ph_type *ph) \ a_attr void \ a_prefix##insert(a_ph_type *ph, a_type *phn) \ { \ - \ memset(&phn->a_field, 0, sizeof(phn(a_type))); \ \ /* \ diff --git a/include/jemalloc/internal/prng_inlines.h b/include/jemalloc/internal/prng_inlines.h index b82a6620..8cc19ce8 100644 --- a/include/jemalloc/internal/prng_inlines.h +++ b/include/jemalloc/internal/prng_inlines.h @@ -20,21 +20,18 @@ size_t prng_range_zu(size_t *state, size_t range, bool atomic); JEMALLOC_ALWAYS_INLINE uint32_t prng_state_next_u32(uint32_t state) { - return ((state * PRNG_A_32) + PRNG_C_32); } JEMALLOC_ALWAYS_INLINE uint64_t prng_state_next_u64(uint64_t state) { - return ((state * PRNG_A_64) + PRNG_C_64); } JEMALLOC_ALWAYS_INLINE size_t prng_state_next_zu(size_t state) { - #if LG_SIZEOF_PTR == 2 return ((state * PRNG_A_32) + PRNG_C_32); #elif LG_SIZEOF_PTR == 3 diff --git a/include/jemalloc/internal/prof_inlines.h b/include/jemalloc/internal/prof_inlines.h index 0b580425..a1ea7a32 100644 --- a/include/jemalloc/internal/prof_inlines.h +++ b/include/jemalloc/internal/prof_inlines.h @@ -29,7 +29,6 @@ void prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, JEMALLOC_ALWAYS_INLINE bool prof_active_get_unlocked(void) { - /* * Even if opt_prof is true, sampling can be temporarily disabled by * setting prof_active to false. No locking is used when reading @@ -42,7 +41,6 @@ prof_active_get_unlocked(void) JEMALLOC_ALWAYS_INLINE bool prof_gdump_get_unlocked(void) { - /* * No locking is used when reading prof_gdump_val in the fast path, so * there are no guarantees regarding how long it will take for all @@ -78,7 +76,6 @@ prof_tdata_get(tsd_t *tsd, bool create) JEMALLOC_ALWAYS_INLINE prof_tctx_t * prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { - cassert(config_prof); assert(ptr != NULL); @@ -89,7 +86,6 @@ JEMALLOC_ALWAYS_INLINE void prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, prof_tctx_t *tctx) { - cassert(config_prof); assert(ptr != NULL); @@ -100,7 +96,6 @@ JEMALLOC_ALWAYS_INLINE void prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, prof_tctx_t *tctx) { - cassert(config_prof); assert(ptr != NULL); @@ -162,7 +157,6 @@ JEMALLOC_ALWAYS_INLINE void prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, prof_tctx_t *tctx) { - cassert(config_prof); assert(ptr != NULL); assert(usize == isalloc(tsdn, extent, ptr)); diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 7efba54d..7e79a6a0 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -74,7 +74,6 @@ rtree_ctx_start_level(const rtree_t *rtree, const rtree_ctx_t *rtree_ctx, JEMALLOC_ALWAYS_INLINE uintptr_t rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level) { - return ((key >> ((ZU(1) << (LG_SIZEOF_PTR+3)) - rtree->levels[level].cumbits)) & ((ZU(1) << rtree->levels[level].bits) - 1)); @@ -83,7 +82,6 @@ rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level) JEMALLOC_ALWAYS_INLINE bool rtree_node_valid(rtree_elm_t *node) { - return ((uintptr_t)node != (uintptr_t)0); } @@ -144,7 +142,6 @@ rtree_elm_read(rtree_elm_t *elm, bool dependent) JEMALLOC_INLINE void rtree_elm_write(rtree_elm_t *elm, const extent_t *extent) { - atomic_write_p(&elm->pun, extent); } @@ -408,7 +405,6 @@ JEMALLOC_INLINE void rtree_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm, const extent_t *extent) { - assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); assert(((uintptr_t)elm->pun & (uintptr_t)0x1) == (uintptr_t)0x1); @@ -422,7 +418,6 @@ rtree_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm, JEMALLOC_INLINE void rtree_elm_release(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm) { - rtree_elm_write(elm, rtree_elm_read_acquired(tsdn, rtree, elm)); if (config_debug) rtree_elm_witness_release(tsdn, rtree, elm); diff --git a/include/jemalloc/internal/spin_inlines.h b/include/jemalloc/internal/spin_inlines.h index b10f67e7..b4e779f8 100644 --- a/include/jemalloc/internal/spin_inlines.h +++ b/include/jemalloc/internal/spin_inlines.h @@ -10,7 +10,6 @@ void spin_adaptive(spin_t *spin); JEMALLOC_INLINE void spin_init(spin_t *spin) { - spin->iteration = 0; } diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index e522d9e6..2762b0e2 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -88,7 +88,6 @@ tcache_get(tsd_t *tsd, bool create) JEMALLOC_ALWAYS_INLINE void tcache_event(tsd_t *tsd, tcache_t *tcache) { - if (TCACHE_GC_INCR == 0) return; diff --git a/include/jemalloc/internal/ticker_inlines.h b/include/jemalloc/internal/ticker_inlines.h index 42f37eb2..1a4395f3 100644 --- a/include/jemalloc/internal/ticker_inlines.h +++ b/include/jemalloc/internal/ticker_inlines.h @@ -13,7 +13,6 @@ bool ticker_tick(ticker_t *ticker); JEMALLOC_INLINE void ticker_init(ticker_t *ticker, int32_t nticks) { - ticker->tick = nticks; ticker->nticks = nticks; } @@ -21,21 +20,18 @@ ticker_init(ticker_t *ticker, int32_t nticks) JEMALLOC_INLINE void ticker_copy(ticker_t *ticker, const ticker_t *other) { - *ticker = *other; } JEMALLOC_INLINE int32_t ticker_read(const ticker_t *ticker) { - return (ticker->tick); } JEMALLOC_INLINE bool ticker_ticks(ticker_t *ticker, int32_t nticks) { - if (unlikely(ticker->tick < nticks)) { ticker->tick = ticker->nticks; return (true); @@ -47,7 +43,6 @@ ticker_ticks(ticker_t *ticker, int32_t nticks) JEMALLOC_INLINE bool ticker_tick(ticker_t *ticker) { - return (ticker_ticks(ticker, 1)); } #endif diff --git a/include/jemalloc/internal/tsd_inlines.h b/include/jemalloc/internal/tsd_inlines.h index ad915d1a..0df21ad6 100644 --- a/include/jemalloc/internal/tsd_inlines.h +++ b/include/jemalloc/internal/tsd_inlines.h @@ -51,21 +51,18 @@ tsd_fetch_impl(bool init) JEMALLOC_ALWAYS_INLINE tsd_t * tsd_fetch(void) { - return (tsd_fetch_impl(true)); } JEMALLOC_ALWAYS_INLINE tsdn_t * tsd_tsdn(tsd_t *tsd) { - return ((tsdn_t *)tsd); } JEMALLOC_INLINE bool tsd_nominal(tsd_t *tsd) { - return (tsd->state == tsd_state_nominal); } @@ -73,21 +70,18 @@ tsd_nominal(tsd_t *tsd) JEMALLOC_ALWAYS_INLINE t * \ tsd_##n##p_get(tsd_t *tsd) \ { \ - \ return (&tsd->n); \ } \ \ JEMALLOC_ALWAYS_INLINE t \ tsd_##n##_get(tsd_t *tsd) \ { \ - \ return (*tsd_##n##p_get(tsd)); \ } \ \ JEMALLOC_ALWAYS_INLINE void \ tsd_##n##_set(tsd_t *tsd, t n) \ { \ - \ assert(tsd->state == tsd_state_nominal); \ tsd->n = n; \ } @@ -97,7 +91,6 @@ MALLOC_TSD JEMALLOC_ALWAYS_INLINE tsdn_t * tsdn_fetch(void) { - if (!tsd_booted_get()) return (NULL); @@ -107,14 +100,12 @@ tsdn_fetch(void) JEMALLOC_ALWAYS_INLINE bool tsdn_null(const tsdn_t *tsdn) { - return (tsdn == NULL); } JEMALLOC_ALWAYS_INLINE tsd_t * tsdn_tsd(tsdn_t *tsdn) { - assert(!tsdn_null(tsdn)); return (&tsdn->tsd); @@ -123,7 +114,6 @@ tsdn_tsd(tsdn_t *tsdn) JEMALLOC_ALWAYS_INLINE rtree_ctx_t * tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback) { - /* * If tsd cannot be accessed, initialize the fallback rtree_ctx and * return a pointer to it. diff --git a/include/jemalloc/internal/tsd_types.h b/include/jemalloc/internal/tsd_types.h index b48eaeca..17e3da9f 100644 --- a/include/jemalloc/internal/tsd_types.h +++ b/include/jemalloc/internal/tsd_types.h @@ -177,7 +177,6 @@ a_attr bool a_name##tsd_booted = false; a_attr bool \ a_name##tsd_cleanup_wrapper(void) \ { \ - \ if (a_name##tsd_initialized) { \ a_name##tsd_initialized = false; \ a_cleanup(&a_name##tsd_tls); \ @@ -187,7 +186,6 @@ a_name##tsd_cleanup_wrapper(void) \ a_attr bool \ a_name##tsd_boot0(void) \ { \ - \ if (a_cleanup != malloc_tsd_no_cleanup) { \ malloc_tsd_cleanup_register( \ &a_name##tsd_cleanup_wrapper); \ @@ -198,39 +196,33 @@ a_name##tsd_boot0(void) \ a_attr void \ a_name##tsd_boot1(void) \ { \ - \ /* Do nothing. */ \ } \ a_attr bool \ a_name##tsd_boot(void) \ { \ - \ return (a_name##tsd_boot0()); \ } \ a_attr bool \ a_name##tsd_booted_get(void) \ { \ - \ return (a_name##tsd_booted); \ } \ a_attr bool \ a_name##tsd_get_allocates(void) \ { \ - \ return (false); \ } \ /* Get/set. */ \ a_attr a_type * \ a_name##tsd_get(bool init) \ { \ - \ assert(a_name##tsd_booted); \ return (&a_name##tsd_tls); \ } \ a_attr void \ a_name##tsd_set(a_type *val) \ { \ - \ assert(a_name##tsd_booted); \ if (likely(&a_name##tsd_tls != val)) \ a_name##tsd_tls = (*val); \ @@ -244,7 +236,6 @@ a_name##tsd_set(a_type *val) \ a_attr bool \ a_name##tsd_boot0(void) \ { \ - \ if (a_cleanup != malloc_tsd_no_cleanup) { \ if (pthread_key_create(&a_name##tsd_tsd, a_cleanup) != \ 0) \ @@ -256,39 +247,33 @@ a_name##tsd_boot0(void) \ a_attr void \ a_name##tsd_boot1(void) \ { \ - \ /* Do nothing. */ \ } \ a_attr bool \ a_name##tsd_boot(void) \ { \ - \ return (a_name##tsd_boot0()); \ } \ a_attr bool \ a_name##tsd_booted_get(void) \ { \ - \ return (a_name##tsd_booted); \ } \ a_attr bool \ a_name##tsd_get_allocates(void) \ { \ - \ return (false); \ } \ /* Get/set. */ \ a_attr a_type * \ a_name##tsd_get(bool init) \ { \ - \ assert(a_name##tsd_booted); \ return (&a_name##tsd_tls); \ } \ a_attr void \ a_name##tsd_set(a_type *val) \ { \ - \ assert(a_name##tsd_booted); \ if (likely(&a_name##tsd_tls != val)) \ a_name##tsd_tls = (*val); \ @@ -331,7 +316,6 @@ a_name##tsd_cleanup_wrapper(void) \ a_attr void \ a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \ { \ - \ if (!TlsSetValue(a_name##tsd_tsd, (void *)wrapper)) { \ malloc_write(": Error setting" \ " TSD for "#a_name"\n"); \ @@ -364,7 +348,6 @@ a_name##tsd_wrapper_get(bool init) \ a_attr bool \ a_name##tsd_boot0(void) \ { \ - \ a_name##tsd_tsd = TlsAlloc(); \ if (a_name##tsd_tsd == TLS_OUT_OF_INDEXES) \ return (true); \ @@ -394,7 +377,6 @@ a_name##tsd_boot1(void) \ a_attr bool \ a_name##tsd_boot(void) \ { \ - \ if (a_name##tsd_boot0()) \ return (true); \ a_name##tsd_boot1(); \ @@ -403,13 +385,11 @@ a_name##tsd_boot(void) \ a_attr bool \ a_name##tsd_booted_get(void) \ { \ - \ return (a_name##tsd_booted); \ } \ a_attr bool \ a_name##tsd_get_allocates(void) \ { \ - \ return (true); \ } \ /* Get/set. */ \ @@ -466,7 +446,6 @@ a_name##tsd_cleanup_wrapper(void *arg) \ a_attr void \ a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \ { \ - \ if (pthread_setspecific(a_name##tsd_tsd, \ (void *)wrapper)) { \ malloc_write(": Error setting" \ @@ -506,7 +485,6 @@ a_name##tsd_wrapper_get(bool init) \ a_attr bool \ a_name##tsd_boot0(void) \ { \ - \ if (pthread_key_create(&a_name##tsd_tsd, \ a_name##tsd_cleanup_wrapper) != 0) \ return (true); \ @@ -532,7 +510,6 @@ a_name##tsd_boot1(void) \ a_attr bool \ a_name##tsd_boot(void) \ { \ - \ if (a_name##tsd_boot0()) \ return (true); \ a_name##tsd_boot1(); \ @@ -541,13 +518,11 @@ a_name##tsd_boot(void) \ a_attr bool \ a_name##tsd_booted_get(void) \ { \ - \ return (a_name##tsd_booted); \ } \ a_attr bool \ a_name##tsd_get_allocates(void) \ { \ - \ return (true); \ } \ /* Get/set. */ \ diff --git a/include/jemalloc/internal/util_inlines.h b/include/jemalloc/internal/util_inlines.h index 93f5b1de..4ceed06b 100644 --- a/include/jemalloc/internal/util_inlines.h +++ b/include/jemalloc/internal/util_inlines.h @@ -27,28 +27,24 @@ int get_errno(void); JEMALLOC_ALWAYS_INLINE unsigned ffs_llu(unsigned long long bitmap) { - return (JEMALLOC_INTERNAL_FFSLL(bitmap)); } JEMALLOC_ALWAYS_INLINE unsigned ffs_lu(unsigned long bitmap) { - return (JEMALLOC_INTERNAL_FFSL(bitmap)); } JEMALLOC_ALWAYS_INLINE unsigned ffs_u(unsigned bitmap) { - return (JEMALLOC_INTERNAL_FFS(bitmap)); } JEMALLOC_ALWAYS_INLINE unsigned ffs_zu(size_t bitmap) { - #if LG_SIZEOF_PTR == LG_SIZEOF_INT return (ffs_u(bitmap)); #elif LG_SIZEOF_PTR == LG_SIZEOF_LONG @@ -63,7 +59,6 @@ ffs_zu(size_t bitmap) JEMALLOC_ALWAYS_INLINE unsigned ffs_u64(uint64_t bitmap) { - #if LG_SIZEOF_LONG == 3 return (ffs_lu(bitmap)); #elif LG_SIZEOF_LONG_LONG == 3 @@ -76,7 +71,6 @@ ffs_u64(uint64_t bitmap) JEMALLOC_ALWAYS_INLINE unsigned ffs_u32(uint32_t bitmap) { - #if LG_SIZEOF_INT == 2 return (ffs_u(bitmap)); #else @@ -88,7 +82,6 @@ ffs_u32(uint32_t bitmap) JEMALLOC_INLINE uint64_t pow2_ceil_u64(uint64_t x) { - x--; x |= x >> 1; x |= x >> 2; @@ -103,7 +96,6 @@ pow2_ceil_u64(uint64_t x) JEMALLOC_INLINE uint32_t pow2_ceil_u32(uint32_t x) { - x--; x |= x >> 1; x |= x >> 2; @@ -118,7 +110,6 @@ pow2_ceil_u32(uint32_t x) JEMALLOC_INLINE size_t pow2_ceil_zu(size_t x) { - #if (LG_SIZEOF_PTR == 3) return (pow2_ceil_u64(x)); #else @@ -163,7 +154,6 @@ lg_floor(size_t x) JEMALLOC_INLINE unsigned lg_floor(size_t x) { - assert(x != 0); #if (LG_SIZEOF_PTR == LG_SIZEOF_INT) @@ -178,7 +168,6 @@ lg_floor(size_t x) JEMALLOC_INLINE unsigned lg_floor(size_t x) { - assert(x != 0); x |= (x >> 1); @@ -200,7 +189,6 @@ lg_floor(size_t x) JEMALLOC_INLINE void set_errno(int errnum) { - #ifdef _WIN32 SetLastError(errnum); #else @@ -212,7 +200,6 @@ set_errno(int errnum) JEMALLOC_INLINE int get_errno(void) { - #ifdef _WIN32 return (GetLastError()); #else diff --git a/include/msvc_compat/strings.h b/include/msvc_compat/strings.h index a3ee2506..47998be2 100644 --- a/include/msvc_compat/strings.h +++ b/include/msvc_compat/strings.h @@ -17,7 +17,6 @@ static __forceinline int ffsl(long x) static __forceinline int ffs(int x) { - return (ffsl(x)); } diff --git a/src/arena.c b/src/arena.c index 1f0c4df5..80af3f99 100644 --- a/src/arena.c +++ b/src/arena.c @@ -40,7 +40,6 @@ static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, static size_t arena_extent_dirty_npages(const extent_t *extent) { - return (extent_size_get(extent) >> LG_PAGE); } @@ -76,7 +75,6 @@ static void arena_extent_cache_dalloc_locked(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { - malloc_mutex_assert_owner(tsdn, &arena->lock); extent_dalloc_cache(tsdn, arena, r_extent_hooks, extent); @@ -87,7 +85,6 @@ void arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { - malloc_mutex_lock(tsdn, &arena->lock); arena_extent_cache_dalloc_locked(tsdn, arena, r_extent_hooks, extent); malloc_mutex_unlock(tsdn, &arena->lock); @@ -97,7 +94,6 @@ void arena_extent_cache_maybe_insert(tsdn_t *tsdn, arena_t *arena, extent_t *extent, bool cache) { - malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); if (cache) { @@ -110,7 +106,6 @@ void arena_extent_cache_maybe_remove(tsdn_t *tsdn, arena_t *arena, extent_t *extent, bool dirty) { - malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); if (dirty) { @@ -196,14 +191,12 @@ arena_slab_reg_dalloc(tsdn_t *tsdn, extent_t *slab, static void arena_nactive_add(arena_t *arena, size_t add_pages) { - arena->nactive += add_pages; } static void arena_nactive_sub(arena_t *arena, size_t sub_pages) { - assert(arena->nactive >= sub_pages); arena->nactive -= sub_pages; } @@ -279,7 +272,6 @@ arena_large_reset_stats_cancel(arena_t *arena, size_t usize) static void arena_large_ralloc_stats_update(arena_t *arena, size_t oldusize, size_t usize) { - arena_large_dalloc_stats_update(arena, oldusize); arena_large_malloc_stats_update(arena, usize); } @@ -391,7 +383,6 @@ arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, static void arena_decay_deadline_init(arena_t *arena) { - /* * Generate a new deadline that is uniformly random within the next * epoch after the current one. @@ -410,7 +401,6 @@ arena_decay_deadline_init(arena_t *arena) static bool arena_decay_deadline_reached(const arena_t *arena, const nstime_t *time) { - return (nstime_compare(&arena->decay.deadline, time) <= 0); } @@ -451,7 +441,6 @@ arena_decay_backlog_update_last(arena_t *arena) static void arena_decay_backlog_update(arena_t *arena, uint64_t nadvance_u64) { - if (nadvance_u64 >= SMOOTHSTEP_NSTEPS) { memset(arena->decay.backlog, 0, (SMOOTHSTEP_NSTEPS-1) * sizeof(size_t)); @@ -509,7 +498,6 @@ arena_decay_epoch_advance_purge(tsdn_t *tsdn, arena_t *arena) static void arena_decay_epoch_advance(tsdn_t *tsdn, arena_t *arena, const nstime_t *time) { - arena_decay_epoch_advance_helper(arena, time); arena_decay_epoch_advance_purge(tsdn, arena); } @@ -517,7 +505,6 @@ arena_decay_epoch_advance(tsdn_t *tsdn, arena_t *arena, const nstime_t *time) static void arena_decay_init(arena_t *arena, ssize_t decay_time) { - arena->decay.time = decay_time; if (decay_time > 0) { nstime_init2(&arena->decay.interval, decay_time, 0); @@ -535,7 +522,6 @@ arena_decay_init(arena_t *arena, ssize_t decay_time) static bool arena_decay_time_valid(ssize_t decay_time) { - if (decay_time < -1) return (false); if (decay_time == -1 || (uint64_t)decay_time <= NSTIME_SEC_MAX) @@ -558,7 +544,6 @@ arena_decay_time_get(tsdn_t *tsdn, arena_t *arena) bool arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { - if (!arena_decay_time_valid(decay_time)) return (true); @@ -623,7 +608,6 @@ arena_maybe_purge_helper(tsdn_t *tsdn, arena_t *arena) void arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_assert_owner(tsdn, &arena->lock); /* Don't recursively purge. */ @@ -762,7 +746,6 @@ label_return: void arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) { - malloc_mutex_lock(tsdn, &arena->lock); if (all) arena_purge_to_limit(tsdn, arena, 0); @@ -783,7 +766,6 @@ arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) static void arena_bin_slabs_nonfull_insert(arena_bin_t *bin, extent_t *slab) { - assert(extent_slab_data_get(slab)->nfree > 0); extent_heap_insert(&bin->slabs_nonfull, slab); } @@ -791,7 +773,6 @@ arena_bin_slabs_nonfull_insert(arena_bin_t *bin, extent_t *slab) static void arena_bin_slabs_nonfull_remove(arena_bin_t *bin, extent_t *slab) { - extent_heap_remove(&bin->slabs_nonfull, slab); } @@ -809,7 +790,6 @@ arena_bin_slabs_nonfull_tryget(arena_bin_t *bin) static void arena_bin_slabs_full_insert(arena_bin_t *bin, extent_t *slab) { - assert(extent_slab_data_get(slab)->nfree == 0); extent_ring_insert(&bin->slabs_full, slab); } @@ -817,7 +797,6 @@ arena_bin_slabs_full_insert(arena_bin_t *bin, extent_t *slab) static void arena_bin_slabs_full_remove(extent_t *slab) { - extent_ring_remove(slab); } @@ -935,7 +914,6 @@ arena_destroy_retained(tsdn_t *tsdn, arena_t *arena) void arena_destroy(tsd_t *tsd, arena_t *arena) { - assert(base_ind_get(arena->base) >= narenas_auto); assert(arena_nthreads_get(arena, false) == 0); assert(arena_nthreads_get(arena, true) == 0); @@ -1176,7 +1154,6 @@ arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_bin_t *tbin, void arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, bool zero) { - if (!zero) memset(ptr, JEMALLOC_ALLOC_JUNK, bin_info->reg_size); } @@ -1188,7 +1165,6 @@ arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, bool zero) void arena_dalloc_junk_small(void *ptr, const arena_bin_info_t *bin_info) { - memset(ptr, JEMALLOC_FREE_JUNK, bin_info->reg_size); } #ifdef JEMALLOC_JET @@ -1255,7 +1231,6 @@ void * arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero) { - assert(!tsdn_null(tsdn) || arena != NULL); if (likely(!tsdn_null(tsdn))) @@ -1320,7 +1295,6 @@ arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, static size_t arena_prof_demote(tsdn_t *tsdn, extent_t *extent, const void *ptr) { - cassert(config_prof); assert(ptr != NULL); @@ -1351,7 +1325,6 @@ arena_dalloc_promoted(tsdn_t *tsdn, extent_t *extent, void *ptr, static void arena_dissociate_bin_slab(extent_t *slab, arena_bin_t *bin) { - /* Dissociate slab from bin. */ if (slab == bin->slabcur) bin->slabcur = NULL; @@ -1375,7 +1348,6 @@ static void arena_dalloc_bin_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, arena_bin_t *bin) { - assert(slab != bin->slabcur); malloc_mutex_unlock(tsdn, &bin->lock); @@ -1393,7 +1365,6 @@ static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, arena_bin_t *bin) { - assert(extent_slab_data_get(slab)->nfree > 0); /* @@ -1446,7 +1417,6 @@ void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) { - arena_dalloc_bin_locked_impl(tsdn, arena, extent, ptr, true); } @@ -1463,7 +1433,6 @@ arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) void arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) { - arena_dalloc_bin(tsdn, arena, extent, ptr); arena_decay_tick(tsdn, arena); } @@ -1508,7 +1477,6 @@ static void * arena_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero, tcache_t *tcache) { - if (alignment == 0) return (arena_malloc(tsdn, arena, usize, size2index(usize), zero, tcache, true)); @@ -1575,7 +1543,6 @@ arena_dss_prec_get(tsdn_t *tsdn, arena_t *arena) bool arena_dss_prec_set(tsdn_t *tsdn, arena_t *arena, dss_prec_t dss_prec) { - if (!have_dss) return (dss_prec != dss_prec_disabled); malloc_mutex_lock(tsdn, &arena->lock); @@ -1587,14 +1554,12 @@ arena_dss_prec_set(tsdn_t *tsdn, arena_t *arena, dss_prec_t dss_prec) ssize_t arena_decay_time_default_get(void) { - return ((ssize_t)atomic_read_zu((size_t *)&decay_time_default)); } bool arena_decay_time_default_set(ssize_t decay_time) { - if (!arena_decay_time_valid(decay_time)) return (true); atomic_write_zu((size_t *)&decay_time_default, (size_t)decay_time); @@ -1605,7 +1570,6 @@ static void arena_basic_stats_merge_locked(arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) { - *nthreads += arena_nthreads_get(arena, false); *dss = dss_prec_names[arena->dss_prec]; *decay_time = arena->decay.time; @@ -1617,7 +1581,6 @@ void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) { - malloc_mutex_lock(tsdn, &arena->lock); arena_basic_stats_merge_locked(arena, nthreads, dss, decay_time, nactive, ndirty); @@ -1686,28 +1649,24 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, unsigned arena_nthreads_get(arena_t *arena, bool internal) { - return (atomic_read_u(&arena->nthreads[internal])); } void arena_nthreads_inc(arena_t *arena, bool internal) { - atomic_add_u(&arena->nthreads[internal], 1); } void arena_nthreads_dec(arena_t *arena, bool internal) { - atomic_sub_u(&arena->nthreads[internal], 1); } size_t arena_extent_sn_next(arena_t *arena) { - return (atomic_add_zu(&arena->extent_sn_next, 1) - 1); } @@ -1813,28 +1772,24 @@ label_error: void arena_boot(void) { - arena_decay_time_default_set(opt_decay_time); } void arena_prefork0(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_prefork(tsdn, &arena->lock); } void arena_prefork1(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_prefork(tsdn, &arena->extents_mtx); } void arena_prefork2(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_prefork(tsdn, &arena->extent_cache_mtx); } diff --git a/src/base.c b/src/base.c index 5eab7cd5..7c0ef2c1 100644 --- a/src/base.c +++ b/src/base.c @@ -30,7 +30,6 @@ base_map(extent_hooks_t *extent_hooks, unsigned ind, size_t size) static void base_unmap(extent_hooks_t *extent_hooks, unsigned ind, void *addr, size_t size) { - /* * Cascade through dalloc, decommit, purge_lazy, and purge_forced, * stopping at first success. This cascade is performed for consistency @@ -107,7 +106,6 @@ static void base_extent_bump_alloc_post(tsdn_t *tsdn, base_t *base, extent_t *extent, size_t gap_size, void *addr, size_t size) { - if (extent_size_get(extent) > 0) { /* * Compute the index for the largest size class that does not @@ -202,7 +200,6 @@ base_extent_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) base_t * b0get(void) { - return (b0); } @@ -263,7 +260,6 @@ base_delete(base_t *base) extent_hooks_t * base_extent_hooks_get(base_t *base) { - return ((extent_hooks_t *)atomic_read_p(&base->extent_hooks_pun)); } @@ -330,7 +326,6 @@ void base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated, size_t *resident, size_t *mapped) { - cassert(config_stats); malloc_mutex_lock(tsdn, &base->mtx); @@ -345,28 +340,24 @@ base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated, size_t *resident, void base_prefork(tsdn_t *tsdn, base_t *base) { - malloc_mutex_prefork(tsdn, &base->mtx); } void base_postfork_parent(tsdn_t *tsdn, base_t *base) { - malloc_mutex_postfork_parent(tsdn, &base->mtx); } void base_postfork_child(tsdn_t *tsdn, base_t *base) { - malloc_mutex_postfork_child(tsdn, &base->mtx); } bool base_boot(tsdn_t *tsdn) { - b0 = base_new(tsdn, 0, (extent_hooks_t *)&extent_hooks_default); return (b0 == NULL); } diff --git a/src/bitmap.c b/src/bitmap.c index 66554451..3d27f059 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -37,7 +37,6 @@ bitmap_info_init(bitmap_info_t *binfo, size_t nbits) static size_t bitmap_info_ngroups(const bitmap_info_t *binfo) { - return (binfo->levels[binfo->nlevels].group_offset); } @@ -74,7 +73,6 @@ bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo) void bitmap_info_init(bitmap_info_t *binfo, size_t nbits) { - assert(nbits > 0); assert(nbits <= (ZU(1) << LG_BITMAP_MAXBITS)); @@ -85,7 +83,6 @@ bitmap_info_init(bitmap_info_t *binfo, size_t nbits) static size_t bitmap_info_ngroups(const bitmap_info_t *binfo) { - return (binfo->ngroups); } @@ -106,6 +103,5 @@ bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo) size_t bitmap_size(const bitmap_info_t *binfo) { - return (bitmap_info_ngroups(binfo) << LG_SIZEOF_BITMAP); } diff --git a/src/ckh.c b/src/ckh.c index 6f0f1e4d..fe79862c 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -411,7 +411,6 @@ label_return: void ckh_delete(tsd_t *tsd, ckh_t *ckh) { - assert(ckh != NULL); #ifdef CKH_VERBOSE @@ -435,7 +434,6 @@ ckh_delete(tsd_t *tsd, ckh_t *ckh) size_t ckh_count(ckh_t *ckh) { - assert(ckh != NULL); return (ckh->count); @@ -539,14 +537,12 @@ ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data) void ckh_string_hash(const void *key, size_t r_hash[2]) { - hash(key, strlen((const char *)key), 0x94122f33U, r_hash); } bool ckh_string_keycomp(const void *k1, const void *k2) { - assert(k1 != NULL); assert(k2 != NULL); @@ -569,6 +565,5 @@ ckh_pointer_hash(const void *key, size_t r_hash[2]) bool ckh_pointer_keycomp(const void *k1, const void *k2) { - return ((k1 == k2) ? true : false); } diff --git a/src/ctl.c b/src/ctl.c index 76fbce4b..8484ba85 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -18,7 +18,6 @@ static ctl_stats_t *ctl_stats; JEMALLOC_INLINE_C const ctl_named_node_t * ctl_named_node(const ctl_node_t *node) { - return ((node->named) ? (const ctl_named_node_t *)node : NULL); } @@ -33,7 +32,6 @@ ctl_named_children(const ctl_named_node_t *node, size_t index) JEMALLOC_INLINE_C const ctl_indexed_node_t * ctl_indexed_node(const ctl_node_t *node) { - return (!node->named ? (const ctl_indexed_node_t *)node : NULL); } @@ -475,7 +473,6 @@ stats_arenas_i2a_impl(size_t i, bool compat, bool validate) static unsigned stats_arenas_i2a(size_t i) { - return (stats_arenas_i2a_impl(i, true, false)); } @@ -513,7 +510,6 @@ stats_arenas_i(size_t i) static void ctl_arena_clear(ctl_arena_stats_t *astats) { - astats->nthreads = 0; astats->dss = dss_prec_names[dss_prec_limit]; astats->decay_time = -1; @@ -985,7 +981,6 @@ label_return: bool ctl_boot(void) { - if (malloc_mutex_init(&ctl_mtx, "ctl", WITNESS_RANK_CTL)) return (true); @@ -997,21 +992,18 @@ ctl_boot(void) void ctl_prefork(tsdn_t *tsdn) { - malloc_mutex_prefork(tsdn, &ctl_mtx); } void ctl_postfork_parent(tsdn_t *tsdn) { - malloc_mutex_postfork_parent(tsdn, &ctl_mtx); } void ctl_postfork_child(tsdn_t *tsdn) { - malloc_mutex_postfork_child(tsdn, &ctl_mtx); } @@ -1540,7 +1532,6 @@ label_return: static void arena_i_purge(tsdn_t *tsdn, unsigned arena_ind, bool all) { - malloc_mutex_lock(tsdn, &ctl_mtx); { unsigned narenas = ctl_stats->narenas; @@ -1918,7 +1909,6 @@ CTL_RO_NL_GEN(arenas_bin_i_slab_size, arena_bin_info[mib[2]].slab_size, size_t) static const ctl_named_node_t * arenas_bin_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { - if (i > NBINS) return (NULL); return (super_arenas_bin_i_node); @@ -1929,7 +1919,6 @@ CTL_RO_NL_GEN(arenas_lextent_i_size, index2size(NBINS+(szind_t)mib[2]), size_t) static const ctl_named_node_t * arenas_lextent_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { - if (i > NSIZES - NBINS) return (NULL); return (super_arenas_lextent_i_node); @@ -2159,7 +2148,6 @@ static const ctl_named_node_t * stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t j) { - if (j > NBINS) return (NULL); return (super_stats_arenas_i_bins_j_node); @@ -2178,7 +2166,6 @@ static const ctl_named_node_t * stats_arenas_i_lextents_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t j) { - if (j > NSIZES - NBINS) return (NULL); return (super_stats_arenas_i_lextents_j_node); diff --git a/src/extent.c b/src/extent.c index 7eb49709..73f79c1c 100644 --- a/src/extent.c +++ b/src/extent.c @@ -94,7 +94,6 @@ extent_alloc(tsdn_t *tsdn, arena_t *arena) void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { - malloc_mutex_lock(tsdn, &arena->extent_cache_mtx); ql_elm_new(extent, ql_link); ql_tail_insert(&arena->extent_cache, extent, ql_link); @@ -104,21 +103,18 @@ extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) extent_hooks_t * extent_hooks_get(arena_t *arena) { - return (base_extent_hooks_get(arena->base)); } extent_hooks_t * extent_hooks_set(arena_t *arena, extent_hooks_t *extent_hooks) { - return (base_extent_hooks_set(arena->base, extent_hooks)); } static void extent_hooks_assure_initialized(arena_t *arena, extent_hooks_t **r_extent_hooks) { - if (*r_extent_hooks == EXTENT_HOOKS_INITIALIZER) *r_extent_hooks = extent_hooks_get(arena); } @@ -226,7 +222,6 @@ extent_rtree_acquire(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, const extent_t *extent, bool dependent, bool init_missing, rtree_elm_t **r_elm_a, rtree_elm_t **r_elm_b) { - *r_elm_a = rtree_elm_acquire(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_base_get(extent), dependent, init_missing); if (!dependent && *r_elm_a == NULL) @@ -252,7 +247,6 @@ static void extent_rtree_write_acquired(tsdn_t *tsdn, rtree_elm_t *elm_a, rtree_elm_t *elm_b, const extent_t *extent) { - rtree_elm_write_acquired(tsdn, &extents_rtree, elm_a, extent); if (elm_b != NULL) rtree_elm_write_acquired(tsdn, &extents_rtree, elm_b, extent); @@ -261,7 +255,6 @@ extent_rtree_write_acquired(tsdn_t *tsdn, rtree_elm_t *elm_a, static void extent_rtree_release(tsdn_t *tsdn, rtree_elm_t *elm_a, rtree_elm_t *elm_b) { - rtree_elm_release(tsdn, &extents_rtree, elm_a); if (elm_b != NULL) rtree_elm_release(tsdn, &extents_rtree, elm_b); @@ -285,7 +278,6 @@ extent_interior_register(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, static void extent_gprof_add(tsdn_t *tsdn, const extent_t *extent) { - cassert(config_prof); if (opt_prof && extent_active_get(extent)) { @@ -307,7 +299,6 @@ extent_gprof_add(tsdn_t *tsdn, const extent_t *extent) static void extent_gprof_sub(tsdn_t *tsdn, const extent_t *extent) { - cassert(config_prof); if (opt_prof && extent_active_get(extent)) { @@ -406,7 +397,6 @@ static void extent_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, bool cache, extent_t *extent) { - /* * Leak extent after making sure its pages have already been purged, so * that this is only a virtual memory leak. @@ -641,7 +631,6 @@ extent_alloc_cache_locked(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) { - malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); return (extent_alloc_cache_impl(tsdn, arena, r_extent_hooks, true, @@ -653,7 +642,6 @@ extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) { - return (extent_alloc_cache_impl(tsdn, arena, r_extent_hooks, false, new_addr, usize, pad, alignment, zero, commit, slab)); } @@ -694,7 +682,6 @@ static void extent_retain(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { - if (config_stats) arena->stats.retained += extent_size_get(extent); extent_record(tsdn, arena, r_extent_hooks, arena->extents_retained, @@ -906,7 +893,6 @@ extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, static bool extent_can_coalesce(const extent_t *a, const extent_t *b) { - if (extent_arena_get(a) != extent_arena_get(b)) return (false); if (extent_active_get(a) != extent_active_get(b)) @@ -924,7 +910,6 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b, extent_heap_t extent_heaps[NPSIZES+1], bool cache) { - if (!extent_can_coalesce(a, b)) return; @@ -1008,7 +993,6 @@ void extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { - assert(extent_base_get(extent) != NULL); assert(extent_size_get(extent) != 0); @@ -1022,7 +1006,6 @@ extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, static bool extent_dalloc_default_impl(void *addr, size_t size) { - if (!have_dss || !extent_in_dss(addr)) return (extent_dalloc_mmap(addr, size)); return (true); @@ -1033,7 +1016,6 @@ static bool extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, size_t size, bool committed, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); return (extent_dalloc_default_impl(addr, size)); @@ -1116,7 +1098,6 @@ static bool extent_commit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); return (pages_commit((void *)((uintptr_t)addr + (uintptr_t)offset), @@ -1142,7 +1123,6 @@ static bool extent_decommit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); return (pages_decommit((void *)((uintptr_t)addr + (uintptr_t)offset), @@ -1171,7 +1151,6 @@ static bool extent_purge_lazy_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); assert(addr != NULL); assert((offset & PAGE_MASK) == 0); @@ -1188,7 +1167,6 @@ extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { - extent_hooks_assure_initialized(arena, r_extent_hooks); return ((*r_extent_hooks)->purge_lazy == NULL || (*r_extent_hooks)->purge_lazy(*r_extent_hooks, @@ -1201,7 +1179,6 @@ static bool extent_purge_forced_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); assert(addr != NULL); assert((offset & PAGE_MASK) == 0); @@ -1218,7 +1195,6 @@ extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { - extent_hooks_assure_initialized(arena, r_extent_hooks); return ((*r_extent_hooks)->purge_forced == NULL || (*r_extent_hooks)->purge_forced(*r_extent_hooks, @@ -1231,7 +1207,6 @@ static bool extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t size_a, size_t size_b, bool committed, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); if (!maps_coalesce) @@ -1310,7 +1285,6 @@ label_error_a: static bool extent_merge_default_impl(void *addr_a, void *addr_b) { - if (!maps_coalesce) return (true); if (have_dss && !extent_dss_mergeable(addr_a, addr_b)) @@ -1324,7 +1298,6 @@ static bool extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, void *addr_b, size_t size_b, bool committed, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); return (extent_merge_default_impl(addr_a, addr_b)); @@ -1396,7 +1369,6 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, bool extent_boot(void) { - if (rtree_new(&extents_rtree, (unsigned)((ZU(1) << (LG_SIZEOF_PTR+3)) - LG_PAGE))) return (true); diff --git a/src/extent_dss.c b/src/extent_dss.c index 0f0c689b..5aa95b1c 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -32,7 +32,6 @@ static void *dss_max; static void * extent_dss_sbrk(intptr_t increment) { - #ifdef JEMALLOC_DSS return (sbrk(increment)); #else @@ -55,7 +54,6 @@ extent_dss_prec_get(void) bool extent_dss_prec_set(dss_prec_t dss_prec) { - if (!have_dss) return (dss_prec != dss_prec_disabled); atomic_write_u(&dss_prec_default, (unsigned)dss_prec); @@ -208,7 +206,6 @@ label_oom: static bool extent_in_dss_helper(void *addr, void *max) { - return ((uintptr_t)addr >= (uintptr_t)dss_base && (uintptr_t)addr < (uintptr_t)max); } @@ -216,7 +213,6 @@ extent_in_dss_helper(void *addr, void *max) bool extent_in_dss(void *addr) { - cassert(have_dss); return (extent_in_dss_helper(addr, atomic_read_p(&dss_max))); @@ -241,7 +237,6 @@ extent_dss_mergeable(void *addr_a, void *addr_b) void extent_dss_boot(void) { - cassert(have_dss); dss_base = extent_dss_sbrk(0); diff --git a/src/extent_mmap.c b/src/extent_mmap.c index 23dd4f88..e685a45b 100644 --- a/src/extent_mmap.c +++ b/src/extent_mmap.c @@ -69,7 +69,6 @@ extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, bool extent_dalloc_mmap(void *addr, size_t size) { - if (config_munmap) pages_unmap(addr, size); return (!config_munmap); diff --git a/src/jemalloc.c b/src/jemalloc.c index a053983f..1dc91833 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -211,7 +211,6 @@ JEMALLOC_ATTR(constructor) static void WINAPI _init_init_lock(void) { - /* * If another constructor in the same binary is using mallctl to e.g. * set up extent hooks, it may end up running before this one, and @@ -276,14 +275,12 @@ static bool malloc_init_hard(void); JEMALLOC_ALWAYS_INLINE_C bool malloc_initialized(void) { - return (malloc_init_state == malloc_init_initialized); } JEMALLOC_ALWAYS_INLINE_C bool malloc_init_a0(void) { - if (unlikely(malloc_init_state == malloc_init_uninitialized)) return (malloc_init_hard_a0()); return (false); @@ -292,7 +289,6 @@ malloc_init_a0(void) JEMALLOC_ALWAYS_INLINE_C bool malloc_init(void) { - if (unlikely(!malloc_initialized()) && malloc_init_hard()) return (true); return (false); @@ -306,7 +302,6 @@ malloc_init(void) static void * a0ialloc(size_t size, bool zero, bool is_internal) { - if (unlikely(malloc_init_a0())) return (NULL); @@ -317,21 +312,18 @@ a0ialloc(size_t size, bool zero, bool is_internal) static void a0idalloc(extent_t *extent, void *ptr, bool is_internal) { - idalloctm(TSDN_NULL, extent, ptr, false, is_internal, true); } void * a0malloc(size_t size) { - return (a0ialloc(size, false, true)); } void a0dalloc(void *ptr) { - a0idalloc(iealloc(NULL, ptr), ptr, true); } @@ -344,7 +336,6 @@ a0dalloc(void *ptr) void * bootstrap_malloc(size_t size) { - if (unlikely(size == 0)) size = 1; @@ -368,7 +359,6 @@ bootstrap_calloc(size_t num, size_t size) void bootstrap_free(void *ptr) { - if (unlikely(ptr == NULL)) return; @@ -378,28 +368,24 @@ bootstrap_free(void *ptr) void arena_set(unsigned ind, arena_t *arena) { - atomic_write_p((void **)&arenas[ind], arena); } static void narenas_total_set(unsigned narenas) { - atomic_write_u(&narenas_total, narenas); } static void narenas_total_inc(void) { - atomic_add_u(&narenas_total, 1); } unsigned narenas_total_get(void) { - return (atomic_read_u(&narenas_total)); } @@ -689,7 +675,6 @@ arenas_tdata_cleanup(tsd_t *tsd) static void stats_print_atexit(void) { - if (config_tcache && config_stats) { tsdn_t *tsdn; unsigned narenas, i; @@ -737,7 +722,6 @@ stats_print_atexit(void) static char * secure_getenv(const char *name) { - # ifdef JEMALLOC_HAVE_ISSETUGID if (issetugid() != 0) return (NULL); @@ -855,7 +839,6 @@ static void malloc_conf_error(const char *msg, const char *k, size_t klen, const char *v, size_t vlen) { - malloc_printf(": %s: %.*s:%.*s\n", msg, (int)klen, k, (int)vlen, v); } @@ -1167,7 +1150,6 @@ malloc_conf_init(void) static bool malloc_init_hard_needed(void) { - if (malloc_initialized() || (IS_INITIALIZER && malloc_init_state == malloc_init_recursible)) { /* @@ -1197,7 +1179,6 @@ malloc_init_hard_needed(void) static bool malloc_init_hard_a0_locked() { - malloc_initializer = INITIALIZER; if (config_prof) @@ -1261,7 +1242,6 @@ malloc_init_hard_a0(void) static bool malloc_init_hard_recursible(void) { - malloc_init_state = malloc_init_recursible; ncpus = malloc_ncpus(); @@ -1285,7 +1265,6 @@ malloc_init_hard_recursible(void) static bool malloc_init_hard_finish(tsdn_t *tsdn) { - if (malloc_mutex_boot()) return (true); @@ -1458,7 +1437,6 @@ JEMALLOC_ALWAYS_INLINE_C void ialloc_post_check(void *ret, tsdn_t *tsdn, size_t usize, const char *func, bool update_errno, bool slow_path) { - assert(!tsdn_null(tsdn) || ret == NULL); if (unlikely(ret == NULL)) { @@ -1617,7 +1595,6 @@ JEMALLOC_EXPORT int JEMALLOC_NOTHROW JEMALLOC_ATTR(nonnull(1)) je_posix_memalign(void **memptr, size_t alignment, size_t size) { - return (imemalign(memptr, alignment, size, sizeof(void *))); } @@ -1754,7 +1731,6 @@ JEMALLOC_INLINE_C void isfree(tsd_t *tsd, extent_t *extent, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) { - witness_assert_lockless(tsd_tsdn(tsd)); assert(ptr != NULL); @@ -1850,7 +1826,6 @@ je_realloc(void *ptr, size_t size) JEMALLOC_EXPORT void JEMALLOC_NOTHROW je_free(void *ptr) { - UTRACE(ptr, 0, 0); if (likely(ptr != NULL)) { tsd_t *tsd = tsd_fetch(); @@ -1959,7 +1934,6 @@ JEMALLOC_ALWAYS_INLINE_C bool imallocx_flags_decode(tsd_t *tsd, size_t size, int flags, size_t *usize, size_t *alignment, bool *zero, tcache_t **tcache, arena_t **arena) { - if ((flags & MALLOCX_LG_ALIGN_MASK) == 0) { *alignment = 0; *usize = s2u(size); @@ -2641,7 +2615,6 @@ JEMALLOC_ATTR(constructor) static void jemalloc_constructor(void) { - malloc_init(); } #endif diff --git a/src/jemalloc_cpp.cpp b/src/jemalloc_cpp.cpp index 4d88f993..84d47aed 100644 --- a/src/jemalloc_cpp.cpp +++ b/src/jemalloc_cpp.cpp @@ -70,55 +70,47 @@ newImpl(std::size_t size) noexcept(IsNoExcept) void * operator new(std::size_t size) { - return (newImpl(size)); } void * operator new[](std::size_t size) { - return (newImpl(size)); } void * operator new(std::size_t size, const std::nothrow_t&) noexcept { - return (newImpl(size)); } void * operator new[](std::size_t size, const std::nothrow_t&) noexcept { - return (newImpl(size)); } void operator delete(void* ptr) noexcept { - je_free(ptr); } void operator delete[](void* ptr) noexcept { - je_free(ptr); } void operator delete(void* ptr, const std::nothrow_t&) noexcept { - je_free(ptr); } void operator delete[](void* ptr, const std::nothrow_t&) noexcept { - je_free(ptr); } @@ -127,13 +119,11 @@ void operator delete[](void* ptr, const std::nothrow_t&) noexcept void operator delete(void* ptr, std::size_t size) noexcept { - je_sdallocx(ptr, size, /*flags=*/0); } void operator delete[](void* ptr, std::size_t size) noexcept { - je_sdallocx(ptr, size, /*flags=*/0); } diff --git a/src/large.c b/src/large.c index ec22e64c..9936b236 100644 --- a/src/large.c +++ b/src/large.c @@ -6,7 +6,6 @@ void * large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero) { - assert(usize == s2u(usize)); return (large_palloc(tsdn, arena, usize, CACHELINE, zero)); @@ -67,7 +66,6 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, void large_dalloc_junk(void *ptr, size_t usize) { - memset(ptr, JEMALLOC_FREE_JUNK, usize); } #ifdef JEMALLOC_JET @@ -83,7 +81,6 @@ large_dalloc_junk_t *large_dalloc_junk = JEMALLOC_N(n_large_dalloc_junk); void large_dalloc_maybe_junk(void *ptr, size_t usize) { - if (config_fill && have_dss && unlikely(opt_junk_free)) { /* * Only bother junk filling if the extent isn't about to be @@ -198,7 +195,6 @@ bool large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, size_t usize_max, bool zero) { - assert(s2u(extent_usize_get(extent)) == extent_usize_get(extent)); /* The following should have been caught by callers. */ assert(usize_min > 0 && usize_max <= LARGE_MAXCLASS); @@ -247,7 +243,6 @@ static void * large_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero) { - if (alignment <= CACHELINE) return (large_malloc(tsdn, arena, usize, zero)); return (large_palloc(tsdn, arena, usize, alignment, zero)); @@ -314,41 +309,35 @@ large_dalloc_impl(tsdn_t *tsdn, extent_t *extent, bool junked_locked) void large_dalloc_junked_locked(tsdn_t *tsdn, extent_t *extent) { - large_dalloc_impl(tsdn, extent, true); } void large_dalloc(tsdn_t *tsdn, extent_t *extent) { - large_dalloc_impl(tsdn, extent, false); } size_t large_salloc(tsdn_t *tsdn, const extent_t *extent) { - return (extent_usize_get(extent)); } prof_tctx_t * large_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent) { - return (extent_prof_tctx_get(extent)); } void large_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx) { - extent_prof_tctx_set(extent, tctx); } void large_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent) { - large_prof_tctx_set(tsdn, extent, (prof_tctx_t *)(uintptr_t)1U); } diff --git a/src/mutex.c b/src/mutex.c index b757ba86..bde536de 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -37,7 +37,6 @@ static int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *, static void pthread_create_once(void) { - pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create"); if (pthread_create_fptr == NULL) { malloc_write(": Error in dlsym(RTLD_NEXT, " @@ -71,7 +70,6 @@ JEMALLOC_EXPORT int _pthread_mutex_init_calloc_cb(pthread_mutex_t *mutex, bool malloc_mutex_init(malloc_mutex_t *mutex, const char *name, witness_rank_t rank) { - #ifdef _WIN32 # if _WIN32_WINNT >= 0x0600 InitializeSRWLock(&mutex->lock); @@ -113,21 +111,18 @@ malloc_mutex_init(malloc_mutex_t *mutex, const char *name, witness_rank_t rank) void malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex) { - malloc_mutex_lock(tsdn, mutex); } void malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex) { - malloc_mutex_unlock(tsdn, mutex); } void malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex) { - #ifdef JEMALLOC_MUTEX_INIT_CB malloc_mutex_unlock(tsdn, mutex); #else @@ -144,7 +139,6 @@ malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex) bool malloc_mutex_boot(void) { - #ifdef JEMALLOC_MUTEX_INIT_CB postpone_init = false; while (postponed_mutexes != NULL) { diff --git a/src/nstime.c b/src/nstime.c index 0948e29f..57ebf2e0 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -5,56 +5,48 @@ void nstime_init(nstime_t *time, uint64_t ns) { - time->ns = ns; } void nstime_init2(nstime_t *time, uint64_t sec, uint64_t nsec) { - time->ns = sec * BILLION + nsec; } uint64_t nstime_ns(const nstime_t *time) { - return (time->ns); } uint64_t nstime_sec(const nstime_t *time) { - return (time->ns / BILLION); } uint64_t nstime_nsec(const nstime_t *time) { - return (time->ns % BILLION); } void nstime_copy(nstime_t *time, const nstime_t *source) { - *time = *source; } int nstime_compare(const nstime_t *a, const nstime_t *b) { - return ((a->ns > b->ns) - (a->ns < b->ns)); } void nstime_add(nstime_t *time, const nstime_t *addend) { - assert(UINT64_MAX - time->ns >= addend->ns); time->ns += addend->ns; @@ -63,7 +55,6 @@ nstime_add(nstime_t *time, const nstime_t *addend) void nstime_subtract(nstime_t *time, const nstime_t *subtrahend) { - assert(nstime_compare(time, subtrahend) >= 0); time->ns -= subtrahend->ns; @@ -72,7 +63,6 @@ nstime_subtract(nstime_t *time, const nstime_t *subtrahend) void nstime_imultiply(nstime_t *time, uint64_t multiplier) { - assert((((time->ns | multiplier) & (UINT64_MAX << (sizeof(uint64_t) << 2))) == 0) || ((time->ns * multiplier) / multiplier == time->ns)); @@ -82,7 +72,6 @@ nstime_imultiply(nstime_t *time, uint64_t multiplier) void nstime_idivide(nstime_t *time, uint64_t divisor) { - assert(divisor != 0); time->ns /= divisor; @@ -91,7 +80,6 @@ nstime_idivide(nstime_t *time, uint64_t divisor) uint64_t nstime_divide(const nstime_t *time, const nstime_t *divisor) { - assert(divisor->ns != 0); return (time->ns / divisor->ns); @@ -135,7 +123,6 @@ nstime_get(nstime_t *time) static void nstime_get(nstime_t *time) { - nstime_init(time, mach_absolute_time()); } #else @@ -157,7 +144,6 @@ nstime_get(nstime_t *time) bool nstime_monotonic(void) { - return (NSTIME_MONOTONIC); #undef NSTIME_MONOTONIC } diff --git a/src/pages.c b/src/pages.c index d5a0a21c..7c26a28a 100644 --- a/src/pages.c +++ b/src/pages.c @@ -64,7 +64,6 @@ pages_map(void *addr, size_t size, bool *commit) void pages_unmap(void *addr, size_t size) { - #ifdef _WIN32 if (VirtualFree(addr, 0, MEM_RELEASE) == 0) #else @@ -121,7 +120,6 @@ pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size, static bool pages_commit_impl(void *addr, size_t size, bool commit) { - if (os_overcommits) return (true); @@ -151,21 +149,18 @@ pages_commit_impl(void *addr, size_t size, bool commit) bool pages_commit(void *addr, size_t size) { - return (pages_commit_impl(addr, size, true)); } bool pages_decommit(void *addr, size_t size) { - return (pages_commit_impl(addr, size, false)); } bool pages_purge_lazy(void *addr, size_t size) { - if (!pages_can_purge_lazy) return (true); @@ -182,7 +177,6 @@ pages_purge_lazy(void *addr, size_t size) bool pages_purge_forced(void *addr, size_t size) { - if (!pages_can_purge_forced) return (true); @@ -196,7 +190,6 @@ pages_purge_forced(void *addr, size_t size) bool pages_huge(void *addr, size_t size) { - assert(HUGEPAGE_ADDR2BASE(addr) == addr); assert(HUGEPAGE_CEILING(size) == size); @@ -210,7 +203,6 @@ pages_huge(void *addr, size_t size) bool pages_nohuge(void *addr, size_t size) { - assert(HUGEPAGE_ADDR2BASE(addr) == addr); assert(HUGEPAGE_CEILING(size) == size); @@ -284,7 +276,6 @@ os_overcommits_proc(void) void pages_boot(void) { - #ifndef _WIN32 mmap_flags = MAP_PRIVATE | MAP_ANON; #endif diff --git a/src/prof.c b/src/prof.c index b9a9d659..237cbb50 100644 --- a/src/prof.c +++ b/src/prof.c @@ -226,7 +226,6 @@ void prof_malloc_sample_object(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, prof_tctx_t *tctx) { - prof_tctx_set(tsdn, extent, ptr, usize, tctx); malloc_mutex_lock(tsdn, tctx->tdata->lock); @@ -243,7 +242,6 @@ prof_malloc_sample_object(tsdn_t *tsdn, extent_t *extent, const void *ptr, void prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_tctx_t *tctx) { - malloc_mutex_lock(tsd_tsdn(tsd), tctx->tdata->lock); assert(tctx->cnts.curobjs > 0); assert(tctx->cnts.curbytes >= usize); @@ -259,7 +257,6 @@ prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_tctx_t *tctx) void bt_init(prof_bt_t *bt, void **vec) { - cassert(config_prof); bt->vec = vec; @@ -269,7 +266,6 @@ bt_init(prof_bt_t *bt, void **vec) JEMALLOC_INLINE_C void prof_enter(tsd_t *tsd, prof_tdata_t *tdata) { - cassert(config_prof); assert(tdata == prof_tdata_get(tsd, false)); @@ -284,7 +280,6 @@ prof_enter(tsd_t *tsd, prof_tdata_t *tdata) JEMALLOC_INLINE_C void prof_leave(tsd_t *tsd, prof_tdata_t *tdata) { - cassert(config_prof); assert(tdata == prof_tdata_get(tsd, false)); @@ -326,7 +321,6 @@ prof_backtrace(prof_bt_t *bt) static _Unwind_Reason_Code prof_unwind_init_callback(struct _Unwind_Context *context, void *arg) { - cassert(config_prof); return (_URC_NO_REASON); @@ -525,7 +519,6 @@ prof_backtrace(prof_bt_t *bt) void prof_backtrace(prof_bt_t *bt) { - cassert(config_prof); not_reached(); } @@ -542,7 +535,6 @@ prof_gctx_mutex_choose(void) static malloc_mutex_t * prof_tdata_mutex_choose(uint64_t thr_uid) { - return (&tdata_locks[thr_uid % PROF_NTDATA_LOCKS]); } @@ -576,7 +568,6 @@ static void prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self, prof_gctx_t *gctx, prof_tdata_t *tdata) { - cassert(config_prof); /* @@ -612,7 +603,6 @@ prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self, prof_gctx_t *gctx, static bool prof_tctx_should_destroy(tsdn_t *tsdn, prof_tctx_t *tctx) { - malloc_mutex_assert_owner(tsdn, tctx->tdata->lock); if (opt_prof_accum) @@ -627,7 +617,6 @@ prof_tctx_should_destroy(tsdn_t *tsdn, prof_tctx_t *tctx) static bool prof_gctx_should_destroy(prof_gctx_t *gctx) { - if (opt_prof_accum) return (false); if (!tctx_tree_empty(&gctx->tctxs)) @@ -1044,7 +1033,6 @@ prof_dump_printf(bool propagate_err, const char *format, ...) static void prof_tctx_merge_tdata(tsdn_t *tsdn, prof_tctx_t *tctx, prof_tdata_t *tdata) { - malloc_mutex_assert_owner(tsdn, tctx->tdata->lock); malloc_mutex_lock(tsdn, tctx->gctx->lock); @@ -1077,7 +1065,6 @@ prof_tctx_merge_tdata(tsdn_t *tsdn, prof_tctx_t *tctx, prof_tdata_t *tdata) static void prof_tctx_merge_gctx(tsdn_t *tsdn, prof_tctx_t *tctx, prof_gctx_t *gctx) { - malloc_mutex_assert_owner(tsdn, gctx->lock); gctx->cnt_summed.curobjs += tctx->dump_cnts.curobjs; @@ -1173,7 +1160,6 @@ label_return: static void prof_dump_gctx_prep(tsdn_t *tsdn, prof_gctx_t *gctx, prof_gctx_tree_t *gctxs) { - cassert(config_prof); malloc_mutex_lock(tsdn, gctx->lock); @@ -1421,7 +1407,6 @@ prof_open_maps(const char *format, ...) static int prof_getpid(void) { - #ifdef _WIN32 return (GetCurrentProcessId()); #else @@ -1491,7 +1476,6 @@ static void prof_leakcheck(const prof_cnt_t *cnt_all, size_t leak_ngctx, const char *filename) { - #ifdef JEMALLOC_PROF /* * Scaling is equivalent AdjustSamples() in jeprof, but the result may @@ -1640,7 +1624,6 @@ label_open_close_error: static void prof_dump_filename(char *filename, char v, uint64_t vseq) { - cassert(config_prof); if (vseq != VSEQ_INVALID) { @@ -1844,7 +1827,6 @@ prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim, prof_tdata_t * prof_tdata_init(tsd_t *tsd) { - return (prof_tdata_init_impl(tsd, prof_thr_uid_alloc(tsd_tsdn(tsd)), 0, NULL, prof_thread_active_init_get(tsd_tsdn(tsd)))); } @@ -1852,7 +1834,6 @@ prof_tdata_init(tsd_t *tsd) static bool prof_tdata_should_destroy_unlocked(prof_tdata_t *tdata, bool even_if_attached) { - if (tdata->attached && !even_if_attached) return (false); if (ckh_count(&tdata->bt2tctx) != 0) @@ -1864,7 +1845,6 @@ static bool prof_tdata_should_destroy(tsdn_t *tsdn, prof_tdata_t *tdata, bool even_if_attached) { - malloc_mutex_assert_owner(tsdn, tdata->lock); return (prof_tdata_should_destroy_unlocked(tdata, even_if_attached)); @@ -1874,7 +1854,6 @@ static void prof_tdata_destroy_locked(tsd_t *tsd, prof_tdata_t *tdata, bool even_if_attached) { - malloc_mutex_assert_owner(tsd_tsdn(tsd), &tdatas_mtx); tdata_tree_remove(&tdatas, tdata); @@ -1893,7 +1872,6 @@ prof_tdata_destroy_locked(tsd_t *tsd, prof_tdata_t *tdata, static void prof_tdata_destroy(tsd_t *tsd, prof_tdata_t *tdata, bool even_if_attached) { - malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx); prof_tdata_destroy_locked(tsd, tdata, even_if_attached); malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx); @@ -2162,7 +2140,6 @@ prof_gdump_set(tsdn_t *tsdn, bool gdump) void prof_boot0(void) { - cassert(config_prof); memcpy(opt_prof_prefix, PROF_PREFIX_DEFAULT, @@ -2172,7 +2149,6 @@ prof_boot0(void) void prof_boot1(void) { - cassert(config_prof); /* @@ -2198,7 +2174,6 @@ prof_boot1(void) bool prof_boot2(tsd_t *tsd) { - cassert(config_prof); if (opt_prof) { @@ -2292,7 +2267,6 @@ prof_boot2(tsd_t *tsd) void prof_prefork0(tsdn_t *tsdn) { - if (opt_prof) { unsigned i; @@ -2309,7 +2283,6 @@ prof_prefork0(tsdn_t *tsdn) void prof_prefork1(tsdn_t *tsdn) { - if (opt_prof) { malloc_mutex_prefork(tsdn, &prof_active_mtx); malloc_mutex_prefork(tsdn, &prof_dump_seq_mtx); @@ -2322,7 +2295,6 @@ prof_prefork1(tsdn_t *tsdn) void prof_postfork_parent(tsdn_t *tsdn) { - if (opt_prof) { unsigned i; @@ -2345,7 +2317,6 @@ prof_postfork_parent(tsdn_t *tsdn) void prof_postfork_child(tsdn_t *tsdn) { - if (opt_prof) { unsigned i; diff --git a/src/rtree.c b/src/rtree.c index fd5e85df..43f21652 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -4,7 +4,6 @@ static unsigned hmin(unsigned ha, unsigned hb) { - return (ha < hb ? ha : hb); } @@ -71,7 +70,6 @@ rtree_new(rtree_t *rtree, unsigned bits) static rtree_elm_t * rtree_node_alloc(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { - return ((rtree_elm_t *)base_alloc(tsdn, b0get(), nelms * sizeof(rtree_elm_t), CACHELINE)); } @@ -88,7 +86,6 @@ rtree_node_alloc_t *rtree_node_alloc = JEMALLOC_N(rtree_node_alloc_impl); UNUSED static void rtree_node_dalloc(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) { - /* Nodes are never deleted during normal operation. */ not_reached(); } @@ -103,7 +100,6 @@ static void rtree_delete_subtree(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node, unsigned level) { - if (level + 1 < rtree->height) { size_t nchildren, i; @@ -157,7 +153,6 @@ rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level, rtree_elm_t * rtree_subtree_read_hard(tsdn_t *tsdn, rtree_t *rtree, unsigned level) { - return (rtree_node_init(tsdn, rtree, level, &rtree->levels[level].subtree)); } @@ -166,7 +161,6 @@ rtree_elm_t * rtree_child_read_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level) { - return (rtree_node_init(tsdn, rtree, level+1, &elm->child)); } diff --git a/src/tcache.c b/src/tcache.c index fad52777..66e255d6 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -26,7 +26,6 @@ static tcaches_t *tcaches_avail; size_t tcache_salloc(tsdn_t *tsdn, const void *ptr) { - return (arena_salloc(tsdn, iealloc(tsdn, ptr), ptr)); } @@ -249,7 +248,6 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, static void tcache_arena_associate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { - if (config_stats) { /* Link into list of extant tcaches. */ malloc_mutex_lock(tsdn, &arena->lock); @@ -262,7 +260,6 @@ tcache_arena_associate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) static void tcache_arena_dissociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { - if (config_stats) { /* Unlink from list of extant tcaches. */ malloc_mutex_lock(tsdn, &arena->lock); @@ -287,7 +284,6 @@ void tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *oldarena, arena_t *newarena) { - tcache_arena_dissociate(tsdn, tcache, oldarena); tcache_arena_associate(tsdn, tcache, newarena); } @@ -473,7 +469,6 @@ tcaches_create(tsd_t *tsd, unsigned *r_ind) static void tcaches_elm_flush(tsd_t *tsd, tcaches_t *elm) { - if (elm->tcache == NULL) return; tcache_destroy(tsd, elm->tcache); @@ -483,7 +478,6 @@ tcaches_elm_flush(tsd_t *tsd, tcaches_t *elm) void tcaches_flush(tsd_t *tsd, unsigned ind) { - tcaches_elm_flush(tsd, &tcaches[ind]); } diff --git a/src/tsd.c b/src/tsd.c index 5d9fc9f9..b4d7e795 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -14,21 +14,18 @@ malloc_tsd_data(, , tsd_t, TSD_INITIALIZER) void * malloc_tsd_malloc(size_t size) { - return (a0malloc(CACHELINE_CEILING(size))); } void malloc_tsd_dalloc(void *wrapper) { - a0dalloc(wrapper); } void malloc_tsd_no_cleanup(void *arg) { - not_reached(); } @@ -61,7 +58,6 @@ _malloc_thread_cleanup(void) void malloc_tsd_cleanup_register(bool (*f)(void)) { - assert(ncleanups < MALLOC_TSD_CLEANUPS_MAX); cleanups[ncleanups] = f; ncleanups++; @@ -127,7 +123,6 @@ malloc_tsd_boot0(void) void malloc_tsd_boot1(void) { - tsd_boot1(); *tsd_arenas_tdata_bypassp_get(tsd_fetch()) = false; } @@ -136,7 +131,6 @@ malloc_tsd_boot1(void) static BOOL WINAPI _tls_callback(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { - switch (fdwReason) { #ifdef JEMALLOC_LAZY_LOCK case DLL_THREAD_ATTACH: @@ -194,7 +188,6 @@ tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block) void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block) { - malloc_mutex_lock(TSDN_NULL, &head->lock); ql_remove(&head->blocks, block, link); malloc_mutex_unlock(TSDN_NULL, &head->lock); diff --git a/src/util.c b/src/util.c index dd8c2363..c6ac4e11 100644 --- a/src/util.c +++ b/src/util.c @@ -48,7 +48,6 @@ static char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, static void wrtmessage(void *cbopaque, const char *s) { - #if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_write) /* * Use syscall(2) rather than write(2) when possible in order to avoid @@ -74,7 +73,6 @@ JEMALLOC_EXPORT void (*je_malloc_message)(void *, const char *s); void malloc_write(const char *s) { - if (je_malloc_message != NULL) je_malloc_message(NULL, s); else @@ -88,7 +86,6 @@ malloc_write(const char *s) int buferror(int err, char *buf, size_t buflen) { - #ifdef _WIN32 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, (LPSTR)buf, (DWORD)buflen, NULL); @@ -292,7 +289,6 @@ d2s(intmax_t x, char sign, char *s, size_t *slen_p) static char * o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p) { - s = u2s(x, 8, false, s, slen_p); if (alt_form && *s != '0') { s--; @@ -305,7 +301,6 @@ o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p) static char * x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p) { - s = u2s(x, 16, uppercase, s, slen_p); if (alt_form) { s -= 2; diff --git a/src/witness.c b/src/witness.c index 0f5c0d73..ffc7e247 100644 --- a/src/witness.c +++ b/src/witness.c @@ -5,7 +5,6 @@ void witness_init(witness_t *witness, const char *name, witness_rank_t rank, witness_comp_t *comp, void *opaque) { - witness->name = name; witness->rank = rank; witness->comp = comp; @@ -41,7 +40,6 @@ witness_lock_error_t *witness_lock_error = JEMALLOC_N(n_witness_lock_error); void witness_owner_error(const witness_t *witness) { - malloc_printf(": Should own %s(%u)\n", witness->name, witness->rank); abort(); @@ -59,7 +57,6 @@ witness_owner_error_t *witness_owner_error = JEMALLOC_N(n_witness_owner_error); void witness_not_owner_error(const witness_t *witness) { - malloc_printf(": Should not own %s(%u)\n", witness->name, witness->rank); abort(); @@ -97,7 +94,6 @@ witness_lockless_error_t *witness_lockless_error = void witnesses_cleanup(tsd_t *tsd) { - witness_assert_lockless(tsd_tsdn(tsd)); /* Do nothing. */ @@ -106,14 +102,12 @@ witnesses_cleanup(tsd_t *tsd) void witness_prefork(tsd_t *tsd) { - tsd_witness_fork_set(tsd, true); } void witness_postfork_parent(tsd_t *tsd) { - tsd_witness_fork_set(tsd, false); } diff --git a/src/zone.c b/src/zone.c index 66ba02b9..1fcff64f 100644 --- a/src/zone.c +++ b/src/zone.c @@ -47,7 +47,6 @@ static void zone_force_unlock(malloc_zone_t *zone); static size_t zone_size(malloc_zone_t *zone, void *ptr) { - /* * There appear to be places within Darwin (such as setenv(3)) that * cause calls to this function with pointers that *no* zone owns. If @@ -63,14 +62,12 @@ zone_size(malloc_zone_t *zone, void *ptr) static void * zone_malloc(malloc_zone_t *zone, size_t size) { - return (je_malloc(size)); } static void * zone_calloc(malloc_zone_t *zone, size_t num, size_t size) { - return (je_calloc(num, size)); } @@ -87,7 +84,6 @@ zone_valloc(malloc_zone_t *zone, size_t size) static void zone_free(malloc_zone_t *zone, void *ptr) { - if (ivsalloc(tsdn_fetch(), ptr) != 0) { je_free(ptr); return; @@ -99,7 +95,6 @@ zone_free(malloc_zone_t *zone, void *ptr) static void * zone_realloc(malloc_zone_t *zone, void *ptr, size_t size) { - if (ivsalloc(tsdn_fetch(), ptr) != 0) return (je_realloc(ptr, size)); @@ -138,7 +133,6 @@ zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size) static void * zone_destroy(malloc_zone_t *zone) { - /* This function should never be called. */ not_reached(); return (NULL); @@ -147,7 +141,6 @@ zone_destroy(malloc_zone_t *zone) static size_t zone_good_size(malloc_zone_t *zone, size_t size) { - if (size == 0) size = 1; return (s2u(size)); @@ -156,7 +149,6 @@ zone_good_size(malloc_zone_t *zone, size_t size) static void zone_force_lock(malloc_zone_t *zone) { - if (isthreaded) jemalloc_prefork(); } @@ -164,7 +156,6 @@ zone_force_lock(malloc_zone_t *zone) static void zone_force_unlock(malloc_zone_t *zone) { - /* * Call jemalloc_postfork_child() rather than * jemalloc_postfork_parent(), because this function is executed by both @@ -179,7 +170,6 @@ zone_force_unlock(malloc_zone_t *zone) static void zone_init(void) { - jemalloc_zone.size = (void *)zone_size; jemalloc_zone.malloc = (void *)zone_malloc; jemalloc_zone.calloc = (void *)zone_calloc; @@ -297,7 +287,6 @@ JEMALLOC_ATTR(constructor) void zone_register(void) { - /* * If something else replaced the system default zone allocator, don't * register jemalloc's. diff --git a/test/include/test/math.h b/test/include/test/math.h index b057b29a..1728d60f 100644 --- a/test/include/test/math.h +++ b/test/include/test/math.h @@ -305,7 +305,6 @@ pt_chi2(double p, double df, double ln_gamma_df_2) JEMALLOC_INLINE double pt_gamma(double p, double shape, double scale, double ln_gamma_shape) { - return (pt_chi2(p, shape * 2.0, ln_gamma_shape) * 0.5 * scale); } #endif diff --git a/test/include/test/mq.h b/test/include/test/mq.h index 7c4df493..a974eb90 100644 --- a/test/include/test/mq.h +++ b/test/include/test/mq.h @@ -46,7 +46,6 @@ a_prefix##init(a_mq_type *mq) { \ a_attr void \ a_prefix##fini(a_mq_type *mq) \ { \ - \ mtx_fini(&mq->lock); \ } \ a_attr unsigned \ diff --git a/test/integration/MALLOCX_ARENA.c b/test/integration/MALLOCX_ARENA.c index 58032da8..1d9e423e 100644 --- a/test/integration/MALLOCX_ARENA.c +++ b/test/integration/MALLOCX_ARENA.c @@ -63,7 +63,6 @@ TEST_END int main(void) { - return (test( test_MALLOCX_ARENA)); } diff --git a/test/integration/aligned_alloc.c b/test/integration/aligned_alloc.c index 36fb6997..52b69acb 100644 --- a/test/integration/aligned_alloc.c +++ b/test/integration/aligned_alloc.c @@ -10,7 +10,6 @@ static void purge(void) { - assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl error"); } @@ -130,7 +129,6 @@ TEST_END int main(void) { - return (test( test_alignment_errors, test_oom_errors, diff --git a/test/integration/allocated.c b/test/integration/allocated.c index 6ce145b3..7570c52f 100644 --- a/test/integration/allocated.c +++ b/test/integration/allocated.c @@ -98,7 +98,6 @@ label_ENOENT: TEST_BEGIN(test_main_thread) { - thd_start(NULL); } TEST_END @@ -115,7 +114,6 @@ TEST_END int main(void) { - /* Run tests multiple times to check for bad interactions. */ return (test( test_main_thread, diff --git a/test/integration/cpp/basic.cpp b/test/integration/cpp/basic.cpp index eeb93c47..4a87a3ba 100644 --- a/test/integration/cpp/basic.cpp +++ b/test/integration/cpp/basic.cpp @@ -12,7 +12,6 @@ TEST_END int main() { - return (test( test_basic)); } diff --git a/test/integration/extent.c b/test/integration/extent.c index e347b66d..30849b0c 100644 --- a/test/integration/extent.c +++ b/test/integration/extent.c @@ -176,7 +176,6 @@ TEST_END int main(void) { - return (test( test_extent_manual_hook, test_extent_auto_hook)); diff --git a/test/integration/mallocx.c b/test/integration/mallocx.c index 2298f729..7617b1b7 100644 --- a/test/integration/mallocx.c +++ b/test/integration/mallocx.c @@ -20,7 +20,6 @@ get_nsizes_impl(const char *cmd) static unsigned get_nlarge(void) { - return (get_nsizes_impl("arenas.nlextents")); } @@ -46,7 +45,6 @@ get_size_impl(const char *cmd, size_t ind) static size_t get_large_size(size_t ind) { - return (get_size_impl("arenas.lextent.0.size", ind)); } @@ -58,7 +56,6 @@ get_large_size(size_t ind) static void purge(void) { - assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl error"); } @@ -225,7 +222,6 @@ TEST_END int main(void) { - return (test( test_overflow, test_oom, diff --git a/test/integration/overflow.c b/test/integration/overflow.c index 3e1e15f9..ad867e7c 100644 --- a/test/integration/overflow.c +++ b/test/integration/overflow.c @@ -43,7 +43,6 @@ TEST_END int main(void) { - return (test( test_overflow)); } diff --git a/test/integration/posix_memalign.c b/test/integration/posix_memalign.c index 9f3156ac..dace10f7 100644 --- a/test/integration/posix_memalign.c +++ b/test/integration/posix_memalign.c @@ -10,7 +10,6 @@ static void purge(void) { - assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl error"); } @@ -124,7 +123,6 @@ TEST_END int main(void) { - return (test( test_alignment_errors, test_oom_errors, diff --git a/test/integration/rallocx.c b/test/integration/rallocx.c index dd89e8cb..0a8b50c7 100644 --- a/test/integration/rallocx.c +++ b/test/integration/rallocx.c @@ -16,7 +16,6 @@ get_nsizes_impl(const char *cmd) static unsigned get_nlarge(void) { - return (get_nsizes_impl("arenas.nlextents")); } @@ -42,7 +41,6 @@ get_size_impl(const char *cmd, size_t ind) static size_t get_large_size(size_t ind) { - return (get_size_impl("arenas.lextent.0.size", ind)); } @@ -249,7 +247,6 @@ TEST_END int main(void) { - return (test( test_grow_and_shrink, test_zero, diff --git a/test/integration/sdallocx.c b/test/integration/sdallocx.c index f92e0589..5d0a8f80 100644 --- a/test/integration/sdallocx.c +++ b/test/integration/sdallocx.c @@ -50,7 +50,6 @@ TEST_END int main(void) { - return (test( test_basic, test_alignment_and_size)); diff --git a/test/integration/thread_arena.c b/test/integration/thread_arena.c index 7a35a635..cf8240d1 100644 --- a/test/integration/thread_arena.c +++ b/test/integration/thread_arena.c @@ -75,7 +75,6 @@ TEST_END int main(void) { - return (test( test_thread_arena)); } diff --git a/test/integration/thread_tcache_enabled.c b/test/integration/thread_tcache_enabled.c index 2c2825e1..1394371b 100644 --- a/test/integration/thread_tcache_enabled.c +++ b/test/integration/thread_tcache_enabled.c @@ -86,7 +86,6 @@ label_ENOENT: TEST_BEGIN(test_main_thread) { - thd_start(NULL); } TEST_END @@ -103,7 +102,6 @@ TEST_END int main(void) { - /* Run tests multiple times to check for bad interactions. */ return (test( test_main_thread, diff --git a/test/integration/xallocx.c b/test/integration/xallocx.c index d35ca39e..647404a7 100644 --- a/test/integration/xallocx.c +++ b/test/integration/xallocx.c @@ -87,14 +87,12 @@ get_nsizes_impl(const char *cmd) static unsigned get_nsmall(void) { - return (get_nsizes_impl("arenas.nbins")); } static unsigned get_nlarge(void) { - return (get_nsizes_impl("arenas.nlextents")); } @@ -120,14 +118,12 @@ get_size_impl(const char *cmd, size_t ind) static size_t get_small_size(size_t ind) { - return (get_size_impl("arenas.bin.0.size", ind)); } static size_t get_large_size(size_t ind) { - return (get_size_impl("arenas.lextent.0.size", ind)); } @@ -397,7 +393,6 @@ TEST_END int main(void) { - return (test( test_same_size, test_extra_no_move, diff --git a/test/src/btalloc.c b/test/src/btalloc.c index 9a253d97..a78cb89b 100644 --- a/test/src/btalloc.c +++ b/test/src/btalloc.c @@ -3,6 +3,5 @@ void * btalloc(size_t size, unsigned bits) { - return (btalloc_0(size, bits)); } diff --git a/test/src/mq.c b/test/src/mq.c index 40b31c15..47f362c0 100644 --- a/test/src/mq.c +++ b/test/src/mq.c @@ -7,7 +7,6 @@ void mq_nanosleep(unsigned ns) { - assert(ns <= 1000*1000*1000); #ifdef _WIN32 diff --git a/test/src/mtx.c b/test/src/mtx.c index 8a5dfdd9..bbfec4ac 100644 --- a/test/src/mtx.c +++ b/test/src/mtx.c @@ -7,7 +7,6 @@ bool mtx_init(mtx_t *mtx) { - #ifdef _WIN32 if (!InitializeCriticalSectionAndSpinCount(&mtx->lock, _CRT_SPINCOUNT)) return (true); @@ -33,7 +32,6 @@ mtx_init(mtx_t *mtx) void mtx_fini(mtx_t *mtx) { - #ifdef _WIN32 #elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) #elif (defined(JEMALLOC_OSSPIN)) @@ -45,7 +43,6 @@ mtx_fini(mtx_t *mtx) void mtx_lock(mtx_t *mtx) { - #ifdef _WIN32 EnterCriticalSection(&mtx->lock); #elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) @@ -60,7 +57,6 @@ mtx_lock(mtx_t *mtx) void mtx_unlock(mtx_t *mtx) { - #ifdef _WIN32 LeaveCriticalSection(&mtx->lock); #elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) diff --git a/test/src/test.c b/test/src/test.c index d70cc750..345cc1c1 100644 --- a/test/src/test.c +++ b/test/src/test.c @@ -34,7 +34,6 @@ test_fail(const char *format, ...) static const char * test_status_string(test_status_t test_status) { - switch (test_status) { case test_status_pass: return "pass"; case test_status_skip: return "skip"; @@ -46,7 +45,6 @@ test_status_string(test_status_t test_status) void p_test_init(const char *name) { - test_count++; test_status = test_status_pass; test_name = name; @@ -55,7 +53,6 @@ p_test_init(const char *name) void p_test_fini(void) { - test_counts[test_status]++; malloc_printf("%s: %s\n", test_name, test_status_string(test_status)); } @@ -127,7 +124,6 @@ p_test_no_malloc_init(test_t *t, ...) void p_test_fail(const char *prefix, const char *message) { - malloc_cprintf(NULL, NULL, "%s%s\n", prefix, message); test_status = test_status_fail; } diff --git a/test/src/thd.c b/test/src/thd.c index c9d00658..e3167089 100644 --- a/test/src/thd.c +++ b/test/src/thd.c @@ -13,7 +13,6 @@ thd_create(thd_t *thd, void *(*proc)(void *), void *arg) void thd_join(thd_t thd, void **ret) { - if (WaitForSingleObject(thd, INFINITE) == WAIT_OBJECT_0 && ret) { DWORD exit_code; GetExitCodeThread(thd, (LPDWORD) &exit_code); @@ -25,7 +24,6 @@ thd_join(thd_t thd, void **ret) void thd_create(thd_t *thd, void *(*proc)(void *), void *arg) { - if (pthread_create(thd, NULL, proc, arg) != 0) test_fail("Error in pthread_create()\n"); } @@ -33,7 +31,6 @@ thd_create(thd_t *thd, void *(*proc)(void *), void *arg) void thd_join(thd_t thd, void **ret) { - pthread_join(thd, ret); } #endif diff --git a/test/src/timer.c b/test/src/timer.c index 3c7e63a2..82f69d0a 100644 --- a/test/src/timer.c +++ b/test/src/timer.c @@ -3,7 +3,6 @@ void timer_start(timedelta_t *timer) { - nstime_init(&timer->t0, 0); nstime_update(&timer->t0); } @@ -11,7 +10,6 @@ timer_start(timedelta_t *timer) void timer_stop(timedelta_t *timer) { - nstime_copy(&timer->t1, &timer->t0); nstime_update(&timer->t1); } diff --git a/test/stress/microbench.c b/test/stress/microbench.c index 7dc45f89..c599d9d3 100644 --- a/test/stress/microbench.c +++ b/test/stress/microbench.c @@ -65,7 +65,6 @@ mallocx_free(void) TEST_BEGIN(test_malloc_vs_mallocx) { - compare_funcs(10*1000*1000, 100*1000*1000, "malloc", malloc_free, "mallocx", mallocx_free); } @@ -95,7 +94,6 @@ malloc_sdallocx(void) TEST_BEGIN(test_free_vs_dallocx) { - compare_funcs(10*1000*1000, 100*1000*1000, "free", malloc_free, "dallocx", malloc_dallocx); } @@ -103,7 +101,6 @@ TEST_END TEST_BEGIN(test_dallocx_vs_sdallocx) { - compare_funcs(10*1000*1000, 100*1000*1000, "dallocx", malloc_dallocx, "sdallocx", malloc_sdallocx); } @@ -140,7 +137,6 @@ malloc_sallocx_free(void) TEST_BEGIN(test_mus_vs_sallocx) { - compare_funcs(10*1000*1000, 100*1000*1000, "malloc_usable_size", malloc_mus_free, "sallocx", malloc_sallocx_free); } @@ -163,7 +159,6 @@ malloc_nallocx_free(void) TEST_BEGIN(test_sallocx_vs_nallocx) { - compare_funcs(10*1000*1000, 100*1000*1000, "sallocx", malloc_sallocx_free, "nallocx", malloc_nallocx_free); } @@ -172,7 +167,6 @@ TEST_END int main(void) { - return (test( test_malloc_vs_mallocx, test_free_vs_dallocx, diff --git a/test/unit/SFMT.c b/test/unit/SFMT.c index ba4be870..cf52670b 100644 --- a/test/unit/SFMT.c +++ b/test/unit/SFMT.c @@ -1596,7 +1596,6 @@ TEST_END int main(void) { - return (test( test_gen_rand_32, test_by_array_32, diff --git a/test/unit/a0.c b/test/unit/a0.c index b9ba45a3..87f7e527 100644 --- a/test/unit/a0.c +++ b/test/unit/a0.c @@ -13,7 +13,6 @@ TEST_END int main(void) { - return (test_no_malloc_init( test_a0)); } diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 65ff1031..257f9729 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -20,14 +20,12 @@ get_nsizes_impl(const char *cmd) static unsigned get_nsmall(void) { - return (get_nsizes_impl("arenas.nbins")); } static unsigned get_nlarge(void) { - return (get_nsizes_impl("arenas.nlextents")); } @@ -53,14 +51,12 @@ get_size_impl(const char *cmd, size_t ind) static size_t get_small_size(size_t ind) { - return (get_size_impl("arenas.bin.0.size", ind)); } static size_t get_large_size(size_t ind) { - return (get_size_impl("arenas.lextent.0.size", ind)); } @@ -164,14 +160,12 @@ do_arena_reset_destroy(const char *name, unsigned arena_ind) static void do_arena_reset(unsigned arena_ind) { - do_arena_reset_destroy("arena.0.reset", arena_ind); } static void do_arena_destroy(unsigned arena_ind) { - do_arena_reset_destroy("arena.0.destroy", arena_ind); } @@ -214,7 +208,6 @@ arena_i_initialized(unsigned arena_ind, bool refresh) TEST_BEGIN(test_arena_destroy_initial) { - assert_false(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false), "Destroyed arena stats should not be initialized"); } @@ -269,7 +262,6 @@ static bool extent_dalloc_unmap(extent_hooks_t *extent_hooks, void *addr, size_t size, bool committed, unsigned arena_ind) { - TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, " "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ? "true" : "false", arena_ind); @@ -338,7 +330,6 @@ TEST_END int main(void) { - return (test( test_arena_reset, test_arena_destroy_initial, diff --git a/test/unit/atomic.c b/test/unit/atomic.c index b8933a69..1d143689 100644 --- a/test/unit/atomic.c +++ b/test/unit/atomic.c @@ -68,7 +68,6 @@ typedef struct p##_test_s p##_test_t; TEST_STRUCT(u64, uint64_t) TEST_BEGIN(test_atomic_u64) { - #if !(LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) test_skip("64-bit atomic operations not supported"); #else @@ -80,7 +79,6 @@ TEST_END TEST_STRUCT(u32, uint32_t) TEST_BEGIN(test_atomic_u32) { - TEST_BODY(u32, uint32_t, uint32_t, u32, "#"FMTx32); } TEST_END @@ -88,7 +86,6 @@ TEST_END TEST_STRUCT(p, void *) TEST_BEGIN(test_atomic_p) { - TEST_BODY(p, void *, uintptr_t, ptr, "p"); } TEST_END @@ -96,7 +93,6 @@ TEST_END TEST_STRUCT(zu, size_t) TEST_BEGIN(test_atomic_zu) { - TEST_BODY(zu, size_t, size_t, zu, "#zx"); } TEST_END @@ -104,7 +100,6 @@ TEST_END TEST_STRUCT(u, unsigned) TEST_BEGIN(test_atomic_u) { - TEST_BODY(u, unsigned, unsigned, u, "#x"); } TEST_END @@ -112,7 +107,6 @@ TEST_END int main(void) { - return (test( test_atomic_u64, test_atomic_u32, diff --git a/test/unit/base.c b/test/unit/base.c index 8f97e8bf..9aa43eab 100644 --- a/test/unit/base.c +++ b/test/unit/base.c @@ -208,7 +208,6 @@ TEST_END int main(void) { - return (test( test_base_hooks_default, test_base_hooks_null, diff --git a/test/unit/bitmap.c b/test/unit/bitmap.c index 10d47c76..b502bfea 100644 --- a/test/unit/bitmap.c +++ b/test/unit/bitmap.c @@ -126,7 +126,6 @@ test_bitmap_initializer_body(const bitmap_info_t *binfo, size_t nbits) TEST_BEGIN(test_bitmap_initializer) { - #define NB(nbits) { \ if (nbits <= BITMAP_MAXBITS) { \ bitmap_info_t binfo = \ @@ -339,7 +338,6 @@ TEST_END int main(void) { - return (test( test_bitmap_initializer, test_bitmap_size, diff --git a/test/unit/ckh.c b/test/unit/ckh.c index 2cbc2268..1f576689 100644 --- a/test/unit/ckh.c +++ b/test/unit/ckh.c @@ -206,7 +206,6 @@ TEST_END int main(void) { - return (test( test_new_delete, test_count_insert_search_remove, diff --git a/test/unit/decay.c b/test/unit/decay.c index 7efecf0f..b3b1dd9d 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -12,14 +12,12 @@ static bool monotonic_mock; static bool nstime_monotonic_mock(void) { - return (monotonic_mock); } static bool nstime_update_mock(nstime_t *time) { - nupdates_mock++; if (monotonic_mock) nstime_copy(time, &time_mock); @@ -357,7 +355,6 @@ TEST_END int main(void) { - return (test( test_decay_ticks, test_decay_ticker, diff --git a/test/unit/extent_quantize.c b/test/unit/extent_quantize.c index 43fa3604..a5c1b7a0 100644 --- a/test/unit/extent_quantize.c +++ b/test/unit/extent_quantize.c @@ -138,7 +138,6 @@ TEST_END int main(void) { - return (test( test_small_extent_size, test_large_extent_size, diff --git a/test/unit/fork.c b/test/unit/fork.c index c530797c..58091c66 100644 --- a/test/unit/fork.c +++ b/test/unit/fork.c @@ -58,7 +58,6 @@ TEST_END int main(void) { - return (test( test_fork)); } diff --git a/test/unit/hash.c b/test/unit/hash.c index 010c9d76..ff237779 100644 --- a/test/unit/hash.c +++ b/test/unit/hash.c @@ -38,7 +38,6 @@ typedef enum { static int hash_variant_bits(hash_variant_t variant) { - switch (variant) { case hash_variant_x86_32: return (32); case hash_variant_x86_128: return (128); @@ -50,7 +49,6 @@ hash_variant_bits(hash_variant_t variant) static const char * hash_variant_string(hash_variant_t variant) { - switch (variant) { case hash_variant_x86_32: return ("hash_x86_32"); case hash_variant_x86_128: return ("hash_x86_128"); @@ -155,21 +153,18 @@ hash_variant_verify(hash_variant_t variant) TEST_BEGIN(test_hash_x86_32) { - hash_variant_verify(hash_variant_x86_32); } TEST_END TEST_BEGIN(test_hash_x86_128) { - hash_variant_verify(hash_variant_x86_128); } TEST_END TEST_BEGIN(test_hash_x64_128) { - hash_variant_verify(hash_variant_x64_128); } TEST_END @@ -177,7 +172,6 @@ TEST_END int main(void) { - return (test( test_hash_x86_32, test_hash_x86_128, diff --git a/test/unit/junk.c b/test/unit/junk.c index 680f0d21..5f34d051 100644 --- a/test/unit/junk.c +++ b/test/unit/junk.c @@ -17,7 +17,6 @@ static bool saw_junking; static void watch_junking(void *p) { - watch_for_junking = p; saw_junking = false; } @@ -55,7 +54,6 @@ large_dalloc_junk_intercept(void *ptr, size_t usize) static void large_dalloc_maybe_junk_intercept(void *ptr, size_t usize) { - large_dalloc_maybe_junk_orig(ptr, usize); if (ptr == watch_for_junking) saw_junking = true; @@ -130,7 +128,6 @@ test_junk(size_t sz_min, size_t sz_max) TEST_BEGIN(test_junk_small) { - test_skip_if(!config_fill); test_junk(1, SMALL_MAXCLASS-1); } @@ -138,7 +135,6 @@ TEST_END TEST_BEGIN(test_junk_large) { - test_skip_if(!config_fill); test_junk(SMALL_MAXCLASS+1, (1U << (LG_LARGE_MINCLASS+1))); } @@ -147,7 +143,6 @@ TEST_END int main(void) { - return (test( test_junk_small, test_junk_large)); diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index fbe76cb4..5b734e1d 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -121,7 +121,6 @@ TEST_END TEST_BEGIN(test_mallctl_config) { - #define TEST_MALLCTL_CONFIG(config, t) do { \ t oldval; \ size_t sz = sizeof(oldval); \ @@ -551,7 +550,6 @@ TEST_END TEST_BEGIN(test_arenas_constants) { - #define TEST_ARENAS_CONSTANT(t, name, expected) do { \ t name; \ size_t sz = sizeof(t); \ @@ -571,7 +569,6 @@ TEST_END TEST_BEGIN(test_arenas_bin_constants) { - #define TEST_ARENAS_BIN_CONSTANT(t, name, expected) do { \ t name; \ size_t sz = sizeof(t); \ @@ -591,7 +588,6 @@ TEST_END TEST_BEGIN(test_arenas_lextent_constants) { - #define TEST_ARENAS_LEXTENT_CONSTANT(t, name, expected) do { \ t name; \ size_t sz = sizeof(t); \ @@ -626,7 +622,6 @@ TEST_END TEST_BEGIN(test_stats_arenas) { - #define TEST_STATS_ARENAS(t, name) do { \ t name; \ size_t sz = sizeof(t); \ @@ -647,7 +642,6 @@ TEST_END int main(void) { - return (test( test_mallctl_errors, test_mallctlnametomib_errors, diff --git a/test/unit/math.c b/test/unit/math.c index adb72bed..8e5ec61b 100644 --- a/test/unit/math.c +++ b/test/unit/math.c @@ -387,7 +387,6 @@ TEST_END int main(void) { - return (test( test_ln_gamma_factorial, test_ln_gamma_misc, diff --git a/test/unit/mq.c b/test/unit/mq.c index bde2a480..bd289c54 100644 --- a/test/unit/mq.c +++ b/test/unit/mq.c @@ -85,7 +85,6 @@ TEST_END int main(void) { - return (test( test_mq_basic, test_mq_threaded)); diff --git a/test/unit/mtx.c b/test/unit/mtx.c index 96ff6948..2eccc98f 100644 --- a/test/unit/mtx.c +++ b/test/unit/mtx.c @@ -53,7 +53,6 @@ TEST_END int main(void) { - return (test( test_mtx_basic, test_mtx_race)); diff --git a/test/unit/nstime.c b/test/unit/nstime.c index 0368bc26..6548ba23 100644 --- a/test/unit/nstime.c +++ b/test/unit/nstime.c @@ -178,7 +178,6 @@ TEST_END TEST_BEGIN(test_nstime_monotonic) { - nstime_monotonic(); } TEST_END @@ -211,7 +210,6 @@ TEST_END int main(void) { - return (test( test_nstime_init, test_nstime_init2, diff --git a/test/unit/pack.c b/test/unit/pack.c index 81ded4ec..316b6df5 100644 --- a/test/unit/pack.c +++ b/test/unit/pack.c @@ -161,7 +161,6 @@ TEST_END int main(void) { - return (test( test_pack)); } diff --git a/test/unit/pages.c b/test/unit/pages.c index f297215a..1e6add95 100644 --- a/test/unit/pages.c +++ b/test/unit/pages.c @@ -24,7 +24,6 @@ TEST_END int main(void) { - return (test( test_pages_huge)); } diff --git a/test/unit/ph.c b/test/unit/ph.c index da442f07..10bf99e4 100644 --- a/test/unit/ph.c +++ b/test/unit/ph.c @@ -148,7 +148,6 @@ TEST_END static void node_remove(heap_t *heap, node_t *node) { - heap_remove(heap, node); node->magic = 0; @@ -283,7 +282,6 @@ TEST_END int main(void) { - return (test( test_ph_empty, test_ph_random)); diff --git a/test/unit/prng.c b/test/unit/prng.c index 80c9d733..f32d82a6 100644 --- a/test/unit/prng.c +++ b/test/unit/prng.c @@ -114,35 +114,30 @@ test_prng_lg_range_zu(bool atomic) TEST_BEGIN(test_prng_lg_range_u32_nonatomic) { - test_prng_lg_range_u32(false); } TEST_END TEST_BEGIN(test_prng_lg_range_u32_atomic) { - test_prng_lg_range_u32(true); } TEST_END TEST_BEGIN(test_prng_lg_range_u64_nonatomic) { - test_prng_lg_range_u64(); } TEST_END TEST_BEGIN(test_prng_lg_range_zu_nonatomic) { - test_prng_lg_range_zu(false); } TEST_END TEST_BEGIN(test_prng_lg_range_zu_atomic) { - test_prng_lg_range_zu(true); } TEST_END @@ -212,35 +207,30 @@ test_prng_range_zu(bool atomic) TEST_BEGIN(test_prng_range_u32_nonatomic) { - test_prng_range_u32(false); } TEST_END TEST_BEGIN(test_prng_range_u32_atomic) { - test_prng_range_u32(true); } TEST_END TEST_BEGIN(test_prng_range_u64_nonatomic) { - test_prng_range_u64(); } TEST_END TEST_BEGIN(test_prng_range_zu_nonatomic) { - test_prng_range_zu(false); } TEST_END TEST_BEGIN(test_prng_range_zu_atomic) { - test_prng_range_zu(true); } TEST_END @@ -248,7 +238,6 @@ TEST_END int main(void) { - return (test( test_prng_lg_range_u32_nonatomic, test_prng_lg_range_u32_atomic, diff --git a/test/unit/prof_accum.c b/test/unit/prof_accum.c index d941b5bc..41ebeea5 100644 --- a/test/unit/prof_accum.c +++ b/test/unit/prof_accum.c @@ -24,7 +24,6 @@ prof_dump_open_intercept(bool propagate_err, const char *filename) static void * alloc_from_permuted_backtrace(unsigned thd_ind, unsigned iteration) { - return (btalloc(1, thd_ind*NALLOCS_PER_THREAD + iteration)); } @@ -86,7 +85,6 @@ TEST_END int main(void) { - return (test( test_idump)); } diff --git a/test/unit/prof_active.c b/test/unit/prof_active.c index d00943a4..d3b341d7 100644 --- a/test/unit/prof_active.c +++ b/test/unit/prof_active.c @@ -38,7 +38,6 @@ static void mallctl_prof_active_get_impl(bool prof_active_old_expected, const char *func, int line) { - mallctl_bool_get("prof.active", prof_active_old_expected, func, line); } #define mallctl_prof_active_get(a) \ @@ -48,7 +47,6 @@ static void mallctl_prof_active_set_impl(bool prof_active_old_expected, bool prof_active_new, const char *func, int line) { - mallctl_bool_set("prof.active", prof_active_old_expected, prof_active_new, func, line); } @@ -59,7 +57,6 @@ static void mallctl_thread_prof_active_get_impl(bool thread_prof_active_old_expected, const char *func, int line) { - mallctl_bool_get("thread.prof.active", thread_prof_active_old_expected, func, line); } @@ -70,7 +67,6 @@ static void mallctl_thread_prof_active_set_impl(bool thread_prof_active_old_expected, bool thread_prof_active_new, const char *func, int line) { - mallctl_bool_set("thread.prof.active", thread_prof_active_old_expected, thread_prof_active_new, func, line); } @@ -96,7 +92,6 @@ prof_sampling_probe_impl(bool expect_sample, const char *func, int line) TEST_BEGIN(test_prof_active) { - test_skip_if(!config_prof); mallctl_prof_active_get(true); @@ -131,7 +126,6 @@ TEST_END int main(void) { - return (test( test_prof_active)); } diff --git a/test/unit/prof_gdump.c b/test/unit/prof_gdump.c index cb99acdf..53f7cad6 100644 --- a/test/unit/prof_gdump.c +++ b/test/unit/prof_gdump.c @@ -76,7 +76,6 @@ TEST_END int main(void) { - return (test( test_gdump)); } diff --git a/test/unit/prof_idump.c b/test/unit/prof_idump.c index c293350f..43824c6a 100644 --- a/test/unit/prof_idump.c +++ b/test/unit/prof_idump.c @@ -53,7 +53,6 @@ TEST_END int main(void) { - return (test( test_idump)); } diff --git a/test/unit/prof_reset.c b/test/unit/prof_reset.c index 59d70796..cc13e378 100644 --- a/test/unit/prof_reset.c +++ b/test/unit/prof_reset.c @@ -19,7 +19,6 @@ prof_dump_open_intercept(bool propagate_err, const char *filename) static void set_prof_active(bool active) { - assert_d_eq(mallctl("prof.active", NULL, NULL, (void *)&active, sizeof(active)), 0, "Unexpected mallctl failure"); } @@ -98,7 +97,6 @@ static bool prof_dump_header_intercept(tsdn_t *tsdn, bool propagate_err, const prof_cnt_t *cnt_all) { - prof_dump_header_intercepted = true; memcpy(&cnt_all_copy, cnt_all, sizeof(prof_cnt_t)); @@ -292,7 +290,6 @@ TEST_END int main(void) { - /* Intercept dumping prior to running any tests. */ prof_dump_open = prof_dump_open_intercept; diff --git a/test/unit/prof_thread_name.c b/test/unit/prof_thread_name.c index 9ec54977..8699936b 100644 --- a/test/unit/prof_thread_name.c +++ b/test/unit/prof_thread_name.c @@ -26,7 +26,6 @@ static void mallctl_thread_name_set_impl(const char *thread_name, const char *func, int line) { - assert_d_eq(mallctl("thread.prof.name", NULL, NULL, (void *)&thread_name, sizeof(thread_name)), 0, "%s():%d: Unexpected mallctl failure reading thread.prof.name", @@ -124,7 +123,6 @@ TEST_END int main(void) { - return (test( test_prof_thread_name_validation, test_prof_thread_name_threaded)); diff --git a/test/unit/ql.c b/test/unit/ql.c index 05fad450..2ebb4502 100644 --- a/test/unit/ql.c +++ b/test/unit/ql.c @@ -198,7 +198,6 @@ TEST_END int main(void) { - return (test( test_ql_empty, test_ql_tail_insert, diff --git a/test/unit/qr.c b/test/unit/qr.c index 8b764e11..7c9c1029 100644 --- a/test/unit/qr.c +++ b/test/unit/qr.c @@ -238,7 +238,6 @@ TEST_END int main(void) { - return (test( test_qr_one, test_qr_after_insert, diff --git a/test/unit/rb.c b/test/unit/rb.c index cf3d3a78..56e00219 100644 --- a/test/unit/rb.c +++ b/test/unit/rb.c @@ -347,7 +347,6 @@ TEST_END int main(void) { - return (test( test_rb_empty, test_rb_random)); diff --git a/test/unit/rtree.c b/test/unit/rtree.c index 03f4e269..d2f37055 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -24,7 +24,6 @@ rtree_node_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) static void rtree_node_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) { - if (rtree != test_rtree) { rtree_node_dalloc_orig(tsdn, rtree, node); return; @@ -283,7 +282,6 @@ TEST_END int main(void) { - rtree_node_alloc_orig = rtree_node_alloc; rtree_node_alloc = rtree_node_alloc_intercept; rtree_node_dalloc_orig = rtree_node_dalloc; diff --git a/test/unit/size_classes.c b/test/unit/size_classes.c index 9b47b204..f7c14bc0 100644 --- a/test/unit/size_classes.c +++ b/test/unit/size_classes.c @@ -178,7 +178,6 @@ TEST_END int main(void) { - return (test( test_size_classes, test_psize_classes, diff --git a/test/unit/slab.c b/test/unit/slab.c index 42e82a8b..7e6a62f5 100644 --- a/test/unit/slab.c +++ b/test/unit/slab.c @@ -29,7 +29,6 @@ TEST_END int main(void) { - return (test( test_arena_slab_regind)); } diff --git a/test/unit/smoothstep.c b/test/unit/smoothstep.c index 4cfb2134..071aede2 100644 --- a/test/unit/smoothstep.c +++ b/test/unit/smoothstep.c @@ -98,7 +98,6 @@ TEST_END int main(void) { - return (test( test_smoothstep_integral, test_smoothstep_monotonic, diff --git a/test/unit/stats.c b/test/unit/stats.c index a99a88f0..18856f12 100644 --- a/test/unit/stats.c +++ b/test/unit/stats.c @@ -120,7 +120,6 @@ TEST_END void * thd_start(void *arg) { - return (NULL); } @@ -350,7 +349,6 @@ TEST_END int main(void) { - return (test( test_stats_summary, test_stats_large, diff --git a/test/unit/ticker.c b/test/unit/ticker.c index e737020a..b8af46c7 100644 --- a/test/unit/ticker.c +++ b/test/unit/ticker.c @@ -68,7 +68,6 @@ TEST_END int main(void) { - return (test( test_ticker_tick, test_ticker_ticks, diff --git a/test/unit/tsd.c b/test/unit/tsd.c index d5f96ac3..5313ef88 100644 --- a/test/unit/tsd.c +++ b/test/unit/tsd.c @@ -78,7 +78,6 @@ thd_start(void *arg) TEST_BEGIN(test_tsd_main_thread) { - thd_start((void *)(uintptr_t)0xa5f3e329); } TEST_END @@ -98,7 +97,6 @@ TEST_END int main(void) { - /* Core tsd bootstrapping must happen prior to data_tsd_boot(). */ if (nallocx(1, 0) == 0) { malloc_printf("Initialization error"); diff --git a/test/unit/util.c b/test/unit/util.c index b1f9abd9..b891a199 100644 --- a/test/unit/util.c +++ b/test/unit/util.c @@ -33,21 +33,18 @@ TEST_BEGIN(test_pow2_ceil_u64) { - TEST_POW2_CEIL(uint64_t, u64, FMTu64); } TEST_END TEST_BEGIN(test_pow2_ceil_u32) { - TEST_POW2_CEIL(uint32_t, u32, FMTu32); } TEST_END TEST_BEGIN(test_pow2_ceil_zu) { - TEST_POW2_CEIL(size_t, zu, "zu"); } TEST_END @@ -307,7 +304,6 @@ TEST_END int main(void) { - return (test( test_pow2_ceil_u64, test_pow2_ceil_u32, diff --git a/test/unit/witness.c b/test/unit/witness.c index 2b012034..13593989 100644 --- a/test/unit/witness.c +++ b/test/unit/witness.c @@ -14,35 +14,30 @@ static void witness_lock_error_intercept(const witness_list_t *witnesses, const witness_t *witness) { - saw_lock_error = true; } static void witness_owner_error_intercept(const witness_t *witness) { - saw_owner_error = true; } static void witness_not_owner_error_intercept(const witness_t *witness) { - saw_not_owner_error = true; } static void witness_lockless_error_intercept(const witness_list_t *witnesses) { - saw_lockless_error = true; } static int witness_comp(const witness_t *a, void *oa, const witness_t *b, void *ob) { - assert_u_eq(a->rank, b->rank, "Witnesses should have equal rank"); assert(oa == (void *)a); @@ -54,7 +49,6 @@ witness_comp(const witness_t *a, void *oa, const witness_t *b, void *ob) static int witness_comp_reverse(const witness_t *a, void *oa, const witness_t *b, void *ob) { - assert_u_eq(a->rank, b->rank, "Witnesses should have equal rank"); assert(oa == (void *)a); @@ -273,7 +267,6 @@ TEST_END int main(void) { - return (test( test_witness, test_witness_comp, diff --git a/test/unit/zero.c b/test/unit/zero.c index c025c831..c752954c 100644 --- a/test/unit/zero.c +++ b/test/unit/zero.c @@ -47,7 +47,6 @@ test_zero(size_t sz_min, size_t sz_max) TEST_BEGIN(test_zero_small) { - test_skip_if(!config_fill); test_zero(1, SMALL_MAXCLASS-1); } @@ -55,7 +54,6 @@ TEST_END TEST_BEGIN(test_zero_large) { - test_skip_if(!config_fill); test_zero(SMALL_MAXCLASS+1, (1U << (LG_LARGE_MINCLASS+1))); } @@ -64,7 +62,6 @@ TEST_END int main(void) { - return (test( test_zero_small, test_zero_large)); -- GitLab From e8990dc7c7b3083ce05823e581780c2b22f5cbbb Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 13 Jan 2017 15:22:16 -0800 Subject: [PATCH 227/544] Remove redundent stats-merging logic when destroying tcache. The removed stats merging logic is already taken care of by tcache_flush. --- src/tcache.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/tcache.c b/src/tcache.c index 66e255d6..d1323418 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -357,11 +357,8 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache) tcache_bin_t *tbin = &tcache->tbins[i]; tcache_bin_flush_small(tsd, tcache, tbin, i, 0); - if (config_stats && tbin->tstats.nrequests != 0) { - arena_bin_t *bin = &arena->bins[i]; - malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); - bin->stats.nrequests += tbin->tstats.nrequests; - malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); + if (config_stats) { + assert(tbin->tstats.nrequests == 0); } } @@ -369,12 +366,8 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache) tcache_bin_t *tbin = &tcache->tbins[i]; tcache_bin_flush_large(tsd, tbin, i, 0, tcache); - if (config_stats && tbin->tstats.nrequests != 0) { - malloc_mutex_lock(tsd_tsdn(tsd), &arena->lock); - arena->stats.nrequests_large += tbin->tstats.nrequests; - arena->stats.lstats[i - NBINS].nrequests += - tbin->tstats.nrequests; - malloc_mutex_unlock(tsd_tsdn(tsd), &arena->lock); + if (config_stats) { + assert(tbin->tstats.nrequests == 0); } } -- GitLab From 41aa41853c1101c5e6f1b5759b830dff22e560df Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 13 Jan 2017 18:17:54 -0800 Subject: [PATCH 228/544] Fix style nits. --- src/jemalloc_cpp.cpp | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/jemalloc_cpp.cpp b/src/jemalloc_cpp.cpp index 84d47aed..5cecfdbf 100644 --- a/src/jemalloc_cpp.cpp +++ b/src/jemalloc_cpp.cpp @@ -17,26 +17,25 @@ void *operator new(std::size_t size); void *operator new[](std::size_t size); -void *operator new(std::size_t size, const std::nothrow_t&) noexcept; -void *operator new[](std::size_t size, const std::nothrow_t&) noexcept; -void operator delete(void* ptr) noexcept; -void operator delete[](void* ptr) noexcept; -void operator delete(void* ptr, const std::nothrow_t&) noexcept; -void operator delete[](void* ptr, const std::nothrow_t&) noexcept; +void *operator new(std::size_t size, const std::nothrow_t &) noexcept; +void *operator new[](std::size_t size, const std::nothrow_t &) noexcept; +void operator delete(void *ptr) noexcept; +void operator delete[](void *ptr) noexcept; +void operator delete(void *ptr, const std::nothrow_t &) noexcept; +void operator delete[](void *ptr, const std::nothrow_t &) noexcept; #if __cpp_sized_deallocation >= 201309 /* C++14's sized-delete operators. */ -void operator delete(void* ptr, std::size_t size) noexcept; -void operator delete[](void* ptr, std::size_t size) noexcept; +void operator delete(void *ptr, std::size_t size) noexcept; +void operator delete[](void *ptr, std::size_t size) noexcept; #endif - template JEMALLOC_INLINE void * newImpl(std::size_t size) noexcept(IsNoExcept) { - void* ptr = je_malloc(size); + void *ptr = je_malloc(size); if (likely(ptr != nullptr)) return (ptr); @@ -55,7 +54,7 @@ newImpl(std::size_t size) noexcept(IsNoExcept) try { handler(); - } catch (const std::bad_alloc&) { + } catch (const std::bad_alloc &) { break; } @@ -80,36 +79,36 @@ operator new[](std::size_t size) } void * -operator new(std::size_t size, const std::nothrow_t&) noexcept +operator new(std::size_t size, const std::nothrow_t &) noexcept { return (newImpl(size)); } void * -operator new[](std::size_t size, const std::nothrow_t&) noexcept +operator new[](std::size_t size, const std::nothrow_t &) noexcept { return (newImpl(size)); } void -operator delete(void* ptr) noexcept +operator delete(void *ptr) noexcept { je_free(ptr); } void -operator delete[](void* ptr) noexcept +operator delete[](void *ptr) noexcept { je_free(ptr); } void -operator delete(void* ptr, const std::nothrow_t&) noexcept +operator delete(void *ptr, const std::nothrow_t &) noexcept { je_free(ptr); } -void operator delete[](void* ptr, const std::nothrow_t&) noexcept +void operator delete[](void *ptr, const std::nothrow_t &) noexcept { je_free(ptr); } @@ -117,12 +116,12 @@ void operator delete[](void* ptr, const std::nothrow_t&) noexcept #if __cpp_sized_deallocation >= 201309 void -operator delete(void* ptr, std::size_t size) noexcept +operator delete(void *ptr, std::size_t size) noexcept { je_sdallocx(ptr, size, /*flags=*/0); } -void operator delete[](void* ptr, std::size_t size) noexcept +void operator delete[](void *ptr, std::size_t size) noexcept { je_sdallocx(ptr, size, /*flags=*/0); } -- GitLab From 8115f05b2675d5449af686ddecc0ae5d5fd23fc2 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 13 Jan 2017 18:43:21 -0800 Subject: [PATCH 229/544] Add nullptr support to sized delete operators. --- src/jemalloc_cpp.cpp | 6 ++++++ test/integration/cpp/basic.cpp | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/jemalloc_cpp.cpp b/src/jemalloc_cpp.cpp index 5cecfdbf..984c944b 100644 --- a/src/jemalloc_cpp.cpp +++ b/src/jemalloc_cpp.cpp @@ -118,11 +118,17 @@ void operator delete[](void *ptr, const std::nothrow_t &) noexcept void operator delete(void *ptr, std::size_t size) noexcept { + if (unlikely(ptr == nullptr)) { + return; + } je_sdallocx(ptr, size, /*flags=*/0); } void operator delete[](void *ptr, std::size_t size) noexcept { + if (unlikely(ptr == nullptr)) { + return; + } je_sdallocx(ptr, size, /*flags=*/0); } diff --git a/test/integration/cpp/basic.cpp b/test/integration/cpp/basic.cpp index 4a87a3ba..b208e1d1 100644 --- a/test/integration/cpp/basic.cpp +++ b/test/integration/cpp/basic.cpp @@ -6,6 +6,16 @@ TEST_BEGIN(test_basic) auto foo = new long(4); assert_ptr_not_null(foo, "Unexpected new[] failure"); delete foo; + // Test nullptr handling. + foo = nullptr; + delete foo; + + auto bar = new long; + assert_ptr_not_null(bar, "Unexpected new failure"); + delete bar; + // Test nullptr handling. + bar = nullptr; + delete bar; } TEST_END -- GitLab From de5e1aff2a96afb18383667954740509538daa86 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 17 Jan 2017 07:19:17 -0800 Subject: [PATCH 230/544] Formatting/comment fixes. --- src/arena.c | 4 ++-- src/extent.c | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/arena.c b/src/arena.c index 80af3f99..70d71fcb 100644 --- a/src/arena.c +++ b/src/arena.c @@ -895,8 +895,8 @@ arena_destroy_retained(tsdn_t *tsdn, arena_t *arena) * own metadata structures, but if deallocation fails, that is the * application's decision/problem. In practice, retained extents are * leaked here if !config_munmap unless the application provided custom - * extent hooks, so best practice to either enable munmap (and avoid dss - * for arenas to be destroyed), or provide custom extent hooks that + * extent hooks, so best practice is to either enable munmap (and avoid + * dss for arenas to be destroyed), or provide custom extent hooks that * either unmap retained extents or track them for later use. */ for (i = 0; i < sizeof(arena->extents_retained)/sizeof(extent_heap_t); diff --git a/src/extent.c b/src/extent.c index 73f79c1c..27cf97cd 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1011,7 +1011,6 @@ extent_dalloc_default_impl(void *addr, size_t size) return (true); } - static bool extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, size_t size, bool committed, unsigned arena_ind) -- GitLab From 1ff09534b58957a6f23b1711d986f79f070f2b06 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 16 Jan 2017 11:09:24 -0800 Subject: [PATCH 231/544] Fix prof_realloc() regression. Mostly revert the prof_realloc() changes in 498856f44a30b31fe713a18eb2fc7c6ecf3a9f63 (Move slabs out of chunks.) so that prof_free_sampled_object() is called when appropriate. Leave the prof_tctx_[re]set() optimization in place, but add an assertion to verify that all eight cases are correctly handled. Add a comment to make clear the code ordering, so that the regression originally fixed by ea8d97b8978a0c0423f0ed64332463a25b787c3d (Fix prof_{malloc,free}_sample_object() call order in prof_realloc().) is not repeated. This resolves #499. --- Makefile.in | 1 + include/jemalloc/internal/private_symbols.txt | 1 + include/jemalloc/internal/prof_externs.h | 3 +- include/jemalloc/internal/prof_inlines.h | 35 ++-- src/prof.c | 163 +++++++++++++----- test/unit/prof_tctx.c | 57 ++++++ 6 files changed, 206 insertions(+), 54 deletions(-) create mode 100644 test/unit/prof_tctx.c diff --git a/Makefile.in b/Makefile.in index edc50b4b..1be7d191 100644 --- a/Makefile.in +++ b/Makefile.in @@ -179,6 +179,7 @@ TESTS_UNIT := \ $(srcroot)test/unit/prof_gdump.c \ $(srcroot)test/unit/prof_idump.c \ $(srcroot)test/unit/prof_reset.c \ + $(srcroot)test/unit/prof_tctx.c \ $(srcroot)test/unit/prof_thread_name.c \ $(srcroot)test/unit/ql.c \ $(srcroot)test/unit/qr.c \ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index c85219a9..745220e3 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -369,6 +369,7 @@ prof_boot0 prof_boot1 prof_boot2 prof_bt_count +prof_cnt_all prof_dump_header prof_dump_open prof_free diff --git a/include/jemalloc/internal/prof_externs.h b/include/jemalloc/internal/prof_externs.h index 3f857145..76505f82 100644 --- a/include/jemalloc/internal/prof_externs.h +++ b/include/jemalloc/internal/prof_externs.h @@ -48,11 +48,12 @@ prof_tctx_t *prof_lookup(tsd_t *tsd, prof_bt_t *bt); #ifdef JEMALLOC_JET size_t prof_tdata_count(void); size_t prof_bt_count(void); -const prof_cnt_t *prof_cnt_all(void); typedef int (prof_dump_open_t)(bool, const char *); extern prof_dump_open_t *prof_dump_open; typedef bool (prof_dump_header_t)(tsdn_t *, bool, const prof_cnt_t *); extern prof_dump_header_t *prof_dump_header; +void prof_cnt_all(uint64_t *curobjs, uint64_t *curbytes, + uint64_t *accumobjs, uint64_t *accumbytes); #endif void prof_idump(tsdn_t *tsdn); bool prof_mdump(tsd_t *tsd, const char *filename); diff --git a/include/jemalloc/internal/prof_inlines.h b/include/jemalloc/internal/prof_inlines.h index a1ea7a32..394b7b37 100644 --- a/include/jemalloc/internal/prof_inlines.h +++ b/include/jemalloc/internal/prof_inlines.h @@ -194,30 +194,39 @@ prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, } } - /* - * The following code must differentiate among eight possible cases, - * based on three boolean conditions. - */ sampled = ((uintptr_t)tctx > (uintptr_t)1U); old_sampled = ((uintptr_t)old_tctx > (uintptr_t)1U); moved = (ptr != old_ptr); - /* - * The following block must only execute if this is a non-moving - * reallocation, because for moving reallocation the old allocation will - * be deallocated via a separate call. - */ - if (unlikely(old_sampled) && !moved) - prof_free_sampled_object(tsd, old_usize, old_tctx); - if (unlikely(sampled)) { prof_malloc_sample_object(tsd_tsdn(tsd), extent, ptr, usize, tctx); } else if (moved) { prof_tctx_set(tsd_tsdn(tsd), extent, ptr, usize, (prof_tctx_t *)(uintptr_t)1U); - } else if (unlikely(old_sampled)) + } else if (unlikely(old_sampled)) { + /* + * prof_tctx_set() would work for the !moved case as well, but + * prof_tctx_reset() is slightly cheaper, and the proper thing + * to do here in the presence of explicit knowledge re: moved + * state. + */ prof_tctx_reset(tsd_tsdn(tsd), extent, ptr, tctx); + } else { + assert((uintptr_t)prof_tctx_get(tsd_tsdn(tsd), extent, ptr) == + (uintptr_t)1U); + } + + /* + * The prof_free_sampled_object() call must come after the + * prof_malloc_sample_object() call, because tctx and old_tctx may be + * the same, in which case reversing the call order could cause the tctx + * to be prematurely destroyed as a side effect of momentarily zeroed + * counters. + */ + if (unlikely(old_sampled)) { + prof_free_sampled_object(tsd, old_usize, old_tctx); + } } JEMALLOC_ALWAYS_INLINE void diff --git a/src/prof.c b/src/prof.c index 237cbb50..b161acfb 100644 --- a/src/prof.c +++ b/src/prof.c @@ -1530,94 +1530,177 @@ label_return: return (ret); } -static bool -prof_dump(tsd_t *tsd, bool propagate_err, const char *filename, bool leakcheck) +static void +prof_dump_prep(tsd_t *tsd, prof_tdata_t *tdata, + struct prof_tdata_merge_iter_arg_s *prof_tdata_merge_iter_arg, + struct prof_gctx_merge_iter_arg_s *prof_gctx_merge_iter_arg, + prof_gctx_tree_t *gctxs) { - prof_tdata_t *tdata; - struct prof_tdata_merge_iter_arg_s prof_tdata_merge_iter_arg; size_t tabind; union { prof_gctx_t *p; void *v; } gctx; - struct prof_gctx_merge_iter_arg_s prof_gctx_merge_iter_arg; - struct prof_gctx_dump_iter_arg_s prof_gctx_dump_iter_arg; - prof_gctx_tree_t gctxs; - - cassert(config_prof); - tdata = prof_tdata_get(tsd, true); - if (tdata == NULL) - return (true); - - malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_mtx); prof_enter(tsd, tdata); /* * Put gctx's in limbo and clear their counters in preparation for * summing. */ - gctx_tree_new(&gctxs); - for (tabind = 0; !ckh_iter(&bt2gctx, &tabind, NULL, &gctx.v);) - prof_dump_gctx_prep(tsd_tsdn(tsd), gctx.p, &gctxs); + gctx_tree_new(gctxs); + for (tabind = 0; !ckh_iter(&bt2gctx, &tabind, NULL, &gctx.v);) { + prof_dump_gctx_prep(tsd_tsdn(tsd), gctx.p, gctxs); + } /* * Iterate over tdatas, and for the non-expired ones snapshot their tctx * stats and merge them into the associated gctx's. */ - prof_tdata_merge_iter_arg.tsdn = tsd_tsdn(tsd); - memset(&prof_tdata_merge_iter_arg.cnt_all, 0, sizeof(prof_cnt_t)); + prof_tdata_merge_iter_arg->tsdn = tsd_tsdn(tsd); + memset(&prof_tdata_merge_iter_arg->cnt_all, 0, sizeof(prof_cnt_t)); malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx); tdata_tree_iter(&tdatas, NULL, prof_tdata_merge_iter, - (void *)&prof_tdata_merge_iter_arg); + (void *)prof_tdata_merge_iter_arg); malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx); /* Merge tctx stats into gctx's. */ - prof_gctx_merge_iter_arg.tsdn = tsd_tsdn(tsd); - prof_gctx_merge_iter_arg.leak_ngctx = 0; - gctx_tree_iter(&gctxs, NULL, prof_gctx_merge_iter, - (void *)&prof_gctx_merge_iter_arg); + prof_gctx_merge_iter_arg->tsdn = tsd_tsdn(tsd); + prof_gctx_merge_iter_arg->leak_ngctx = 0; + gctx_tree_iter(gctxs, NULL, prof_gctx_merge_iter, + (void *)prof_gctx_merge_iter_arg); prof_leave(tsd, tdata); +} +static bool +prof_dump_file(tsd_t *tsd, bool propagate_err, const char *filename, + bool leakcheck, prof_tdata_t *tdata, + struct prof_tdata_merge_iter_arg_s *prof_tdata_merge_iter_arg, + struct prof_gctx_merge_iter_arg_s *prof_gctx_merge_iter_arg, + struct prof_gctx_dump_iter_arg_s *prof_gctx_dump_iter_arg, + prof_gctx_tree_t *gctxs) +{ /* Create dump file. */ - if ((prof_dump_fd = prof_dump_open(propagate_err, filename)) == -1) - goto label_open_close_error; + if ((prof_dump_fd = prof_dump_open(propagate_err, filename)) == -1) { + return true; + } /* Dump profile header. */ if (prof_dump_header(tsd_tsdn(tsd), propagate_err, - &prof_tdata_merge_iter_arg.cnt_all)) + &prof_tdata_merge_iter_arg->cnt_all)) { goto label_write_error; + } /* Dump per gctx profile stats. */ - prof_gctx_dump_iter_arg.tsdn = tsd_tsdn(tsd); - prof_gctx_dump_iter_arg.propagate_err = propagate_err; - if (gctx_tree_iter(&gctxs, NULL, prof_gctx_dump_iter, - (void *)&prof_gctx_dump_iter_arg) != NULL) + prof_gctx_dump_iter_arg->tsdn = tsd_tsdn(tsd); + prof_gctx_dump_iter_arg->propagate_err = propagate_err; + if (gctx_tree_iter(gctxs, NULL, prof_gctx_dump_iter, + (void *)prof_gctx_dump_iter_arg) != NULL) { goto label_write_error; + } /* Dump /proc//maps if possible. */ - if (prof_dump_maps(propagate_err)) + if (prof_dump_maps(propagate_err)) { goto label_write_error; + } + + if (prof_dump_close(propagate_err)) { + return true; + } + + return false; +label_write_error: + prof_dump_close(propagate_err); + return true; +} + +static bool +prof_dump(tsd_t *tsd, bool propagate_err, const char *filename, bool leakcheck) +{ + prof_tdata_t *tdata; + struct prof_tdata_merge_iter_arg_s prof_tdata_merge_iter_arg; + struct prof_gctx_merge_iter_arg_s prof_gctx_merge_iter_arg; + struct prof_gctx_dump_iter_arg_s prof_gctx_dump_iter_arg; + prof_gctx_tree_t gctxs; + bool err; + + cassert(config_prof); - if (prof_dump_close(propagate_err)) - goto label_open_close_error; + tdata = prof_tdata_get(tsd, true); + if (tdata == NULL) { + return true; + } + + malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_mtx); + prof_dump_prep(tsd, tdata, &prof_tdata_merge_iter_arg, + &prof_gctx_merge_iter_arg, &gctxs); + err = prof_dump_file(tsd, propagate_err, filename, leakcheck, tdata, + &prof_tdata_merge_iter_arg, &prof_gctx_merge_iter_arg, + &prof_gctx_dump_iter_arg, &gctxs); prof_gctx_finish(tsd, &gctxs); + malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_mtx); + if (err) { + return true; + } + if (leakcheck) { prof_leakcheck(&prof_tdata_merge_iter_arg.cnt_all, prof_gctx_merge_iter_arg.leak_ngctx, filename); } - return (false); -label_write_error: - prof_dump_close(propagate_err); -label_open_close_error: + return false; +} + +#ifdef JEMALLOC_JET +void +prof_cnt_all(uint64_t *curobjs, uint64_t *curbytes, uint64_t *accumobjs, + uint64_t *accumbytes) +{ + tsd_t *tsd; + prof_tdata_t *tdata; + struct prof_tdata_merge_iter_arg_s prof_tdata_merge_iter_arg; + struct prof_gctx_merge_iter_arg_s prof_gctx_merge_iter_arg; + prof_gctx_tree_t gctxs; + + tsd = tsd_fetch(); + tdata = prof_tdata_get(tsd, false); + if (tdata == NULL) { + if (curobjs != NULL) { + *curobjs = 0; + } + if (curbytes != NULL) { + *curbytes = 0; + } + if (accumobjs != NULL) { + *accumobjs = 0; + } + if (accumbytes != NULL) { + *accumbytes = 0; + } + return; + } + + prof_dump_prep(tsd, tdata, &prof_tdata_merge_iter_arg, + &prof_gctx_merge_iter_arg, &gctxs); prof_gctx_finish(tsd, &gctxs); - malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_mtx); - return (true); + + if (curobjs != NULL) { + *curobjs = prof_tdata_merge_iter_arg.cnt_all.curobjs; + } + if (curbytes != NULL) { + *curbytes = prof_tdata_merge_iter_arg.cnt_all.curbytes; + } + if (accumobjs != NULL) { + *accumobjs = prof_tdata_merge_iter_arg.cnt_all.accumobjs; + } + if (accumbytes != NULL) { + *accumbytes = prof_tdata_merge_iter_arg.cnt_all.accumbytes; + } } +#endif #define DUMP_FILENAME_BUFSIZE (PATH_MAX + 1) #define VSEQ_INVALID UINT64_C(0xffffffffffffffff) diff --git a/test/unit/prof_tctx.c b/test/unit/prof_tctx.c new file mode 100644 index 00000000..8f928ebf --- /dev/null +++ b/test/unit/prof_tctx.c @@ -0,0 +1,57 @@ +#include "test/jemalloc_test.h" + +#ifdef JEMALLOC_PROF +const char *malloc_conf = "prof:true,lg_prof_sample:0"; +#endif + +TEST_BEGIN(test_prof_realloc) +{ + tsdn_t *tsdn; + int flags; + void *p, *q; + extent_t *extent_p, *extent_q; + prof_tctx_t *tctx_p, *tctx_q; + uint64_t curobjs_0, curobjs_1, curobjs_2, curobjs_3; + + test_skip_if(!config_prof); + + tsdn = tsdn_fetch(); + flags = MALLOCX_TCACHE_NONE; + + prof_cnt_all(&curobjs_0, NULL, NULL, NULL); + p = mallocx(1024, flags); + assert_ptr_not_null(p, "Unexpected mallocx() failure"); + extent_p = iealloc(tsdn, p); + assert_ptr_not_null(extent_p, "Unexpected iealloc() failure"); + tctx_p = prof_tctx_get(tsdn, extent_p, p); + assert_ptr_ne(tctx_p, (prof_tctx_t *)(uintptr_t)1U, + "Expected valid tctx"); + prof_cnt_all(&curobjs_1, NULL, NULL, NULL); + assert_u64_eq(curobjs_0 + 1, curobjs_1, + "Allocation should have increased sample size"); + + q = rallocx(p, 2048, flags); + assert_ptr_ne(p, q, "Expected move"); + assert_ptr_not_null(p, "Unexpected rmallocx() failure"); + extent_q = iealloc(tsdn, q); + assert_ptr_not_null(extent_q, "Unexpected iealloc() failure"); + tctx_q = prof_tctx_get(tsdn, extent_q, q); + assert_ptr_ne(tctx_q, (prof_tctx_t *)(uintptr_t)1U, + "Expected valid tctx"); + prof_cnt_all(&curobjs_2, NULL, NULL, NULL); + assert_u64_eq(curobjs_1, curobjs_2, + "Reallocation should not have changed sample size"); + + dallocx(q, flags); + prof_cnt_all(&curobjs_3, NULL, NULL, NULL); + assert_u64_eq(curobjs_0, curobjs_3, + "Sample size should have returned to base level"); +} +TEST_END + +int +main(void) +{ + return test( + test_prof_realloc); +} -- GitLab From 0f7376eb6295fcd751956cb3df248e838eea003f Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Tue, 17 Jan 2017 15:54:36 +0900 Subject: [PATCH 232/544] Don't rely on OSX SDK malloc/malloc.h for malloc_zone struct definitions The SDK jemalloc is built against might be not be the latest for various reasons, but the resulting binary ought to work on newer versions of OSX. In order to ensure this, we need the fullest definitions possible, so copy what we need from the latest version of malloc/malloc.h available on opensource.apple.com. --- configure.ac | 31 ----- .../jemalloc/internal/jemalloc_internal.h.in | 1 - .../internal/jemalloc_internal_defs.h.in | 1 - src/zone.c | 122 ++++++++++++------ 4 files changed, 86 insertions(+), 69 deletions(-) diff --git a/configure.ac b/configure.ac index f886aeb5..99a69957 100644 --- a/configure.ac +++ b/configure.ac @@ -1869,37 +1869,6 @@ if test "x${enable_zone_allocator}" = "x1" ; then AC_MSG_ERROR([--enable-zone-allocator is only supported on Darwin]) fi AC_DEFINE([JEMALLOC_ZONE], [ ]) - - dnl The szone version jumped from 3 to 6 between the OS X 10.5.x and 10.6 - dnl releases. malloc_zone_t and malloc_introspection_t have new fields in - dnl 10.6, which is the only source-level indication of the change. - AC_MSG_CHECKING([malloc zone version]) - AC_DEFUN([JE_ZONE_PROGRAM], - [AC_LANG_PROGRAM( - [#include ], - [static int foo[[sizeof($1) $2 sizeof(void *) * $3 ? 1 : -1]]] - )]) - - AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,==,14)],[JEMALLOC_ZONE_VERSION=3],[ - AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,==,15)],[JEMALLOC_ZONE_VERSION=5],[ - AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,==,16)],[ - AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_introspection_t,==,9)],[JEMALLOC_ZONE_VERSION=6],[ - AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_introspection_t,==,13)],[JEMALLOC_ZONE_VERSION=7],[JEMALLOC_ZONE_VERSION=] - )])],[ - AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,==,17)],[JEMALLOC_ZONE_VERSION=8],[ - AC_COMPILE_IFELSE([JE_ZONE_PROGRAM(malloc_zone_t,>,17)],[JEMALLOC_ZONE_VERSION=9],[JEMALLOC_ZONE_VERSION=] - )])])])]) - if test "x${JEMALLOC_ZONE_VERSION}" = "x"; then - AC_MSG_RESULT([unsupported]) - AC_MSG_ERROR([Unsupported malloc zone version]) - fi - if test "${JEMALLOC_ZONE_VERSION}" = 9; then - JEMALLOC_ZONE_VERSION=8 - AC_MSG_RESULT([> 8]) - else - AC_MSG_RESULT([$JEMALLOC_ZONE_VERSION]) - fi - AC_DEFINE_UNQUOTED(JEMALLOC_ZONE_VERSION, [$JEMALLOC_ZONE_VERSION]) fi dnl ============================================================================ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 00dce68d..dc9df35f 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -162,7 +162,6 @@ static const bool have_thp = #include #include #include -#include #endif #include "jemalloc/internal/ph.h" diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 722c41dd..c777ab02 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -243,7 +243,6 @@ * Darwin (OS X) uses zones to work around Mach-O symbol override shortcomings. */ #undef JEMALLOC_ZONE -#undef JEMALLOC_ZONE_VERSION /* * Methods for determining whether the OS overcommits. diff --git a/src/zone.c b/src/zone.c index 1fcff64f..f4dbb8f9 100644 --- a/src/zone.c +++ b/src/zone.c @@ -3,6 +3,75 @@ # error "This source file is for zones on Darwin (OS X)." #endif +/* Definitions of the following structs in malloc/malloc.h might be too old + * for the built binary to run on newer versions of OSX. So use the newest + * possible version of those structs. + */ +typedef struct _malloc_zone_t { + void *reserved1; + void *reserved2; + size_t (*size)(struct _malloc_zone_t *, const void *); + void *(*malloc)(struct _malloc_zone_t *, size_t); + void *(*calloc)(struct _malloc_zone_t *, size_t, size_t); + void *(*valloc)(struct _malloc_zone_t *, size_t); + void (*free)(struct _malloc_zone_t *, void *); + void *(*realloc)(struct _malloc_zone_t *, void *, size_t); + void (*destroy)(struct _malloc_zone_t *); + const char *zone_name; + unsigned (*batch_malloc)(struct _malloc_zone_t *, size_t, void **, unsigned); + void (*batch_free)(struct _malloc_zone_t *, void **, unsigned); + struct malloc_introspection_t *introspect; + unsigned version; + void *(*memalign)(struct _malloc_zone_t *, size_t, size_t); + void (*free_definite_size)(struct _malloc_zone_t *, void *, size_t); + size_t (*pressure_relief)(struct _malloc_zone_t *, size_t); +} malloc_zone_t; + +typedef struct { + vm_address_t address; + vm_size_t size; +} vm_range_t; + +typedef struct malloc_statistics_t { + unsigned blocks_in_use; + size_t size_in_use; + size_t max_size_in_use; + size_t size_allocated; +} malloc_statistics_t; + +typedef kern_return_t memory_reader_t(task_t, vm_address_t, vm_size_t, void **); + +typedef void vm_range_recorder_t(task_t, void *, unsigned type, vm_range_t *, unsigned); + +typedef struct malloc_introspection_t { + kern_return_t (*enumerator)(task_t, void *, unsigned, vm_address_t, memory_reader_t, vm_range_recorder_t); + size_t (*good_size)(malloc_zone_t *, size_t); + boolean_t (*check)(malloc_zone_t *); + void (*print)(malloc_zone_t *, boolean_t); + void (*log)(malloc_zone_t *, void *); + void (*force_lock)(malloc_zone_t *); + void (*force_unlock)(malloc_zone_t *); + void (*statistics)(malloc_zone_t *, malloc_statistics_t *); + boolean_t (*zone_locked)(malloc_zone_t *); + boolean_t (*enable_discharge_checking)(malloc_zone_t *); + boolean_t (*disable_discharge_checking)(malloc_zone_t *); + void (*discharge)(malloc_zone_t *, void *); +#ifdef __BLOCKS__ + void (*enumerate_discharged_pointers)(malloc_zone_t *, void (^)(void *, void *)); +#else + void *enumerate_unavailable_without_blocks; +#endif + void (*reinit_lock)(malloc_zone_t *); +} malloc_introspection_t; + +extern kern_return_t malloc_get_all_zones(task_t, memory_reader_t, vm_address_t **, unsigned *); + +extern malloc_zone_t *malloc_default_zone(void); + +extern void malloc_zone_register(malloc_zone_t *zone); + +extern void malloc_zone_unregister(malloc_zone_t *zone); + /* * The malloc_default_purgeable_zone() function is only available on >= 10.6. * We need to check whether it is present at runtime, thus the weak_import. @@ -20,21 +89,17 @@ static struct malloc_introspection_t jemalloc_zone_introspect; /******************************************************************************/ /* Function prototypes for non-inline static functions. */ -static size_t zone_size(malloc_zone_t *zone, void *ptr); +static size_t zone_size(malloc_zone_t *zone, const void *ptr); static void *zone_malloc(malloc_zone_t *zone, size_t size); static void *zone_calloc(malloc_zone_t *zone, size_t num, size_t size); static void *zone_valloc(malloc_zone_t *zone, size_t size); static void zone_free(malloc_zone_t *zone, void *ptr); static void *zone_realloc(malloc_zone_t *zone, void *ptr, size_t size); -#if (JEMALLOC_ZONE_VERSION >= 5) static void *zone_memalign(malloc_zone_t *zone, size_t alignment, -#endif -#if (JEMALLOC_ZONE_VERSION >= 6) size_t size); static void zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size); -#endif -static void *zone_destroy(malloc_zone_t *zone); +static void zone_destroy(malloc_zone_t *zone); static size_t zone_good_size(malloc_zone_t *zone, size_t size); static void zone_force_lock(malloc_zone_t *zone); static void zone_force_unlock(malloc_zone_t *zone); @@ -45,7 +110,7 @@ static void zone_force_unlock(malloc_zone_t *zone); */ static size_t -zone_size(malloc_zone_t *zone, void *ptr) +zone_size(malloc_zone_t *zone, const void *ptr) { /* * There appear to be places within Darwin (such as setenv(3)) that @@ -101,7 +166,6 @@ zone_realloc(malloc_zone_t *zone, void *ptr, size_t size) return (realloc(ptr, size)); } -#if (JEMALLOC_ZONE_VERSION >= 5) static void * zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size) { @@ -111,9 +175,7 @@ zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size) return (ret); } -#endif -#if (JEMALLOC_ZONE_VERSION >= 6) static void zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size) { @@ -128,14 +190,12 @@ zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size) free(ptr); } -#endif -static void * +static void zone_destroy(malloc_zone_t *zone) { /* This function should never be called. */ not_reached(); - return (NULL); } static size_t @@ -170,48 +230,38 @@ zone_force_unlock(malloc_zone_t *zone) static void zone_init(void) { - jemalloc_zone.size = (void *)zone_size; - jemalloc_zone.malloc = (void *)zone_malloc; - jemalloc_zone.calloc = (void *)zone_calloc; - jemalloc_zone.valloc = (void *)zone_valloc; - jemalloc_zone.free = (void *)zone_free; - jemalloc_zone.realloc = (void *)zone_realloc; - jemalloc_zone.destroy = (void *)zone_destroy; + jemalloc_zone.size = zone_size; + jemalloc_zone.malloc = zone_malloc; + jemalloc_zone.calloc = zone_calloc; + jemalloc_zone.valloc = zone_valloc; + jemalloc_zone.free = zone_free; + jemalloc_zone.realloc = zone_realloc; + jemalloc_zone.destroy = zone_destroy; jemalloc_zone.zone_name = "jemalloc_zone"; jemalloc_zone.batch_malloc = NULL; jemalloc_zone.batch_free = NULL; jemalloc_zone.introspect = &jemalloc_zone_introspect; - jemalloc_zone.version = JEMALLOC_ZONE_VERSION; -#if (JEMALLOC_ZONE_VERSION >= 5) + jemalloc_zone.version = 8; jemalloc_zone.memalign = zone_memalign; -#endif -#if (JEMALLOC_ZONE_VERSION >= 6) jemalloc_zone.free_definite_size = zone_free_definite_size; -#endif -#if (JEMALLOC_ZONE_VERSION >= 8) jemalloc_zone.pressure_relief = NULL; -#endif jemalloc_zone_introspect.enumerator = NULL; - jemalloc_zone_introspect.good_size = (void *)zone_good_size; + jemalloc_zone_introspect.good_size = zone_good_size; jemalloc_zone_introspect.check = NULL; jemalloc_zone_introspect.print = NULL; jemalloc_zone_introspect.log = NULL; - jemalloc_zone_introspect.force_lock = (void *)zone_force_lock; - jemalloc_zone_introspect.force_unlock = (void *)zone_force_unlock; + jemalloc_zone_introspect.force_lock = zone_force_lock; + jemalloc_zone_introspect.force_unlock = zone_force_unlock; jemalloc_zone_introspect.statistics = NULL; -#if (JEMALLOC_ZONE_VERSION >= 6) jemalloc_zone_introspect.zone_locked = NULL; -#endif -#if (JEMALLOC_ZONE_VERSION >= 7) jemalloc_zone_introspect.enable_discharge_checking = NULL; jemalloc_zone_introspect.disable_discharge_checking = NULL; jemalloc_zone_introspect.discharge = NULL; -# ifdef __BLOCKS__ +#ifdef __BLOCKS__ jemalloc_zone_introspect.enumerate_discharged_pointers = NULL; -# else +#else jemalloc_zone_introspect.enumerate_unavailable_without_blocks = NULL; -# endif #endif } -- GitLab From 12ab4383e9ea743e8e6b9115be73f2c6dfde5e24 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Tue, 17 Jan 2017 16:20:05 +0900 Subject: [PATCH 233/544] Add dummy implementations for most remaining OSX zone allocator functions Some system libraries are using malloc_default_zone() and then using some of the malloc_zone_* API. Under normal conditions, those functions check the malloc_zone_t/malloc_introspection_t struct for the values that are allowed to be NULL, so that a NULL deref doesn't happen. As of OSX 10.12, malloc_default_zone() doesn't return the actual default zone anymore, but returns a fake, wrapper zone. The wrapper zone defines all the possible functions in the malloc_zone_t/malloc_introspection_t struct (almost), and calls the function from the registered default zone (jemalloc in our case) on its own. Without checking whether the pointers are NULL. This means that a system library that calls e.g. malloc_zone_batch_malloc(malloc_default_zone(), ...) ends up trying to call jemalloc_zone.batch_malloc, which is NULL, and crash follows. So as of OSX 10.12, the default zone is required to have all the functions available (really, the same as the wrapper zone), even if they do nothing. This is arguably a bug in libsystem_malloc in OSX 10.12, but jemalloc still needs to work in that case. --- src/zone.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 108 insertions(+), 10 deletions(-) diff --git a/src/zone.c b/src/zone.c index f4dbb8f9..c54f4a4f 100644 --- a/src/zone.c +++ b/src/zone.c @@ -100,9 +100,24 @@ static void *zone_memalign(malloc_zone_t *zone, size_t alignment, static void zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size); static void zone_destroy(malloc_zone_t *zone); +static unsigned zone_batch_malloc(struct _malloc_zone_t *zone, size_t size, + void **results, unsigned num_requested); +static void zone_batch_free(struct _malloc_zone_t *zone, + void **to_be_freed, unsigned num_to_be_freed); +static size_t zone_pressure_relief(struct _malloc_zone_t *zone, size_t goal); static size_t zone_good_size(malloc_zone_t *zone, size_t size); +static kern_return_t zone_enumerator(task_t task, void *data, unsigned type_mask, + vm_address_t zone_address, memory_reader_t reader, + vm_range_recorder_t recorder); +static boolean_t zone_check(malloc_zone_t *zone); +static void zone_print(malloc_zone_t *zone, boolean_t verbose); +static void zone_log(malloc_zone_t *zone, void *address); static void zone_force_lock(malloc_zone_t *zone); static void zone_force_unlock(malloc_zone_t *zone); +static void zone_statistics(malloc_zone_t *zone, + malloc_statistics_t *stats); +static boolean_t zone_locked(malloc_zone_t *zone); +static void zone_reinit_lock(malloc_zone_t *zone); /******************************************************************************/ /* @@ -198,6 +213,39 @@ zone_destroy(malloc_zone_t *zone) not_reached(); } +static unsigned +zone_batch_malloc(struct _malloc_zone_t *zone, size_t size, void **results, + unsigned num_requested) +{ + unsigned i; + + for (i = 0; i < num_requested; i++) { + results[i] = je_malloc(size); + if (!results[i]) + break; + } + + return i; +} + +static void +zone_batch_free(struct _malloc_zone_t *zone, void **to_be_freed, + unsigned num_to_be_freed) +{ + unsigned i; + + for (i = 0; i < num_to_be_freed; i++) { + zone_free(zone, to_be_freed[i]); + to_be_freed[i] = NULL; + } +} + +static size_t +zone_pressure_relief(struct _malloc_zone_t *zone, size_t goal) +{ + return 0; +} + static size_t zone_good_size(malloc_zone_t *zone, size_t size) { @@ -206,6 +254,30 @@ zone_good_size(malloc_zone_t *zone, size_t size) return (s2u(size)); } +static kern_return_t +zone_enumerator(task_t task, void *data, unsigned type_mask, + vm_address_t zone_address, memory_reader_t reader, + vm_range_recorder_t recorder) +{ + return KERN_SUCCESS; +} + +static boolean_t +zone_check(malloc_zone_t *zone) +{ + return true; +} + +static void +zone_print(malloc_zone_t *zone, boolean_t verbose) +{ +} + +static void +zone_log(malloc_zone_t *zone, void *address) +{ +} + static void zone_force_lock(malloc_zone_t *zone) { @@ -227,6 +299,31 @@ zone_force_unlock(malloc_zone_t *zone) jemalloc_postfork_child(); } +static void +zone_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) +{ + /* We make no effort to actually fill the values */ + stats->blocks_in_use = 0; + stats->size_in_use = 0; + stats->max_size_in_use = 0; + stats->size_allocated = 0; +} + +static boolean_t +zone_locked(malloc_zone_t *zone) +{ + /* Pretend no lock is being held */ + return false; +} + +static void +zone_reinit_lock(malloc_zone_t *zone) +{ + /* As of OSX 10.12, this function is only used when force_unlock would + * be used if the zone version were < 9. So just use force_unlock. */ + zone_force_unlock(zone); +} + static void zone_init(void) { @@ -238,23 +335,23 @@ zone_init(void) jemalloc_zone.realloc = zone_realloc; jemalloc_zone.destroy = zone_destroy; jemalloc_zone.zone_name = "jemalloc_zone"; - jemalloc_zone.batch_malloc = NULL; - jemalloc_zone.batch_free = NULL; + jemalloc_zone.batch_malloc = zone_batch_malloc; + jemalloc_zone.batch_free = zone_batch_free; jemalloc_zone.introspect = &jemalloc_zone_introspect; - jemalloc_zone.version = 8; + jemalloc_zone.version = 9; jemalloc_zone.memalign = zone_memalign; jemalloc_zone.free_definite_size = zone_free_definite_size; - jemalloc_zone.pressure_relief = NULL; + jemalloc_zone.pressure_relief = zone_pressure_relief; - jemalloc_zone_introspect.enumerator = NULL; + jemalloc_zone_introspect.enumerator = zone_enumerator; jemalloc_zone_introspect.good_size = zone_good_size; - jemalloc_zone_introspect.check = NULL; - jemalloc_zone_introspect.print = NULL; - jemalloc_zone_introspect.log = NULL; + jemalloc_zone_introspect.check = zone_check; + jemalloc_zone_introspect.print = zone_print; + jemalloc_zone_introspect.log = zone_log; jemalloc_zone_introspect.force_lock = zone_force_lock; jemalloc_zone_introspect.force_unlock = zone_force_unlock; - jemalloc_zone_introspect.statistics = NULL; - jemalloc_zone_introspect.zone_locked = NULL; + jemalloc_zone_introspect.statistics = zone_statistics; + jemalloc_zone_introspect.zone_locked = zone_locked; jemalloc_zone_introspect.enable_discharge_checking = NULL; jemalloc_zone_introspect.disable_discharge_checking = NULL; jemalloc_zone_introspect.discharge = NULL; @@ -263,6 +360,7 @@ zone_init(void) #else jemalloc_zone_introspect.enumerate_unavailable_without_blocks = NULL; #endif + jemalloc_zone_introspect.reinit_lock = zone_reinit_lock; } static malloc_zone_t * -- GitLab From 58424e679d7c1095c0ac2f148ee558d6a067f577 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 22 Apr 2016 18:37:44 -0700 Subject: [PATCH 234/544] Added stats about number of bytes cached in tcache currently. --- include/jemalloc/internal/stats_structs.h | 3 +++ src/arena.c | 15 +++++++++++++++ src/ctl.c | 9 +++++++++ src/stats.c | 13 +++++++++++++ 4 files changed, 40 insertions(+) diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index aaa0bf4f..32ef6118 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -100,6 +100,9 @@ struct arena_stats_s { uint64_t ndalloc_large; uint64_t nrequests_large; + /* Number of bytes cached in tcache associated with this arena. */ + size_t tcache_bytes; + /* One element for each large size class. */ malloc_large_stats_t lstats[NSIZES - NBINS]; }; diff --git a/src/arena.c b/src/arena.c index 70d71fcb..7362c4e6 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1625,6 +1625,21 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, lstats[i].nrequests += arena->stats.lstats[i].nrequests; lstats[i].curlextents += arena->stats.lstats[i].curlextents; } + + if (config_tcache) { + tcache_bin_t *tbin; + tcache_t *tcache; + + /* tcache_bytes counts currently cached bytes. */ + astats->tcache_bytes = 0; + ql_foreach(tcache, &arena->tcache_ql, link) { + for (i = 0; i < nhbins; i++) { + tbin = &tcache->tbins[i]; + astats->tcache_bytes += tbin->ncached * + index2size(i); + } + } + } malloc_mutex_unlock(tsdn, &arena->lock); for (i = 0; i < NBINS; i++) { diff --git a/src/ctl.c b/src/ctl.c index 8484ba85..9c582d65 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -161,6 +161,7 @@ CTL_PROTO(stats_arenas_i_nmadvise) CTL_PROTO(stats_arenas_i_purged) CTL_PROTO(stats_arenas_i_base) CTL_PROTO(stats_arenas_i_internal) +CTL_PROTO(stats_arenas_i_tcache_bytes) CTL_PROTO(stats_arenas_i_resident) INDEX_PROTO(stats_arenas_i) CTL_PROTO(stats_allocated) @@ -382,6 +383,7 @@ static const ctl_named_node_t stats_arenas_i_node[] = { {NAME("purged"), CTL(stats_arenas_i_purged)}, {NAME("base"), CTL(stats_arenas_i_base)}, {NAME("internal"), CTL(stats_arenas_i_internal)}, + {NAME("tcache_bytes"), CTL(stats_arenas_i_tcache_bytes)}, {NAME("resident"), CTL(stats_arenas_i_resident)}, {NAME("small"), CHILD(named, stats_arenas_i_small)}, {NAME("large"), CHILD(named, stats_arenas_i_large)}, @@ -601,6 +603,11 @@ ctl_arena_stats_sdmerge(ctl_arena_stats_t *sdstats, ctl_arena_stats_t *astats, sdstats->astats.nrequests_large += astats->astats.nrequests_large; + if (config_tcache) { + sdstats->astats.tcache_bytes += + astats->astats.tcache_bytes; + } + for (i = 0; i < NBINS; i++) { sdstats->bstats[i].nmalloc += astats->bstats[i].nmalloc; sdstats->bstats[i].ndalloc += astats->bstats[i].ndalloc; @@ -2105,6 +2112,8 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_base, stats_arenas_i(mib[2])->astats.base, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_internal, stats_arenas_i(mib[2])->astats.internal, size_t) +CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_tcache_bytes, + stats_arenas_i(mib[2])->astats.tcache_bytes, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_resident, stats_arenas_i(mib[2])->astats.resident, size_t) diff --git a/src/stats.c b/src/stats.c index ef349a50..f20fd4ce 100644 --- a/src/stats.c +++ b/src/stats.c @@ -261,6 +261,7 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, uint64_t small_nmalloc, small_ndalloc, small_nrequests; size_t large_allocated; uint64_t large_nmalloc, large_ndalloc, large_nrequests; + size_t tcache_bytes; CTL_GET("arenas.page", &page, size_t); @@ -423,6 +424,18 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, "internal: %12zu\n", internal); } + if (config_tcache) { + CTL_M2_GET("stats.arenas.0.tcache_bytes", i, &tcache_bytes, + size_t); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"tcache\": %zu,\n", tcache_bytes); + } else { + malloc_cprintf(write_cb, cbopaque, + "tcache: %12zu\n", tcache_bytes); + } + } + CTL_M2_GET("stats.arenas.0.resident", i, &resident, size_t); if (json) { malloc_cprintf(write_cb, cbopaque, -- GitLab From 7a61ebe71f7cadd54c68ea5fb0b33f6aee290aef Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 19 Jan 2017 09:11:46 -0800 Subject: [PATCH 235/544] Remove -Werror=declaration-after-statement. This partially resolves #536. --- configure.ac | 1 - 1 file changed, 1 deletion(-) diff --git a/configure.ac b/configure.ac index 99a69957..4a1168b0 100644 --- a/configure.ac +++ b/configure.ac @@ -239,7 +239,6 @@ if test "x$GCC" = "xyes" ; then fi fi JE_CFLAGS_ADD([-Wall]) - JE_CFLAGS_ADD([-Werror=declaration-after-statement]) JE_CFLAGS_ADD([-Wshorten-64-to-32]) JE_CFLAGS_ADD([-Wsign-compare]) JE_CFLAGS_ADD([-pipe]) -- GitLab From 66bf773ef2980b0baf6d46a4b65ccedd9f1e1931 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 18 Jan 2017 01:01:19 -0800 Subject: [PATCH 236/544] Test JSON output of malloc_stats_print() and fix bugs. Implement and test a JSON validation parser. Use the parser to validate JSON output from malloc_stats_print(), with a significant subset of supported output options. This resolves #551. --- Makefile.in | 1 + src/stats.c | 65 +-- test/unit/stats_print.c | 1006 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 1044 insertions(+), 28 deletions(-) create mode 100644 test/unit/stats_print.c diff --git a/Makefile.in b/Makefile.in index 1be7d191..acd31f73 100644 --- a/Makefile.in +++ b/Makefile.in @@ -190,6 +190,7 @@ TESTS_UNIT := \ $(srcroot)test/unit/slab.c \ $(srcroot)test/unit/smoothstep.c \ $(srcroot)test/unit/stats.c \ + $(srcroot)test/unit/stats_print.c \ $(srcroot)test/unit/ticker.c \ $(srcroot)test/unit/nstime.c \ $(srcroot)test/unit/tsd.c \ diff --git a/src/stats.c b/src/stats.c index f20fd4ce..020d56bd 100644 --- a/src/stats.c +++ b/src/stats.c @@ -37,7 +37,7 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, bool json, bool large, unsigned i) { size_t page; - bool config_tcache, in_gap, in_gap_prev; + bool in_gap, in_gap_prev; unsigned nbins, j; CTL_GET("arenas.page", &page, size_t); @@ -47,7 +47,6 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\"bins\": [\n"); } else { - CTL_GET("config.tcache", &config_tcache, bool); if (config_tcache) { malloc_cprintf(write_cb, cbopaque, "bins: size ind allocated nmalloc" @@ -700,9 +699,11 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "\t\t\t\"nbins\": %u,\n", nbins); - CTL_GET("arenas.nhbins", &uv, unsigned); - malloc_cprintf(write_cb, cbopaque, - "\t\t\t\"nhbins\": %u,\n", uv); + if (config_tcache) { + CTL_GET("arenas.nhbins", &uv, unsigned); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"nhbins\": %u,\n", uv); + } malloc_cprintf(write_cb, cbopaque, "\t\t\t\"bin\": [\n"); @@ -867,8 +868,10 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, MALLCTL_ARENAS_ALL, bins, large); if (json) { malloc_cprintf(write_cb, cbopaque, - "\t\t\t}%s\n", (ninitialized > 1) ? - "," : ""); + "\t\t\t}%s\n", + ((destroyed_initialized && + destroyed) || unmerged) ? "," : + ""); } } @@ -886,31 +889,37 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, MALLCTL_ARENAS_DESTROYED, bins, large); if (json) { malloc_cprintf(write_cb, cbopaque, - "\t\t\t}%s\n", (ninitialized > 1) ? - "," : ""); + "\t\t\t}%s\n", unmerged ? "," : + ""); } } /* Unmerged stats. */ - for (i = j = 0; i < narenas; i++) { - if (initialized[i]) { - if (json) { - j++; - malloc_cprintf(write_cb, - cbopaque, - "\t\t\t\"%u\": {\n", i); - } else { - malloc_cprintf(write_cb, - cbopaque, "\narenas[%u]:\n", - i); - } - stats_arena_print(write_cb, cbopaque, - json, i, bins, large); - if (json) { - malloc_cprintf(write_cb, - cbopaque, - "\t\t\t}%s\n", (j < - ninitialized) ? "," : ""); + if (unmerged) { + for (i = j = 0; i < narenas; i++) { + if (initialized[i]) { + if (json) { + j++; + malloc_cprintf(write_cb, + cbopaque, + "\t\t\t\"%u\": {\n", + i); + } else { + malloc_cprintf(write_cb, + cbopaque, + "\narenas[%u]:\n", + i); + } + stats_arena_print(write_cb, + cbopaque, json, i, bins, + large); + if (json) { + malloc_cprintf(write_cb, + cbopaque, + "\t\t\t}%s\n", (j < + ninitialized) ? "," + : ""); + } } } } diff --git a/test/unit/stats_print.c b/test/unit/stats_print.c new file mode 100644 index 00000000..5accd8e2 --- /dev/null +++ b/test/unit/stats_print.c @@ -0,0 +1,1006 @@ +#include "test/jemalloc_test.h" + +typedef enum { + TOKEN_TYPE_NONE, + TOKEN_TYPE_ERROR, + TOKEN_TYPE_EOI, + TOKEN_TYPE_NULL, + TOKEN_TYPE_FALSE, + TOKEN_TYPE_TRUE, + TOKEN_TYPE_LBRACKET, + TOKEN_TYPE_RBRACKET, + TOKEN_TYPE_LBRACE, + TOKEN_TYPE_RBRACE, + TOKEN_TYPE_COLON, + TOKEN_TYPE_COMMA, + TOKEN_TYPE_STRING, + TOKEN_TYPE_NUMBER +} token_type_t; + +typedef struct parser_s parser_t; +typedef struct { + parser_t *parser; + token_type_t token_type; + size_t pos; + size_t len; + size_t line; + size_t col; +} token_t; + +struct parser_s { + bool verbose; + char *buf; /* '\0'-terminated. */ + size_t len; /* Number of characters preceding '\0' in buf. */ + size_t pos; + size_t line; + size_t col; + token_t token; +}; + +static void +token_init(token_t *token, parser_t *parser, token_type_t token_type, + size_t pos, size_t len, size_t line, size_t col) +{ + token->parser = parser; + token->token_type = token_type; + token->pos = pos; + token->len = len; + token->line = line; + token->col = col; +} + +static void +token_error(token_t *token) +{ + if (!token->parser->verbose) { + return; + } + switch (token->token_type) { + case TOKEN_TYPE_NONE: + not_reached(); + case TOKEN_TYPE_ERROR: + malloc_printf("%zu:%zu: Unexpected character in token: ", + token->line, token->col); + break; + default: + malloc_printf("%zu:%zu: Unexpected token: ", token->line, + token->col); + break; + } + write(STDERR_FILENO, &token->parser->buf[token->pos], token->len); + malloc_printf("\n"); +} + +static void +parser_init(parser_t *parser, bool verbose) +{ + parser->verbose = verbose; + parser->buf = NULL; + parser->len = 0; + parser->pos = 0; + parser->line = 1; + parser->col = 0; +} + +static void +parser_fini(parser_t *parser) +{ + if (parser->buf != NULL) { + dallocx(parser->buf, MALLOCX_TCACHE_NONE); + } +} + +static bool +parser_append(parser_t *parser, const char *str) +{ + size_t len = strlen(str); + char *buf = (parser->buf == NULL) ? mallocx(len + 1, + MALLOCX_TCACHE_NONE) : rallocx(parser->buf, parser->len + len + 1, + MALLOCX_TCACHE_NONE); + if (buf == NULL) { + return true; + } + memcpy(&buf[parser->len], str, len + 1); + parser->buf = buf; + parser->len += len; + return false; +} + +static bool +parser_tokenize(parser_t *parser) +{ + enum { + STATE_START, + STATE_EOI, + STATE_N, STATE_NU, STATE_NUL, STATE_NULL, + STATE_F, STATE_FA, STATE_FAL, STATE_FALS, STATE_FALSE, + STATE_T, STATE_TR, STATE_TRU, STATE_TRUE, + STATE_LBRACKET, + STATE_RBRACKET, + STATE_LBRACE, + STATE_RBRACE, + STATE_COLON, + STATE_COMMA, + STATE_CHARS, + STATE_CHAR_ESCAPE, + STATE_CHAR_U, STATE_CHAR_UD, STATE_CHAR_UDD, STATE_CHAR_UDDD, + STATE_STRING, + STATE_MINUS, + STATE_LEADING_ZERO, + STATE_DIGITS, + STATE_DECIMAL, + STATE_FRAC_DIGITS, + STATE_EXP, + STATE_EXP_SIGN, + STATE_EXP_DIGITS, + STATE_ACCEPT + } state = STATE_START; + size_t token_pos, token_line, token_col; + + assert_zu_le(parser->pos, parser->len, + "Position is past end of buffer"); + + while (state != STATE_ACCEPT) { + char c = parser->buf[parser->pos]; + + switch (state) { + case STATE_START: + token_pos = parser->pos; + token_line = parser->line; + token_col = parser->col; + switch (c) { + case ' ': case '\b': case '\n': case '\r': case '\t': + break; + case '\0': + state = STATE_EOI; + break; + case 'n': + state = STATE_N; + break; + case 'f': + state = STATE_F; + break; + case 't': + state = STATE_T; + break; + case '[': + state = STATE_LBRACKET; + break; + case ']': + state = STATE_RBRACKET; + break; + case '{': + state = STATE_LBRACE; + break; + case '}': + state = STATE_RBRACE; + break; + case ':': + state = STATE_COLON; + break; + case ',': + state = STATE_COMMA; + break; + case '"': + state = STATE_CHARS; + break; + case '-': + state = STATE_MINUS; + break; + case '0': + state = STATE_LEADING_ZERO; + break; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + state = STATE_DIGITS; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_EOI: + token_init(&parser->token, parser, + TOKEN_TYPE_EOI, token_pos, parser->pos - + token_pos, token_line, token_col); + state = STATE_ACCEPT; + break; + case STATE_N: + switch (c) { + case 'u': + state = STATE_NU; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_NU: + switch (c) { + case 'l': + state = STATE_NUL; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_NUL: + switch (c) { + case 'l': + state = STATE_NULL; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_NULL: + switch (c) { + case ' ': case '\b': case '\n': case '\r': case '\t': + case '\0': + case '[': case ']': case '{': case '}': case ':': + case ',': + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + token_init(&parser->token, parser, TOKEN_TYPE_NULL, + token_pos, parser->pos - token_pos, token_line, + token_col); + state = STATE_ACCEPT; + break; + case STATE_F: + switch (c) { + case 'a': + state = STATE_FA; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_FA: + switch (c) { + case 'l': + state = STATE_FAL; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_FAL: + switch (c) { + case 's': + state = STATE_FALS; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_FALS: + switch (c) { + case 'e': + state = STATE_FALSE; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_FALSE: + switch (c) { + case ' ': case '\b': case '\n': case '\r': case '\t': + case '\0': + case '[': case ']': case '{': case '}': case ':': + case ',': + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + token_init(&parser->token, parser, + TOKEN_TYPE_FALSE, token_pos, parser->pos - + token_pos, token_line, token_col); + state = STATE_ACCEPT; + break; + case STATE_T: + switch (c) { + case 'r': + state = STATE_TR; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_TR: + switch (c) { + case 'u': + state = STATE_TRU; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_TRU: + switch (c) { + case 'e': + state = STATE_TRUE; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_TRUE: + switch (c) { + case ' ': case '\b': case '\n': case '\r': case '\t': + case '\0': + case '[': case ']': case '{': case '}': case ':': + case ',': + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + token_init(&parser->token, parser, TOKEN_TYPE_TRUE, + token_pos, parser->pos - token_pos, token_line, + token_col); + state = STATE_ACCEPT; + break; + case STATE_LBRACKET: + token_init(&parser->token, parser, TOKEN_TYPE_LBRACKET, + token_pos, parser->pos - token_pos, token_line, + token_col); + state = STATE_ACCEPT; + break; + case STATE_RBRACKET: + token_init(&parser->token, parser, TOKEN_TYPE_RBRACKET, + token_pos, parser->pos - token_pos, token_line, + token_col); + state = STATE_ACCEPT; + break; + case STATE_LBRACE: + token_init(&parser->token, parser, TOKEN_TYPE_LBRACE, + token_pos, parser->pos - token_pos, token_line, + token_col); + state = STATE_ACCEPT; + break; + case STATE_RBRACE: + token_init(&parser->token, parser, TOKEN_TYPE_RBRACE, + token_pos, parser->pos - token_pos, token_line, + token_col); + state = STATE_ACCEPT; + break; + case STATE_COLON: + token_init(&parser->token, parser, TOKEN_TYPE_COLON, + token_pos, parser->pos - token_pos, token_line, + token_col); + state = STATE_ACCEPT; + break; + case STATE_COMMA: + token_init(&parser->token, parser, TOKEN_TYPE_COMMA, + token_pos, parser->pos - token_pos, token_line, + token_col); + state = STATE_ACCEPT; + break; + case STATE_CHARS: + switch (c) { + case '\\': + state = STATE_CHAR_ESCAPE; + break; + case '"': + state = STATE_STRING; + break; + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: + case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: + case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: + case 0x0f: case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: + case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: + case 0x1e: case 0x1f: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + default: + break; + } + break; + case STATE_CHAR_ESCAPE: + switch (c) { + case '"': case '\\': case '/': case 'b': case 'n': + case 'r': case 't': + state = STATE_CHARS; + break; + case 'u': + state = STATE_CHAR_U; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_CHAR_U: + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': + state = STATE_CHAR_UD; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_CHAR_UD: + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': + state = STATE_CHAR_UDD; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_CHAR_UDD: + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': + state = STATE_CHAR_UDDD; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_CHAR_UDDD: + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': + state = STATE_CHARS; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_STRING: + token_init(&parser->token, parser, TOKEN_TYPE_STRING, + token_pos, parser->pos - token_pos, token_line, + token_col); + state = STATE_ACCEPT; + break; + case STATE_MINUS: + switch (c) { + case '0': + state = STATE_LEADING_ZERO; + break; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + state = STATE_DIGITS; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_LEADING_ZERO: + switch (c) { + case '.': + state = STATE_DECIMAL; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_NUMBER, token_pos, parser->pos - + token_pos, token_line, token_col); + state = STATE_ACCEPT; + break; + } + break; + case STATE_DIGITS: + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + break; + case '.': + state = STATE_DECIMAL; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_NUMBER, token_pos, parser->pos - + token_pos, token_line, token_col); + state = STATE_ACCEPT; + break; + } + break; + case STATE_DECIMAL: + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + state = STATE_FRAC_DIGITS; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_FRAC_DIGITS: + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + break; + case 'e': case 'E': + state = STATE_EXP; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_NUMBER, token_pos, parser->pos - + token_pos, token_line, token_col); + state = STATE_ACCEPT; + break; + } + break; + case STATE_EXP: + switch (c) { + case '-': case '+': + state = STATE_EXP_SIGN; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + state = STATE_EXP_DIGITS; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_EXP_SIGN: + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + state = STATE_EXP_DIGITS; + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_ERROR, token_pos, parser->pos + 1 + - token_pos, token_line, token_col); + return true; + } + break; + case STATE_EXP_DIGITS: + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + break; + default: + token_init(&parser->token, parser, + TOKEN_TYPE_NUMBER, token_pos, parser->pos - + token_pos, token_line, token_col); + state = STATE_ACCEPT; + break; + } + break; + default: + not_reached(); + } + + if (state != STATE_ACCEPT) { + if (c == '\n') { + parser->line++; + parser->col = 0; + } else { + parser->col++; + } + parser->pos++; + } + } + return false; +} + +static bool parser_parse_array(parser_t *parser); +static bool parser_parse_object(parser_t *parser); + +static bool +parser_parse_value(parser_t *parser) +{ + switch (parser->token.token_type) { + case TOKEN_TYPE_NULL: + case TOKEN_TYPE_FALSE: + case TOKEN_TYPE_TRUE: + case TOKEN_TYPE_STRING: + case TOKEN_TYPE_NUMBER: + return false; + case TOKEN_TYPE_LBRACE: + return parser_parse_object(parser); + case TOKEN_TYPE_LBRACKET: + return parser_parse_array(parser); + default: + return true; + } + not_reached(); +} + +static bool +parser_parse_pair(parser_t *parser) +{ + assert_d_eq(parser->token.token_type, TOKEN_TYPE_STRING, + "Pair should start with string"); + if (parser_tokenize(parser)) { + return true; + } + switch (parser->token.token_type) { + case TOKEN_TYPE_COLON: + if (parser_tokenize(parser)) { + return true; + } + return parser_parse_value(parser); + default: + return true; + } +} + +static bool +parser_parse_values(parser_t *parser) +{ + if (parser_parse_value(parser)) { + return true; + } + + while (true) { + if (parser_tokenize(parser)) { + return true; + } + switch (parser->token.token_type) { + case TOKEN_TYPE_COMMA: + if (parser_tokenize(parser)) { + return true; + } + if (parser_parse_value(parser)) { + return true; + } + break; + case TOKEN_TYPE_RBRACKET: + return false; + default: + return true; + } + } +} + +static bool +parser_parse_array(parser_t *parser) +{ + assert_d_eq(parser->token.token_type, TOKEN_TYPE_LBRACKET, + "Array should start with ["); + if (parser_tokenize(parser)) { + return true; + } + switch (parser->token.token_type) { + case TOKEN_TYPE_RBRACKET: + return false; + default: + return parser_parse_values(parser); + } + not_reached(); +} + +static bool +parser_parse_pairs(parser_t *parser) +{ + assert_d_eq(parser->token.token_type, TOKEN_TYPE_STRING, + "Object should start with string"); + if (parser_parse_pair(parser)) { + return true; + } + + while (true) { + if (parser_tokenize(parser)) { + return true; + } + switch (parser->token.token_type) { + case TOKEN_TYPE_COMMA: + if (parser_tokenize(parser)) { + return true; + } + switch (parser->token.token_type) { + case TOKEN_TYPE_STRING: + if (parser_parse_pair(parser)) { + return true; + } + break; + default: + return true; + } + break; + case TOKEN_TYPE_RBRACE: + return false; + default: + return true; + } + } +} + +static bool +parser_parse_object(parser_t *parser) +{ + assert_d_eq(parser->token.token_type, TOKEN_TYPE_LBRACE, + "Object should start with {"); + if (parser_tokenize(parser)) { + return true; + } + switch (parser->token.token_type) { + case TOKEN_TYPE_STRING: + return parser_parse_pairs(parser); + case TOKEN_TYPE_RBRACE: + return false; + default: + return true; + } + not_reached(); +} + +static bool +parser_parse(parser_t *parser) +{ + if (parser_tokenize(parser)) { + goto label_error; + } + if (parser_parse_value(parser)) { + goto label_error; + } + + if (parser_tokenize(parser)) { + goto label_error; + } + switch (parser->token.token_type) { + case TOKEN_TYPE_EOI: + return false; + default: + goto label_error; + } + not_reached(); + +label_error: + token_error(&parser->token); + return true; +} + +TEST_BEGIN(test_json_parser) +{ + size_t i; + const char *invalid_inputs[] = { + /* Tokenizer error case tests. */ + "{ \"string\": X }", + "{ \"string\": nXll }", + "{ \"string\": nuXl }", + "{ \"string\": nulX }", + "{ \"string\": nullX }", + "{ \"string\": fXlse }", + "{ \"string\": faXse }", + "{ \"string\": falXe }", + "{ \"string\": falsX }", + "{ \"string\": falseX }", + "{ \"string\": tXue }", + "{ \"string\": trXe }", + "{ \"string\": truX }", + "{ \"string\": trueX }", + "{ \"string\": \"\n\" }", + "{ \"string\": \"\\z\" }", + "{ \"string\": \"\\uX000\" }", + "{ \"string\": \"\\u0X00\" }", + "{ \"string\": \"\\u00X0\" }", + "{ \"string\": \"\\u000X\" }", + "{ \"string\": -X }", + "{ \"string\": 0.X }", + "{ \"string\": 0.0eX }", + "{ \"string\": 0.0e+X }", + + /* Parser error test cases. */ + "{\"string\": }", + "{\"string\" }", + "{\"string\": [ 0 }", + "{\"string\": {\"a\":0, 1 } }", + "{\"string\": {\"a\":0: } }", + "{", + "{}{", + }; + const char *valid_inputs[] = { + /* Token tests. */ + "null", + "false", + "true", + "{}", + "{\"a\": 0}", + "[]", + "[0, 1]", + "0", + "1", + "10", + "-10", + "10.23", + "10.23e4", + "10.23e-4", + "10.23e+4", + "10.23E4", + "10.23E-4", + "10.23E+4", + "-10.23", + "-10.23e4", + "-10.23e-4", + "-10.23e+4", + "-10.23E4", + "-10.23E-4", + "-10.23E+4", + "\"value\"", + "\" \\\" \\/ \\b \\n \\r \\t \\u0abc \\u1DEF \"", + + /* Parser test with various nesting. */ + "{\"a\":null, \"b\":[1,[{\"c\":2},3]], \"d\":{\"e\":true}}", + }; + + for (i = 0; i < sizeof(invalid_inputs)/sizeof(const char *); i++) { + const char *input = invalid_inputs[i]; + parser_t parser; + parser_init(&parser, false); + assert_false(parser_append(&parser, input), + "Unexpected input appending failure"); + assert_true(parser_parse(&parser), + "Unexpected parse success for input: %s", input); + parser_fini(&parser); + } + + for (i = 0; i < sizeof(valid_inputs)/sizeof(const char *); i++) { + const char *input = valid_inputs[i]; + parser_t parser; + parser_init(&parser, true); + assert_false(parser_append(&parser, input), + "Unexpected input appending failure"); + assert_false(parser_parse(&parser), + "Unexpected parse error for input: %s", input); + parser_fini(&parser); + } +} +TEST_END + +void +write_cb(void *opaque, const char *str) +{ + parser_t *parser = (parser_t *)opaque; + if (parser_append(parser, str)) { + test_fail("Unexpected input appending failure"); + } +} + +TEST_BEGIN(test_stats_print_json) +{ + const char *opts[] = { + "J", + "Jg", + "Jm", + "Jd", + "Jmd", + "Jgd", + "Jgm", + "Jgmd", + "Ja", + "Jb", + "Jl", + "Jbl", + "Jal", + "Jab", + "Jabl", + "Jgmdabl", + }; + unsigned arena_ind, i; + + for (i = 0; i < 3; i++) { + unsigned j; + + switch (i) { + case 0: + break; + case 1: { + size_t sz = sizeof(arena_ind); + assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, + &sz, NULL, 0), 0, "Unexpected mallctl failure"); + break; + } case 2: { + size_t mib[3]; + size_t miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("arena.0.destroy", + mib, &miblen), 0, + "Unexpected mallctlnametomib failure"); + mib[1] = arena_ind; + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, + 0), 0, "Unexpected mallctlbymib failure"); + break; + } default: + not_reached(); + } + + for (j = 0; j < sizeof(opts)/sizeof(const char *); j++) { + parser_t parser; + + parser_init(&parser, true); + malloc_stats_print(write_cb, (void *)&parser, opts[j]); + assert_false(parser_parse(&parser), + "Unexpected parse error, opts=\"%s\"", opts[j]); + parser_fini(&parser); + } + } +} +TEST_END + +int +main(void) +{ + return (test( + test_json_parser, + test_stats_print_json)); +} -- GitLab From 9eb1b1c8814beb4026fe8a9d3e77bb44e9ad0144 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 18 Jan 2017 23:03:37 -0800 Subject: [PATCH 237/544] Fix --disable-stats support. Fix numerous regressions that were exposed by --disable-stats, both in the core library and in the tests. --- include/jemalloc/internal/ctl_structs.h | 46 +-- include/jemalloc/internal/ctl_types.h | 2 + src/ctl.c | 356 +++++++++++++----------- src/extent.c | 8 +- test/unit/base.c | 32 ++- 5 files changed, 249 insertions(+), 195 deletions(-) diff --git a/include/jemalloc/internal/ctl_structs.h b/include/jemalloc/internal/ctl_structs.h index 8f94c6c4..18806a59 100644 --- a/include/jemalloc/internal/ctl_structs.h +++ b/include/jemalloc/internal/ctl_structs.h @@ -22,18 +22,6 @@ struct ctl_indexed_node_s { }; struct ctl_arena_stats_s { - unsigned arena_ind; - bool initialized; - ql_elm(ctl_arena_stats_t) destroyed_link; - - unsigned nthreads; - const char *dss; - ssize_t decay_time; - size_t pactive; - size_t pdirty; - - /* The remainder are only populated if config_stats is true. */ - arena_stats_t astats; /* Aggregate stats for small size classes, based on bin stats. */ @@ -47,22 +35,42 @@ struct ctl_arena_stats_s { }; struct ctl_stats_s { - uint64_t epoch; size_t allocated; size_t active; size_t metadata; size_t resident; size_t mapped; size_t retained; +}; + +struct ctl_arena_s { + unsigned arena_ind; + bool initialized; + ql_elm(ctl_arena_t) destroyed_link; + + /* Basic stats, supported even if !config_stats. */ + unsigned nthreads; + const char *dss; + ssize_t decay_time; + size_t pactive; + size_t pdirty; + + /* NULL if !config_stats. */ + ctl_arena_stats_t *astats; +}; + +struct ctl_arenas_s { + uint64_t epoch; unsigned narenas; - ql_head(ctl_arena_stats_t) destroyed; + ql_head(ctl_arena_t) destroyed; + /* - * Element 0 contains merged stats for extant arenas (accessed via - * MALLCTL_ARENAS_ALL), element 1 contains merged stats for destroyed - * arenas (accessed via MALLCTL_ARENAS_DESTROYED), and the remaining - * MALLOCX_ARENA_MAX+1 elements correspond to arenas. + * Element 0 corresponds to merged stats for extant arenas (accessed via + * MALLCTL_ARENAS_ALL), element 1 corresponds to merged stats for + * destroyed arenas (accessed via MALLCTL_ARENAS_DESTROYED), and the + * remaining MALLOCX_ARENA_MAX+1 elements correspond to arenas. */ - ctl_arena_stats_t *arenas[MALLOCX_ARENA_MAX + 3]; + ctl_arena_t *arenas[MALLOCX_ARENA_MAX + 3]; }; #endif /* JEMALLOC_INTERNAL_CTL_STRUCTS_H */ diff --git a/include/jemalloc/internal/ctl_types.h b/include/jemalloc/internal/ctl_types.h index 848c4f10..7853a4b2 100644 --- a/include/jemalloc/internal/ctl_types.h +++ b/include/jemalloc/internal/ctl_types.h @@ -6,5 +6,7 @@ typedef struct ctl_named_node_s ctl_named_node_t; typedef struct ctl_indexed_node_s ctl_indexed_node_t; typedef struct ctl_arena_stats_s ctl_arena_stats_t; typedef struct ctl_stats_s ctl_stats_t; +typedef struct ctl_arena_s ctl_arena_t; +typedef struct ctl_arenas_s ctl_arenas_t; #endif /* JEMALLOC_INTERNAL_CTL_TYPES_H */ diff --git a/src/ctl.c b/src/ctl.c index 9c582d65..b19c9d31 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -11,6 +11,7 @@ static malloc_mutex_t ctl_mtx; static bool ctl_initialized; static ctl_stats_t *ctl_stats; +static ctl_arenas_t *ctl_arenas; /******************************************************************************/ /* Helpers for named and indexed nodes. */ @@ -432,12 +433,10 @@ static const ctl_named_node_t super_root_node[] = { /******************************************************************************/ static unsigned -stats_arenas_i2a_impl(size_t i, bool compat, bool validate) +arenas_i2a_impl(size_t i, bool compat, bool validate) { unsigned a; - cassert(config_stats); - switch (i) { case MALLCTL_ARENAS_ALL: a = 0; @@ -446,7 +445,7 @@ stats_arenas_i2a_impl(size_t i, bool compat, bool validate) a = 1; break; default: - if (compat && i == ctl_stats->narenas) { + if (compat && i == ctl_arenas->narenas) { /* * Provide deprecated backward compatibility for * accessing the merged stats at index narenas rather @@ -454,16 +453,16 @@ stats_arenas_i2a_impl(size_t i, bool compat, bool validate) * removal in 6.0.0. */ a = 0; - } else if (validate && i >= ctl_stats->narenas) + } else if (validate && i >= ctl_arenas->narenas) a = UINT_MAX; else { /* * This function should never be called for an index * more than one past the range of indices that have - * initialized stats. + * initialized ctl data. */ - assert(i < ctl_stats->narenas || (!validate && i == - ctl_stats->narenas)); + assert(i < ctl_arenas->narenas || (!validate && i == + ctl_arenas->narenas)); a = (unsigned)i + 2; } break; @@ -473,103 +472,127 @@ stats_arenas_i2a_impl(size_t i, bool compat, bool validate) } static unsigned -stats_arenas_i2a(size_t i) +arenas_i2a(size_t i) { - return (stats_arenas_i2a_impl(i, true, false)); + return (arenas_i2a_impl(i, true, false)); } -static ctl_arena_stats_t * -stats_arenas_i_impl(tsdn_t *tsdn, size_t i, bool compat, bool init) +static ctl_arena_t * +arenas_i_impl(tsdn_t *tsdn, size_t i, bool compat, bool init) { - ctl_arena_stats_t *ret; + ctl_arena_t *ret; assert(!compat || !init); - ret = ctl_stats->arenas[stats_arenas_i2a_impl(i, compat, false)]; + ret = ctl_arenas->arenas[arenas_i2a_impl(i, compat, false)]; if (init && ret == NULL) { - ret = (ctl_arena_stats_t *)base_alloc(tsdn, b0get(), - sizeof(ctl_arena_stats_t), QUANTUM); - if (ret == NULL) - return (NULL); + if (config_stats) { + struct container_s { + ctl_arena_t ctl_arena; + ctl_arena_stats_t astats; + }; + struct container_s *cont = + (struct container_s *)base_alloc(tsdn, b0get(), + sizeof(struct container_s), QUANTUM); + if (cont == NULL) { + return NULL; + } + ret = &cont->ctl_arena; + ret->astats = &cont->astats; + } else { + ret = (ctl_arena_t *)base_alloc(tsdn, b0get(), + sizeof(ctl_arena_t), QUANTUM); + if (ret == NULL) { + return NULL; + } + } ret->arena_ind = (unsigned)i; - ctl_stats->arenas[stats_arenas_i2a_impl(i, compat, false)] = - ret; + ctl_arenas->arenas[arenas_i2a_impl(i, compat, false)] = ret; } - assert(ret == NULL || stats_arenas_i2a(ret->arena_ind) == - stats_arenas_i2a(i)); + assert(ret == NULL || arenas_i2a(ret->arena_ind) == arenas_i2a(i)); return (ret); } -static ctl_arena_stats_t * -stats_arenas_i(size_t i) +static ctl_arena_t * +arenas_i(size_t i) { - ctl_arena_stats_t *ret = stats_arenas_i_impl(TSDN_NULL, i, true, false); + ctl_arena_t *ret = arenas_i_impl(TSDN_NULL, i, true, false); assert(ret != NULL); return (ret); } static void -ctl_arena_clear(ctl_arena_stats_t *astats) +ctl_arena_clear(ctl_arena_t *ctl_arena) { - astats->nthreads = 0; - astats->dss = dss_prec_names[dss_prec_limit]; - astats->decay_time = -1; - astats->pactive = 0; - astats->pdirty = 0; + ctl_arena->nthreads = 0; + ctl_arena->dss = dss_prec_names[dss_prec_limit]; + ctl_arena->decay_time = -1; + ctl_arena->pactive = 0; + ctl_arena->pdirty = 0; if (config_stats) { - memset(&astats->astats, 0, sizeof(arena_stats_t)); - astats->allocated_small = 0; - astats->nmalloc_small = 0; - astats->ndalloc_small = 0; - astats->nrequests_small = 0; - memset(astats->bstats, 0, NBINS * sizeof(malloc_bin_stats_t)); - memset(astats->lstats, 0, (NSIZES - NBINS) * + memset(&ctl_arena->astats->astats, 0, sizeof(arena_stats_t)); + ctl_arena->astats->allocated_small = 0; + ctl_arena->astats->nmalloc_small = 0; + ctl_arena->astats->ndalloc_small = 0; + ctl_arena->astats->nrequests_small = 0; + memset(ctl_arena->astats->bstats, 0, NBINS * + sizeof(malloc_bin_stats_t)); + memset(ctl_arena->astats->lstats, 0, (NSIZES - NBINS) * sizeof(malloc_large_stats_t)); } } static void -ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_stats_t *cstats, arena_t *arena) +ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_t *ctl_arena, arena_t *arena) { unsigned i; if (config_stats) { - arena_stats_merge(tsdn, arena, &cstats->nthreads, &cstats->dss, - &cstats->decay_time, &cstats->pactive, &cstats->pdirty, - &cstats->astats, cstats->bstats, cstats->lstats); + arena_stats_merge(tsdn, arena, &ctl_arena->nthreads, + &ctl_arena->dss, &ctl_arena->decay_time, + &ctl_arena->pactive, &ctl_arena->pdirty, + &ctl_arena->astats->astats, ctl_arena->astats->bstats, + ctl_arena->astats->lstats); for (i = 0; i < NBINS; i++) { - cstats->allocated_small += cstats->bstats[i].curregs * + ctl_arena->astats->allocated_small += + ctl_arena->astats->bstats[i].curregs * index2size(i); - cstats->nmalloc_small += cstats->bstats[i].nmalloc; - cstats->ndalloc_small += cstats->bstats[i].ndalloc; - cstats->nrequests_small += cstats->bstats[i].nrequests; + ctl_arena->astats->nmalloc_small += + ctl_arena->astats->bstats[i].nmalloc; + ctl_arena->astats->ndalloc_small += + ctl_arena->astats->bstats[i].ndalloc; + ctl_arena->astats->nrequests_small += + ctl_arena->astats->bstats[i].nrequests; } } else { - arena_basic_stats_merge(tsdn, arena, &cstats->nthreads, - &cstats->dss, &cstats->decay_time, &cstats->pactive, - &cstats->pdirty); + arena_basic_stats_merge(tsdn, arena, &ctl_arena->nthreads, + &ctl_arena->dss, &ctl_arena->decay_time, + &ctl_arena->pactive, &ctl_arena->pdirty); } } static void -ctl_arena_stats_sdmerge(ctl_arena_stats_t *sdstats, ctl_arena_stats_t *astats, +ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, bool destroyed) { unsigned i; if (!destroyed) { - sdstats->nthreads += astats->nthreads; - sdstats->pactive += astats->pactive; - sdstats->pdirty += astats->pdirty; + ctl_sdarena->nthreads += ctl_arena->nthreads; + ctl_sdarena->pactive += ctl_arena->pactive; + ctl_sdarena->pdirty += ctl_arena->pdirty; } else { - assert(astats->nthreads == 0); - assert(astats->pactive == 0); - assert(astats->pdirty == 0); + assert(ctl_arena->nthreads == 0); + assert(ctl_arena->pactive == 0); + assert(ctl_arena->pdirty == 0); } if (config_stats) { + ctl_arena_stats_t *sdstats = ctl_sdarena->astats; + ctl_arena_stats_t *astats = ctl_arena->astats; + if (!destroyed) { sdstats->astats.mapped += astats->astats.mapped; sdstats->astats.retained += astats->astats.retained; @@ -648,39 +671,40 @@ ctl_arena_stats_sdmerge(ctl_arena_stats_t *sdstats, ctl_arena_stats_t *astats, } static void -ctl_arena_refresh(tsdn_t *tsdn, arena_t *arena, ctl_arena_stats_t *sdstats, +ctl_arena_refresh(tsdn_t *tsdn, arena_t *arena, ctl_arena_t *ctl_sdarena, unsigned i, bool destroyed) { - ctl_arena_stats_t *astats = stats_arenas_i(i); + ctl_arena_t *ctl_arena = arenas_i(i); - ctl_arena_clear(astats); - ctl_arena_stats_amerge(tsdn, astats, arena); + ctl_arena_clear(ctl_arena); + ctl_arena_stats_amerge(tsdn, ctl_arena, arena); /* Merge into sum stats as well. */ - ctl_arena_stats_sdmerge(sdstats, astats, destroyed); + ctl_arena_stats_sdmerge(ctl_sdarena, ctl_arena, destroyed); } static unsigned ctl_arena_init(tsdn_t *tsdn, extent_hooks_t *extent_hooks) { unsigned arena_ind; - ctl_arena_stats_t *astats; + ctl_arena_t *ctl_arena; - if ((astats = ql_last(&ctl_stats->destroyed, destroyed_link)) != NULL) { - ql_remove(&ctl_stats->destroyed, astats, destroyed_link); - arena_ind = astats->arena_ind; + if ((ctl_arena = ql_last(&ctl_arenas->destroyed, destroyed_link)) != + NULL) { + ql_remove(&ctl_arenas->destroyed, ctl_arena, destroyed_link); + arena_ind = ctl_arena->arena_ind; } else - arena_ind = ctl_stats->narenas; + arena_ind = ctl_arenas->narenas; /* Trigger stats allocation. */ - if (stats_arenas_i_impl(tsdn, arena_ind, false, true) == NULL) + if (arenas_i_impl(tsdn, arena_ind, false, true) == NULL) return (UINT_MAX); /* Initialize new arena. */ if (arena_init(tsdn, arena_ind, extent_hooks) == NULL) return (UINT_MAX); - if (arena_ind == ctl_stats->narenas) - ctl_stats->narenas++; + if (arena_ind == ctl_arenas->narenas) + ctl_arenas->narenas++; return (arena_ind); } @@ -689,39 +713,41 @@ static void ctl_refresh(tsdn_t *tsdn) { unsigned i; - ctl_arena_stats_t *sstats = stats_arenas_i(MALLCTL_ARENAS_ALL); - VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats->narenas); + ctl_arena_t *ctl_sarena = arenas_i(MALLCTL_ARENAS_ALL); + VARIABLE_ARRAY(arena_t *, tarenas, ctl_arenas->narenas); /* * Clear sum stats, since they will be merged into by * ctl_arena_refresh(). */ - ctl_arena_clear(sstats); + ctl_arena_clear(ctl_sarena); - for (i = 0; i < ctl_stats->narenas; i++) + for (i = 0; i < ctl_arenas->narenas; i++) { tarenas[i] = arena_get(tsdn, i, false); + } - for (i = 0; i < ctl_stats->narenas; i++) { - ctl_arena_stats_t *astats = stats_arenas_i(i); + for (i = 0; i < ctl_arenas->narenas; i++) { + ctl_arena_t *ctl_arena = arenas_i(i); bool initialized = (tarenas[i] != NULL); - astats->initialized = initialized; - if (initialized) - ctl_arena_refresh(tsdn, tarenas[i], sstats, i, false); + ctl_arena->initialized = initialized; + if (initialized) { + ctl_arena_refresh(tsdn, tarenas[i], ctl_sarena, i, + false); + } } if (config_stats) { - ctl_stats->allocated = sstats->allocated_small + - sstats->astats.allocated_large; - ctl_stats->active = (sstats->pactive << LG_PAGE); - ctl_stats->metadata = sstats->astats.base + - sstats->astats.internal; - ctl_stats->resident = sstats->astats.resident; - ctl_stats->mapped = sstats->astats.mapped; - ctl_stats->retained = sstats->astats.retained; + ctl_stats->allocated = ctl_sarena->astats->allocated_small + + ctl_sarena->astats->astats.allocated_large; + ctl_stats->active = (ctl_sarena->pactive << LG_PAGE); + ctl_stats->metadata = ctl_sarena->astats->astats.base + + ctl_sarena->astats->astats.internal; + ctl_stats->resident = ctl_sarena->astats->astats.resident; + ctl_stats->mapped = ctl_sarena->astats->astats.mapped; + ctl_stats->retained = ctl_sarena->astats->astats.retained; } - - ctl_stats->epoch++; + ctl_arenas->epoch++; } static bool @@ -731,14 +757,23 @@ ctl_init(tsdn_t *tsdn) malloc_mutex_lock(tsdn, &ctl_mtx); if (!ctl_initialized) { - ctl_arena_stats_t *sstats, *dstats; + ctl_arena_t *ctl_sarena, *ctl_darena; unsigned i; /* - * Allocate demand-zeroed space for pointers to the full range - * of supported arena indices. + * Allocate demand-zeroed space for pointers to the full + * range of supported arena indices. */ - if (ctl_stats == NULL) { + if (ctl_arenas == NULL) { + ctl_arenas = (ctl_arenas_t *)base_alloc(tsdn, + b0get(), sizeof(ctl_arenas_t), QUANTUM); + if (ctl_arenas == NULL) { + ret = true; + goto label_return; + } + } + + if (config_stats && ctl_stats == NULL) { ctl_stats = (ctl_stats_t *)base_alloc(tsdn, b0get(), sizeof(ctl_stats_t), QUANTUM); if (ctl_stats == NULL) { @@ -748,40 +783,40 @@ ctl_init(tsdn_t *tsdn) } /* - * Allocate space for the current full range of arenas here - * rather than doing it lazily elsewhere, in order to limit when - * OOM-caused errors can occur. + * Allocate space for the current full range of arenas + * here rather than doing it lazily elsewhere, in order + * to limit when OOM-caused errors can occur. */ - if ((sstats = stats_arenas_i_impl(tsdn, MALLCTL_ARENAS_ALL, - false, true)) == NULL) { + if ((ctl_sarena = arenas_i_impl(tsdn, MALLCTL_ARENAS_ALL, false, + true)) == NULL) { ret = true; goto label_return; } - sstats->initialized = true; + ctl_sarena->initialized = true; - if ((dstats = stats_arenas_i_impl(tsdn, - MALLCTL_ARENAS_DESTROYED, false, true)) == NULL) { + if ((ctl_darena = arenas_i_impl(tsdn, MALLCTL_ARENAS_DESTROYED, + false, true)) == NULL) { ret = true; goto label_return; } - ctl_arena_clear(dstats); + ctl_arena_clear(ctl_darena); /* - * Don't toggle stats for MALLCTL_ARENAS_DESTROYED to - * initialized until an arena is actually destroyed, so that - * arena..initialized can be used to query whether the stats - * are relevant. + * Don't toggle ctl_darena to initialized until an arena is + * actually destroyed, so that arena..initialized can be used + * to query whether the stats are relevant. */ - ctl_stats->narenas = narenas_total_get(); - for (i = 0; i < ctl_stats->narenas; i++) { - if (stats_arenas_i_impl(tsdn, i, false, true) == NULL) { + ctl_arenas->narenas = narenas_total_get(); + for (i = 0; i < ctl_arenas->narenas; i++) { + if (arenas_i_impl(tsdn, i, false, true) == NULL) { ret = true; goto label_return; } } - ql_new(&ctl_stats->destroyed); + ql_new(&ctl_arenas->destroyed); ctl_refresh(tsdn); + ctl_initialized = true; } @@ -1228,7 +1263,7 @@ epoch_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, WRITE(newval, uint64_t); if (newp != NULL) ctl_refresh(tsd_tsdn(tsd)); - READ(ctl_stats->epoch, uint64_t); + READ(ctl_arenas->epoch, uint64_t); ret = 0; label_return: @@ -1526,7 +1561,7 @@ arena_i_initialized_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, MIB_UNSIGNED(arena_ind, 1); malloc_mutex_lock(tsdn, &ctl_mtx); - initialized = stats_arenas_i(arena_ind)->initialized; + initialized = arenas_i(arena_ind)->initialized; malloc_mutex_unlock(tsdn, &ctl_mtx); READ(initialized, bool); @@ -1541,7 +1576,7 @@ arena_i_purge(tsdn_t *tsdn, unsigned arena_ind, bool all) { malloc_mutex_lock(tsdn, &ctl_mtx); { - unsigned narenas = ctl_stats->narenas; + unsigned narenas = ctl_arenas->narenas; /* * Access via index narenas is deprecated, and scheduled for @@ -1666,7 +1701,7 @@ arena_i_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, int ret; unsigned arena_ind; arena_t *arena; - ctl_arena_stats_t *dstats, *astats; + ctl_arena_t *ctl_darena, *ctl_arena; ret = arena_i_reset_destroy_helper(tsd, mib, miblen, oldp, oldlenp, newp, newlen, &arena_ind, &arena); @@ -1682,16 +1717,16 @@ arena_i_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, /* Merge stats after resetting and purging arena. */ arena_reset(tsd, arena); arena_purge(tsd_tsdn(tsd), arena, true); - dstats = stats_arenas_i(MALLCTL_ARENAS_DESTROYED); - dstats->initialized = true; - ctl_arena_refresh(tsd_tsdn(tsd), arena, dstats, arena_ind, true); + ctl_darena = arenas_i(MALLCTL_ARENAS_DESTROYED); + ctl_darena->initialized = true; + ctl_arena_refresh(tsd_tsdn(tsd), arena, ctl_darena, arena_ind, true); /* Destroy arena. */ arena_destroy(tsd, arena); - astats = stats_arenas_i(arena_ind); - astats->initialized = false; + ctl_arena = arenas_i(arena_ind); + ctl_arena->initialized = false; /* Record arena index for later recycling via arenas.create. */ - ql_elm_new(astats, destroyed_link); - ql_tail_insert(&ctl_stats->destroyed, astats, destroyed_link); + ql_elm_new(ctl_arena, destroyed_link); + ql_tail_insert(&ctl_arenas->destroyed, ctl_arena, destroyed_link); assert(ret == 0); label_return: @@ -1734,7 +1769,7 @@ arena_i_dss_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, * 6.0.0. */ if (arena_ind == MALLCTL_ARENAS_ALL || arena_ind == - ctl_stats->narenas) { + ctl_arenas->narenas) { if (dss_prec != dss_prec_limit && extent_dss_prec_set(dss_prec)) { ret = EFAULT; @@ -1842,7 +1877,7 @@ arena_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) case MALLCTL_ARENAS_DESTROYED: break; default: - if (i > ctl_stats->narenas) { + if (i > ctl_arenas->narenas) { ret = NULL; goto label_return; } @@ -1870,7 +1905,7 @@ arenas_narenas_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = EINVAL; goto label_return; } - narenas = ctl_stats->narenas; + narenas = ctl_arenas->narenas; READ(narenas, unsigned); ret = 0; @@ -2091,67 +2126,66 @@ CTL_RO_CGEN(config_stats, stats_resident, ctl_stats->resident, size_t) CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats->mapped, size_t) CTL_RO_CGEN(config_stats, stats_retained, ctl_stats->retained, size_t) -CTL_RO_GEN(stats_arenas_i_dss, stats_arenas_i(mib[2])->dss, const char *) -CTL_RO_GEN(stats_arenas_i_decay_time, stats_arenas_i(mib[2])->decay_time, +CTL_RO_GEN(stats_arenas_i_dss, arenas_i(mib[2])->dss, const char *) +CTL_RO_GEN(stats_arenas_i_decay_time, arenas_i(mib[2])->decay_time, ssize_t) -CTL_RO_GEN(stats_arenas_i_nthreads, stats_arenas_i(mib[2])->nthreads, - unsigned) -CTL_RO_GEN(stats_arenas_i_pactive, stats_arenas_i(mib[2])->pactive, size_t) -CTL_RO_GEN(stats_arenas_i_pdirty, stats_arenas_i(mib[2])->pdirty, size_t) +CTL_RO_GEN(stats_arenas_i_nthreads, arenas_i(mib[2])->nthreads, unsigned) +CTL_RO_GEN(stats_arenas_i_pactive, arenas_i(mib[2])->pactive, size_t) +CTL_RO_GEN(stats_arenas_i_pdirty, arenas_i(mib[2])->pdirty, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_mapped, - stats_arenas_i(mib[2])->astats.mapped, size_t) + arenas_i(mib[2])->astats->astats.mapped, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_retained, - stats_arenas_i(mib[2])->astats.retained, size_t) + arenas_i(mib[2])->astats->astats.retained, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_npurge, - stats_arenas_i(mib[2])->astats.npurge, uint64_t) + arenas_i(mib[2])->astats->astats.npurge, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise, - stats_arenas_i(mib[2])->astats.nmadvise, uint64_t) + arenas_i(mib[2])->astats->astats.nmadvise, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_purged, - stats_arenas_i(mib[2])->astats.purged, uint64_t) + arenas_i(mib[2])->astats->astats.purged, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_base, - stats_arenas_i(mib[2])->astats.base, size_t) + arenas_i(mib[2])->astats->astats.base, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_internal, - stats_arenas_i(mib[2])->astats.internal, size_t) + arenas_i(mib[2])->astats->astats.internal, size_t) CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_tcache_bytes, - stats_arenas_i(mib[2])->astats.tcache_bytes, size_t) + arenas_i(mib[2])->astats->astats.tcache_bytes, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_resident, - stats_arenas_i(mib[2])->astats.resident, size_t) + arenas_i(mib[2])->astats->astats.resident, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated, - stats_arenas_i(mib[2])->allocated_small, size_t) + arenas_i(mib[2])->astats->allocated_small, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_small_nmalloc, - stats_arenas_i(mib[2])->nmalloc_small, uint64_t) + arenas_i(mib[2])->astats->nmalloc_small, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc, - stats_arenas_i(mib[2])->ndalloc_small, uint64_t) + arenas_i(mib[2])->astats->ndalloc_small, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests, - stats_arenas_i(mib[2])->nrequests_small, uint64_t) + arenas_i(mib[2])->astats->nrequests_small, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated, - stats_arenas_i(mib[2])->astats.allocated_large, size_t) + arenas_i(mib[2])->astats->astats.allocated_large, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc, - stats_arenas_i(mib[2])->astats.nmalloc_large, uint64_t) + arenas_i(mib[2])->astats->astats.nmalloc_large, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc, - stats_arenas_i(mib[2])->astats.ndalloc_large, uint64_t) + arenas_i(mib[2])->astats->astats.ndalloc_large, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests, - stats_arenas_i(mib[2])->astats.nmalloc_large, uint64_t) /* Intentional. */ + arenas_i(mib[2])->astats->astats.nmalloc_large, uint64_t) /* Intentional. */ CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc, - stats_arenas_i(mib[2])->bstats[mib[4]].nmalloc, uint64_t) + arenas_i(mib[2])->astats->bstats[mib[4]].nmalloc, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_ndalloc, - stats_arenas_i(mib[2])->bstats[mib[4]].ndalloc, uint64_t) + arenas_i(mib[2])->astats->bstats[mib[4]].ndalloc, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nrequests, - stats_arenas_i(mib[2])->bstats[mib[4]].nrequests, uint64_t) + arenas_i(mib[2])->astats->bstats[mib[4]].nrequests, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curregs, - stats_arenas_i(mib[2])->bstats[mib[4]].curregs, size_t) + arenas_i(mib[2])->astats->bstats[mib[4]].curregs, size_t) CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nfills, - stats_arenas_i(mib[2])->bstats[mib[4]].nfills, uint64_t) + arenas_i(mib[2])->astats->bstats[mib[4]].nfills, uint64_t) CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nflushes, - stats_arenas_i(mib[2])->bstats[mib[4]].nflushes, uint64_t) + arenas_i(mib[2])->astats->bstats[mib[4]].nflushes, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nslabs, - stats_arenas_i(mib[2])->bstats[mib[4]].nslabs, uint64_t) + arenas_i(mib[2])->astats->bstats[mib[4]].nslabs, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreslabs, - stats_arenas_i(mib[2])->bstats[mib[4]].reslabs, uint64_t) + arenas_i(mib[2])->astats->bstats[mib[4]].reslabs, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curslabs, - stats_arenas_i(mib[2])->bstats[mib[4]].curslabs, size_t) + arenas_i(mib[2])->astats->bstats[mib[4]].curslabs, size_t) static const ctl_named_node_t * stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, @@ -2163,13 +2197,13 @@ stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, } CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nmalloc, - stats_arenas_i(mib[2])->lstats[mib[4]].nmalloc, uint64_t) + arenas_i(mib[2])->astats->lstats[mib[4]].nmalloc, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_ndalloc, - stats_arenas_i(mib[2])->lstats[mib[4]].ndalloc, uint64_t) + arenas_i(mib[2])->astats->lstats[mib[4]].ndalloc, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nrequests, - stats_arenas_i(mib[2])->lstats[mib[4]].nrequests, uint64_t) + arenas_i(mib[2])->astats->lstats[mib[4]].nrequests, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_curlextents, - stats_arenas_i(mib[2])->lstats[mib[4]].curlextents, size_t) + arenas_i(mib[2])->astats->lstats[mib[4]].curlextents, size_t) static const ctl_named_node_t * stats_arenas_i_lextents_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, @@ -2187,8 +2221,8 @@ stats_arenas_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) size_t a; malloc_mutex_lock(tsdn, &ctl_mtx); - a = stats_arenas_i2a_impl(i, true, true); - if (a == UINT_MAX || !ctl_stats->arenas[a]->initialized) { + a = arenas_i2a_impl(i, true, true); + if (a == UINT_MAX || !ctl_arenas->arenas[a]->initialized) { ret = NULL; goto label_return; } diff --git a/src/extent.c b/src/extent.c index 27cf97cd..be40aaad 100644 --- a/src/extent.c +++ b/src/extent.c @@ -820,9 +820,11 @@ extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, extent = extent_recycle(tsdn, arena, r_extent_hooks, arena->extents_retained, false, false, new_addr, usize, pad, alignment, zero, commit, slab); - if (extent != NULL && config_stats) { - size_t size = usize + pad; - arena->stats.retained -= size; + if (extent != NULL) { + if (config_stats) { + size_t size = usize + pad; + arena->stats.retained -= size; + } if (config_prof) extent_gprof_add(tsdn, extent); } diff --git a/test/unit/base.c b/test/unit/base.c index 9aa43eab..76e96da8 100644 --- a/test/unit/base.c +++ b/test/unit/base.c @@ -33,16 +33,20 @@ TEST_BEGIN(test_base_hooks_default) tsdn = tsdn_fetch(); base = base_new(tsdn, 0, (extent_hooks_t *)&extent_hooks_default); - base_stats_get(tsdn, base, &allocated0, &resident, &mapped); - assert_zu_ge(allocated0, sizeof(base_t), - "Base header should count as allocated"); + if (config_stats) { + base_stats_get(tsdn, base, &allocated0, &resident, &mapped); + assert_zu_ge(allocated0, sizeof(base_t), + "Base header should count as allocated"); + } assert_ptr_not_null(base_alloc(tsdn, base, 42, 1), "Unexpected base_alloc() failure"); - base_stats_get(tsdn, base, &allocated1, &resident, &mapped); - assert_zu_ge(allocated1 - allocated0, 42, - "At least 42 bytes were allocated by base_alloc()"); + if (config_stats) { + base_stats_get(tsdn, base, &allocated1, &resident, &mapped); + assert_zu_ge(allocated1 - allocated0, 42, + "At least 42 bytes were allocated by base_alloc()"); + } base_delete(base); } @@ -67,16 +71,20 @@ TEST_BEGIN(test_base_hooks_null) base = base_new(tsdn, 0, &hooks); assert_ptr_not_null(base, "Unexpected base_new() failure"); - base_stats_get(tsdn, base, &allocated0, &resident, &mapped); - assert_zu_ge(allocated0, sizeof(base_t), - "Base header should count as allocated"); + if (config_stats) { + base_stats_get(tsdn, base, &allocated0, &resident, &mapped); + assert_zu_ge(allocated0, sizeof(base_t), + "Base header should count as allocated"); + } assert_ptr_not_null(base_alloc(tsdn, base, 42, 1), "Unexpected base_alloc() failure"); - base_stats_get(tsdn, base, &allocated1, &resident, &mapped); - assert_zu_ge(allocated1 - allocated0, 42, - "At least 42 bytes were allocated by base_alloc()"); + if (config_stats) { + base_stats_get(tsdn, base, &allocated1, &resident, &mapped); + assert_zu_ge(allocated1 - allocated0, 42, + "At least 42 bytes were allocated by base_alloc()"); + } base_delete(base); -- GitLab From 5154ff32ee8c37bacb6afd8a07b923eb33228357 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 18 Jan 2017 14:04:24 -0800 Subject: [PATCH 238/544] Unify the allocation paths This unifies the allocation paths for malloc, posix_memalign, aligned_alloc, calloc, memalign, valloc, and mallocx, so that they all share common code where they can. There's more work that could be done here, but I think this is the smallest discrete change in this direction. --- src/jemalloc.c | 897 ++++++++++++++++++++++++++++--------------------- 1 file changed, 505 insertions(+), 392 deletions(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index 1dc91833..af2a53a2 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1352,250 +1352,457 @@ malloc_init_hard(void) */ /******************************************************************************/ /* - * Begin malloc(3)-compatible functions. + * Begin allocation-path internal functions and data structures. */ -static void * -ialloc_prof_sample(tsd_t *tsd, size_t usize, szind_t ind, bool zero, - prof_tctx_t *tctx, bool slow_path) -{ - void *p; +/* + * Settings determined by the documented behavior of the allocation functions. + */ +typedef struct static_opts_s static_opts_t; +struct static_opts_s { + /* Whether or not allocations of size 0 should be treated as size 1. */ + bool bump_empty_alloc; + /* + * Whether to assert that allocations are not of size 0 (after any + * bumping). + */ + bool assert_nonempty_alloc; - if (tctx == NULL) - return (NULL); - if (usize <= SMALL_MAXCLASS) { - szind_t ind_large = size2index(LARGE_MINCLASS); - p = ialloc(tsd, LARGE_MINCLASS, ind_large, zero, slow_path); - if (p == NULL) - return (NULL); - arena_prof_promote(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, - usize); - } else - p = ialloc(tsd, usize, ind, zero, slow_path); + /* + * Whether or not to modify the 'result' argument to malloc in case of + * error. + */ + bool null_out_result_on_error; + /* Whether to set errno when we encounter an error condition. */ + bool set_errno_on_error; - return (p); -} + /* + * The minimum valid alignment for functions requesting aligned storage. + */ + size_t min_alignment; -JEMALLOC_ALWAYS_INLINE_C void * -ialloc_prof(tsd_t *tsd, size_t usize, szind_t ind, bool zero, bool slow_path) -{ - void *p; - prof_tctx_t *tctx; + /* The error string to use if we oom. */ + const char *oom_string; + /* The error string to use if the passed-in alignment is invalid. */ + const char *invalid_alignment_string; - tctx = prof_alloc_prep(tsd, usize, prof_active_get_unlocked(), true); - if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) - p = ialloc_prof_sample(tsd, usize, ind, zero, tctx, slow_path); - else - p = ialloc(tsd, usize, ind, zero, slow_path); - if (unlikely(p == NULL)) { - prof_alloc_rollback(tsd, tctx, true); - return (NULL); - } - prof_malloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, usize, tctx); + /* + * False if we're configured to skip some time-consuming operations. + * + * This isn't really a malloc "behavior", but it acts as a useful + * summary of several other static (or at least, static after program + * initialization) options. + */ + bool slow; +}; - return (p); +JEMALLOC_ALWAYS_INLINE_C void +static_opts_init(static_opts_t *static_opts) { + static_opts->bump_empty_alloc = false; + static_opts->assert_nonempty_alloc = false; + static_opts->null_out_result_on_error = false; + static_opts->set_errno_on_error = false; + static_opts->min_alignment = 0; + static_opts->oom_string = ""; + static_opts->invalid_alignment_string = ""; + static_opts->slow = false; } /* - * ialloc_body() is inlined so that fast and slow paths are generated separately - * with statically known slow_path. - * - * This function guarantees that *tsdn is non-NULL on success. + * These correspond to the macros in jemalloc/jemalloc_macros.h. Broadly, we + * should have one constant here per magic value there. Note however that the + * representations need not be related. */ -JEMALLOC_ALWAYS_INLINE_C void * -ialloc_body(size_t size, bool zero, tsdn_t **tsdn, size_t *usize, - bool slow_path) -{ - tsd_t *tsd; - szind_t ind; +#define TCACHE_IND_NONE ((unsigned)-1) +#define TCACHE_IND_AUTOMATIC ((unsigned)-2) +#define ARENA_IND_AUTOMATIC ((unsigned)-1) + +typedef struct dynamic_opts_s dynamic_opts_t; +struct dynamic_opts_s { + void **result; + size_t num_items; + size_t item_size; + size_t alignment; + bool zero; + unsigned tcache_ind; + unsigned arena_ind; +}; - if (slow_path && unlikely(malloc_init())) { - *tsdn = NULL; - return (NULL); - } +JEMALLOC_ALWAYS_INLINE_C void +dynamic_opts_init(dynamic_opts_t *dynamic_opts) { + dynamic_opts->result = NULL; + dynamic_opts->num_items = 0; + dynamic_opts->item_size = 0; + dynamic_opts->alignment = 0; + dynamic_opts->zero = false; + dynamic_opts->tcache_ind = TCACHE_IND_AUTOMATIC; + dynamic_opts->arena_ind = ARENA_IND_AUTOMATIC; +} - tsd = tsd_fetch(); - *tsdn = tsd_tsdn(tsd); - witness_assert_lockless(tsd_tsdn(tsd)); +/* ind is ignored if dopts->alignment > 0. */ +JEMALLOC_ALWAYS_INLINE_C void * +imalloc_no_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd, + size_t size, size_t usize, szind_t ind) { + tcache_t *tcache; + arena_t *arena; - ind = size2index(size); - if (unlikely(ind >= NSIZES)) - return (NULL); + /* Fill in the tcache. */ + if (dopts->tcache_ind == TCACHE_IND_AUTOMATIC) { + tcache = tcache_get(tsd, true); + } else if (dopts->tcache_ind == TCACHE_IND_NONE) { + tcache = NULL; + } else { + tcache = tcaches_get(tsd, dopts->tcache_ind); + } - if (config_stats || (config_prof && opt_prof)) { - *usize = index2size(ind); - assert(*usize > 0 && *usize <= LARGE_MAXCLASS); + /* Fill in the arena. */ + if (dopts->arena_ind == ARENA_IND_AUTOMATIC) { + /* + * In case of automatic arena management, we defer arena + * computation until as late as we can, hoping to fill the + * allocation out of the tcache. + */ + arena = NULL; + } else { + arena = arena_get(tsd_tsdn(tsd), dopts->arena_ind, true); } - if (config_prof && opt_prof) - return (ialloc_prof(tsd, *usize, ind, zero, slow_path)); + if (unlikely(dopts->alignment != 0)) { + return ipalloct(tsd_tsdn(tsd), usize, dopts->alignment, + dopts->zero, tcache, arena); + } - return (ialloc(tsd, size, ind, zero, slow_path)); + return iallocztm(tsd_tsdn(tsd), size, ind, dopts->zero, tcache, false, + arena, sopts->slow); } -JEMALLOC_ALWAYS_INLINE_C void -ialloc_post_check(void *ret, tsdn_t *tsdn, size_t usize, const char *func, - bool update_errno, bool slow_path) -{ - assert(!tsdn_null(tsdn) || ret == NULL); +JEMALLOC_ALWAYS_INLINE_C void * +imalloc_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd, + size_t usize, szind_t ind) { + void *ret; - if (unlikely(ret == NULL)) { - if (slow_path && config_xmalloc && unlikely(opt_xmalloc)) { - malloc_printf(": Error in %s(): out of " - "memory\n", func); - abort(); + /* + * For small allocations, sampling bumps the usize. If so, we allocate + * from the ind_large bucket. + */ + szind_t ind_large; + size_t bumped_usize = usize; + + if (usize <= SMALL_MAXCLASS) { + assert(((dopts->alignment == 0) ? s2u(LARGE_MINCLASS) : + sa2u(LARGE_MINCLASS, dopts->alignment)) == LARGE_MINCLASS); + ind_large = size2index(LARGE_MINCLASS); + bumped_usize = s2u(LARGE_MINCLASS); + ret = imalloc_no_sample(sopts, dopts, tsd, bumped_usize, + bumped_usize, ind_large); + if (unlikely(ret == NULL)) { + return NULL; } - if (update_errno) - set_errno(ENOMEM); - } - if (config_stats && likely(ret != NULL)) { - assert(usize == isalloc(tsdn, iealloc(tsdn, ret), ret)); - *tsd_thread_allocatedp_get(tsdn_tsd(tsdn)) += usize; + arena_prof_promote(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), ret), + ret, usize); + } else { + ret = imalloc_no_sample(sopts, dopts, tsd, usize, usize, ind); } - witness_assert_lockless(tsdn); + + return ret; } -JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN -void JEMALLOC_NOTHROW * -JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1) -je_malloc(size_t size) -{ - void *ret; - tsdn_t *tsdn; - size_t usize JEMALLOC_CC_SILENCE_INIT(0); +/* + * Returns true if the allocation will overflow, and false otherwise. Sets + * *size to the product either way. + */ +JEMALLOC_ALWAYS_INLINE_C bool +compute_size_with_overflow(dynamic_opts_t *dopts, size_t *size) { + /* + * This function is just num_items * item_size, except that we have to + * check for overflow. + */ - if (size == 0) - size = 1; + /* A size_t with its high-half bits all set to 1. */ + const static size_t high_bits = SIZE_T_MAX >> (sizeof(size_t) * 8 / 2); - if (likely(!malloc_slow)) { - ret = ialloc_body(size, false, &tsdn, &usize, false); - ialloc_post_check(ret, tsdn, usize, "malloc", true, false); - } else { - ret = ialloc_body(size, false, &tsdn, &usize, true); - ialloc_post_check(ret, tsdn, usize, "malloc", true, true); - UTRACE(0, size, ret); + *size = dopts->item_size * dopts->num_items; + + if (unlikely(*size == 0)) { + return (dopts->num_items != 0 && dopts->item_size != 0); } - return (ret); + /* + * We got a non-zero size, but we don't know if we overflowed to get + * there. To avoid having to do a divide, we'll be clever and note that + * if both A and B can be represented in N/2 bits, then their product + * can be represented in N bits (without the possibility of overflow). + */ + if (likely((high_bits & (dopts->num_items | dopts->item_size)) == 0)) { + return false; + } + if (likely(*size / dopts->item_size == dopts->num_items)) { + return false; + } + return true; } -static void * -imemalign_prof_sample(tsd_t *tsd, size_t alignment, size_t usize, - prof_tctx_t *tctx) -{ - void *p; - - if (tctx == NULL) - return (NULL); - if (usize <= SMALL_MAXCLASS) { - assert(sa2u(LARGE_MINCLASS, alignment) == LARGE_MINCLASS); - p = ipalloc(tsd, LARGE_MINCLASS, alignment, false); - if (p == NULL) - return (NULL); - arena_prof_promote(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, - usize); - } else - p = ipalloc(tsd, usize, alignment, false); +JEMALLOC_ALWAYS_INLINE_C int +imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { + /* Where the actual allocated memory will live. */ + void *allocation = NULL; + /* Filled in by compute_size_with_overflow below. */ + size_t size = 0; + /* We compute a value for this right before allocating. */ + tsd_t *tsd = NULL; + /* + * For unaligned allocations, we need only ind. For aligned + * allocations, or in case of stats or profiling we need usize. + * + * These are actually dead stores, in that their values are reset before + * any branch on their value is taken. Sometimes though, it's + * convenient to pass them as arguments before this point. To avoid + * undefined behavior then, we initialize them with dummy stores. + */ + szind_t ind = 0; + size_t usize = 0; - return (p); -} + /* Initialize (if we can't prove we don't have to). */ + if (sopts->slow) { + if (unlikely(malloc_init())) { + goto label_oom; + } + } -JEMALLOC_ALWAYS_INLINE_C void * -imemalign_prof(tsd_t *tsd, size_t alignment, size_t usize) -{ - void *p; - prof_tctx_t *tctx; + /* Compute the amount of memory the user wants. */ + bool overflow = compute_size_with_overflow(dopts, &size); + if (unlikely(overflow)) { + goto label_oom; + } - tctx = prof_alloc_prep(tsd, usize, prof_active_get_unlocked(), true); - if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) - p = imemalign_prof_sample(tsd, alignment, usize, tctx); - else - p = ipalloc(tsd, usize, alignment, false); - if (unlikely(p == NULL)) { - prof_alloc_rollback(tsd, tctx, true); - return (NULL); + /* Validate the user input. */ + if (sopts->bump_empty_alloc) { + if (unlikely(size == 0)) { + size = 1; + } } - prof_malloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, usize, tctx); - return (p); -} + if (sopts->assert_nonempty_alloc) { + assert (size != 0); + } -JEMALLOC_ATTR(nonnull(1)) -static int -imemalign(void **memptr, size_t alignment, size_t size, size_t min_alignment) -{ - int ret; - tsd_t *tsd; - size_t usize; - void *result; + if (unlikely(dopts->alignment < sopts->min_alignment + || (dopts->alignment & (dopts->alignment - 1)) != 0)) { + goto label_invalid_alignment; + } - assert(min_alignment != 0); + /* This is the beginning of the "core" algorithm. */ - if (unlikely(malloc_init())) { - tsd = NULL; - result = NULL; - goto label_oom; + if (dopts->alignment == 0) { + ind = size2index(size); + if (unlikely(ind >= NSIZES)) { + goto label_oom; + } + if (config_stats || (config_prof && opt_prof)) { + usize = index2size(ind); + assert(usize > 0 && usize <= LARGE_MAXCLASS); + } + } else { + usize = sa2u(size, dopts->alignment); + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { + goto label_oom; + } } + + /* + * We always need the tsd, even if we aren't going to use the tcache for + * some reason. Let's grab it right away. + */ tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); - if (size == 0) - size = 1; - /* Make sure that alignment is a large enough power of 2. */ - if (unlikely(((alignment - 1) & alignment) != 0 - || (alignment < min_alignment))) { - if (config_xmalloc && unlikely(opt_xmalloc)) { - malloc_write(": Error allocating " - "aligned memory: invalid alignment\n"); - abort(); + + /* If profiling is on, get our profiling context. */ + if (config_prof && opt_prof) { + /* + * Note that if we're going down this path, usize must have been + * initialized in the previous if statement. + */ + prof_tctx_t *tctx = prof_alloc_prep( + tsd, usize, prof_active_get_unlocked(), true); + if (likely((uintptr_t)tctx == (uintptr_t)1U)) { + allocation = imalloc_no_sample( + sopts, dopts, tsd, usize, usize, ind); + } else if ((uintptr_t)tctx > (uintptr_t)1U) { + /* + * Note that ind might still be 0 here. This is fine; + * imalloc_sample ignores ind if dopts->alignment > 0. + */ + allocation = imalloc_sample( + sopts, dopts, tsd, usize, ind); + } else { + allocation = NULL; } - result = NULL; - ret = EINVAL; - goto label_return; - } - usize = sa2u(size, alignment); - if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { - result = NULL; - goto label_oom; + if (unlikely(allocation == NULL)) { + prof_alloc_rollback(tsd, tctx, true); + goto label_oom; + } + + prof_malloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), allocation), + allocation, usize, tctx); + + } else { + /* + * If dopts->alignment > 0, then ind is still 0, but usize was + * computed in the previous if statement. Down the positive + * alignment path, imalloc_no_sample ind and size (relying only + * on usize). + */ + allocation = imalloc_no_sample(sopts, dopts, tsd, usize, usize, + ind); + if (unlikely(allocation == NULL)) { + goto label_oom; + } } - if (config_prof && opt_prof) - result = imemalign_prof(tsd, alignment, usize); - else - result = ipalloc(tsd, usize, alignment, false); - if (unlikely(result == NULL)) - goto label_oom; - assert(((uintptr_t)result & (alignment - 1)) == ZU(0)); + /* + * Allocation has been done at this point. We still have some + * post-allocation work to do though. + */ + assert(dopts->alignment == 0 + || ((uintptr_t)allocation & (dopts->alignment - 1)) == ZU(0)); - *memptr = result; - ret = 0; -label_return: - if (config_stats && likely(result != NULL)) { + if (config_stats) { assert(usize == isalloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), - result), result)); + allocation), allocation)); *tsd_thread_allocatedp_get(tsd) += usize; } - UTRACE(0, size, result); + + if (sopts->slow) { + UTRACE(0, size, allocation); + } + witness_assert_lockless(tsd_tsdn(tsd)); - return (ret); + + + + /* Success! */ + *dopts->result = allocation; + return 0; + label_oom: - assert(result == NULL); + if (unlikely(sopts->slow) && config_xmalloc && unlikely(opt_xmalloc)) { + malloc_write(sopts->oom_string); + abort(); + } + + if (sopts->slow) { + UTRACE(NULL, size, NULL); + } + + witness_assert_lockless(tsd_tsdn(tsd)); + + if (sopts->set_errno_on_error) { + set_errno(ENOMEM); + } + + if (sopts->null_out_result_on_error) { + *dopts->result = NULL; + } + + return ENOMEM; + + /* + * This label is only jumped to by one goto; we move it out of line + * anyways to avoid obscuring the non-error paths, and for symmetry with + * the oom case. + */ +label_invalid_alignment: if (config_xmalloc && unlikely(opt_xmalloc)) { - malloc_write(": Error allocating aligned memory: " - "out of memory\n"); + malloc_write(sopts->invalid_alignment_string); abort(); } - ret = ENOMEM; + + if (sopts->set_errno_on_error) { + set_errno(EINVAL); + } + + if (sopts->slow) { + UTRACE(NULL, size, NULL); + } + witness_assert_lockless(tsd_tsdn(tsd)); - goto label_return; + + if (sopts->null_out_result_on_error) { + *dopts->result = NULL; + } + + return EINVAL; +} + +/* Returns the errno-style error code of the allocation. */ +JEMALLOC_ALWAYS_INLINE_C int +imalloc(static_opts_t *sopts, dynamic_opts_t *dopts) { + if (unlikely(malloc_slow)) { + sopts->slow = true; + return imalloc_body(sopts, dopts); + } else { + sopts->slow = false; + return imalloc_body(sopts, dopts); + } +} +/******************************************************************************/ +/* + * Begin malloc(3)-compatible functions. + */ + +JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN +void JEMALLOC_NOTHROW * +JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1) +je_malloc(size_t size) +{ + void *ret; + static_opts_t sopts; + dynamic_opts_t dopts; + + static_opts_init(&sopts); + dynamic_opts_init(&dopts); + + sopts.bump_empty_alloc = true; + sopts.null_out_result_on_error = true; + sopts.set_errno_on_error = true; + sopts.oom_string = ": Error in malloc(): out of memory\n"; + + dopts.result = &ret; + dopts.num_items = 1; + dopts.item_size = size; + + imalloc(&sopts, &dopts); + + return ret; } JEMALLOC_EXPORT int JEMALLOC_NOTHROW JEMALLOC_ATTR(nonnull(1)) je_posix_memalign(void **memptr, size_t alignment, size_t size) { - return (imemalign(memptr, alignment, size, sizeof(void *))); + int ret; + static_opts_t sopts; + dynamic_opts_t dopts; + + static_opts_init(&sopts); + dynamic_opts_init(&dopts); + + sopts.bump_empty_alloc = true; + sopts.min_alignment = sizeof(void *); + sopts.oom_string = + ": Error allocating aligned memory: out of memory\n"; + sopts.invalid_alignment_string = + ": Error allocating aligned memory: invalid alignment\n"; + + dopts.result = memptr; + dopts.num_items = 1; + dopts.item_size = size; + dopts.alignment = alignment; + + ret = imalloc(&sopts, &dopts); + return ret; } JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN @@ -1604,12 +1811,28 @@ JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(2) je_aligned_alloc(size_t alignment, size_t size) { void *ret; - int err; - if (unlikely((err = imemalign(&ret, alignment, size, 1)) != 0)) { - ret = NULL; - set_errno(err); - } + static_opts_t sopts; + dynamic_opts_t dopts; + + static_opts_init(&sopts); + dynamic_opts_init(&dopts); + + sopts.bump_empty_alloc = true; + sopts.null_out_result_on_error = true; + sopts.set_errno_on_error = true; + sopts.min_alignment = 1; + sopts.oom_string = + ": Error allocating aligned memory: out of memory\n"; + sopts.invalid_alignment_string = + ": Error allocating aligned memory: invalid alignment\n"; + + dopts.result = &ret; + dopts.num_items = 1; + dopts.item_size = size; + dopts.alignment = alignment; + + imalloc(&sopts, &dopts); return (ret); } @@ -1619,35 +1842,25 @@ JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE2(1, 2) je_calloc(size_t num, size_t size) { void *ret; - tsdn_t *tsdn; - size_t num_size; - size_t usize JEMALLOC_CC_SILENCE_INIT(0); + static_opts_t sopts; + dynamic_opts_t dopts; - num_size = num * size; - if (unlikely(num_size == 0)) { - if (num == 0 || size == 0) - num_size = 1; - else - num_size = LARGE_MAXCLASS + 1; /* Trigger OOM. */ - /* - * Try to avoid division here. We know that it isn't possible to - * overflow during multiplication if neither operand uses any of the - * most significant half of the bits in a size_t. - */ - } else if (unlikely(((num | size) & (SIZE_T_MAX << (sizeof(size_t) << - 2))) && (num_size / size != num))) - num_size = LARGE_MAXCLASS + 1; /* size_t overflow. */ + static_opts_init(&sopts); + dynamic_opts_init(&dopts); - if (likely(!malloc_slow)) { - ret = ialloc_body(num_size, true, &tsdn, &usize, false); - ialloc_post_check(ret, tsdn, usize, "calloc", true, false); - } else { - ret = ialloc_body(num_size, true, &tsdn, &usize, true); - ialloc_post_check(ret, tsdn, usize, "calloc", true, true); - UTRACE(0, num_size, ret); - } + sopts.bump_empty_alloc = true; + sopts.null_out_result_on_error = true; + sopts.set_errno_on_error = true; + sopts.oom_string = ": Error in calloc(): out of memory\n"; - return (ret); + dopts.result = &ret; + dopts.num_items = num; + dopts.item_size = size; + dopts.zero = true; + + imalloc(&sopts, &dopts); + + return ret; } static void * @@ -1795,11 +2008,7 @@ je_realloc(void *ptr, size_t size) tsdn = tsd_tsdn(tsd); } else { /* realloc(NULL, size) is equivalent to malloc(size). */ - if (likely(!malloc_slow)) - ret = ialloc_body(size, false, &tsdn, &usize, false); - else - ret = ialloc_body(size, false, &tsdn, &usize, true); - assert(!tsdn_null(tsdn) || ret == NULL); + return je_malloc(size); } if (unlikely(ret == NULL)) { @@ -1852,10 +2061,28 @@ void JEMALLOC_NOTHROW * JEMALLOC_ATTR(malloc) je_memalign(size_t alignment, size_t size) { - void *ret JEMALLOC_CC_SILENCE_INIT(NULL); - if (unlikely(imemalign(&ret, alignment, size, 1) != 0)) - ret = NULL; - return (ret); + void *ret; + static_opts_t sopts; + dynamic_opts_t dopts; + + static_opts_init(&sopts); + dynamic_opts_init(&dopts); + + sopts.bump_empty_alloc = true; + sopts.min_alignment = 1; + sopts.oom_string = + ": Error allocating aligned memory: out of memory\n"; + sopts.invalid_alignment_string = + ": Error allocating aligned memory: invalid alignment\n"; + sopts.null_out_result_on_error = true; + + dopts.result = &ret; + dopts.num_items = 1; + dopts.item_size = size; + dopts.alignment = alignment; + + imalloc(&sopts, &dopts); + return ret; } #endif @@ -1865,9 +2092,29 @@ void JEMALLOC_NOTHROW * JEMALLOC_ATTR(malloc) je_valloc(size_t size) { - void *ret JEMALLOC_CC_SILENCE_INIT(NULL); - if (unlikely(imemalign(&ret, PAGE, size, 1) != 0)) - ret = NULL; + void *ret; + + static_opts_t sopts; + dynamic_opts_t dopts; + + static_opts_init(&sopts); + dynamic_opts_init(&dopts); + + sopts.bump_empty_alloc = true; + sopts.null_out_result_on_error = true; + sopts.min_alignment = PAGE; + sopts.oom_string = + ": Error allocating aligned memory: out of memory\n"; + sopts.invalid_alignment_string = + ": Error allocating aligned memory: invalid alignment\n"; + + dopts.result = &ret; + dopts.num_items = 1; + dopts.item_size = size; + dopts.alignment = PAGE; + + imalloc(&sopts, &dopts); + return (ret); } #endif @@ -1930,183 +2177,49 @@ int __posix_memalign(void** r, size_t a, size_t s) * Begin non-standard functions. */ -JEMALLOC_ALWAYS_INLINE_C bool -imallocx_flags_decode(tsd_t *tsd, size_t size, int flags, size_t *usize, - size_t *alignment, bool *zero, tcache_t **tcache, arena_t **arena) -{ - if ((flags & MALLOCX_LG_ALIGN_MASK) == 0) { - *alignment = 0; - *usize = s2u(size); - } else { - *alignment = MALLOCX_ALIGN_GET_SPECIFIED(flags); - *usize = sa2u(size, *alignment); - } - if (unlikely(*usize == 0 || *usize > LARGE_MAXCLASS)) - return (true); - *zero = MALLOCX_ZERO_GET(flags); - if ((flags & MALLOCX_TCACHE_MASK) != 0) { - if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) - *tcache = NULL; - else - *tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags)); - } else - *tcache = tcache_get(tsd, true); - if ((flags & MALLOCX_ARENA_MASK) != 0) { - unsigned arena_ind = MALLOCX_ARENA_GET(flags); - *arena = arena_get(tsd_tsdn(tsd), arena_ind, true); - if (unlikely(*arena == NULL)) - return (true); - } else - *arena = NULL; - return (false); -} - -JEMALLOC_ALWAYS_INLINE_C void * -imallocx_flags(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, - tcache_t *tcache, arena_t *arena, bool slow_path) -{ - szind_t ind; - - if (unlikely(alignment != 0)) - return (ipalloct(tsdn, usize, alignment, zero, tcache, arena)); - ind = size2index(usize); - assert(ind < NSIZES); - return (iallocztm(tsdn, usize, ind, zero, tcache, false, arena, - slow_path)); -} - -static void * -imallocx_prof_sample(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, - tcache_t *tcache, arena_t *arena, bool slow_path) -{ - void *p; - - if (usize <= SMALL_MAXCLASS) { - assert(((alignment == 0) ? s2u(LARGE_MINCLASS) : - sa2u(LARGE_MINCLASS, alignment)) == LARGE_MINCLASS); - p = imallocx_flags(tsdn, LARGE_MINCLASS, alignment, zero, - tcache, arena, slow_path); - if (p == NULL) - return (NULL); - arena_prof_promote(tsdn, iealloc(tsdn, p), p, usize); - } else - p = imallocx_flags(tsdn, usize, alignment, zero, tcache, arena, - slow_path); - - return (p); -} - -JEMALLOC_ALWAYS_INLINE_C void * -imallocx_prof(tsd_t *tsd, size_t size, int flags, size_t *usize, bool slow_path) -{ - void *p; - size_t alignment; - bool zero; - tcache_t *tcache; - arena_t *arena; - prof_tctx_t *tctx; - - if (unlikely(imallocx_flags_decode(tsd, size, flags, usize, &alignment, - &zero, &tcache, &arena))) - return (NULL); - tctx = prof_alloc_prep(tsd, *usize, prof_active_get_unlocked(), true); - if (likely((uintptr_t)tctx == (uintptr_t)1U)) { - p = imallocx_flags(tsd_tsdn(tsd), *usize, alignment, zero, - tcache, arena, slow_path); - } else if ((uintptr_t)tctx > (uintptr_t)1U) { - p = imallocx_prof_sample(tsd_tsdn(tsd), *usize, alignment, zero, - tcache, arena, slow_path); - } else - p = NULL; - if (unlikely(p == NULL)) { - prof_alloc_rollback(tsd, tctx, true); - return (NULL); - } - prof_malloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, *usize, tctx); - - assert(alignment == 0 || ((uintptr_t)p & (alignment - 1)) == ZU(0)); - return (p); -} - -JEMALLOC_ALWAYS_INLINE_C void * -imallocx_no_prof(tsd_t *tsd, size_t size, int flags, size_t *usize, - bool slow_path) -{ - void *p; - size_t alignment; - bool zero; - tcache_t *tcache; - arena_t *arena; - - if (unlikely(imallocx_flags_decode(tsd, size, flags, usize, &alignment, - &zero, &tcache, &arena))) - return (NULL); - p = imallocx_flags(tsd_tsdn(tsd), *usize, alignment, zero, tcache, - arena, slow_path); - assert(alignment == 0 || ((uintptr_t)p & (alignment - 1)) == ZU(0)); - return (p); -} - -/* This function guarantees that *tsdn is non-NULL on success. */ -JEMALLOC_ALWAYS_INLINE_C void * -imallocx_body(size_t size, int flags, tsdn_t **tsdn, size_t *usize, - bool slow_path) -{ - tsd_t *tsd; - - if (slow_path && unlikely(malloc_init())) { - *tsdn = NULL; - return (NULL); - } - - tsd = tsd_fetch(); - *tsdn = tsd_tsdn(tsd); - witness_assert_lockless(tsd_tsdn(tsd)); - - if (likely(flags == 0)) { - szind_t ind = size2index(size); - if (unlikely(ind >= NSIZES)) - return (NULL); - if (config_stats || (config_prof && opt_prof)) { - *usize = index2size(ind); - assert(*usize > 0 && *usize <= LARGE_MAXCLASS); - } - - if (config_prof && opt_prof) { - return (ialloc_prof(tsd, *usize, ind, false, - slow_path)); - } - - return (ialloc(tsd, size, ind, false, slow_path)); - } - - if (config_prof && opt_prof) - return (imallocx_prof(tsd, size, flags, usize, slow_path)); - - return (imallocx_no_prof(tsd, size, flags, usize, slow_path)); -} - JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN void JEMALLOC_NOTHROW * JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1) je_mallocx(size_t size, int flags) { - tsdn_t *tsdn; - void *p; - size_t usize; + void *ret; + static_opts_t sopts; + dynamic_opts_t dopts; + + static_opts_init(&sopts); + dynamic_opts_init(&dopts); + + sopts.assert_nonempty_alloc = true; + sopts.null_out_result_on_error = true; + sopts.oom_string = ": Error in mallocx(): out of memory\n"; + + dopts.result = &ret; + dopts.num_items = 1; + dopts.item_size = size; + if (unlikely(flags != 0)) { + if ((flags & MALLOCX_LG_ALIGN_MASK) != 0) { + dopts.alignment = MALLOCX_ALIGN_GET_SPECIFIED(flags); + } - assert(size != 0); + dopts.zero = MALLOCX_ZERO_GET(flags); - if (likely(!malloc_slow)) { - p = imallocx_body(size, flags, &tsdn, &usize, false); - ialloc_post_check(p, tsdn, usize, "mallocx", false, false); - } else { - p = imallocx_body(size, flags, &tsdn, &usize, true); - ialloc_post_check(p, tsdn, usize, "mallocx", false, true); - UTRACE(0, size, p); + if ((flags & MALLOCX_TCACHE_MASK) != 0) { + if ((flags & MALLOCX_TCACHE_MASK) + == MALLOCX_TCACHE_NONE) { + dopts.tcache_ind = TCACHE_IND_NONE; + } else { + dopts.tcache_ind = MALLOCX_TCACHE_GET(flags); + } + } else { + dopts.tcache_ind = TCACHE_IND_AUTOMATIC; + } + + if ((flags & MALLOCX_ARENA_MASK) != 0) + dopts.arena_ind = MALLOCX_ARENA_GET(flags); } - return (p); + imalloc(&sopts, &dopts); + return ret; } static void * -- GitLab From c4c2592c834d8a37beb0a0d53842095160cbf9ee Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 15 Jan 2017 16:56:30 -0800 Subject: [PATCH 239/544] Update brace style. Add braces around single-line blocks, and remove line breaks before function-opening braces. This resolves #537. --- include/jemalloc/internal/arena_inlines_a.h | 27 +- include/jemalloc/internal/arena_inlines_b.h | 59 +- include/jemalloc/internal/assert.h | 3 +- include/jemalloc/internal/atomic_inlines.h | 180 ++---- include/jemalloc/internal/base_inlines.h | 3 +- include/jemalloc/internal/bitmap_inlines.h | 24 +- include/jemalloc/internal/extent_inlines.h | 111 ++-- include/jemalloc/internal/hash_inlines.h | 30 +- .../jemalloc/internal/jemalloc_internal.h.in | 172 +++--- .../internal/jemalloc_internal_decls.h | 3 +- include/jemalloc/internal/mutex_inlines.h | 18 +- include/jemalloc/internal/ph.h | 50 +- include/jemalloc/internal/prng_inlines.h | 27 +- include/jemalloc/internal/prof_inlines.h | 59 +- include/jemalloc/internal/qr.h | 6 +- include/jemalloc/internal/rb.h | 3 +- include/jemalloc/internal/rtree_inlines.h | 99 ++- include/jemalloc/internal/spin_inlines.h | 12 +- include/jemalloc/internal/tcache_inlines.h | 90 +-- include/jemalloc/internal/ticker_inlines.h | 15 +- include/jemalloc/internal/tsd_inlines.h | 42 +- include/jemalloc/internal/tsd_types.h | 161 +++-- include/jemalloc/internal/util_inlines.h | 48 +- include/jemalloc/internal/util_types.h | 3 +- include/jemalloc/internal/witness_inlines.h | 75 ++- include/msvc_compat/strings.h | 20 +- .../vc2015/test_threads/test_threads.cpp | 3 +- .../vc2015/test_threads/test_threads_main.cpp | 3 +- src/arena.c | 516 ++++++++-------- src/base.c | 99 ++- src/bitmap.c | 30 +- src/ckh.c | 101 ++-- src/ctl.c | 344 +++++------ src/extent.c | 375 ++++++------ src/extent_dss.c | 68 ++- src/extent_mmap.c | 22 +- src/jemalloc.c | 497 +++++++-------- src/jemalloc_cpp.cpp | 33 +- src/large.c | 87 ++- src/mutex.c | 40 +- src/nstime.c | 57 +- src/pages.c | 85 +-- src/prof.c | 568 +++++++++--------- src/rtree.c | 70 +-- src/stats.c | 45 +- src/tcache.c | 120 ++-- src/tsd.c | 42 +- src/util.c | 96 +-- src/witness.c | 27 +- src/zone.c | 96 ++- test/include/test/SFMT.h | 34 +- test/include/test/btalloc.h | 7 +- test/include/test/extent_hooks.h | 51 +- test/include/test/jemalloc_test.h.in | 3 +- test/include/test/math.h | 50 +- test/include/test/mq.h | 27 +- test/include/test/test.h | 3 +- test/integration/MALLOCX_ARENA.c | 12 +- test/integration/aligned_alloc.c | 21 +- test/integration/allocated.c | 24 +- test/integration/cpp/basic.cpp | 6 +- test/integration/extent.c | 18 +- test/integration/mallocx.c | 42 +- test/integration/overflow.c | 6 +- test/integration/posix_memalign.c | 21 +- test/integration/rallocx.c | 33 +- test/integration/sdallocx.c | 15 +- test/integration/thread_arena.c | 9 +- test/integration/thread_tcache_enabled.c | 12 +- test/integration/xallocx.c | 63 +- test/src/btalloc.c | 3 +- test/src/mq.c | 3 +- test/src/mtx.c | 19 +- test/src/test.c | 30 +- test/src/thd.c | 18 +- test/src/timer.c | 18 +- test/stress/microbench.c | 57 +- test/unit/SFMT.c | 15 +- test/unit/a0.c | 6 +- test/unit/arena_reset.c | 69 +-- test/unit/atomic.c | 18 +- test/unit/base.c | 12 +- test/unit/bitmap.c | 51 +- test/unit/ckh.c | 18 +- test/unit/decay.c | 27 +- test/unit/extent_quantize.c | 12 +- test/unit/fork.c | 9 +- test/unit/hash.c | 27 +- test/unit/junk.c | 33 +- test/unit/mallctl.c | 75 +-- test/unit/math.c | 33 +- test/unit/mq.c | 21 +- test/unit/mtx.c | 18 +- test/unit/nstime.c | 36 +- test/unit/pack.c | 27 +- test/unit/pages.c | 6 +- test/unit/ph.c | 57 +- test/unit/prng.c | 51 +- test/unit/prof_accum.c | 18 +- test/unit/prof_active.c | 27 +- test/unit/prof_gdump.c | 9 +- test/unit/prof_idump.c | 9 +- test/unit/prof_reset.c | 36 +- test/unit/prof_tctx.c | 6 +- test/unit/prof_thread_name.c | 21 +- test/unit/ql.c | 42 +- test/unit/qr.c | 42 +- test/unit/rb.c | 84 +-- test/unit/rtree.c | 39 +- test/unit/size_classes.c | 15 +- test/unit/slab.c | 6 +- test/unit/smoothstep.c | 15 +- test/unit/stats.c | 30 +- test/unit/stats_print.c | 51 +- test/unit/ticker.c | 12 +- test/unit/tsd.c | 15 +- test/unit/util.c | 24 +- test/unit/witness.c | 40 +- test/unit/zero.c | 12 +- 119 files changed, 2971 insertions(+), 3572 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_a.h b/include/jemalloc/internal/arena_inlines_a.h index d241b8a1..3c2b9b0a 100644 --- a/include/jemalloc/internal/arena_inlines_a.h +++ b/include/jemalloc/internal/arena_inlines_a.h @@ -14,32 +14,27 @@ bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) JEMALLOC_INLINE unsigned -arena_ind_get(const arena_t *arena) -{ +arena_ind_get(const arena_t *arena) { return (base_ind_get(arena->base)); } JEMALLOC_INLINE void -arena_internal_add(arena_t *arena, size_t size) -{ +arena_internal_add(arena_t *arena, size_t size) { atomic_add_zu(&arena->stats.internal, size); } JEMALLOC_INLINE void -arena_internal_sub(arena_t *arena, size_t size) -{ +arena_internal_sub(arena_t *arena, size_t size) { atomic_sub_zu(&arena->stats.internal, size); } JEMALLOC_INLINE size_t -arena_internal_get(arena_t *arena) -{ +arena_internal_get(arena_t *arena) { return (atomic_read_zu(&arena->stats.internal)); } JEMALLOC_INLINE bool -arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes) -{ +arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes) { cassert(config_prof); assert(prof_interval != 0); @@ -52,22 +47,22 @@ arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes) } JEMALLOC_INLINE bool -arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes) -{ +arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes) { cassert(config_prof); - if (likely(prof_interval == 0)) + if (likely(prof_interval == 0)) { return (false); + } return (arena_prof_accum_impl(arena, accumbytes)); } JEMALLOC_INLINE bool -arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) -{ +arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) { cassert(config_prof); - if (likely(prof_interval == 0)) + if (likely(prof_interval == 0)) { return (false); + } { bool ret; diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 94614668..5772781d 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -23,39 +23,37 @@ void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) JEMALLOC_INLINE szind_t -arena_bin_index(arena_t *arena, arena_bin_t *bin) -{ +arena_bin_index(arena_t *arena, arena_bin_t *bin) { szind_t binind = (szind_t)(bin - arena->bins); assert(binind < NBINS); return (binind); } JEMALLOC_INLINE prof_tctx_t * -arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) -{ +arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { cassert(config_prof); assert(ptr != NULL); - if (unlikely(!extent_slab_get(extent))) + if (unlikely(!extent_slab_get(extent))) { return (large_prof_tctx_get(tsdn, extent)); + } return ((prof_tctx_t *)(uintptr_t)1U); } JEMALLOC_INLINE void arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize, prof_tctx_t *tctx) -{ + size_t usize, prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); - if (unlikely(!extent_slab_get(extent))) + if (unlikely(!extent_slab_get(extent))) { large_prof_tctx_set(tsdn, extent, tctx); + } } JEMALLOC_INLINE void arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, - prof_tctx_t *tctx) -{ + prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); assert(!extent_slab_get(extent)); @@ -64,24 +62,25 @@ arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, } JEMALLOC_ALWAYS_INLINE void -arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) -{ +arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) { tsd_t *tsd; ticker_t *decay_ticker; - if (unlikely(tsdn_null(tsdn))) + if (unlikely(tsdn_null(tsdn))) { return; + } tsd = tsdn_tsd(tsdn); decay_ticker = decay_ticker_get(tsd, arena_ind_get(arena)); - if (unlikely(decay_ticker == NULL)) + if (unlikely(decay_ticker == NULL)) { return; - if (unlikely(ticker_ticks(decay_ticker, nticks))) + } + if (unlikely(ticker_ticks(decay_ticker, nticks))) { arena_purge(tsdn, arena, false); + } } JEMALLOC_ALWAYS_INLINE void -arena_decay_tick(tsdn_t *tsdn, arena_t *arena) -{ +arena_decay_tick(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_assert_not_owner(tsdn, &arena->lock); arena_decay_ticks(tsdn, arena, 1); @@ -89,8 +88,7 @@ arena_decay_tick(tsdn_t *tsdn, arena_t *arena) JEMALLOC_ALWAYS_INLINE void * arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, - tcache_t *tcache, bool slow_path) -{ + tcache_t *tcache, bool slow_path) { assert(!tsdn_null(tsdn) || tcache == NULL); assert(size != 0); @@ -111,31 +109,29 @@ arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, } JEMALLOC_ALWAYS_INLINE arena_t * -arena_aalloc(tsdn_t *tsdn, const void *ptr) -{ +arena_aalloc(tsdn_t *tsdn, const void *ptr) { return (extent_arena_get(iealloc(tsdn, ptr))); } /* Return the size of the allocation pointed to by ptr. */ JEMALLOC_ALWAYS_INLINE size_t -arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) -{ +arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { size_t ret; assert(ptr != NULL); - if (likely(extent_slab_get(extent))) + if (likely(extent_slab_get(extent))) { ret = index2size(extent_slab_data_get_const(extent)->binind); - else + } else { ret = large_salloc(tsdn, extent); + } return (ret); } JEMALLOC_ALWAYS_INLINE void arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, - bool slow_path) -{ + bool slow_path) { assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); @@ -160,15 +156,15 @@ arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, usize, slow_path); } - } else + } else { large_dalloc(tsdn, extent); + } } } JEMALLOC_ALWAYS_INLINE void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, - tcache_t *tcache, bool slow_path) -{ + tcache_t *tcache, bool slow_path) { assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); @@ -192,8 +188,9 @@ arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, size, slow_path); } - } else + } else { large_dalloc(tsdn, extent); + } } } diff --git a/include/jemalloc/internal/assert.h b/include/jemalloc/internal/assert.h index 6f8f7eb9..5da0ef42 100644 --- a/include/jemalloc/internal/assert.h +++ b/include/jemalloc/internal/assert.h @@ -37,8 +37,9 @@ #ifndef assert_not_implemented #define assert_not_implemented(e) do { \ - if (unlikely(config_debug && !(e))) \ + if (unlikely(config_debug && !(e))) { \ not_implemented(); \ + } \ } while (0) #endif diff --git a/include/jemalloc/internal/atomic_inlines.h b/include/jemalloc/internal/atomic_inlines.h index 89d1b354..790a08a2 100644 --- a/include/jemalloc/internal/atomic_inlines.h +++ b/include/jemalloc/internal/atomic_inlines.h @@ -53,8 +53,7 @@ void atomic_write_u(unsigned *p, unsigned x); #if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) # if (defined(__amd64__) || defined(__x86_64__)) JEMALLOC_INLINE uint64_t -atomic_add_u64(uint64_t *p, uint64_t x) -{ +atomic_add_u64(uint64_t *p, uint64_t x) { uint64_t t = x; asm volatile ( @@ -67,8 +66,7 @@ atomic_add_u64(uint64_t *p, uint64_t x) } JEMALLOC_INLINE uint64_t -atomic_sub_u64(uint64_t *p, uint64_t x) -{ +atomic_sub_u64(uint64_t *p, uint64_t x) { uint64_t t; x = (uint64_t)(-(int64_t)x); @@ -83,8 +81,7 @@ atomic_sub_u64(uint64_t *p, uint64_t x) } JEMALLOC_INLINE bool -atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) -{ +atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { uint8_t success; asm volatile ( @@ -99,8 +96,7 @@ atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) } JEMALLOC_INLINE void -atomic_write_u64(uint64_t *p, uint64_t x) -{ +atomic_write_u64(uint64_t *p, uint64_t x) { asm volatile ( "xchgq %1, %0;" /* Lock is implied by xchgq. */ : "=m" (*p), "+r" (x) /* Outputs. */ @@ -110,36 +106,31 @@ atomic_write_u64(uint64_t *p, uint64_t x) } # elif (defined(JEMALLOC_C11ATOMICS)) JEMALLOC_INLINE uint64_t -atomic_add_u64(uint64_t *p, uint64_t x) -{ +atomic_add_u64(uint64_t *p, uint64_t x) { volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; return (atomic_fetch_add(a, x) + x); } JEMALLOC_INLINE uint64_t -atomic_sub_u64(uint64_t *p, uint64_t x) -{ +atomic_sub_u64(uint64_t *p, uint64_t x) { volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; return (atomic_fetch_sub(a, x) - x); } JEMALLOC_INLINE bool -atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) -{ +atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; return (!atomic_compare_exchange_strong(a, &c, s)); } JEMALLOC_INLINE void -atomic_write_u64(uint64_t *p, uint64_t x) -{ +atomic_write_u64(uint64_t *p, uint64_t x) { volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; atomic_store(a, x); } # elif (defined(JEMALLOC_ATOMIC9)) JEMALLOC_INLINE uint64_t -atomic_add_u64(uint64_t *p, uint64_t x) -{ +atomic_add_u64(uint64_t *p, uint64_t x) { /* * atomic_fetchadd_64() doesn't exist, but we only ever use this * function on LP64 systems, so atomic_fetchadd_long() will do. @@ -150,50 +141,43 @@ atomic_add_u64(uint64_t *p, uint64_t x) } JEMALLOC_INLINE uint64_t -atomic_sub_u64(uint64_t *p, uint64_t x) -{ +atomic_sub_u64(uint64_t *p, uint64_t x) { assert(sizeof(uint64_t) == sizeof(unsigned long)); return (atomic_fetchadd_long(p, (unsigned long)(-(long)x)) - x); } JEMALLOC_INLINE bool -atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) -{ +atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { assert(sizeof(uint64_t) == sizeof(unsigned long)); return (!atomic_cmpset_long(p, (unsigned long)c, (unsigned long)s)); } JEMALLOC_INLINE void -atomic_write_u64(uint64_t *p, uint64_t x) -{ +atomic_write_u64(uint64_t *p, uint64_t x) { assert(sizeof(uint64_t) == sizeof(unsigned long)); atomic_store_rel_long(p, x); } # elif (defined(JEMALLOC_OSATOMIC)) JEMALLOC_INLINE uint64_t -atomic_add_u64(uint64_t *p, uint64_t x) -{ +atomic_add_u64(uint64_t *p, uint64_t x) { return (OSAtomicAdd64((int64_t)x, (int64_t *)p)); } JEMALLOC_INLINE uint64_t -atomic_sub_u64(uint64_t *p, uint64_t x) -{ +atomic_sub_u64(uint64_t *p, uint64_t x) { return (OSAtomicAdd64(-((int64_t)x), (int64_t *)p)); } JEMALLOC_INLINE bool -atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) -{ +atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { return (!OSAtomicCompareAndSwap64(c, s, (int64_t *)p)); } JEMALLOC_INLINE void -atomic_write_u64(uint64_t *p, uint64_t x) -{ +atomic_write_u64(uint64_t *p, uint64_t x) { uint64_t o; /*The documented OSAtomic*() API does not expose an atomic exchange. */ @@ -203,20 +187,17 @@ atomic_write_u64(uint64_t *p, uint64_t x) } # elif (defined(_MSC_VER)) JEMALLOC_INLINE uint64_t -atomic_add_u64(uint64_t *p, uint64_t x) -{ +atomic_add_u64(uint64_t *p, uint64_t x) { return (InterlockedExchangeAdd64(p, x) + x); } JEMALLOC_INLINE uint64_t -atomic_sub_u64(uint64_t *p, uint64_t x) -{ +atomic_sub_u64(uint64_t *p, uint64_t x) { return (InterlockedExchangeAdd64(p, -((int64_t)x)) - x); } JEMALLOC_INLINE bool -atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) -{ +atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { uint64_t o; o = InterlockedCompareExchange64(p, s, c); @@ -224,33 +205,28 @@ atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) } JEMALLOC_INLINE void -atomic_write_u64(uint64_t *p, uint64_t x) -{ +atomic_write_u64(uint64_t *p, uint64_t x) { InterlockedExchange64(p, x); } # elif (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || \ defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8)) JEMALLOC_INLINE uint64_t -atomic_add_u64(uint64_t *p, uint64_t x) -{ +atomic_add_u64(uint64_t *p, uint64_t x) { return (__sync_add_and_fetch(p, x)); } JEMALLOC_INLINE uint64_t -atomic_sub_u64(uint64_t *p, uint64_t x) -{ +atomic_sub_u64(uint64_t *p, uint64_t x) { return (__sync_sub_and_fetch(p, x)); } JEMALLOC_INLINE bool -atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) -{ +atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { return (!__sync_bool_compare_and_swap(p, c, s)); } JEMALLOC_INLINE void -atomic_write_u64(uint64_t *p, uint64_t x) -{ +atomic_write_u64(uint64_t *p, uint64_t x) { __sync_lock_test_and_set(p, x); } # else @@ -262,8 +238,7 @@ atomic_write_u64(uint64_t *p, uint64_t x) /* 32-bit operations. */ #if (defined(__i386__) || defined(__amd64__) || defined(__x86_64__)) JEMALLOC_INLINE uint32_t -atomic_add_u32(uint32_t *p, uint32_t x) -{ +atomic_add_u32(uint32_t *p, uint32_t x) { uint32_t t = x; asm volatile ( @@ -276,8 +251,7 @@ atomic_add_u32(uint32_t *p, uint32_t x) } JEMALLOC_INLINE uint32_t -atomic_sub_u32(uint32_t *p, uint32_t x) -{ +atomic_sub_u32(uint32_t *p, uint32_t x) { uint32_t t; x = (uint32_t)(-(int32_t)x); @@ -292,8 +266,7 @@ atomic_sub_u32(uint32_t *p, uint32_t x) } JEMALLOC_INLINE bool -atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) -{ +atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { uint8_t success; asm volatile ( @@ -308,8 +281,7 @@ atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) } JEMALLOC_INLINE void -atomic_write_u32(uint32_t *p, uint32_t x) -{ +atomic_write_u32(uint32_t *p, uint32_t x) { asm volatile ( "xchgl %1, %0;" /* Lock is implied by xchgl. */ : "=m" (*p), "+r" (x) /* Outputs. */ @@ -319,78 +291,66 @@ atomic_write_u32(uint32_t *p, uint32_t x) } # elif (defined(JEMALLOC_C11ATOMICS)) JEMALLOC_INLINE uint32_t -atomic_add_u32(uint32_t *p, uint32_t x) -{ +atomic_add_u32(uint32_t *p, uint32_t x) { volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; return (atomic_fetch_add(a, x) + x); } JEMALLOC_INLINE uint32_t -atomic_sub_u32(uint32_t *p, uint32_t x) -{ +atomic_sub_u32(uint32_t *p, uint32_t x) { volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; return (atomic_fetch_sub(a, x) - x); } JEMALLOC_INLINE bool -atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) -{ +atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; return (!atomic_compare_exchange_strong(a, &c, s)); } JEMALLOC_INLINE void -atomic_write_u32(uint32_t *p, uint32_t x) -{ +atomic_write_u32(uint32_t *p, uint32_t x) { volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; atomic_store(a, x); } #elif (defined(JEMALLOC_ATOMIC9)) JEMALLOC_INLINE uint32_t -atomic_add_u32(uint32_t *p, uint32_t x) -{ +atomic_add_u32(uint32_t *p, uint32_t x) { return (atomic_fetchadd_32(p, x) + x); } JEMALLOC_INLINE uint32_t -atomic_sub_u32(uint32_t *p, uint32_t x) -{ +atomic_sub_u32(uint32_t *p, uint32_t x) { return (atomic_fetchadd_32(p, (uint32_t)(-(int32_t)x)) - x); } JEMALLOC_INLINE bool -atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) -{ +atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { return (!atomic_cmpset_32(p, c, s)); } JEMALLOC_INLINE void -atomic_write_u32(uint32_t *p, uint32_t x) -{ +atomic_write_u32(uint32_t *p, uint32_t x) { atomic_store_rel_32(p, x); } #elif (defined(JEMALLOC_OSATOMIC)) JEMALLOC_INLINE uint32_t -atomic_add_u32(uint32_t *p, uint32_t x) -{ +atomic_add_u32(uint32_t *p, uint32_t x) { return (OSAtomicAdd32((int32_t)x, (int32_t *)p)); } JEMALLOC_INLINE uint32_t -atomic_sub_u32(uint32_t *p, uint32_t x) -{ +atomic_sub_u32(uint32_t *p, uint32_t x) { return (OSAtomicAdd32(-((int32_t)x), (int32_t *)p)); } JEMALLOC_INLINE bool -atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) -{ +atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { return (!OSAtomicCompareAndSwap32(c, s, (int32_t *)p)); } JEMALLOC_INLINE void -atomic_write_u32(uint32_t *p, uint32_t x) -{ +atomic_write_u32(uint32_t *p, uint32_t x) { uint32_t o; /*The documented OSAtomic*() API does not expose an atomic exchange. */ @@ -400,20 +360,17 @@ atomic_write_u32(uint32_t *p, uint32_t x) } #elif (defined(_MSC_VER)) JEMALLOC_INLINE uint32_t -atomic_add_u32(uint32_t *p, uint32_t x) -{ +atomic_add_u32(uint32_t *p, uint32_t x) { return (InterlockedExchangeAdd(p, x) + x); } JEMALLOC_INLINE uint32_t -atomic_sub_u32(uint32_t *p, uint32_t x) -{ +atomic_sub_u32(uint32_t *p, uint32_t x) { return (InterlockedExchangeAdd(p, -((int32_t)x)) - x); } JEMALLOC_INLINE bool -atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) -{ +atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { uint32_t o; o = InterlockedCompareExchange(p, s, c); @@ -421,33 +378,28 @@ atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) } JEMALLOC_INLINE void -atomic_write_u32(uint32_t *p, uint32_t x) -{ +atomic_write_u32(uint32_t *p, uint32_t x) { InterlockedExchange(p, x); } #elif (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || \ defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4)) JEMALLOC_INLINE uint32_t -atomic_add_u32(uint32_t *p, uint32_t x) -{ +atomic_add_u32(uint32_t *p, uint32_t x) { return (__sync_add_and_fetch(p, x)); } JEMALLOC_INLINE uint32_t -atomic_sub_u32(uint32_t *p, uint32_t x) -{ +atomic_sub_u32(uint32_t *p, uint32_t x) { return (__sync_sub_and_fetch(p, x)); } JEMALLOC_INLINE bool -atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) -{ +atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { return (!__sync_bool_compare_and_swap(p, c, s)); } JEMALLOC_INLINE void -atomic_write_u32(uint32_t *p, uint32_t x) -{ +atomic_write_u32(uint32_t *p, uint32_t x) { __sync_lock_test_and_set(p, x); } #else @@ -457,8 +409,7 @@ atomic_write_u32(uint32_t *p, uint32_t x) /******************************************************************************/ /* Pointer operations. */ JEMALLOC_INLINE void * -atomic_add_p(void **p, void *x) -{ +atomic_add_p(void **p, void *x) { #if (LG_SIZEOF_PTR == 3) return ((void *)atomic_add_u64((uint64_t *)p, (uint64_t)x)); #elif (LG_SIZEOF_PTR == 2) @@ -467,8 +418,7 @@ atomic_add_p(void **p, void *x) } JEMALLOC_INLINE void * -atomic_sub_p(void **p, void *x) -{ +atomic_sub_p(void **p, void *x) { #if (LG_SIZEOF_PTR == 3) return ((void *)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x))); #elif (LG_SIZEOF_PTR == 2) @@ -477,8 +427,7 @@ atomic_sub_p(void **p, void *x) } JEMALLOC_INLINE bool -atomic_cas_p(void **p, void *c, void *s) -{ +atomic_cas_p(void **p, void *c, void *s) { #if (LG_SIZEOF_PTR == 3) return (atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); #elif (LG_SIZEOF_PTR == 2) @@ -487,8 +436,7 @@ atomic_cas_p(void **p, void *c, void *s) } JEMALLOC_INLINE void -atomic_write_p(void **p, const void *x) -{ +atomic_write_p(void **p, const void *x) { #if (LG_SIZEOF_PTR == 3) atomic_write_u64((uint64_t *)p, (uint64_t)x); #elif (LG_SIZEOF_PTR == 2) @@ -499,8 +447,7 @@ atomic_write_p(void **p, const void *x) /******************************************************************************/ /* size_t operations. */ JEMALLOC_INLINE size_t -atomic_add_zu(size_t *p, size_t x) -{ +atomic_add_zu(size_t *p, size_t x) { #if (LG_SIZEOF_PTR == 3) return ((size_t)atomic_add_u64((uint64_t *)p, (uint64_t)x)); #elif (LG_SIZEOF_PTR == 2) @@ -509,8 +456,7 @@ atomic_add_zu(size_t *p, size_t x) } JEMALLOC_INLINE size_t -atomic_sub_zu(size_t *p, size_t x) -{ +atomic_sub_zu(size_t *p, size_t x) { #if (LG_SIZEOF_PTR == 3) return ((size_t)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x))); #elif (LG_SIZEOF_PTR == 2) @@ -519,8 +465,7 @@ atomic_sub_zu(size_t *p, size_t x) } JEMALLOC_INLINE bool -atomic_cas_zu(size_t *p, size_t c, size_t s) -{ +atomic_cas_zu(size_t *p, size_t c, size_t s) { #if (LG_SIZEOF_PTR == 3) return (atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); #elif (LG_SIZEOF_PTR == 2) @@ -529,8 +474,7 @@ atomic_cas_zu(size_t *p, size_t c, size_t s) } JEMALLOC_INLINE void -atomic_write_zu(size_t *p, size_t x) -{ +atomic_write_zu(size_t *p, size_t x) { #if (LG_SIZEOF_PTR == 3) atomic_write_u64((uint64_t *)p, (uint64_t)x); #elif (LG_SIZEOF_PTR == 2) @@ -541,8 +485,7 @@ atomic_write_zu(size_t *p, size_t x) /******************************************************************************/ /* unsigned operations. */ JEMALLOC_INLINE unsigned -atomic_add_u(unsigned *p, unsigned x) -{ +atomic_add_u(unsigned *p, unsigned x) { #if (LG_SIZEOF_INT == 3) return ((unsigned)atomic_add_u64((uint64_t *)p, (uint64_t)x)); #elif (LG_SIZEOF_INT == 2) @@ -551,8 +494,7 @@ atomic_add_u(unsigned *p, unsigned x) } JEMALLOC_INLINE unsigned -atomic_sub_u(unsigned *p, unsigned x) -{ +atomic_sub_u(unsigned *p, unsigned x) { #if (LG_SIZEOF_INT == 3) return ((unsigned)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x))); @@ -563,8 +505,7 @@ atomic_sub_u(unsigned *p, unsigned x) } JEMALLOC_INLINE bool -atomic_cas_u(unsigned *p, unsigned c, unsigned s) -{ +atomic_cas_u(unsigned *p, unsigned c, unsigned s) { #if (LG_SIZEOF_INT == 3) return (atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); #elif (LG_SIZEOF_INT == 2) @@ -573,8 +514,7 @@ atomic_cas_u(unsigned *p, unsigned c, unsigned s) } JEMALLOC_INLINE void -atomic_write_u(unsigned *p, unsigned x) -{ +atomic_write_u(unsigned *p, unsigned x) { #if (LG_SIZEOF_INT == 3) atomic_write_u64((uint64_t *)p, (uint64_t)x); #elif (LG_SIZEOF_INT == 2) diff --git a/include/jemalloc/internal/base_inlines.h b/include/jemalloc/internal/base_inlines.h index 63547d65..94fb1a95 100644 --- a/include/jemalloc/internal/base_inlines.h +++ b/include/jemalloc/internal/base_inlines.h @@ -7,8 +7,7 @@ unsigned base_ind_get(const base_t *base); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BASE_C_)) JEMALLOC_INLINE unsigned -base_ind_get(const base_t *base) -{ +base_ind_get(const base_t *base) { return (base->ind); } #endif diff --git a/include/jemalloc/internal/bitmap_inlines.h b/include/jemalloc/internal/bitmap_inlines.h index 5400f9d1..1a2411df 100644 --- a/include/jemalloc/internal/bitmap_inlines.h +++ b/include/jemalloc/internal/bitmap_inlines.h @@ -11,8 +11,7 @@ void bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BITMAP_C_)) JEMALLOC_INLINE bool -bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) -{ +bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) { #ifdef BITMAP_USE_TREE size_t rgoff = binfo->levels[binfo->nlevels].group_offset - 1; bitmap_t rg = bitmap[rgoff]; @@ -22,16 +21,16 @@ bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) size_t i; for (i = 0; i < binfo->ngroups; i++) { - if (bitmap[i] != 0) + if (bitmap[i] != 0) { return (false); + } } return (true); #endif } JEMALLOC_INLINE bool -bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) -{ +bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { size_t goff; bitmap_t g; @@ -42,8 +41,7 @@ bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) } JEMALLOC_INLINE void -bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) -{ +bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { size_t goff; bitmap_t *gp; bitmap_t g; @@ -69,8 +67,9 @@ bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); *gp = g; - if (g != 0) + if (g != 0) { break; + } } } #endif @@ -78,8 +77,7 @@ bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) /* sfu: set first unset. */ JEMALLOC_INLINE size_t -bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) -{ +bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) { size_t bit; bitmap_t g; unsigned i; @@ -109,8 +107,7 @@ bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) } JEMALLOC_INLINE void -bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) -{ +bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { size_t goff; bitmap_t *gp; bitmap_t g; @@ -140,8 +137,9 @@ bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) == 0); g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); *gp = g; - if (!propagate) + if (!propagate) { break; + } } } #endif /* BITMAP_USE_TREE */ diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index 87e0bcd0..274e69c6 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -43,8 +43,7 @@ int extent_snad_comp(const extent_t *a, const extent_t *b); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_)) JEMALLOC_INLINE extent_t * -extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent) -{ +extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent) { rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); @@ -53,132 +52,112 @@ extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent) } JEMALLOC_INLINE arena_t * -extent_arena_get(const extent_t *extent) -{ +extent_arena_get(const extent_t *extent) { return (extent->e_arena); } JEMALLOC_INLINE void * -extent_base_get(const extent_t *extent) -{ +extent_base_get(const extent_t *extent) { assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || !extent->e_slab); return (PAGE_ADDR2BASE(extent->e_addr)); } JEMALLOC_INLINE void * -extent_addr_get(const extent_t *extent) -{ +extent_addr_get(const extent_t *extent) { assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || !extent->e_slab); return (extent->e_addr); } JEMALLOC_INLINE size_t -extent_size_get(const extent_t *extent) -{ +extent_size_get(const extent_t *extent) { return (extent->e_size); } JEMALLOC_INLINE size_t -extent_usize_get(const extent_t *extent) -{ +extent_usize_get(const extent_t *extent) { assert(!extent->e_slab); return (extent->e_usize); } JEMALLOC_INLINE void * -extent_before_get(const extent_t *extent) -{ +extent_before_get(const extent_t *extent) { return ((void *)((uintptr_t)extent_base_get(extent) - PAGE)); } JEMALLOC_INLINE void * -extent_last_get(const extent_t *extent) -{ +extent_last_get(const extent_t *extent) { return ((void *)((uintptr_t)extent_base_get(extent) + extent_size_get(extent) - PAGE)); } JEMALLOC_INLINE void * -extent_past_get(const extent_t *extent) -{ +extent_past_get(const extent_t *extent) { return ((void *)((uintptr_t)extent_base_get(extent) + extent_size_get(extent))); } JEMALLOC_INLINE size_t -extent_sn_get(const extent_t *extent) -{ +extent_sn_get(const extent_t *extent) { return (extent->e_sn); } JEMALLOC_INLINE bool -extent_active_get(const extent_t *extent) -{ +extent_active_get(const extent_t *extent) { return (extent->e_active); } JEMALLOC_INLINE bool -extent_retained_get(const extent_t *extent) -{ +extent_retained_get(const extent_t *extent) { return (qr_next(extent, qr_link) == extent); } JEMALLOC_INLINE bool -extent_zeroed_get(const extent_t *extent) -{ +extent_zeroed_get(const extent_t *extent) { return (extent->e_zeroed); } JEMALLOC_INLINE bool -extent_committed_get(const extent_t *extent) -{ +extent_committed_get(const extent_t *extent) { return (extent->e_committed); } JEMALLOC_INLINE bool -extent_slab_get(const extent_t *extent) -{ +extent_slab_get(const extent_t *extent) { return (extent->e_slab); } JEMALLOC_INLINE arena_slab_data_t * -extent_slab_data_get(extent_t *extent) -{ +extent_slab_data_get(extent_t *extent) { assert(extent->e_slab); return (&extent->e_slab_data); } JEMALLOC_INLINE const arena_slab_data_t * -extent_slab_data_get_const(const extent_t *extent) -{ +extent_slab_data_get_const(const extent_t *extent) { assert(extent->e_slab); return (&extent->e_slab_data); } JEMALLOC_INLINE prof_tctx_t * -extent_prof_tctx_get(const extent_t *extent) -{ +extent_prof_tctx_get(const extent_t *extent) { return ((prof_tctx_t *)atomic_read_p( &((extent_t *)extent)->e_prof_tctx_pun)); } JEMALLOC_INLINE void -extent_arena_set(extent_t *extent, arena_t *arena) -{ +extent_arena_set(extent_t *extent, arena_t *arena) { extent->e_arena = arena; } JEMALLOC_INLINE void -extent_addr_set(extent_t *extent, void *addr) -{ +extent_addr_set(extent_t *extent, void *addr) { extent->e_addr = addr; } JEMALLOC_INLINE void -extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment) -{ +extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment) { assert(extent_base_get(extent) == extent_addr_get(extent)); if (alignment < PAGE) { @@ -197,58 +176,49 @@ extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment) } JEMALLOC_INLINE void -extent_size_set(extent_t *extent, size_t size) -{ +extent_size_set(extent_t *extent, size_t size) { extent->e_size = size; } JEMALLOC_INLINE void -extent_usize_set(extent_t *extent, size_t usize) -{ +extent_usize_set(extent_t *extent, size_t usize) { extent->e_usize = usize; } JEMALLOC_INLINE void -extent_sn_set(extent_t *extent, size_t sn) -{ +extent_sn_set(extent_t *extent, size_t sn) { extent->e_sn = sn; } JEMALLOC_INLINE void -extent_active_set(extent_t *extent, bool active) -{ +extent_active_set(extent_t *extent, bool active) { extent->e_active = active; } JEMALLOC_INLINE void -extent_zeroed_set(extent_t *extent, bool zeroed) -{ +extent_zeroed_set(extent_t *extent, bool zeroed) { extent->e_zeroed = zeroed; } JEMALLOC_INLINE void -extent_committed_set(extent_t *extent, bool committed) -{ +extent_committed_set(extent_t *extent, bool committed) { extent->e_committed = committed; } JEMALLOC_INLINE void -extent_slab_set(extent_t *extent, bool slab) -{ +extent_slab_set(extent_t *extent, bool slab) { extent->e_slab = slab; } JEMALLOC_INLINE void -extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) -{ +extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) { atomic_write_p(&extent->e_prof_tctx_pun, tctx); } JEMALLOC_INLINE void extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, size_t usize, size_t sn, bool active, bool zeroed, bool committed, - bool slab) -{ + bool slab) { assert(addr == PAGE_ADDR2BASE(addr) || !slab); extent_arena_set(extent, arena); @@ -260,26 +230,24 @@ extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, extent_zeroed_set(extent, zeroed); extent_committed_set(extent, committed); extent_slab_set(extent, slab); - if (config_prof) + if (config_prof) { extent_prof_tctx_set(extent, NULL); + } qr_new(extent, qr_link); } JEMALLOC_INLINE void -extent_ring_insert(extent_t *sentinel, extent_t *extent) -{ +extent_ring_insert(extent_t *sentinel, extent_t *extent) { qr_meld(sentinel, extent, extent_t, qr_link); } JEMALLOC_INLINE void -extent_ring_remove(extent_t *extent) -{ +extent_ring_remove(extent_t *extent) { qr_remove(extent, qr_link); } JEMALLOC_INLINE int -extent_sn_comp(const extent_t *a, const extent_t *b) -{ +extent_sn_comp(const extent_t *a, const extent_t *b) { size_t a_sn = extent_sn_get(a); size_t b_sn = extent_sn_get(b); @@ -287,8 +255,7 @@ extent_sn_comp(const extent_t *a, const extent_t *b) } JEMALLOC_INLINE int -extent_ad_comp(const extent_t *a, const extent_t *b) -{ +extent_ad_comp(const extent_t *a, const extent_t *b) { uintptr_t a_addr = (uintptr_t)extent_addr_get(a); uintptr_t b_addr = (uintptr_t)extent_addr_get(b); @@ -296,13 +263,13 @@ extent_ad_comp(const extent_t *a, const extent_t *b) } JEMALLOC_INLINE int -extent_snad_comp(const extent_t *a, const extent_t *b) -{ +extent_snad_comp(const extent_t *a, const extent_t *b) { int ret; ret = extent_sn_comp(a, b); - if (ret != 0) + if (ret != 0) { return (ret); + } ret = extent_ad_comp(a, b); return (ret); diff --git a/include/jemalloc/internal/hash_inlines.h b/include/jemalloc/internal/hash_inlines.h index 4bb78505..82ac1f42 100644 --- a/include/jemalloc/internal/hash_inlines.h +++ b/include/jemalloc/internal/hash_inlines.h @@ -21,20 +21,17 @@ void hash(const void *key, size_t len, const uint32_t seed, /******************************************************************************/ /* Internal implementation. */ JEMALLOC_INLINE uint32_t -hash_rotl_32(uint32_t x, int8_t r) -{ +hash_rotl_32(uint32_t x, int8_t r) { return ((x << r) | (x >> (32 - r))); } JEMALLOC_INLINE uint64_t -hash_rotl_64(uint64_t x, int8_t r) -{ +hash_rotl_64(uint64_t x, int8_t r) { return ((x << r) | (x >> (64 - r))); } JEMALLOC_INLINE uint32_t -hash_get_block_32(const uint32_t *p, int i) -{ +hash_get_block_32(const uint32_t *p, int i) { /* Handle unaligned read. */ if (unlikely((uintptr_t)p & (sizeof(uint32_t)-1)) != 0) { uint32_t ret; @@ -47,8 +44,7 @@ hash_get_block_32(const uint32_t *p, int i) } JEMALLOC_INLINE uint64_t -hash_get_block_64(const uint64_t *p, int i) -{ +hash_get_block_64(const uint64_t *p, int i) { /* Handle unaligned read. */ if (unlikely((uintptr_t)p & (sizeof(uint64_t)-1)) != 0) { uint64_t ret; @@ -61,8 +57,7 @@ hash_get_block_64(const uint64_t *p, int i) } JEMALLOC_INLINE uint32_t -hash_fmix_32(uint32_t h) -{ +hash_fmix_32(uint32_t h) { h ^= h >> 16; h *= 0x85ebca6b; h ^= h >> 13; @@ -73,8 +68,7 @@ hash_fmix_32(uint32_t h) } JEMALLOC_INLINE uint64_t -hash_fmix_64(uint64_t k) -{ +hash_fmix_64(uint64_t k) { k ^= k >> 33; k *= KQU(0xff51afd7ed558ccd); k ^= k >> 33; @@ -85,8 +79,7 @@ hash_fmix_64(uint64_t k) } JEMALLOC_INLINE uint32_t -hash_x86_32(const void *key, int len, uint32_t seed) -{ +hash_x86_32(const void *key, int len, uint32_t seed) { const uint8_t *data = (const uint8_t *) key; const int nblocks = len / 4; @@ -137,8 +130,7 @@ hash_x86_32(const void *key, int len, uint32_t seed) UNUSED JEMALLOC_INLINE void hash_x86_128(const void *key, const int len, uint32_t seed, - uint64_t r_out[2]) -{ + uint64_t r_out[2]) { const uint8_t * data = (const uint8_t *) key; const int nblocks = len / 16; @@ -239,8 +231,7 @@ hash_x86_128(const void *key, const int len, uint32_t seed, UNUSED JEMALLOC_INLINE void hash_x64_128(const void *key, const int len, const uint32_t seed, - uint64_t r_out[2]) -{ + uint64_t r_out[2]) { const uint8_t *data = (const uint8_t *) key; const int nblocks = len / 16; @@ -318,8 +309,7 @@ hash_x64_128(const void *key, const int len, const uint32_t seed, /******************************************************************************/ /* API. */ JEMALLOC_INLINE void -hash(const void *key, size_t len, const uint32_t seed, size_t r_hash[2]) -{ +hash(const void *key, size_t len, const uint32_t seed, size_t r_hash[2]) { assert(len <= INT_MAX); /* Unfortunate implementation limitation. */ #if (LG_SIZEOF_PTR == 3 && !defined(JEMALLOC_BIG_ENDIAN)) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index dc9df35f..c951fab4 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -550,10 +550,10 @@ ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) JEMALLOC_ALWAYS_INLINE pszind_t -psz2ind(size_t psz) -{ - if (unlikely(psz > LARGE_MAXCLASS)) +psz2ind(size_t psz) { + if (unlikely(psz > LARGE_MAXCLASS)) { return (NPSIZES); + } { pszind_t x = lg_floor((psz<<1)-1); pszind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_PAGE) ? 0 : x - @@ -573,10 +573,10 @@ psz2ind(size_t psz) } JEMALLOC_INLINE size_t -pind2sz_compute(pszind_t pind) -{ - if (unlikely(pind == NPSIZES)) +pind2sz_compute(pszind_t pind) { + if (unlikely(pind == NPSIZES)) { return (LARGE_MAXCLASS + PAGE); + } { size_t grp = pind >> LG_SIZE_CLASS_GROUP; size_t mod = pind & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); @@ -595,25 +595,23 @@ pind2sz_compute(pszind_t pind) } JEMALLOC_INLINE size_t -pind2sz_lookup(pszind_t pind) -{ +pind2sz_lookup(pszind_t pind) { size_t ret = (size_t)pind2sz_tab[pind]; assert(ret == pind2sz_compute(pind)); return (ret); } JEMALLOC_INLINE size_t -pind2sz(pszind_t pind) -{ +pind2sz(pszind_t pind) { assert(pind < NPSIZES+1); return (pind2sz_lookup(pind)); } JEMALLOC_INLINE size_t -psz2u(size_t psz) -{ - if (unlikely(psz > LARGE_MAXCLASS)) +psz2u(size_t psz) { + if (unlikely(psz > LARGE_MAXCLASS)) { return (LARGE_MAXCLASS + PAGE); + } { size_t x = lg_floor((psz<<1)-1); size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? @@ -626,10 +624,10 @@ psz2u(size_t psz) } JEMALLOC_INLINE szind_t -size2index_compute(size_t size) -{ - if (unlikely(size > LARGE_MAXCLASS)) +size2index_compute(size_t size) { + if (unlikely(size > LARGE_MAXCLASS)) { return (NSIZES); + } #if (NTBINS != 0) if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { szind_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; @@ -656,8 +654,7 @@ size2index_compute(size_t size) } JEMALLOC_ALWAYS_INLINE szind_t -size2index_lookup(size_t size) -{ +size2index_lookup(size_t size) { assert(size <= LOOKUP_MAXCLASS); { szind_t ret = (size2index_tab[(size-1) >> LG_TINY_MIN]); @@ -667,20 +664,20 @@ size2index_lookup(size_t size) } JEMALLOC_ALWAYS_INLINE szind_t -size2index(size_t size) -{ +size2index(size_t size) { assert(size > 0); - if (likely(size <= LOOKUP_MAXCLASS)) + if (likely(size <= LOOKUP_MAXCLASS)) { return (size2index_lookup(size)); + } return (size2index_compute(size)); } JEMALLOC_INLINE size_t -index2size_compute(szind_t index) -{ +index2size_compute(szind_t index) { #if (NTBINS > 0) - if (index < NTBINS) + if (index < NTBINS) { return (ZU(1) << (LG_TINY_MAXCLASS - NTBINS + 1 + index)); + } #endif { size_t reduced_index = index - NTBINS; @@ -702,25 +699,23 @@ index2size_compute(szind_t index) } JEMALLOC_ALWAYS_INLINE size_t -index2size_lookup(szind_t index) -{ +index2size_lookup(szind_t index) { size_t ret = (size_t)index2size_tab[index]; assert(ret == index2size_compute(index)); return (ret); } JEMALLOC_ALWAYS_INLINE size_t -index2size(szind_t index) -{ +index2size(szind_t index) { assert(index < NSIZES); return (index2size_lookup(index)); } JEMALLOC_ALWAYS_INLINE size_t -s2u_compute(size_t size) -{ - if (unlikely(size > LARGE_MAXCLASS)) +s2u_compute(size_t size) { + if (unlikely(size > LARGE_MAXCLASS)) { return (0); + } #if (NTBINS > 0) if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { size_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; @@ -741,8 +736,7 @@ s2u_compute(size_t size) } JEMALLOC_ALWAYS_INLINE size_t -s2u_lookup(size_t size) -{ +s2u_lookup(size_t size) { size_t ret = index2size_lookup(size2index_lookup(size)); assert(ret == s2u_compute(size)); @@ -754,11 +748,11 @@ s2u_lookup(size_t size) * specified size. */ JEMALLOC_ALWAYS_INLINE size_t -s2u(size_t size) -{ +s2u(size_t size) { assert(size > 0); - if (likely(size <= LOOKUP_MAXCLASS)) + if (likely(size <= LOOKUP_MAXCLASS)) { return (s2u_lookup(size)); + } return (s2u_compute(size)); } @@ -767,8 +761,7 @@ s2u(size_t size) * specified size and alignment. */ JEMALLOC_ALWAYS_INLINE size_t -sa2u(size_t size, size_t alignment) -{ +sa2u(size_t size, size_t alignment) { size_t usize; assert(alignment != 0 && ((alignment - 1) & alignment) == 0); @@ -790,19 +783,21 @@ sa2u(size_t size, size_t alignment) * 192 | 11000000 | 64 */ usize = s2u(ALIGNMENT_CEILING(size, alignment)); - if (usize < LARGE_MINCLASS) + if (usize < LARGE_MINCLASS) { return (usize); + } } /* Large size class. Beware of overflow. */ - if (unlikely(alignment > LARGE_MAXCLASS)) + if (unlikely(alignment > LARGE_MAXCLASS)) { return (0); + } /* Make sure result is a large size class. */ - if (size <= LARGE_MINCLASS) + if (size <= LARGE_MINCLASS) { usize = LARGE_MINCLASS; - else { + } else { usize = s2u(size); if (usize < size) { /* size_t overflow. */ @@ -823,35 +818,33 @@ sa2u(size_t size, size_t alignment) /* Choose an arena based on a per-thread value. */ JEMALLOC_INLINE arena_t * -arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) -{ +arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { arena_t *ret; - if (arena != NULL) + if (arena != NULL) { return (arena); + } ret = internal ? tsd_iarena_get(tsd) : tsd_arena_get(tsd); - if (unlikely(ret == NULL)) + if (unlikely(ret == NULL)) { ret = arena_choose_hard(tsd, internal); + } return (ret); } JEMALLOC_INLINE arena_t * -arena_choose(tsd_t *tsd, arena_t *arena) -{ +arena_choose(tsd_t *tsd, arena_t *arena) { return (arena_choose_impl(tsd, arena, false)); } JEMALLOC_INLINE arena_t * -arena_ichoose(tsd_t *tsd, arena_t *arena) -{ +arena_ichoose(tsd_t *tsd, arena_t *arena) { return (arena_choose_impl(tsd, arena, true)); } JEMALLOC_INLINE arena_tdata_t * -arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing) -{ +arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing) { arena_tdata_t *tdata; arena_tdata_t *arenas_tdata = tsd_arenas_tdata_get(tsd); @@ -869,14 +862,14 @@ arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing) } tdata = &arenas_tdata[ind]; - if (likely(tdata != NULL) || !refresh_if_missing) + if (likely(tdata != NULL) || !refresh_if_missing) { return (tdata); + } return (arena_tdata_get_hard(tsd, ind)); } JEMALLOC_INLINE arena_t * -arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing) -{ +arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing) { arena_t *ret; assert(ind <= MALLOCX_ARENA_MAX); @@ -893,13 +886,13 @@ arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing) } JEMALLOC_INLINE ticker_t * -decay_ticker_get(tsd_t *tsd, unsigned ind) -{ +decay_ticker_get(tsd_t *tsd, unsigned ind) { arena_tdata_t *tdata; tdata = arena_tdata_get(tsd, ind, true); - if (unlikely(tdata == NULL)) + if (unlikely(tdata == NULL)) { return (NULL); + } return (&tdata->decay_ticker); } #endif @@ -917,8 +910,7 @@ extent_t *iealloc(tsdn_t *tsdn, const void *ptr); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) JEMALLOC_ALWAYS_INLINE extent_t * -iealloc(tsdn_t *tsdn, const void *ptr) -{ +iealloc(tsdn_t *tsdn, const void *ptr) { return (extent_lookup(tsdn, ptr, true)); } #endif @@ -958,8 +950,7 @@ bool ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) JEMALLOC_ALWAYS_INLINE arena_t * -iaalloc(tsdn_t *tsdn, const void *ptr) -{ +iaalloc(tsdn_t *tsdn, const void *ptr) { assert(ptr != NULL); return (arena_aalloc(tsdn, ptr)); @@ -973,8 +964,7 @@ iaalloc(tsdn_t *tsdn, const void *ptr) * size_t sz = isalloc(tsdn, extent, ptr); */ JEMALLOC_ALWAYS_INLINE size_t -isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) -{ +isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { assert(ptr != NULL); return (arena_salloc(tsdn, extent, ptr)); @@ -982,8 +972,7 @@ isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) JEMALLOC_ALWAYS_INLINE void * iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, - bool is_internal, arena_t *arena, bool slow_path) -{ + bool is_internal, arena_t *arena, bool slow_path) { void *ret; assert(size != 0); @@ -1000,16 +989,14 @@ iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, } JEMALLOC_ALWAYS_INLINE void * -ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, bool slow_path) -{ +ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, bool slow_path) { return (iallocztm(tsd_tsdn(tsd), size, ind, zero, tcache_get(tsd, true), false, NULL, slow_path)); } JEMALLOC_ALWAYS_INLINE void * ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, - tcache_t *tcache, bool is_internal, arena_t *arena) -{ + tcache_t *tcache, bool is_internal, arena_t *arena) { void *ret; assert(usize != 0); @@ -1029,21 +1016,18 @@ ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, JEMALLOC_ALWAYS_INLINE void * ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, - tcache_t *tcache, arena_t *arena) -{ + tcache_t *tcache, arena_t *arena) { return (ipallocztm(tsdn, usize, alignment, zero, tcache, false, arena)); } JEMALLOC_ALWAYS_INLINE void * -ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero) -{ +ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero) { return (ipallocztm(tsd_tsdn(tsd), usize, alignment, zero, tcache_get(tsd, true), false, NULL)); } JEMALLOC_ALWAYS_INLINE size_t -ivsalloc(tsdn_t *tsdn, const void *ptr) -{ +ivsalloc(tsdn_t *tsdn, const void *ptr) { extent_t *extent; /* @@ -1055,8 +1039,9 @@ ivsalloc(tsdn_t *tsdn, const void *ptr) * failure. * */ extent = extent_lookup(tsdn, ptr, false); - if (extent == NULL) + if (extent == NULL) { return (0); + } assert(extent_active_get(extent)); /* Only slab members should be looked up via interior pointers. */ assert(extent_addr_get(extent) == ptr || extent_slab_get(extent)); @@ -1066,8 +1051,7 @@ ivsalloc(tsdn_t *tsdn, const void *ptr) JEMALLOC_ALWAYS_INLINE void idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, - bool is_internal, bool slow_path) -{ + bool is_internal, bool slow_path) { assert(ptr != NULL); assert(!is_internal || tcache == NULL); assert(!is_internal || arena_ind_get(iaalloc(tsdn, ptr)) < @@ -1081,41 +1065,42 @@ idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, } JEMALLOC_ALWAYS_INLINE void -idalloc(tsd_t *tsd, extent_t *extent, void *ptr) -{ +idalloc(tsd_t *tsd, extent_t *extent, void *ptr) { idalloctm(tsd_tsdn(tsd), extent, ptr, tcache_get(tsd, false), false, true); } JEMALLOC_ALWAYS_INLINE void isdalloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, - tcache_t *tcache, bool slow_path) -{ + tcache_t *tcache, bool slow_path) { arena_sdalloc(tsdn, extent, ptr, size, tcache, slow_path); } JEMALLOC_ALWAYS_INLINE void * iralloct_realign(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t extra, size_t alignment, bool zero, tcache_t *tcache, - arena_t *arena) -{ + arena_t *arena) { void *p; size_t usize, copysize; usize = sa2u(size + extra, alignment); - if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { return (NULL); + } p = ipalloct(tsdn, usize, alignment, zero, tcache, arena); if (p == NULL) { - if (extra == 0) + if (extra == 0) { return (NULL); + } /* Try again, without extra this time. */ usize = sa2u(size, alignment); - if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { return (NULL); + } p = ipalloct(tsdn, usize, alignment, zero, tcache, arena); - if (p == NULL) + if (p == NULL) { return (NULL); + } } /* * Copy at most size bytes (not size+extra), since the caller has no @@ -1129,8 +1114,7 @@ iralloct_realign(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, JEMALLOC_ALWAYS_INLINE void * iralloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, - size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) -{ + size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) { assert(ptr != NULL); assert(size != 0); @@ -1150,16 +1134,14 @@ iralloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, JEMALLOC_ALWAYS_INLINE void * iralloc(tsd_t *tsd, extent_t *extent, void *ptr, size_t oldsize, size_t size, - size_t alignment, bool zero) -{ + size_t alignment, bool zero) { return (iralloct(tsd_tsdn(tsd), extent, ptr, oldsize, size, alignment, zero, tcache_get(tsd, true), NULL)); } JEMALLOC_ALWAYS_INLINE bool ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, - size_t extra, size_t alignment, bool zero) -{ + size_t extra, size_t alignment, bool zero) { assert(ptr != NULL); assert(size != 0); diff --git a/include/jemalloc/internal/jemalloc_internal_decls.h b/include/jemalloc/internal/jemalloc_internal_decls.h index 277027f0..fd80fdf0 100644 --- a/include/jemalloc/internal/jemalloc_internal_decls.h +++ b/include/jemalloc/internal/jemalloc_internal_decls.h @@ -61,8 +61,7 @@ typedef intptr_t ssize_t; # pragma warning(disable: 4996) #if _MSC_VER < 1800 static int -isblank(int c) -{ +isblank(int c) { return (c == '\t' || c == ' '); } #endif diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index d65fa13c..0c6c5dd5 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -10,8 +10,7 @@ void malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) JEMALLOC_INLINE void -malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) -{ +malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) { if (isthreaded) { witness_assert_not_owner(tsdn, &mutex->witness); #ifdef _WIN32 @@ -32,8 +31,7 @@ malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) } JEMALLOC_INLINE void -malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) -{ +malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) { if (isthreaded) { witness_unlock(tsdn, &mutex->witness); #ifdef _WIN32 @@ -53,17 +51,17 @@ malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) } JEMALLOC_INLINE void -malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) -{ - if (isthreaded) +malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { + if (isthreaded) { witness_assert_owner(tsdn, &mutex->witness); + } } JEMALLOC_INLINE void -malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) -{ - if (isthreaded) +malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { + if (isthreaded) { witness_assert_not_owner(tsdn, &mutex->witness); + } } #endif diff --git a/include/jemalloc/internal/ph.h b/include/jemalloc/internal/ph.h index 9efb7b74..61dfdc0b 100644 --- a/include/jemalloc/internal/ph.h +++ b/include/jemalloc/internal/ph.h @@ -58,17 +58,18 @@ struct { \ phn_prev_set(a_type, a_field, a_phn1, a_phn0); \ phn0child = phn_lchild_get(a_type, a_field, a_phn0); \ phn_next_set(a_type, a_field, a_phn1, phn0child); \ - if (phn0child != NULL) \ + if (phn0child != NULL) { \ phn_prev_set(a_type, a_field, phn0child, a_phn1); \ + } \ phn_lchild_set(a_type, a_field, a_phn0, a_phn1); \ } while (0) #define phn_merge(a_type, a_field, a_phn0, a_phn1, a_cmp, r_phn) do { \ - if (a_phn0 == NULL) \ + if (a_phn0 == NULL) { \ r_phn = a_phn1; \ - else if (a_phn1 == NULL) \ + } else if (a_phn1 == NULL) { \ r_phn = a_phn0; \ - else if (a_cmp(a_phn0, a_phn1) < 0) { \ + } else if (a_cmp(a_phn0, a_phn1) < 0) { \ phn_merge_ordered(a_type, a_field, a_phn0, a_phn1, \ a_cmp); \ r_phn = a_phn0; \ @@ -95,8 +96,9 @@ struct { \ */ \ if (phn1 != NULL) { \ a_type *phnrest = phn_next_get(a_type, a_field, phn1); \ - if (phnrest != NULL) \ + if (phnrest != NULL) { \ phn_prev_set(a_type, a_field, phnrest, NULL); \ + } \ phn_prev_set(a_type, a_field, phn0, NULL); \ phn_next_set(a_type, a_field, phn0, NULL); \ phn_prev_set(a_type, a_field, phn1, NULL); \ @@ -150,8 +152,9 @@ struct { \ NULL); \ phn_merge(a_type, a_field, phn0, phn1, \ a_cmp, phn0); \ - if (head == NULL) \ + if (head == NULL) { \ break; \ + } \ phn_next_set(a_type, a_field, tail, \ phn0); \ tail = phn0; \ @@ -179,9 +182,9 @@ struct { \ #define ph_merge_children(a_type, a_field, a_phn, a_cmp, r_phn) do { \ a_type *lchild = phn_lchild_get(a_type, a_field, a_phn); \ - if (lchild == NULL) \ + if (lchild == NULL) { \ r_phn = NULL; \ - else { \ + } else { \ ph_merge_siblings(a_type, a_field, lchild, a_cmp, \ r_phn); \ } \ @@ -205,26 +208,23 @@ a_attr void a_prefix##remove(a_ph_type *ph, a_type *phn); */ #define ph_gen(a_attr, a_prefix, a_ph_type, a_type, a_field, a_cmp) \ a_attr void \ -a_prefix##new(a_ph_type *ph) \ -{ \ +a_prefix##new(a_ph_type *ph) { \ memset(ph, 0, sizeof(ph(a_type))); \ } \ a_attr bool \ -a_prefix##empty(a_ph_type *ph) \ -{ \ +a_prefix##empty(a_ph_type *ph) { \ return (ph->ph_root == NULL); \ } \ a_attr a_type * \ -a_prefix##first(a_ph_type *ph) \ -{ \ - if (ph->ph_root == NULL) \ +a_prefix##first(a_ph_type *ph) { \ + if (ph->ph_root == NULL) { \ return (NULL); \ + } \ ph_merge_aux(a_type, a_field, ph, a_cmp); \ return (ph->ph_root); \ } \ a_attr void \ -a_prefix##insert(a_ph_type *ph, a_type *phn) \ -{ \ +a_prefix##insert(a_ph_type *ph, a_type *phn) { \ memset(&phn->a_field, 0, sizeof(phn(a_type))); \ \ /* \ @@ -235,9 +235,9 @@ a_prefix##insert(a_ph_type *ph, a_type *phn) \ * constant-time, whereas eager merging would make insert \ * O(log n). \ */ \ - if (ph->ph_root == NULL) \ + if (ph->ph_root == NULL) { \ ph->ph_root = phn; \ - else { \ + } else { \ phn_next_set(a_type, a_field, phn, phn_next_get(a_type, \ a_field, ph->ph_root)); \ if (phn_next_get(a_type, a_field, ph->ph_root) != \ @@ -251,12 +251,12 @@ a_prefix##insert(a_ph_type *ph, a_type *phn) \ } \ } \ a_attr a_type * \ -a_prefix##remove_first(a_ph_type *ph) \ -{ \ +a_prefix##remove_first(a_ph_type *ph) { \ a_type *ret; \ \ - if (ph->ph_root == NULL) \ + if (ph->ph_root == NULL) { \ return (NULL); \ + } \ ph_merge_aux(a_type, a_field, ph, a_cmp); \ \ ret = ph->ph_root; \ @@ -267,8 +267,7 @@ a_prefix##remove_first(a_ph_type *ph) \ return (ret); \ } \ a_attr void \ -a_prefix##remove(a_ph_type *ph, a_type *phn) \ -{ \ +a_prefix##remove(a_ph_type *ph, a_type *phn) { \ a_type *replace, *parent; \ \ /* \ @@ -286,8 +285,9 @@ a_prefix##remove(a_ph_type *ph, a_type *phn) \ \ /* Get parent (if phn is leftmost child) before mutating. */ \ if ((parent = phn_prev_get(a_type, a_field, phn)) != NULL) { \ - if (phn_lchild_get(a_type, a_field, parent) != phn) \ + if (phn_lchild_get(a_type, a_field, parent) != phn) { \ parent = NULL; \ + } \ } \ /* Find a possible replacement node, and link to parent. */ \ ph_merge_children(a_type, a_field, phn, a_cmp, replace); \ diff --git a/include/jemalloc/internal/prng_inlines.h b/include/jemalloc/internal/prng_inlines.h index 8cc19ce8..124b1baa 100644 --- a/include/jemalloc/internal/prng_inlines.h +++ b/include/jemalloc/internal/prng_inlines.h @@ -18,20 +18,17 @@ size_t prng_range_zu(size_t *state, size_t range, bool atomic); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PRNG_C_)) JEMALLOC_ALWAYS_INLINE uint32_t -prng_state_next_u32(uint32_t state) -{ +prng_state_next_u32(uint32_t state) { return ((state * PRNG_A_32) + PRNG_C_32); } JEMALLOC_ALWAYS_INLINE uint64_t -prng_state_next_u64(uint64_t state) -{ +prng_state_next_u64(uint64_t state) { return ((state * PRNG_A_64) + PRNG_C_64); } JEMALLOC_ALWAYS_INLINE size_t -prng_state_next_zu(size_t state) -{ +prng_state_next_zu(size_t state) { #if LG_SIZEOF_PTR == 2 return ((state * PRNG_A_32) + PRNG_C_32); #elif LG_SIZEOF_PTR == 3 @@ -42,8 +39,7 @@ prng_state_next_zu(size_t state) } JEMALLOC_ALWAYS_INLINE uint32_t -prng_lg_range_u32(uint32_t *state, unsigned lg_range, bool atomic) -{ +prng_lg_range_u32(uint32_t *state, unsigned lg_range, bool atomic) { uint32_t ret, state1; assert(lg_range > 0); @@ -67,8 +63,7 @@ prng_lg_range_u32(uint32_t *state, unsigned lg_range, bool atomic) /* 64-bit atomic operations cannot be supported on all relevant platforms. */ JEMALLOC_ALWAYS_INLINE uint64_t -prng_lg_range_u64(uint64_t *state, unsigned lg_range) -{ +prng_lg_range_u64(uint64_t *state, unsigned lg_range) { uint64_t ret, state1; assert(lg_range > 0); @@ -82,8 +77,7 @@ prng_lg_range_u64(uint64_t *state, unsigned lg_range) } JEMALLOC_ALWAYS_INLINE size_t -prng_lg_range_zu(size_t *state, unsigned lg_range, bool atomic) -{ +prng_lg_range_zu(size_t *state, unsigned lg_range, bool atomic) { size_t ret, state1; assert(lg_range > 0); @@ -106,8 +100,7 @@ prng_lg_range_zu(size_t *state, unsigned lg_range, bool atomic) } JEMALLOC_ALWAYS_INLINE uint32_t -prng_range_u32(uint32_t *state, uint32_t range, bool atomic) -{ +prng_range_u32(uint32_t *state, uint32_t range, bool atomic) { uint32_t ret; unsigned lg_range; @@ -125,8 +118,7 @@ prng_range_u32(uint32_t *state, uint32_t range, bool atomic) } JEMALLOC_ALWAYS_INLINE uint64_t -prng_range_u64(uint64_t *state, uint64_t range) -{ +prng_range_u64(uint64_t *state, uint64_t range) { uint64_t ret; unsigned lg_range; @@ -144,8 +136,7 @@ prng_range_u64(uint64_t *state, uint64_t range) } JEMALLOC_ALWAYS_INLINE size_t -prng_range_zu(size_t *state, size_t range, bool atomic) -{ +prng_range_zu(size_t *state, size_t range, bool atomic) { size_t ret; unsigned lg_range; diff --git a/include/jemalloc/internal/prof_inlines.h b/include/jemalloc/internal/prof_inlines.h index 394b7b37..bb9093a8 100644 --- a/include/jemalloc/internal/prof_inlines.h +++ b/include/jemalloc/internal/prof_inlines.h @@ -27,8 +27,7 @@ void prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PROF_C_)) JEMALLOC_ALWAYS_INLINE bool -prof_active_get_unlocked(void) -{ +prof_active_get_unlocked(void) { /* * Even if opt_prof is true, sampling can be temporarily disabled by * setting prof_active to false. No locking is used when reading @@ -39,8 +38,7 @@ prof_active_get_unlocked(void) } JEMALLOC_ALWAYS_INLINE bool -prof_gdump_get_unlocked(void) -{ +prof_gdump_get_unlocked(void) { /* * No locking is used when reading prof_gdump_val in the fast path, so * there are no guarantees regarding how long it will take for all @@ -50,8 +48,7 @@ prof_gdump_get_unlocked(void) } JEMALLOC_ALWAYS_INLINE prof_tdata_t * -prof_tdata_get(tsd_t *tsd, bool create) -{ +prof_tdata_get(tsd_t *tsd, bool create) { prof_tdata_t *tdata; cassert(config_prof); @@ -74,8 +71,7 @@ prof_tdata_get(tsd_t *tsd, bool create) } JEMALLOC_ALWAYS_INLINE prof_tctx_t * -prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) -{ +prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { cassert(config_prof); assert(ptr != NULL); @@ -84,8 +80,7 @@ prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) JEMALLOC_ALWAYS_INLINE void prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, - prof_tctx_t *tctx) -{ + prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); @@ -94,8 +89,7 @@ prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, JEMALLOC_ALWAYS_INLINE void prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, - prof_tctx_t *tctx) -{ + prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); @@ -104,37 +98,40 @@ prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, JEMALLOC_ALWAYS_INLINE bool prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update, - prof_tdata_t **tdata_out) -{ + prof_tdata_t **tdata_out) { prof_tdata_t *tdata; cassert(config_prof); tdata = prof_tdata_get(tsd, true); - if (unlikely((uintptr_t)tdata <= (uintptr_t)PROF_TDATA_STATE_MAX)) + if (unlikely((uintptr_t)tdata <= (uintptr_t)PROF_TDATA_STATE_MAX)) { tdata = NULL; + } - if (tdata_out != NULL) + if (tdata_out != NULL) { *tdata_out = tdata; + } - if (unlikely(tdata == NULL)) + if (unlikely(tdata == NULL)) { return (true); + } if (likely(tdata->bytes_until_sample >= usize)) { - if (update) + if (update) { tdata->bytes_until_sample -= usize; + } return (true); } else { /* Compute new sample threshold. */ - if (update) + if (update) { prof_sample_threshold_update(tdata); + } return (!tdata->active); } } JEMALLOC_ALWAYS_INLINE prof_tctx_t * -prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update) -{ +prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update) { prof_tctx_t *ret; prof_tdata_t *tdata; prof_bt_t bt; @@ -142,9 +139,9 @@ prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update) assert(usize == s2u(usize)); if (!prof_active || likely(prof_sample_accum_update(tsd, usize, update, - &tdata))) + &tdata))) { ret = (prof_tctx_t *)(uintptr_t)1U; - else { + } else { bt_init(&bt, tdata->vec); prof_backtrace(&bt); ret = prof_lookup(tsd, &bt); @@ -155,15 +152,14 @@ prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update) JEMALLOC_ALWAYS_INLINE void prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, - prof_tctx_t *tctx) -{ + prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); assert(usize == isalloc(tsdn, extent, ptr)); - if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) + if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) { prof_malloc_sample_object(tsdn, extent, ptr, usize, tctx); - else { + } else { prof_tctx_set(tsdn, extent, ptr, usize, (prof_tctx_t *)(uintptr_t)1U); } @@ -172,8 +168,7 @@ prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, JEMALLOC_ALWAYS_INLINE void prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, prof_tctx_t *tctx, bool prof_active, bool updated, extent_t *old_extent, - const void *old_ptr, size_t old_usize, prof_tctx_t *old_tctx) -{ + const void *old_ptr, size_t old_usize, prof_tctx_t *old_tctx) { bool sampled, old_sampled, moved; cassert(config_prof); @@ -230,15 +225,15 @@ prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, } JEMALLOC_ALWAYS_INLINE void -prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, size_t usize) -{ +prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, size_t usize) { prof_tctx_t *tctx = prof_tctx_get(tsd_tsdn(tsd), extent, ptr); cassert(config_prof); assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr)); - if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) + if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) { prof_free_sampled_object(tsd, usize, tctx); + } } #endif diff --git a/include/jemalloc/internal/qr.h b/include/jemalloc/internal/qr.h index 06dfdafd..a04f7504 100644 --- a/include/jemalloc/internal/qr.h +++ b/include/jemalloc/internal/qr.h @@ -25,14 +25,12 @@ struct { \ (a_qrelm)->a_field.qre_prev = (a_qr); \ } while (0) -#define qr_after_insert(a_qrelm, a_qr, a_field) \ - do \ - { \ +#define qr_after_insert(a_qrelm, a_qr, a_field) do { \ (a_qr)->a_field.qre_next = (a_qrelm)->a_field.qre_next; \ (a_qr)->a_field.qre_prev = (a_qrelm); \ (a_qr)->a_field.qre_next->a_field.qre_prev = (a_qr); \ (a_qrelm)->a_field.qre_next = (a_qr); \ - } while (0) +} while (0) #define qr_meld(a_qr_a, a_qr_b, a_type, a_field) do { \ a_type *t; \ diff --git a/include/jemalloc/internal/rb.h b/include/jemalloc/internal/rb.h index 3770342f..a4b5a65e 100644 --- a/include/jemalloc/internal/rb.h +++ b/include/jemalloc/internal/rb.h @@ -550,8 +550,7 @@ a_prefix##remove(a_rbt_type *rbtree, a_type *node) { \ /* Find node's successor, in preparation for swap. */ \ pathp->cmp = 1; \ nodep = pathp; \ - for (pathp++; pathp->node != NULL; \ - pathp++) { \ + for (pathp++; pathp->node != NULL; pathp++) { \ pathp->cmp = -1; \ pathp[1].node = rbtn_left_get(a_type, a_field, \ pathp->node); \ diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 7e79a6a0..9e512e9f 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -37,12 +37,12 @@ void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_RTREE_C_)) JEMALLOC_ALWAYS_INLINE unsigned -rtree_start_level(const rtree_t *rtree, uintptr_t key) -{ +rtree_start_level(const rtree_t *rtree, uintptr_t key) { unsigned start_level; - if (unlikely(key == 0)) + if (unlikely(key == 0)) { return (rtree->height - 1); + } start_level = rtree->start_level[(lg_floor(key) + 1) >> LG_RTREE_BITS_PER_LEVEL]; @@ -52,8 +52,7 @@ rtree_start_level(const rtree_t *rtree, uintptr_t key) JEMALLOC_ALWAYS_INLINE unsigned rtree_ctx_start_level(const rtree_t *rtree, const rtree_ctx_t *rtree_ctx, - uintptr_t key) -{ + uintptr_t key) { unsigned start_level; uintptr_t key_diff; @@ -72,48 +71,45 @@ rtree_ctx_start_level(const rtree_t *rtree, const rtree_ctx_t *rtree_ctx, } JEMALLOC_ALWAYS_INLINE uintptr_t -rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level) -{ +rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level) { return ((key >> ((ZU(1) << (LG_SIZEOF_PTR+3)) - rtree->levels[level].cumbits)) & ((ZU(1) << rtree->levels[level].bits) - 1)); } JEMALLOC_ALWAYS_INLINE bool -rtree_node_valid(rtree_elm_t *node) -{ +rtree_node_valid(rtree_elm_t *node) { return ((uintptr_t)node != (uintptr_t)0); } JEMALLOC_ALWAYS_INLINE rtree_elm_t * -rtree_child_tryread(rtree_elm_t *elm, bool dependent) -{ +rtree_child_tryread(rtree_elm_t *elm, bool dependent) { rtree_elm_t *child; /* Double-checked read (first read may be stale). */ child = elm->child; - if (!dependent && !rtree_node_valid(child)) + if (!dependent && !rtree_node_valid(child)) { child = (rtree_elm_t *)atomic_read_p(&elm->pun); + } assert(!dependent || child != NULL); return (child); } JEMALLOC_ALWAYS_INLINE rtree_elm_t * rtree_child_read(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level, - bool dependent) -{ + bool dependent) { rtree_elm_t *child; child = rtree_child_tryread(elm, dependent); - if (!dependent && unlikely(!rtree_node_valid(child))) + if (!dependent && unlikely(!rtree_node_valid(child))) { child = rtree_child_read_hard(tsdn, rtree, elm, level); + } assert(!dependent || child != NULL); return (child); } JEMALLOC_ALWAYS_INLINE extent_t * -rtree_elm_read(rtree_elm_t *elm, bool dependent) -{ +rtree_elm_read(rtree_elm_t *elm, bool dependent) { extent_t *extent; if (dependent) { @@ -140,14 +136,12 @@ rtree_elm_read(rtree_elm_t *elm, bool dependent) } JEMALLOC_INLINE void -rtree_elm_write(rtree_elm_t *elm, const extent_t *extent) -{ +rtree_elm_write(rtree_elm_t *elm, const extent_t *extent) { atomic_write_p(&elm->pun, extent); } JEMALLOC_ALWAYS_INLINE rtree_elm_t * -rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent) -{ +rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent) { rtree_elm_t *subtree; /* Double-checked read (first read may be stale). */ @@ -161,21 +155,21 @@ rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent) } JEMALLOC_ALWAYS_INLINE rtree_elm_t * -rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, unsigned level, bool dependent) -{ +rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, unsigned level, + bool dependent) { rtree_elm_t *subtree; subtree = rtree_subtree_tryread(rtree, level, dependent); - if (!dependent && unlikely(!rtree_node_valid(subtree))) + if (!dependent && unlikely(!rtree_node_valid(subtree))) { subtree = rtree_subtree_read_hard(tsdn, rtree, level); + } assert(!dependent || subtree != NULL); return (subtree); } JEMALLOC_ALWAYS_INLINE rtree_elm_t * rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, - uintptr_t key, bool dependent, bool init_missing) -{ + uintptr_t key, bool dependent, bool init_missing) { uintptr_t subkey; unsigned start_level; rtree_elm_t *node; @@ -184,9 +178,9 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, if (dependent || init_missing) { if (likely(rtree_ctx->valid)) { - if (key == rtree_ctx->key) + if (key == rtree_ctx->key) { return (rtree_ctx->elms[rtree->height]); - else { + } else { unsigned no_ctx_start_level = rtree_start_level(rtree, key); unsigned ctx_start_level; @@ -237,8 +231,9 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, case level: \ assert(level < (RTREE_HEIGHT_MAX-1)); \ if (!dependent && unlikely(!rtree_node_valid(node))) { \ - if (init_missing) \ + if (init_missing) { \ rtree_ctx->valid = false; \ + } \ return (NULL); \ } \ subkey = rtree_subkey(rtree, key, level - \ @@ -255,8 +250,9 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, case level: \ assert(level == (RTREE_HEIGHT_MAX-1)); \ if (!dependent && unlikely(!rtree_node_valid(node))) { \ - if (init_missing) \ + if (init_missing) { \ rtree_ctx->valid = false; \ + } \ return (NULL); \ } \ subkey = rtree_subkey(rtree, key, level - \ @@ -330,16 +326,16 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, JEMALLOC_INLINE bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, - const extent_t *extent) -{ + const extent_t *extent) { rtree_elm_t *elm; assert(extent != NULL); /* Use rtree_clear() for this case. */ assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, false, true); - if (elm == NULL) + if (elm == NULL) { return (true); + } assert(rtree_elm_read(elm, false) == NULL); rtree_elm_write(elm, extent); @@ -348,27 +344,27 @@ rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, JEMALLOC_ALWAYS_INLINE extent_t * rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, - bool dependent) -{ + bool dependent) { rtree_elm_t *elm; elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, dependent, false); - if (elm == NULL) + if (elm == NULL) { return (NULL); + } return (rtree_elm_read(elm, dependent)); } JEMALLOC_INLINE rtree_elm_t * rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, - uintptr_t key, bool dependent, bool init_missing) -{ + uintptr_t key, bool dependent, bool init_missing) { rtree_elm_t *elm; elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, dependent, init_missing); - if (!dependent && elm == NULL) + if (!dependent && elm == NULL) { return (NULL); + } { extent_t *extent; void *s; @@ -380,52 +376,53 @@ rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, } while (atomic_cas_p(&elm->pun, (void *)extent, s)); } - if (config_debug) + if (config_debug) { rtree_elm_witness_acquire(tsdn, rtree, key, elm); + } return (elm); } JEMALLOC_INLINE extent_t * -rtree_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm) -{ +rtree_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm) { extent_t *extent; assert(((uintptr_t)elm->pun & (uintptr_t)0x1) == (uintptr_t)0x1); extent = (extent_t *)((uintptr_t)elm->pun & ~((uintptr_t)0x1)); assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); - if (config_debug) + if (config_debug) { rtree_elm_witness_access(tsdn, rtree, elm); + } return (extent); } JEMALLOC_INLINE void rtree_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm, - const extent_t *extent) -{ + const extent_t *extent) { assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); assert(((uintptr_t)elm->pun & (uintptr_t)0x1) == (uintptr_t)0x1); - if (config_debug) + if (config_debug) { rtree_elm_witness_access(tsdn, rtree, elm); + } elm->pun = (void *)((uintptr_t)extent | (uintptr_t)0x1); assert(rtree_elm_read_acquired(tsdn, rtree, elm) == extent); } JEMALLOC_INLINE void -rtree_elm_release(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm) -{ +rtree_elm_release(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm) { rtree_elm_write(elm, rtree_elm_read_acquired(tsdn, rtree, elm)); - if (config_debug) + if (config_debug) { rtree_elm_witness_release(tsdn, rtree, elm); + } } JEMALLOC_INLINE void -rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key) -{ +rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, + uintptr_t key) { rtree_elm_t *elm; elm = rtree_elm_acquire(tsdn, rtree, rtree_ctx, key, true, false); diff --git a/include/jemalloc/internal/spin_inlines.h b/include/jemalloc/internal/spin_inlines.h index b4e779f8..1ffc4232 100644 --- a/include/jemalloc/internal/spin_inlines.h +++ b/include/jemalloc/internal/spin_inlines.h @@ -8,21 +8,21 @@ void spin_adaptive(spin_t *spin); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_SPIN_C_)) JEMALLOC_INLINE void -spin_init(spin_t *spin) -{ +spin_init(spin_t *spin) { spin->iteration = 0; } JEMALLOC_INLINE void -spin_adaptive(spin_t *spin) -{ +spin_adaptive(spin_t *spin) { volatile uint64_t i; - for (i = 0; i < (KQU(1) << spin->iteration); i++) + for (i = 0; i < (KQU(1) << spin->iteration); i++) { CPU_SPINWAIT; + } - if (spin->iteration < 63) + if (spin->iteration < 63) { spin->iteration++; + } } #endif diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index 2762b0e2..4721ba30 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -21,8 +21,7 @@ tcache_t *tcaches_get(tsd_t *tsd, unsigned ind); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TCACHE_C_)) JEMALLOC_INLINE void -tcache_flush(void) -{ +tcache_flush(void) { tsd_t *tsd; cassert(config_tcache); @@ -32,8 +31,7 @@ tcache_flush(void) } JEMALLOC_INLINE bool -tcache_enabled_get(void) -{ +tcache_enabled_get(void) { tsd_t *tsd; tcache_enabled_t tcache_enabled; @@ -50,8 +48,7 @@ tcache_enabled_get(void) } JEMALLOC_INLINE void -tcache_enabled_set(bool enabled) -{ +tcache_enabled_set(bool enabled) { tsd_t *tsd; tcache_enabled_t tcache_enabled; @@ -62,21 +59,23 @@ tcache_enabled_set(bool enabled) tcache_enabled = (tcache_enabled_t)enabled; tsd_tcache_enabled_set(tsd, tcache_enabled); - if (!enabled) + if (!enabled) { tcache_cleanup(tsd); + } } JEMALLOC_ALWAYS_INLINE tcache_t * -tcache_get(tsd_t *tsd, bool create) -{ +tcache_get(tsd_t *tsd, bool create) { tcache_t *tcache; - if (!config_tcache) + if (!config_tcache) { return (NULL); + } tcache = tsd_tcache_get(tsd); - if (!create) + if (!create) { return (tcache); + } if (unlikely(tcache == NULL) && tsd_nominal(tsd)) { tcache = tcache_get_hard(tsd); tsd_tcache_set(tsd, tcache); @@ -86,18 +85,18 @@ tcache_get(tsd_t *tsd, bool create) } JEMALLOC_ALWAYS_INLINE void -tcache_event(tsd_t *tsd, tcache_t *tcache) -{ - if (TCACHE_GC_INCR == 0) +tcache_event(tsd_t *tsd, tcache_t *tcache) { + if (TCACHE_GC_INCR == 0) { return; + } - if (unlikely(ticker_tick(&tcache->gc_ticker))) + if (unlikely(ticker_tick(&tcache->gc_ticker))) { tcache_event_hard(tsd, tcache); + } } JEMALLOC_ALWAYS_INLINE void * -tcache_alloc_easy(tcache_bin_t *tbin, bool *tcache_success) -{ +tcache_alloc_easy(tcache_bin_t *tbin, bool *tcache_success) { void *ret; if (unlikely(tbin->ncached == 0)) { @@ -116,16 +115,16 @@ tcache_alloc_easy(tcache_bin_t *tbin, bool *tcache_success) ret = *(tbin->avail - tbin->ncached); tbin->ncached--; - if (unlikely((int)tbin->ncached < tbin->low_water)) + if (unlikely((int)tbin->ncached < tbin->low_water)) { tbin->low_water = tbin->ncached; + } return (ret); } JEMALLOC_ALWAYS_INLINE void * tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, - szind_t binind, bool zero, bool slow_path) -{ + szind_t binind, bool zero, bool slow_path) { void *ret; tcache_bin_t *tbin; bool tcache_success; @@ -138,13 +137,15 @@ tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, if (unlikely(!tcache_success)) { bool tcache_hard_success; arena = arena_choose(tsd, arena); - if (unlikely(arena == NULL)) + if (unlikely(arena == NULL)) { return (NULL); + } ret = tcache_alloc_small_hard(tsd_tsdn(tsd), arena, tcache, tbin, binind, &tcache_hard_success); - if (tcache_hard_success == false) + if (tcache_hard_success == false) { return (NULL); + } } assert(ret); @@ -162,8 +163,9 @@ tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, if (unlikely(opt_junk_alloc)) { arena_alloc_junk_small(ret, &arena_bin_info[binind], false); - } else if (unlikely(opt_zero)) + } else if (unlikely(opt_zero)) { memset(ret, 0, usize); + } } } else { if (slow_path && config_fill && unlikely(opt_junk_alloc)) { @@ -173,18 +175,19 @@ tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, memset(ret, 0, usize); } - if (config_stats) + if (config_stats) { tbin->tstats.nrequests++; - if (config_prof) + } + if (config_prof) { tcache->prof_accumbytes += usize; + } tcache_event(tsd, tcache); return (ret); } JEMALLOC_ALWAYS_INLINE void * tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, - szind_t binind, bool zero, bool slow_path) -{ + szind_t binind, bool zero, bool slow_path) { void *ret; tcache_bin_t *tbin; bool tcache_success; @@ -199,12 +202,14 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, * expensive to create one and not use it. */ arena = arena_choose(tsd, arena); - if (unlikely(arena == NULL)) + if (unlikely(arena == NULL)) { return (NULL); + } ret = large_malloc(tsd_tsdn(tsd), arena, s2u(size), zero); - if (ret == NULL) + if (ret == NULL) { return (NULL); + } } else { size_t usize JEMALLOC_CC_SILENCE_INIT(0); @@ -220,16 +225,20 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, if (unlikely(opt_junk_alloc)) { memset(ret, JEMALLOC_ALLOC_JUNK, usize); - } else if (unlikely(opt_zero)) + } else if (unlikely(opt_zero)) { memset(ret, 0, usize); + } } - } else + } else { memset(ret, 0, usize); + } - if (config_stats) + if (config_stats) { tbin->tstats.nrequests++; - if (config_prof) + } + if (config_prof) { tcache->prof_accumbytes += usize; + } } tcache_event(tsd, tcache); @@ -238,15 +247,15 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, JEMALLOC_ALWAYS_INLINE void tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, - bool slow_path) -{ + bool slow_path) { tcache_bin_t *tbin; tcache_bin_info_t *tbin_info; assert(tcache_salloc(tsd_tsdn(tsd), ptr) <= SMALL_MAXCLASS); - if (slow_path && config_fill && unlikely(opt_junk_free)) + if (slow_path && config_fill && unlikely(opt_junk_free)) { arena_dalloc_junk_small(ptr, &arena_bin_info[binind]); + } tbin = &tcache->tbins[binind]; tbin_info = &tcache_bin_info[binind]; @@ -263,8 +272,7 @@ tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, JEMALLOC_ALWAYS_INLINE void tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, size_t size, - bool slow_path) -{ + bool slow_path) { szind_t binind; tcache_bin_t *tbin; tcache_bin_info_t *tbin_info; @@ -274,8 +282,9 @@ tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, size_t size, binind = size2index(size); - if (slow_path && config_fill && unlikely(opt_junk_free)) + if (slow_path && config_fill && unlikely(opt_junk_free)) { large_dalloc_junk(ptr, size); + } tbin = &tcache->tbins[binind]; tbin_info = &tcache_bin_info[binind]; @@ -291,8 +300,7 @@ tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, size_t size, } JEMALLOC_ALWAYS_INLINE tcache_t * -tcaches_get(tsd_t *tsd, unsigned ind) -{ +tcaches_get(tsd_t *tsd, unsigned ind) { tcaches_t *elm = &tcaches[ind]; if (unlikely(elm->tcache == NULL)) { elm->tcache = tcache_create(tsd_tsdn(tsd), arena_choose(tsd, diff --git a/include/jemalloc/internal/ticker_inlines.h b/include/jemalloc/internal/ticker_inlines.h index 1a4395f3..6cc61343 100644 --- a/include/jemalloc/internal/ticker_inlines.h +++ b/include/jemalloc/internal/ticker_inlines.h @@ -11,27 +11,23 @@ bool ticker_tick(ticker_t *ticker); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TICKER_C_)) JEMALLOC_INLINE void -ticker_init(ticker_t *ticker, int32_t nticks) -{ +ticker_init(ticker_t *ticker, int32_t nticks) { ticker->tick = nticks; ticker->nticks = nticks; } JEMALLOC_INLINE void -ticker_copy(ticker_t *ticker, const ticker_t *other) -{ +ticker_copy(ticker_t *ticker, const ticker_t *other) { *ticker = *other; } JEMALLOC_INLINE int32_t -ticker_read(const ticker_t *ticker) -{ +ticker_read(const ticker_t *ticker) { return (ticker->tick); } JEMALLOC_INLINE bool -ticker_ticks(ticker_t *ticker, int32_t nticks) -{ +ticker_ticks(ticker_t *ticker, int32_t nticks) { if (unlikely(ticker->tick < nticks)) { ticker->tick = ticker->nticks; return (true); @@ -41,8 +37,7 @@ ticker_ticks(ticker_t *ticker, int32_t nticks) } JEMALLOC_INLINE bool -ticker_tick(ticker_t *ticker) -{ +ticker_tick(ticker_t *ticker) { return (ticker_ticks(ticker, 1)); } #endif diff --git a/include/jemalloc/internal/tsd_inlines.h b/include/jemalloc/internal/tsd_inlines.h index 0df21ad6..2093d610 100644 --- a/include/jemalloc/internal/tsd_inlines.h +++ b/include/jemalloc/internal/tsd_inlines.h @@ -25,12 +25,12 @@ malloc_tsd_externs(, tsd_t) malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, , tsd_t, tsd_initializer, tsd_cleanup) JEMALLOC_ALWAYS_INLINE tsd_t * -tsd_fetch_impl(bool init) -{ +tsd_fetch_impl(bool init) { tsd_t *tsd = tsd_get(init); - if (!init && tsd_get_allocates() && tsd == NULL) + if (!init && tsd_get_allocates() && tsd == NULL) { return (NULL); + } assert(tsd != NULL); if (unlikely(tsd->state != tsd_state_nominal)) { @@ -41,47 +41,42 @@ tsd_fetch_impl(bool init) } else if (tsd->state == tsd_state_purgatory) { tsd->state = tsd_state_reincarnated; tsd_set(tsd); - } else + } else { assert(tsd->state == tsd_state_reincarnated); + } } return (tsd); } JEMALLOC_ALWAYS_INLINE tsd_t * -tsd_fetch(void) -{ +tsd_fetch(void) { return (tsd_fetch_impl(true)); } JEMALLOC_ALWAYS_INLINE tsdn_t * -tsd_tsdn(tsd_t *tsd) -{ +tsd_tsdn(tsd_t *tsd) { return ((tsdn_t *)tsd); } JEMALLOC_INLINE bool -tsd_nominal(tsd_t *tsd) -{ +tsd_nominal(tsd_t *tsd) { return (tsd->state == tsd_state_nominal); } #define O(n, t, c) \ JEMALLOC_ALWAYS_INLINE t * \ -tsd_##n##p_get(tsd_t *tsd) \ -{ \ +tsd_##n##p_get(tsd_t *tsd) { \ return (&tsd->n); \ } \ \ JEMALLOC_ALWAYS_INLINE t \ -tsd_##n##_get(tsd_t *tsd) \ -{ \ +tsd_##n##_get(tsd_t *tsd) { \ return (*tsd_##n##p_get(tsd)); \ } \ \ JEMALLOC_ALWAYS_INLINE void \ -tsd_##n##_set(tsd_t *tsd, t n) \ -{ \ +tsd_##n##_set(tsd_t *tsd, t n) { \ assert(tsd->state == tsd_state_nominal); \ tsd->n = n; \ } @@ -89,31 +84,28 @@ MALLOC_TSD #undef O JEMALLOC_ALWAYS_INLINE tsdn_t * -tsdn_fetch(void) -{ - if (!tsd_booted_get()) +tsdn_fetch(void) { + if (!tsd_booted_get()) { return (NULL); + } return (tsd_tsdn(tsd_fetch_impl(false))); } JEMALLOC_ALWAYS_INLINE bool -tsdn_null(const tsdn_t *tsdn) -{ +tsdn_null(const tsdn_t *tsdn) { return (tsdn == NULL); } JEMALLOC_ALWAYS_INLINE tsd_t * -tsdn_tsd(tsdn_t *tsdn) -{ +tsdn_tsd(tsdn_t *tsdn) { assert(!tsdn_null(tsdn)); return (&tsdn->tsd); } JEMALLOC_ALWAYS_INLINE rtree_ctx_t * -tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback) -{ +tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback) { /* * If tsd cannot be accessed, initialize the fallback rtree_ctx and * return a pointer to it. diff --git a/include/jemalloc/internal/tsd_types.h b/include/jemalloc/internal/tsd_types.h index 17e3da9f..ec40d9a7 100644 --- a/include/jemalloc/internal/tsd_types.h +++ b/include/jemalloc/internal/tsd_types.h @@ -175,8 +175,7 @@ a_attr bool a_name##tsd_booted = false; a_cleanup) \ /* Initialization/cleanup. */ \ a_attr bool \ -a_name##tsd_cleanup_wrapper(void) \ -{ \ +a_name##tsd_cleanup_wrapper(void) { \ if (a_name##tsd_initialized) { \ a_name##tsd_initialized = false; \ a_cleanup(&a_name##tsd_tls); \ @@ -184,8 +183,7 @@ a_name##tsd_cleanup_wrapper(void) \ return (a_name##tsd_initialized); \ } \ a_attr bool \ -a_name##tsd_boot0(void) \ -{ \ +a_name##tsd_boot0(void) { \ if (a_cleanup != malloc_tsd_no_cleanup) { \ malloc_tsd_cleanup_register( \ &a_name##tsd_cleanup_wrapper); \ @@ -194,96 +192,88 @@ a_name##tsd_boot0(void) \ return (false); \ } \ a_attr void \ -a_name##tsd_boot1(void) \ -{ \ +a_name##tsd_boot1(void) { \ /* Do nothing. */ \ } \ a_attr bool \ -a_name##tsd_boot(void) \ -{ \ +a_name##tsd_boot(void) { \ return (a_name##tsd_boot0()); \ } \ a_attr bool \ -a_name##tsd_booted_get(void) \ -{ \ +a_name##tsd_booted_get(void) { \ return (a_name##tsd_booted); \ } \ a_attr bool \ -a_name##tsd_get_allocates(void) \ -{ \ +a_name##tsd_get_allocates(void) { \ return (false); \ } \ /* Get/set. */ \ a_attr a_type * \ -a_name##tsd_get(bool init) \ -{ \ +a_name##tsd_get(bool init) { \ assert(a_name##tsd_booted); \ return (&a_name##tsd_tls); \ } \ a_attr void \ -a_name##tsd_set(a_type *val) \ -{ \ +a_name##tsd_set(a_type *val) { \ assert(a_name##tsd_booted); \ - if (likely(&a_name##tsd_tls != val)) \ + if (likely(&a_name##tsd_tls != val)) { \ a_name##tsd_tls = (*val); \ - if (a_cleanup != malloc_tsd_no_cleanup) \ + } \ + if (a_cleanup != malloc_tsd_no_cleanup) { \ a_name##tsd_initialized = true; \ + } \ } #elif (defined(JEMALLOC_TLS)) #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ a_cleanup) \ /* Initialization/cleanup. */ \ a_attr bool \ -a_name##tsd_boot0(void) \ -{ \ +a_name##tsd_boot0(void) { \ if (a_cleanup != malloc_tsd_no_cleanup) { \ if (pthread_key_create(&a_name##tsd_tsd, a_cleanup) != \ - 0) \ + 0) { \ return (true); \ + } \ } \ a_name##tsd_booted = true; \ return (false); \ } \ a_attr void \ -a_name##tsd_boot1(void) \ -{ \ +a_name##tsd_boot1(void) { \ /* Do nothing. */ \ } \ a_attr bool \ -a_name##tsd_boot(void) \ -{ \ +a_name##tsd_boot(void) { \ return (a_name##tsd_boot0()); \ } \ a_attr bool \ -a_name##tsd_booted_get(void) \ -{ \ +a_name##tsd_booted_get(void) { \ return (a_name##tsd_booted); \ } \ a_attr bool \ -a_name##tsd_get_allocates(void) \ -{ \ +a_name##tsd_get_allocates(void) { \ return (false); \ } \ /* Get/set. */ \ a_attr a_type * \ -a_name##tsd_get(bool init) \ -{ \ +a_name##tsd_get(bool init) { \ assert(a_name##tsd_booted); \ return (&a_name##tsd_tls); \ } \ a_attr void \ -a_name##tsd_set(a_type *val) \ -{ \ +a_name##tsd_set(a_type *val) { \ assert(a_name##tsd_booted); \ - if (likely(&a_name##tsd_tls != val)) \ + if (likely(&a_name##tsd_tls != val)) { \ a_name##tsd_tls = (*val); \ + } \ if (a_cleanup != malloc_tsd_no_cleanup) { \ if (pthread_setspecific(a_name##tsd_tsd, \ (void *)(&a_name##tsd_tls))) { \ malloc_write(": Error" \ " setting TSD for "#a_name"\n"); \ - if (opt_abort) \ + if (opt_abort) { \ abort(); \ + } \ } \ } \ } @@ -292,15 +282,15 @@ a_name##tsd_set(a_type *val) \ a_cleanup) \ /* Initialization/cleanup. */ \ a_attr bool \ -a_name##tsd_cleanup_wrapper(void) \ -{ \ +a_name##tsd_cleanup_wrapper(void) { \ DWORD error = GetLastError(); \ a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ TlsGetValue(a_name##tsd_tsd); \ SetLastError(error); \ \ - if (wrapper == NULL) \ + if (wrapper == NULL) { \ return (false); \ + } \ if (a_cleanup != malloc_tsd_no_cleanup && \ wrapper->initialized) { \ wrapper->initialized = false; \ @@ -314,8 +304,7 @@ a_name##tsd_cleanup_wrapper(void) \ return (false); \ } \ a_attr void \ -a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \ -{ \ +a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) { \ if (!TlsSetValue(a_name##tsd_tsd, (void *)wrapper)) { \ malloc_write(": Error setting" \ " TSD for "#a_name"\n"); \ @@ -323,8 +312,7 @@ a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \ } \ } \ a_attr a_name##tsd_wrapper_t * \ -a_name##tsd_wrapper_get(bool init) \ -{ \ +a_name##tsd_wrapper_get(bool init) { \ DWORD error = GetLastError(); \ a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ TlsGetValue(a_name##tsd_tsd); \ @@ -346,11 +334,11 @@ a_name##tsd_wrapper_get(bool init) \ return (wrapper); \ } \ a_attr bool \ -a_name##tsd_boot0(void) \ -{ \ +a_name##tsd_boot0(void) { \ a_name##tsd_tsd = TlsAlloc(); \ - if (a_name##tsd_tsd == TLS_OUT_OF_INDEXES) \ + if (a_name##tsd_tsd == TLS_OUT_OF_INDEXES) { \ return (true); \ + } \ if (a_cleanup != malloc_tsd_no_cleanup) { \ malloc_tsd_cleanup_register( \ &a_name##tsd_cleanup_wrapper); \ @@ -360,8 +348,7 @@ a_name##tsd_boot0(void) \ return (false); \ } \ a_attr void \ -a_name##tsd_boot1(void) \ -{ \ +a_name##tsd_boot1(void) { \ a_name##tsd_wrapper_t *wrapper; \ wrapper = (a_name##tsd_wrapper_t *) \ malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ @@ -375,54 +362,52 @@ a_name##tsd_boot1(void) \ a_name##tsd_wrapper_set(wrapper); \ } \ a_attr bool \ -a_name##tsd_boot(void) \ -{ \ - if (a_name##tsd_boot0()) \ +a_name##tsd_boot(void) { \ + if (a_name##tsd_boot0()) { \ return (true); \ + } \ a_name##tsd_boot1(); \ return (false); \ } \ a_attr bool \ -a_name##tsd_booted_get(void) \ -{ \ +a_name##tsd_booted_get(void) { \ return (a_name##tsd_booted); \ } \ a_attr bool \ -a_name##tsd_get_allocates(void) \ -{ \ +a_name##tsd_get_allocates(void) { \ return (true); \ } \ /* Get/set. */ \ a_attr a_type * \ -a_name##tsd_get(bool init) \ -{ \ +a_name##tsd_get(bool init) { \ a_name##tsd_wrapper_t *wrapper; \ \ assert(a_name##tsd_booted); \ wrapper = a_name##tsd_wrapper_get(init); \ - if (a_name##tsd_get_allocates() && !init && wrapper == NULL) \ + if (a_name##tsd_get_allocates() && !init && wrapper == NULL) { \ return (NULL); \ + } \ return (&wrapper->val); \ } \ a_attr void \ -a_name##tsd_set(a_type *val) \ -{ \ +a_name##tsd_set(a_type *val) { \ a_name##tsd_wrapper_t *wrapper; \ \ assert(a_name##tsd_booted); \ wrapper = a_name##tsd_wrapper_get(true); \ - if (likely(&wrapper->val != val)) \ + if (likely(&wrapper->val != val)) { \ wrapper->val = *(val); \ - if (a_cleanup != malloc_tsd_no_cleanup) \ + } \ + if (a_cleanup != malloc_tsd_no_cleanup) { \ wrapper->initialized = true; \ + } \ } #else #define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ a_cleanup) \ /* Initialization/cleanup. */ \ a_attr void \ -a_name##tsd_cleanup_wrapper(void *arg) \ -{ \ +a_name##tsd_cleanup_wrapper(void *arg) { \ a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *)arg; \ \ if (a_cleanup != malloc_tsd_no_cleanup && \ @@ -435,8 +420,9 @@ a_name##tsd_cleanup_wrapper(void *arg) \ (void *)wrapper)) { \ malloc_write(": Error" \ " setting TSD for "#a_name"\n"); \ - if (opt_abort) \ + if (opt_abort) { \ abort(); \ + } \ } \ return; \ } \ @@ -444,8 +430,7 @@ a_name##tsd_cleanup_wrapper(void *arg) \ malloc_tsd_dalloc(wrapper); \ } \ a_attr void \ -a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \ -{ \ +a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) { \ if (pthread_setspecific(a_name##tsd_tsd, \ (void *)wrapper)) { \ malloc_write(": Error setting" \ @@ -454,8 +439,7 @@ a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) \ } \ } \ a_attr a_name##tsd_wrapper_t * \ -a_name##tsd_wrapper_get(bool init) \ -{ \ +a_name##tsd_wrapper_get(bool init) { \ a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ pthread_getspecific(a_name##tsd_tsd); \ \ @@ -464,8 +448,9 @@ a_name##tsd_wrapper_get(bool init) \ wrapper = (a_name##tsd_wrapper_t *) \ tsd_init_check_recursion(&a_name##tsd_init_head, \ &block); \ - if (wrapper) \ - return (wrapper); \ + if (wrapper) { \ + return (wrapper); \ + } \ wrapper = (a_name##tsd_wrapper_t *) \ malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ block.data = (void *)wrapper; \ @@ -483,18 +468,17 @@ a_name##tsd_wrapper_get(bool init) \ return (wrapper); \ } \ a_attr bool \ -a_name##tsd_boot0(void) \ -{ \ +a_name##tsd_boot0(void) { \ if (pthread_key_create(&a_name##tsd_tsd, \ - a_name##tsd_cleanup_wrapper) != 0) \ + a_name##tsd_cleanup_wrapper) != 0) { \ return (true); \ + } \ a_name##tsd_wrapper_set(&a_name##tsd_boot_wrapper); \ a_name##tsd_booted = true; \ return (false); \ } \ a_attr void \ -a_name##tsd_boot1(void) \ -{ \ +a_name##tsd_boot1(void) { \ a_name##tsd_wrapper_t *wrapper; \ wrapper = (a_name##tsd_wrapper_t *) \ malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ @@ -508,46 +492,45 @@ a_name##tsd_boot1(void) \ a_name##tsd_wrapper_set(wrapper); \ } \ a_attr bool \ -a_name##tsd_boot(void) \ -{ \ - if (a_name##tsd_boot0()) \ +a_name##tsd_boot(void) { \ + if (a_name##tsd_boot0()) { \ return (true); \ + } \ a_name##tsd_boot1(); \ return (false); \ } \ a_attr bool \ -a_name##tsd_booted_get(void) \ -{ \ +a_name##tsd_booted_get(void) { \ return (a_name##tsd_booted); \ } \ a_attr bool \ -a_name##tsd_get_allocates(void) \ -{ \ +a_name##tsd_get_allocates(void) { \ return (true); \ } \ /* Get/set. */ \ a_attr a_type * \ -a_name##tsd_get(bool init) \ -{ \ +a_name##tsd_get(bool init) { \ a_name##tsd_wrapper_t *wrapper; \ \ assert(a_name##tsd_booted); \ wrapper = a_name##tsd_wrapper_get(init); \ - if (a_name##tsd_get_allocates() && !init && wrapper == NULL) \ + if (a_name##tsd_get_allocates() && !init && wrapper == NULL) { \ return (NULL); \ + } \ return (&wrapper->val); \ } \ a_attr void \ -a_name##tsd_set(a_type *val) \ -{ \ +a_name##tsd_set(a_type *val) { \ a_name##tsd_wrapper_t *wrapper; \ \ assert(a_name##tsd_booted); \ wrapper = a_name##tsd_wrapper_get(true); \ - if (likely(&wrapper->val != val)) \ + if (likely(&wrapper->val != val)) { \ wrapper->val = *(val); \ - if (a_cleanup != malloc_tsd_no_cleanup) \ + } \ + if (a_cleanup != malloc_tsd_no_cleanup) { \ wrapper->initialized = true; \ + } \ } #endif diff --git a/include/jemalloc/internal/util_inlines.h b/include/jemalloc/internal/util_inlines.h index 4ceed06b..271673ae 100644 --- a/include/jemalloc/internal/util_inlines.h +++ b/include/jemalloc/internal/util_inlines.h @@ -25,26 +25,22 @@ int get_errno(void); #endif JEMALLOC_ALWAYS_INLINE unsigned -ffs_llu(unsigned long long bitmap) -{ +ffs_llu(unsigned long long bitmap) { return (JEMALLOC_INTERNAL_FFSLL(bitmap)); } JEMALLOC_ALWAYS_INLINE unsigned -ffs_lu(unsigned long bitmap) -{ +ffs_lu(unsigned long bitmap) { return (JEMALLOC_INTERNAL_FFSL(bitmap)); } JEMALLOC_ALWAYS_INLINE unsigned -ffs_u(unsigned bitmap) -{ +ffs_u(unsigned bitmap) { return (JEMALLOC_INTERNAL_FFS(bitmap)); } JEMALLOC_ALWAYS_INLINE unsigned -ffs_zu(size_t bitmap) -{ +ffs_zu(size_t bitmap) { #if LG_SIZEOF_PTR == LG_SIZEOF_INT return (ffs_u(bitmap)); #elif LG_SIZEOF_PTR == LG_SIZEOF_LONG @@ -57,8 +53,7 @@ ffs_zu(size_t bitmap) } JEMALLOC_ALWAYS_INLINE unsigned -ffs_u64(uint64_t bitmap) -{ +ffs_u64(uint64_t bitmap) { #if LG_SIZEOF_LONG == 3 return (ffs_lu(bitmap)); #elif LG_SIZEOF_LONG_LONG == 3 @@ -69,8 +64,7 @@ ffs_u64(uint64_t bitmap) } JEMALLOC_ALWAYS_INLINE unsigned -ffs_u32(uint32_t bitmap) -{ +ffs_u32(uint32_t bitmap) { #if LG_SIZEOF_INT == 2 return (ffs_u(bitmap)); #else @@ -80,8 +74,7 @@ ffs_u32(uint32_t bitmap) } JEMALLOC_INLINE uint64_t -pow2_ceil_u64(uint64_t x) -{ +pow2_ceil_u64(uint64_t x) { x--; x |= x >> 1; x |= x >> 2; @@ -94,8 +87,7 @@ pow2_ceil_u64(uint64_t x) } JEMALLOC_INLINE uint32_t -pow2_ceil_u32(uint32_t x) -{ +pow2_ceil_u32(uint32_t x) { x--; x |= x >> 1; x |= x >> 2; @@ -108,8 +100,7 @@ pow2_ceil_u32(uint32_t x) /* Compute the smallest power of 2 that is >= x. */ JEMALLOC_INLINE size_t -pow2_ceil_zu(size_t x) -{ +pow2_ceil_zu(size_t x) { #if (LG_SIZEOF_PTR == 3) return (pow2_ceil_u64(x)); #else @@ -119,8 +110,7 @@ pow2_ceil_zu(size_t x) #if (defined(__i386__) || defined(__amd64__) || defined(__x86_64__)) JEMALLOC_INLINE unsigned -lg_floor(size_t x) -{ +lg_floor(size_t x) { size_t ret; assert(x != 0); @@ -134,8 +124,7 @@ lg_floor(size_t x) } #elif (defined(_MSC_VER)) JEMALLOC_INLINE unsigned -lg_floor(size_t x) -{ +lg_floor(size_t x) { unsigned long ret; assert(x != 0); @@ -152,8 +141,7 @@ lg_floor(size_t x) } #elif (defined(JEMALLOC_HAVE_BUILTIN_CLZ)) JEMALLOC_INLINE unsigned -lg_floor(size_t x) -{ +lg_floor(size_t x) { assert(x != 0); #if (LG_SIZEOF_PTR == LG_SIZEOF_INT) @@ -166,8 +154,7 @@ lg_floor(size_t x) } #else JEMALLOC_INLINE unsigned -lg_floor(size_t x) -{ +lg_floor(size_t x) { assert(x != 0); x |= (x >> 1); @@ -178,8 +165,9 @@ lg_floor(size_t x) #if (LG_SIZEOF_PTR == 3) x |= (x >> 32); #endif - if (x == SIZE_T_MAX) + if (x == SIZE_T_MAX) { return ((8 << LG_SIZEOF_PTR) - 1); + } x++; return (ffs_zu(x) - 2); } @@ -187,8 +175,7 @@ lg_floor(size_t x) /* Set error code. */ JEMALLOC_INLINE void -set_errno(int errnum) -{ +set_errno(int errnum) { #ifdef _WIN32 SetLastError(errnum); #else @@ -198,8 +185,7 @@ set_errno(int errnum) /* Get last error code. */ JEMALLOC_INLINE int -get_errno(void) -{ +get_errno(void) { #ifdef _WIN32 return (GetLastError()); #else diff --git a/include/jemalloc/internal/util_types.h b/include/jemalloc/internal/util_types.h index 7f727993..4fe206bc 100644 --- a/include/jemalloc/internal/util_types.h +++ b/include/jemalloc/internal/util_types.h @@ -87,8 +87,9 @@ /* Use to assert a particular configuration, e.g., cassert(config_debug). */ #define cassert(c) do { \ - if (unlikely(!(c))) \ + if (unlikely(!(c))) { \ not_reached(); \ + } \ } while (0) #endif /* JEMALLOC_INTERNAL_UTIL_TYPES_H */ diff --git a/include/jemalloc/internal/witness_inlines.h b/include/jemalloc/internal/witness_inlines.h index 259aa2e5..2e5ebccc 100644 --- a/include/jemalloc/internal/witness_inlines.h +++ b/include/jemalloc/internal/witness_inlines.h @@ -13,8 +13,7 @@ void witness_unlock(tsdn_t *tsdn, witness_t *witness); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) /* Helper, not intended for direct use. */ JEMALLOC_INLINE bool -witness_owner(tsd_t *tsd, const witness_t *witness) -{ +witness_owner(tsd_t *tsd, const witness_t *witness) { witness_list_t *witnesses; witness_t *w; @@ -22,90 +21,101 @@ witness_owner(tsd_t *tsd, const witness_t *witness) witnesses = tsd_witnessesp_get(tsd); ql_foreach(w, witnesses, link) { - if (w == witness) + if (w == witness) { return (true); + } } return (false); } JEMALLOC_INLINE void -witness_assert_owner(tsdn_t *tsdn, const witness_t *witness) -{ +witness_assert_owner(tsdn_t *tsdn, const witness_t *witness) { tsd_t *tsd; - if (!config_debug) + if (!config_debug) { return; + } - if (tsdn_null(tsdn)) + if (tsdn_null(tsdn)) { return; + } tsd = tsdn_tsd(tsdn); - if (witness->rank == WITNESS_RANK_OMIT) + if (witness->rank == WITNESS_RANK_OMIT) { return; + } - if (witness_owner(tsd, witness)) + if (witness_owner(tsd, witness)) { return; + } witness_owner_error(witness); } JEMALLOC_INLINE void -witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness) -{ +witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness) { tsd_t *tsd; witness_list_t *witnesses; witness_t *w; - if (!config_debug) + if (!config_debug) { return; + } - if (tsdn_null(tsdn)) + if (tsdn_null(tsdn)) { return; + } tsd = tsdn_tsd(tsdn); - if (witness->rank == WITNESS_RANK_OMIT) + if (witness->rank == WITNESS_RANK_OMIT) { return; + } witnesses = tsd_witnessesp_get(tsd); ql_foreach(w, witnesses, link) { - if (w == witness) + if (w == witness) { witness_not_owner_error(witness); + } } } JEMALLOC_INLINE void -witness_assert_lockless(tsdn_t *tsdn) -{ +witness_assert_lockless(tsdn_t *tsdn) { tsd_t *tsd; witness_list_t *witnesses; witness_t *w; - if (!config_debug) + if (!config_debug) { return; + } - if (tsdn_null(tsdn)) + if (tsdn_null(tsdn)) { return; + } tsd = tsdn_tsd(tsdn); witnesses = tsd_witnessesp_get(tsd); w = ql_last(witnesses, link); - if (w != NULL) + if (w != NULL) { witness_lockless_error(witnesses); + } } JEMALLOC_INLINE void -witness_lock(tsdn_t *tsdn, witness_t *witness) -{ +witness_lock(tsdn_t *tsdn, witness_t *witness) { tsd_t *tsd; witness_list_t *witnesses; witness_t *w; - if (!config_debug) + if (!config_debug) { return; + } - if (tsdn_null(tsdn)) + if (tsdn_null(tsdn)) { return; + } tsd = tsdn_tsd(tsdn); - if (witness->rank == WITNESS_RANK_OMIT) + if (witness->rank == WITNESS_RANK_OMIT) { return; + } witness_assert_not_owner(tsdn, witness); @@ -133,19 +143,21 @@ witness_lock(tsdn_t *tsdn, witness_t *witness) } JEMALLOC_INLINE void -witness_unlock(tsdn_t *tsdn, witness_t *witness) -{ +witness_unlock(tsdn_t *tsdn, witness_t *witness) { tsd_t *tsd; witness_list_t *witnesses; - if (!config_debug) + if (!config_debug) { return; + } - if (tsdn_null(tsdn)) + if (tsdn_null(tsdn)) { return; + } tsd = tsdn_tsd(tsdn); - if (witness->rank == WITNESS_RANK_OMIT) + if (witness->rank == WITNESS_RANK_OMIT) { return; + } /* * Check whether owner before removal, rather than relying on @@ -155,8 +167,9 @@ witness_unlock(tsdn_t *tsdn, witness_t *witness) if (witness_owner(tsd, witness)) { witnesses = tsd_witnessesp_get(tsd); ql_remove(witnesses, witness, link); - } else + } else { witness_assert_owner(tsdn, witness); + } } #endif diff --git a/include/msvc_compat/strings.h b/include/msvc_compat/strings.h index 47998be2..971b36d4 100644 --- a/include/msvc_compat/strings.h +++ b/include/msvc_compat/strings.h @@ -6,17 +6,16 @@ #ifdef _MSC_VER # include # pragma intrinsic(_BitScanForward) -static __forceinline int ffsl(long x) -{ +static __forceinline int ffsl(long x) { unsigned long i; - if (_BitScanForward(&i, x)) + if (_BitScanForward(&i, x)) { return (i + 1); + } return (0); } -static __forceinline int ffs(int x) -{ +static __forceinline int ffs(int x) { return (ffsl(x)); } @@ -24,12 +23,12 @@ static __forceinline int ffs(int x) # pragma intrinsic(_BitScanForward64) # endif -static __forceinline int ffsll(unsigned __int64 x) -{ +static __forceinline int ffsll(unsigned __int64 x) { unsigned long i; #ifdef _M_X64 - if (_BitScanForward64(&i, x)) + if (_BitScanForward64(&i, x)) { return (i + 1); + } return (0); #else // Fallback for 32-bit build where 64-bit version not available @@ -41,10 +40,11 @@ static __forceinline int ffsll(unsigned __int64 x) s.ll = x; - if (_BitScanForward(&i, s.l[0])) + if (_BitScanForward(&i, s.l[0])) { return (i + 1); - else if(_BitScanForward(&i, s.l[1])) + } else if(_BitScanForward(&i, s.l[1])) { return (i + 33); + } return (0); #endif } diff --git a/msvc/projects/vc2015/test_threads/test_threads.cpp b/msvc/projects/vc2015/test_threads/test_threads.cpp index a3d1a792..92e31624 100644 --- a/msvc/projects/vc2015/test_threads/test_threads.cpp +++ b/msvc/projects/vc2015/test_threads/test_threads.cpp @@ -16,8 +16,7 @@ using std::thread; using std::uniform_int_distribution; using std::minstd_rand; -int test_threads() -{ +int test_threads() { je_malloc_conf = "narenas:3"; int narenas = 0; size_t sz = sizeof(narenas); diff --git a/msvc/projects/vc2015/test_threads/test_threads_main.cpp b/msvc/projects/vc2015/test_threads/test_threads_main.cpp index ffd96e6a..0a022fba 100644 --- a/msvc/projects/vc2015/test_threads/test_threads_main.cpp +++ b/msvc/projects/vc2015/test_threads/test_threads_main.cpp @@ -5,8 +5,7 @@ using namespace std::chrono_literals; -int main(int argc, char** argv) -{ +int main(int argc, char** argv) { int rc = test_threads(); return rc; } diff --git a/src/arena.c b/src/arena.c index 7362c4e6..5cf9bd07 100644 --- a/src/arena.c +++ b/src/arena.c @@ -38,16 +38,14 @@ static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, /******************************************************************************/ static size_t -arena_extent_dirty_npages(const extent_t *extent) -{ +arena_extent_dirty_npages(const extent_t *extent) { return (extent_size_get(extent) >> LG_PAGE); } static extent_t * arena_extent_cache_alloc_locked(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool slab) -{ + size_t alignment, bool *zero, bool slab) { bool commit = true; malloc_mutex_assert_owner(tsdn, &arena->lock); @@ -59,8 +57,7 @@ arena_extent_cache_alloc_locked(tsdn_t *tsdn, arena_t *arena, extent_t * arena_extent_cache_alloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, - size_t alignment, bool *zero) -{ + size_t alignment, bool *zero) { extent_t *extent; malloc_mutex_lock(tsdn, &arena->lock); @@ -73,8 +70,7 @@ arena_extent_cache_alloc(tsdn_t *tsdn, arena_t *arena, static void arena_extent_cache_dalloc_locked(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent) -{ + extent_hooks_t **r_extent_hooks, extent_t *extent) { malloc_mutex_assert_owner(tsdn, &arena->lock); extent_dalloc_cache(tsdn, arena, r_extent_hooks, extent); @@ -83,8 +79,7 @@ arena_extent_cache_dalloc_locked(tsdn_t *tsdn, arena_t *arena, void arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent) -{ + extent_hooks_t **r_extent_hooks, extent_t *extent) { malloc_mutex_lock(tsdn, &arena->lock); arena_extent_cache_dalloc_locked(tsdn, arena, r_extent_hooks, extent); malloc_mutex_unlock(tsdn, &arena->lock); @@ -92,8 +87,7 @@ arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, void arena_extent_cache_maybe_insert(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - bool cache) -{ + bool cache) { malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); if (cache) { @@ -104,8 +98,7 @@ arena_extent_cache_maybe_insert(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void arena_extent_cache_maybe_remove(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - bool dirty) -{ + bool dirty) { malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); if (dirty) { @@ -117,8 +110,7 @@ arena_extent_cache_maybe_remove(tsdn_t *tsdn, arena_t *arena, extent_t *extent, JEMALLOC_INLINE_C void * arena_slab_reg_alloc(tsdn_t *tsdn, extent_t *slab, - const arena_bin_info_t *bin_info) -{ + const arena_bin_info_t *bin_info) { void *ret; arena_slab_data_t *slab_data = extent_slab_data_get(slab); size_t regind; @@ -137,8 +129,7 @@ arena_slab_reg_alloc(tsdn_t *tsdn, extent_t *slab, JEMALLOC_INLINE_C #endif size_t -arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr) -{ +arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr) { size_t diff, regind; /* Freeing a pointer outside the slab can cause assertion failure. */ @@ -174,8 +165,7 @@ arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr) JEMALLOC_INLINE_C void arena_slab_reg_dalloc(tsdn_t *tsdn, extent_t *slab, - arena_slab_data_t *slab_data, void *ptr) -{ + arena_slab_data_t *slab_data, void *ptr) { szind_t binind = slab_data->binind; const arena_bin_info_t *bin_info = &arena_bin_info[binind]; size_t regind = arena_slab_regind(slab, binind, ptr); @@ -189,27 +179,25 @@ arena_slab_reg_dalloc(tsdn_t *tsdn, extent_t *slab, } static void -arena_nactive_add(arena_t *arena, size_t add_pages) -{ +arena_nactive_add(arena_t *arena, size_t add_pages) { arena->nactive += add_pages; } static void -arena_nactive_sub(arena_t *arena, size_t sub_pages) -{ +arena_nactive_sub(arena_t *arena, size_t sub_pages) { assert(arena->nactive >= sub_pages); arena->nactive -= sub_pages; } static void -arena_large_malloc_stats_update(arena_t *arena, size_t usize) -{ +arena_large_malloc_stats_update(arena_t *arena, size_t usize) { szind_t index, hindex; cassert(config_stats); - if (usize < LARGE_MINCLASS) + if (usize < LARGE_MINCLASS) { usize = LARGE_MINCLASS; + } index = size2index(usize); hindex = (index >= NBINS) ? index - NBINS : 0; @@ -221,14 +209,14 @@ arena_large_malloc_stats_update(arena_t *arena, size_t usize) } static void -arena_large_malloc_stats_update_undo(arena_t *arena, size_t usize) -{ +arena_large_malloc_stats_update_undo(arena_t *arena, size_t usize) { szind_t index, hindex; cassert(config_stats); - if (usize < LARGE_MINCLASS) + if (usize < LARGE_MINCLASS) { usize = LARGE_MINCLASS; + } index = size2index(usize); hindex = (index >= NBINS) ? index - NBINS : 0; @@ -240,14 +228,14 @@ arena_large_malloc_stats_update_undo(arena_t *arena, size_t usize) } static void -arena_large_dalloc_stats_update(arena_t *arena, size_t usize) -{ +arena_large_dalloc_stats_update(arena_t *arena, size_t usize) { szind_t index, hindex; cassert(config_stats); - if (usize < LARGE_MINCLASS) + if (usize < LARGE_MINCLASS) { usize = LARGE_MINCLASS; + } index = size2index(usize); hindex = (index >= NBINS) ? index - NBINS : 0; @@ -258,8 +246,7 @@ arena_large_dalloc_stats_update(arena_t *arena, size_t usize) } static void -arena_large_reset_stats_cancel(arena_t *arena, size_t usize) -{ +arena_large_reset_stats_cancel(arena_t *arena, size_t usize) { szind_t index = size2index(usize); szind_t hindex = (index >= NBINS) ? index - NBINS : 0; @@ -270,16 +257,15 @@ arena_large_reset_stats_cancel(arena_t *arena, size_t usize) } static void -arena_large_ralloc_stats_update(arena_t *arena, size_t oldusize, size_t usize) -{ +arena_large_ralloc_stats_update(arena_t *arena, size_t oldusize, size_t usize) { arena_large_dalloc_stats_update(arena, oldusize); arena_large_malloc_stats_update(arena, usize); } static extent_t * arena_extent_alloc_large_hard(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, size_t usize, size_t alignment, bool *zero) -{ + extent_hooks_t **r_extent_hooks, size_t usize, size_t alignment, + bool *zero) { extent_t *extent; bool commit = true; @@ -301,8 +287,7 @@ arena_extent_alloc_large_hard(tsdn_t *tsdn, arena_t *arena, extent_t * arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, - size_t alignment, bool *zero) -{ + size_t alignment, bool *zero) { extent_t *extent; extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; @@ -328,14 +313,14 @@ arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, void arena_extent_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - bool locked) -{ + bool locked) { extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; - if (!locked) + if (!locked) { malloc_mutex_lock(tsdn, &arena->lock); - else + } else { malloc_mutex_assert_owner(tsdn, &arena->lock); + } if (config_stats) { arena_large_dalloc_stats_update(arena, extent_usize_get(extent)); @@ -344,14 +329,14 @@ arena_extent_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, arena_nactive_sub(arena, extent_size_get(extent) >> LG_PAGE); arena_extent_cache_dalloc_locked(tsdn, arena, &extent_hooks, extent); - if (!locked) + if (!locked) { malloc_mutex_unlock(tsdn, &arena->lock); + } } void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - size_t oldusize) -{ + size_t oldusize) { size_t usize = extent_usize_get(extent); size_t udiff = oldusize - usize; @@ -366,8 +351,7 @@ arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - size_t oldusize) -{ + size_t oldusize) { size_t usize = extent_usize_get(extent); size_t udiff = usize - oldusize; @@ -381,8 +365,7 @@ arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, } static void -arena_decay_deadline_init(arena_t *arena) -{ +arena_decay_deadline_init(arena_t *arena) { /* * Generate a new deadline that is uniformly random within the next * epoch after the current one. @@ -399,14 +382,12 @@ arena_decay_deadline_init(arena_t *arena) } static bool -arena_decay_deadline_reached(const arena_t *arena, const nstime_t *time) -{ +arena_decay_deadline_reached(const arena_t *arena, const nstime_t *time) { return (nstime_compare(&arena->decay.deadline, time) <= 0); } static size_t -arena_decay_backlog_npages_limit(const arena_t *arena) -{ +arena_decay_backlog_npages_limit(const arena_t *arena) { static const uint64_t h_steps[] = { #define STEP(step, h, x, y) \ h, @@ -423,24 +404,23 @@ arena_decay_backlog_npages_limit(const arena_t *arena) * to round down to the nearest whole number of pages. */ sum = 0; - for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) + for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) { sum += arena->decay.backlog[i] * h_steps[i]; + } npages_limit_backlog = (size_t)(sum >> SMOOTHSTEP_BFP); return (npages_limit_backlog); } static void -arena_decay_backlog_update_last(arena_t *arena) -{ +arena_decay_backlog_update_last(arena_t *arena) { size_t ndirty_delta = (arena->ndirty > arena->decay.nunpurged) ? arena->ndirty - arena->decay.nunpurged : 0; arena->decay.backlog[SMOOTHSTEP_NSTEPS-1] = ndirty_delta; } static void -arena_decay_backlog_update(arena_t *arena, uint64_t nadvance_u64) -{ +arena_decay_backlog_update(arena_t *arena, uint64_t nadvance_u64) { if (nadvance_u64 >= SMOOTHSTEP_NSTEPS) { memset(arena->decay.backlog, 0, (SMOOTHSTEP_NSTEPS-1) * sizeof(size_t)); @@ -461,8 +441,7 @@ arena_decay_backlog_update(arena_t *arena, uint64_t nadvance_u64) } static void -arena_decay_epoch_advance_helper(arena_t *arena, const nstime_t *time) -{ +arena_decay_epoch_advance_helper(arena_t *arena, const nstime_t *time) { uint64_t nadvance_u64; nstime_t delta; @@ -486,25 +465,23 @@ arena_decay_epoch_advance_helper(arena_t *arena, const nstime_t *time) } static void -arena_decay_epoch_advance_purge(tsdn_t *tsdn, arena_t *arena) -{ +arena_decay_epoch_advance_purge(tsdn_t *tsdn, arena_t *arena) { size_t ndirty_limit = arena_decay_backlog_npages_limit(arena); - if (arena->ndirty > ndirty_limit) + if (arena->ndirty > ndirty_limit) { arena_purge_to_limit(tsdn, arena, ndirty_limit); + } arena->decay.nunpurged = arena->ndirty; } static void -arena_decay_epoch_advance(tsdn_t *tsdn, arena_t *arena, const nstime_t *time) -{ +arena_decay_epoch_advance(tsdn_t *tsdn, arena_t *arena, const nstime_t *time) { arena_decay_epoch_advance_helper(arena, time); arena_decay_epoch_advance_purge(tsdn, arena); } static void -arena_decay_init(arena_t *arena, ssize_t decay_time) -{ +arena_decay_init(arena_t *arena, ssize_t decay_time) { arena->decay.time = decay_time; if (decay_time > 0) { nstime_init2(&arena->decay.interval, decay_time, 0); @@ -520,18 +497,18 @@ arena_decay_init(arena_t *arena, ssize_t decay_time) } static bool -arena_decay_time_valid(ssize_t decay_time) -{ - if (decay_time < -1) +arena_decay_time_valid(ssize_t decay_time) { + if (decay_time < -1) { return (false); - if (decay_time == -1 || (uint64_t)decay_time <= NSTIME_SEC_MAX) + } + if (decay_time == -1 || (uint64_t)decay_time <= NSTIME_SEC_MAX) { return (true); + } return (false); } ssize_t -arena_decay_time_get(tsdn_t *tsdn, arena_t *arena) -{ +arena_decay_time_get(tsdn_t *tsdn, arena_t *arena) { ssize_t decay_time; malloc_mutex_lock(tsdn, &arena->lock); @@ -542,10 +519,10 @@ arena_decay_time_get(tsdn_t *tsdn, arena_t *arena) } bool -arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) -{ - if (!arena_decay_time_valid(decay_time)) +arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { + if (!arena_decay_time_valid(decay_time)) { return (true); + } malloc_mutex_lock(tsdn, &arena->lock); /* @@ -564,14 +541,14 @@ arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) } static void -arena_maybe_purge_helper(tsdn_t *tsdn, arena_t *arena) -{ +arena_maybe_purge_helper(tsdn_t *tsdn, arena_t *arena) { nstime_t time; /* Purge all or nothing if the option is disabled. */ if (arena->decay.time <= 0) { - if (arena->decay.time == 0) + if (arena->decay.time == 0) { arena_purge_to_limit(tsdn, arena, 0); + } return; } @@ -601,33 +578,34 @@ arena_maybe_purge_helper(tsdn_t *tsdn, arena_t *arena) * during the current epoch are not subject to purge until a future * epoch, so as a result purging only happens during epoch advances. */ - if (arena_decay_deadline_reached(arena, &time)) + if (arena_decay_deadline_reached(arena, &time)) { arena_decay_epoch_advance(tsdn, arena, &time); + } } void -arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) -{ +arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_assert_owner(tsdn, &arena->lock); /* Don't recursively purge. */ - if (arena->purging) + if (arena->purging) { return; + } arena_maybe_purge_helper(tsdn, arena); } static size_t -arena_dirty_count(tsdn_t *tsdn, arena_t *arena) -{ +arena_dirty_count(tsdn_t *tsdn, arena_t *arena) { extent_t *extent; size_t ndirty = 0; malloc_mutex_lock(tsdn, &arena->extents_mtx); for (extent = qr_next(&arena->extents_dirty, qr_link); extent != - &arena->extents_dirty; extent = qr_next(extent, qr_link)) + &arena->extents_dirty; extent = qr_next(extent, qr_link)) { ndirty += extent_size_get(extent) >> LG_PAGE; + } malloc_mutex_unlock(tsdn, &arena->extents_mtx); @@ -636,8 +614,7 @@ arena_dirty_count(tsdn_t *tsdn, arena_t *arena) static size_t arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - size_t ndirty_limit, extent_t *purge_extents_sentinel) -{ + size_t ndirty_limit, extent_t *purge_extents_sentinel) { extent_t *extent, *next; size_t nstashed = 0; @@ -651,8 +628,9 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, UNUSED extent_t *textent; npages = extent_size_get(extent) >> LG_PAGE; - if (arena->ndirty - (nstashed + npages) < ndirty_limit) + if (arena->ndirty - (nstashed + npages) < ndirty_limit) { break; + } next = qr_next(extent, qr_link); /* Allocate. */ @@ -675,20 +653,21 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, static size_t arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *purge_extents_sentinel) -{ + extent_hooks_t **r_extent_hooks, extent_t *purge_extents_sentinel) { UNUSED size_t nmadvise; size_t npurged; extent_t *extent, *next; - if (config_stats) + if (config_stats) { nmadvise = 0; + } npurged = 0; for (extent = qr_next(purge_extents_sentinel, qr_link); extent != purge_extents_sentinel; extent = next) { - if (config_stats) + if (config_stats) { nmadvise++; + } npurged += extent_size_get(extent) >> LG_PAGE; next = qr_next(extent, qr_link); @@ -709,8 +688,7 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, * invariant: (arena->ndirty >= ndirty_limit) */ static void -arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) -{ +arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) { extent_hooks_t *extent_hooks = extent_hooks_get(arena); size_t npurge, npurged; extent_t purge_extents_sentinel; @@ -730,33 +708,34 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) npurge = arena_stash_dirty(tsdn, arena, &extent_hooks, ndirty_limit, &purge_extents_sentinel); - if (npurge == 0) + if (npurge == 0) { goto label_return; + } npurged = arena_purge_stashed(tsdn, arena, &extent_hooks, &purge_extents_sentinel); assert(npurged == npurge); - if (config_stats) + if (config_stats) { arena->stats.npurge++; + } label_return: arena->purging = false; } void -arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) -{ +arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) { malloc_mutex_lock(tsdn, &arena->lock); - if (all) + if (all) { arena_purge_to_limit(tsdn, arena, 0); - else + } else { arena_maybe_purge(tsdn, arena); + } malloc_mutex_unlock(tsdn, &arena->lock); } static void -arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) -{ +arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) { extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; arena_nactive_sub(arena, extent_size_get(slab) >> LG_PAGE); @@ -764,45 +743,41 @@ arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) } static void -arena_bin_slabs_nonfull_insert(arena_bin_t *bin, extent_t *slab) -{ +arena_bin_slabs_nonfull_insert(arena_bin_t *bin, extent_t *slab) { assert(extent_slab_data_get(slab)->nfree > 0); extent_heap_insert(&bin->slabs_nonfull, slab); } static void -arena_bin_slabs_nonfull_remove(arena_bin_t *bin, extent_t *slab) -{ +arena_bin_slabs_nonfull_remove(arena_bin_t *bin, extent_t *slab) { extent_heap_remove(&bin->slabs_nonfull, slab); } static extent_t * -arena_bin_slabs_nonfull_tryget(arena_bin_t *bin) -{ +arena_bin_slabs_nonfull_tryget(arena_bin_t *bin) { extent_t *slab = extent_heap_remove_first(&bin->slabs_nonfull); - if (slab == NULL) + if (slab == NULL) { return (NULL); - if (config_stats) + } + if (config_stats) { bin->stats.reslabs++; + } return (slab); } static void -arena_bin_slabs_full_insert(arena_bin_t *bin, extent_t *slab) -{ +arena_bin_slabs_full_insert(arena_bin_t *bin, extent_t *slab) { assert(extent_slab_data_get(slab)->nfree == 0); extent_ring_insert(&bin->slabs_full, slab); } static void -arena_bin_slabs_full_remove(extent_t *slab) -{ +arena_bin_slabs_full_remove(extent_t *slab) { extent_ring_remove(slab); } void -arena_reset(tsd_t *tsd, arena_t *arena) -{ +arena_reset(tsd_t *tsd, arena_t *arena) { unsigned i; extent_t *extent; @@ -828,16 +803,19 @@ arena_reset(tsd_t *tsd, arena_t *arena) size_t usize; malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx); - if (config_stats || (config_prof && opt_prof)) + if (config_stats || (config_prof && opt_prof)) { usize = isalloc(tsd_tsdn(tsd), extent, ptr); + } /* Remove large allocation from prof sample set. */ - if (config_prof && opt_prof) + if (config_prof && opt_prof) { prof_free(tsd, extent, ptr, usize); + } large_dalloc(tsd_tsdn(tsd), extent); malloc_mutex_lock(tsd_tsdn(tsd), &arena->large_mtx); /* Cancel out unwanted effects on stats. */ - if (config_stats) + if (config_stats) { arena_large_reset_stats_cancel(arena, usize); + } } malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx); @@ -883,8 +861,7 @@ arena_reset(tsd_t *tsd, arena_t *arena) } static void -arena_destroy_retained(tsdn_t *tsdn, arena_t *arena) -{ +arena_destroy_retained(tsdn_t *tsdn, arena_t *arena) { extent_hooks_t *extent_hooks = extent_hooks_get(arena); size_t i; @@ -912,8 +889,7 @@ arena_destroy_retained(tsdn_t *tsdn, arena_t *arena) } void -arena_destroy(tsd_t *tsd, arena_t *arena) -{ +arena_destroy(tsd_t *tsd, arena_t *arena) { assert(base_ind_get(arena->base) >= narenas_auto); assert(arena_nthreads_get(arena, false) == 0); assert(arena_nthreads_get(arena, true) == 0); @@ -949,8 +925,7 @@ arena_destroy(tsd_t *tsd, arena_t *arena) static extent_t * arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, const arena_bin_info_t *bin_info) -{ + extent_hooks_t **r_extent_hooks, const arena_bin_info_t *bin_info) { extent_t *slab; bool zero, commit; @@ -966,8 +941,7 @@ arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, static extent_t * arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, - const arena_bin_info_t *bin_info) -{ + const arena_bin_info_t *bin_info) { extent_t *slab; arena_slab_data_t *slab_data; extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; @@ -978,8 +952,9 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, if (slab == NULL) { slab = arena_slab_alloc_hard(tsdn, arena, &extent_hooks, bin_info); - if (slab == NULL) + if (slab == NULL) { return (NULL); + } } assert(extent_slab_get(slab)); @@ -991,23 +966,24 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, slab_data->nfree = bin_info->nregs; bitmap_init(slab_data->bitmap, &bin_info->bitmap_info); - if (config_stats) + if (config_stats) { arena->stats.mapped += extent_size_get(slab); + } return (slab); } static extent_t * arena_bin_nonfull_slab_get(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, - szind_t binind) -{ + szind_t binind) { extent_t *slab; const arena_bin_info_t *bin_info; /* Look for a usable slab. */ slab = arena_bin_slabs_nonfull_tryget(bin); - if (slab != NULL) + if (slab != NULL) { return (slab); + } /* No existing slabs have any space available. */ bin_info = &arena_bin_info[binind]; @@ -1034,8 +1010,9 @@ arena_bin_nonfull_slab_get(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, * so search one more time. */ slab = arena_bin_slabs_nonfull_tryget(bin); - if (slab != NULL) + if (slab != NULL) { return (slab); + } return (NULL); } @@ -1043,8 +1020,7 @@ arena_bin_nonfull_slab_get(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, /* Re-fill bin->slabcur, then call arena_slab_reg_alloc(). */ static void * arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, - szind_t binind) -{ + szind_t binind) { const arena_bin_info_t *bin_info; extent_t *slab; @@ -1088,8 +1064,9 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, bin->slabcur = NULL; } - if (slab == NULL) + if (slab == NULL) { return (NULL); + } bin->slabcur = slab; assert(extent_slab_data_get(bin->slabcur)->nfree > 0); @@ -1099,15 +1076,15 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_bin_t *tbin, - szind_t binind, uint64_t prof_accumbytes) -{ + szind_t binind, uint64_t prof_accumbytes) { unsigned i, nfill; arena_bin_t *bin; assert(tbin->ncached == 0); - if (config_prof && arena_prof_accum(tsdn, arena, prof_accumbytes)) + if (config_prof && arena_prof_accum(tsdn, arena, prof_accumbytes)) { prof_idump(tsdn); + } bin = &arena->bins[binind]; malloc_mutex_lock(tsdn, &bin->lock); for (i = 0, nfill = (tcache_bin_info[binind].ncached_max >> @@ -1118,8 +1095,9 @@ arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_bin_t *tbin, extent_slab_data_get(slab)->nfree > 0) { ptr = arena_slab_reg_alloc(tsdn, slab, &arena_bin_info[binind]); - } else + } else { ptr = arena_bin_malloc_hard(tsdn, arena, bin, binind); + } if (ptr == NULL) { /* * OOM. tbin->avail isn't yet filled down to its first @@ -1152,10 +1130,10 @@ arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_bin_t *tbin, } void -arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, bool zero) -{ - if (!zero) +arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, bool zero) { + if (!zero) { memset(ptr, JEMALLOC_ALLOC_JUNK, bin_info->reg_size); + } } #ifdef JEMALLOC_JET @@ -1163,8 +1141,7 @@ arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, bool zero) #define arena_dalloc_junk_small JEMALLOC_N(n_arena_dalloc_junk_small) #endif void -arena_dalloc_junk_small(void *ptr, const arena_bin_info_t *bin_info) -{ +arena_dalloc_junk_small(void *ptr, const arena_bin_info_t *bin_info) { memset(ptr, JEMALLOC_FREE_JUNK, bin_info->reg_size); } #ifdef JEMALLOC_JET @@ -1175,8 +1152,7 @@ arena_dalloc_junk_small_t *arena_dalloc_junk_small = #endif static void * -arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) -{ +arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) { void *ret; arena_bin_t *bin; size_t usize; @@ -1188,10 +1164,11 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) malloc_mutex_lock(tsdn, &bin->lock); if ((slab = bin->slabcur) != NULL && extent_slab_data_get(slab)->nfree > - 0) + 0) { ret = arena_slab_reg_alloc(tsdn, slab, &arena_bin_info[binind]); - else + } else { ret = arena_bin_malloc_hard(tsdn, arena, bin, binind); + } if (ret == NULL) { malloc_mutex_unlock(tsdn, &bin->lock); @@ -1204,16 +1181,18 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) bin->stats.curregs++; } malloc_mutex_unlock(tsdn, &bin->lock); - if (config_prof && arena_prof_accum(tsdn, arena, usize)) + if (config_prof && arena_prof_accum(tsdn, arena, usize)) { prof_idump(tsdn); + } if (!zero) { if (config_fill) { if (unlikely(opt_junk_alloc)) { arena_alloc_junk_small(ret, &arena_bin_info[binind], false); - } else if (unlikely(opt_zero)) + } else if (unlikely(opt_zero)) { memset(ret, 0, usize); + } } } else { if (config_fill && unlikely(opt_junk_alloc)) { @@ -1229,24 +1208,25 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) void * arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, - bool zero) -{ + bool zero) { assert(!tsdn_null(tsdn) || arena != NULL); - if (likely(!tsdn_null(tsdn))) + if (likely(!tsdn_null(tsdn))) { arena = arena_choose(tsdn_tsd(tsdn), arena); - if (unlikely(arena == NULL)) + } + if (unlikely(arena == NULL)) { return (NULL); + } - if (likely(size <= SMALL_MAXCLASS)) + if (likely(size <= SMALL_MAXCLASS)) { return (arena_malloc_small(tsdn, arena, ind, zero)); + } return (large_malloc(tsdn, arena, index2size(ind), zero)); } void * arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, - bool zero, tcache_t *tcache) -{ + bool zero, tcache_t *tcache) { void *ret; if (usize <= SMALL_MAXCLASS && (alignment < PAGE || (alignment == PAGE @@ -1255,18 +1235,18 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, ret = arena_malloc(tsdn, arena, usize, size2index(usize), zero, tcache, true); } else { - if (likely(alignment <= CACHELINE)) + if (likely(alignment <= CACHELINE)) { ret = large_malloc(tsdn, arena, usize, zero); - else + } else { ret = large_palloc(tsdn, arena, usize, alignment, zero); + } } return (ret); } void arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize) -{ + size_t usize) { arena_t *arena = extent_arena_get(extent); cassert(config_prof); @@ -1283,18 +1263,18 @@ arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, * canceling. */ malloc_mutex_lock(tsdn, &arena->lock); - if (arena->prof_accumbytes >= LARGE_MINCLASS - usize) + if (arena->prof_accumbytes >= LARGE_MINCLASS - usize) { arena->prof_accumbytes -= LARGE_MINCLASS - usize; - else + } else { arena->prof_accumbytes = 0; + } malloc_mutex_unlock(tsdn, &arena->lock); assert(isalloc(tsdn, extent, ptr) == usize); } static size_t -arena_prof_demote(tsdn_t *tsdn, extent_t *extent, const void *ptr) -{ +arena_prof_demote(tsdn_t *tsdn, extent_t *extent, const void *ptr) { cassert(config_prof); assert(ptr != NULL); @@ -1307,8 +1287,7 @@ arena_prof_demote(tsdn_t *tsdn, extent_t *extent, const void *ptr) void arena_dalloc_promoted(tsdn_t *tsdn, extent_t *extent, void *ptr, - tcache_t *tcache, bool slow_path) -{ + tcache_t *tcache, bool slow_path) { size_t usize; cassert(config_prof); @@ -1318,17 +1297,17 @@ arena_dalloc_promoted(tsdn_t *tsdn, extent_t *extent, void *ptr, if (usize <= tcache_maxclass) { tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, usize, slow_path); - } else + } else { large_dalloc(tsdn, extent); + } } static void -arena_dissociate_bin_slab(extent_t *slab, arena_bin_t *bin) -{ +arena_dissociate_bin_slab(extent_t *slab, arena_bin_t *bin) { /* Dissociate slab from bin. */ - if (slab == bin->slabcur) + if (slab == bin->slabcur) { bin->slabcur = NULL; - else { + } else { szind_t binind = extent_slab_data_get(slab)->binind; const arena_bin_info_t *bin_info = &arena_bin_info[binind]; @@ -1337,17 +1316,17 @@ arena_dissociate_bin_slab(extent_t *slab, arena_bin_t *bin) * slab only contains one region, then it never gets inserted * into the non-full slabs heap. */ - if (bin_info->nregs == 1) + if (bin_info->nregs == 1) { arena_bin_slabs_full_remove(slab); - else + } else { arena_bin_slabs_nonfull_remove(bin, slab); + } } } static void arena_dalloc_bin_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, - arena_bin_t *bin) -{ + arena_bin_t *bin) { assert(slab != bin->slabcur); malloc_mutex_unlock(tsdn, &bin->lock); @@ -1357,14 +1336,14 @@ arena_dalloc_bin_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, malloc_mutex_unlock(tsdn, &arena->lock); /****************************/ malloc_mutex_lock(tsdn, &bin->lock); - if (config_stats) + if (config_stats) { bin->stats.curslabs--; + } } static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, - arena_bin_t *bin) -{ + arena_bin_t *bin) { assert(extent_slab_data_get(slab)->nfree > 0); /* @@ -1375,28 +1354,31 @@ arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, */ if (bin->slabcur != NULL && extent_snad_comp(bin->slabcur, slab) > 0) { /* Switch slabcur. */ - if (extent_slab_data_get(bin->slabcur)->nfree > 0) + if (extent_slab_data_get(bin->slabcur)->nfree > 0) { arena_bin_slabs_nonfull_insert(bin, bin->slabcur); - else + } else { arena_bin_slabs_full_insert(bin, bin->slabcur); + } bin->slabcur = slab; - if (config_stats) + if (config_stats) { bin->stats.reslabs++; - } else + } + } else { arena_bin_slabs_nonfull_insert(bin, slab); + } } static void arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, extent_t *slab, - void *ptr, bool junked) -{ + void *ptr, bool junked) { arena_slab_data_t *slab_data = extent_slab_data_get(slab); szind_t binind = slab_data->binind; arena_bin_t *bin = &arena->bins[binind]; const arena_bin_info_t *bin_info = &arena_bin_info[binind]; - if (!junked && config_fill && unlikely(opt_junk_free)) + if (!junked && config_fill && unlikely(opt_junk_free)) { arena_dalloc_junk_small(ptr, bin_info); + } arena_slab_reg_dalloc(tsdn, slab, slab_data, ptr); if (slab_data->nfree == bin_info->nregs) { @@ -1415,14 +1397,12 @@ arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, extent_t *slab, void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - void *ptr) -{ + void *ptr) { arena_dalloc_bin_locked_impl(tsdn, arena, extent, ptr, true); } static void -arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) -{ +arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) { arena_bin_t *bin = &arena->bins[extent_slab_data_get(extent)->binind]; malloc_mutex_lock(tsdn, &bin->lock); @@ -1431,23 +1411,22 @@ arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) } void -arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) -{ +arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) { arena_dalloc_bin(tsdn, arena, extent, ptr); arena_decay_tick(tsdn, arena); } bool arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, - size_t size, size_t extra, bool zero) -{ + size_t size, size_t extra, bool zero) { size_t usize_min, usize_max; /* Calls with non-zero extra had to clamp extra. */ assert(extra == 0 || size + extra <= LARGE_MAXCLASS); - if (unlikely(size > LARGE_MAXCLASS)) + if (unlikely(size > LARGE_MAXCLASS)) { return (true); + } usize_min = s2u(size); usize_max = s2u(size + extra); @@ -1460,8 +1439,9 @@ arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, oldsize); if ((usize_max > SMALL_MAXCLASS || size2index(usize_max) != size2index(oldsize)) && (size > oldsize || usize_max < - oldsize)) + oldsize)) { return (true); + } arena_decay_tick(tsdn, extent_arena_get(extent)); return (false); @@ -1475,33 +1455,36 @@ arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, static void * arena_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, - size_t alignment, bool zero, tcache_t *tcache) -{ - if (alignment == 0) + size_t alignment, bool zero, tcache_t *tcache) { + if (alignment == 0) { return (arena_malloc(tsdn, arena, usize, size2index(usize), zero, tcache, true)); + } usize = sa2u(usize, alignment); - if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { return (NULL); + } return (ipalloct(tsdn, usize, alignment, zero, tcache, arena)); } void * arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, - size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache) -{ + size_t oldsize, size_t size, size_t alignment, bool zero, + tcache_t *tcache) { void *ret; size_t usize, copysize; usize = s2u(size); - if (unlikely(usize == 0 || size > LARGE_MAXCLASS)) + if (unlikely(usize == 0 || size > LARGE_MAXCLASS)) { return (NULL); + } if (likely(usize <= SMALL_MAXCLASS)) { /* Try to avoid moving the allocation. */ if (!arena_ralloc_no_move(tsdn, extent, ptr, oldsize, usize, 0, - zero)) + zero)) { return (ptr); + } } if (oldsize >= LARGE_MINCLASS && usize >= LARGE_MINCLASS) { @@ -1515,8 +1498,9 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, */ ret = arena_ralloc_move_helper(tsdn, arena, usize, alignment, zero, tcache); - if (ret == NULL) + if (ret == NULL) { return (NULL); + } /* * Junk/zero-filling were already done by @@ -1530,8 +1514,7 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, } dss_prec_t -arena_dss_prec_get(tsdn_t *tsdn, arena_t *arena) -{ +arena_dss_prec_get(tsdn_t *tsdn, arena_t *arena) { dss_prec_t ret; malloc_mutex_lock(tsdn, &arena->lock); @@ -1541,10 +1524,10 @@ arena_dss_prec_get(tsdn_t *tsdn, arena_t *arena) } bool -arena_dss_prec_set(tsdn_t *tsdn, arena_t *arena, dss_prec_t dss_prec) -{ - if (!have_dss) +arena_dss_prec_set(tsdn_t *tsdn, arena_t *arena, dss_prec_t dss_prec) { + if (!have_dss) { return (dss_prec != dss_prec_disabled); + } malloc_mutex_lock(tsdn, &arena->lock); arena->dss_prec = dss_prec; malloc_mutex_unlock(tsdn, &arena->lock); @@ -1552,24 +1535,22 @@ arena_dss_prec_set(tsdn_t *tsdn, arena_t *arena, dss_prec_t dss_prec) } ssize_t -arena_decay_time_default_get(void) -{ +arena_decay_time_default_get(void) { return ((ssize_t)atomic_read_zu((size_t *)&decay_time_default)); } bool -arena_decay_time_default_set(ssize_t decay_time) -{ - if (!arena_decay_time_valid(decay_time)) +arena_decay_time_default_set(ssize_t decay_time) { + if (!arena_decay_time_valid(decay_time)) { return (true); + } atomic_write_zu((size_t *)&decay_time_default, (size_t)decay_time); return (false); } static void arena_basic_stats_merge_locked(arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) -{ + const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) { *nthreads += arena_nthreads_get(arena, false); *dss = dss_prec_names[arena->dss_prec]; *decay_time = arena->decay.time; @@ -1579,8 +1560,7 @@ arena_basic_stats_merge_locked(arena_t *arena, unsigned *nthreads, void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) -{ + const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) { malloc_mutex_lock(tsdn, &arena->lock); arena_basic_stats_merge_locked(arena, nthreads, dss, decay_time, nactive, ndirty); @@ -1591,8 +1571,7 @@ void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty, arena_stats_t *astats, malloc_bin_stats_t *bstats, - malloc_large_stats_t *lstats) -{ + malloc_large_stats_t *lstats) { size_t base_allocated, base_resident, base_mapped; unsigned i; @@ -1662,57 +1641,57 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, } unsigned -arena_nthreads_get(arena_t *arena, bool internal) -{ +arena_nthreads_get(arena_t *arena, bool internal) { return (atomic_read_u(&arena->nthreads[internal])); } void -arena_nthreads_inc(arena_t *arena, bool internal) -{ +arena_nthreads_inc(arena_t *arena, bool internal) { atomic_add_u(&arena->nthreads[internal], 1); } void -arena_nthreads_dec(arena_t *arena, bool internal) -{ +arena_nthreads_dec(arena_t *arena, bool internal) { atomic_sub_u(&arena->nthreads[internal], 1); } size_t -arena_extent_sn_next(arena_t *arena) -{ +arena_extent_sn_next(arena_t *arena) { return (atomic_add_zu(&arena->extent_sn_next, 1) - 1); } arena_t * -arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) -{ +arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena_t *arena; base_t *base; unsigned i; - if (ind == 0) + if (ind == 0) { base = b0get(); - else { + } else { base = base_new(tsdn, ind, extent_hooks); - if (base == NULL) + if (base == NULL) { return (NULL); + } } arena = (arena_t *)base_alloc(tsdn, base, sizeof(arena_t), CACHELINE); - if (arena == NULL) + if (arena == NULL) { goto label_error; + } arena->nthreads[0] = arena->nthreads[1] = 0; - if (malloc_mutex_init(&arena->lock, "arena", WITNESS_RANK_ARENA)) + if (malloc_mutex_init(&arena->lock, "arena", WITNESS_RANK_ARENA)) { goto label_error; + } - if (config_stats && config_tcache) + if (config_stats && config_tcache) { ql_new(&arena->tcache_ql); + } - if (config_prof) + if (config_prof) { arena->prof_accumbytes = 0; + } if (config_cache_oblivious) { /* @@ -1738,8 +1717,9 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) ql_new(&arena->large); if (malloc_mutex_init(&arena->large_mtx, "arena_large", - WITNESS_RANK_ARENA_LARGE)) + WITNESS_RANK_ARENA_LARGE)) { goto label_error; + } for (i = 0; i < NPSIZES+1; i++) { extent_heap_new(&arena->extents_cached[i]); @@ -1750,83 +1730,85 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) false, false); if (malloc_mutex_init(&arena->extents_mtx, "arena_extents", - WITNESS_RANK_ARENA_EXTENTS)) + WITNESS_RANK_ARENA_EXTENTS)) { goto label_error; + } - if (!config_munmap) + if (!config_munmap) { arena->extent_grow_next = psz2ind(HUGEPAGE); + } ql_new(&arena->extent_cache); if (malloc_mutex_init(&arena->extent_cache_mtx, "arena_extent_cache", - WITNESS_RANK_ARENA_EXTENT_CACHE)) + WITNESS_RANK_ARENA_EXTENT_CACHE)) { goto label_error; + } /* Initialize bins. */ for (i = 0; i < NBINS; i++) { arena_bin_t *bin = &arena->bins[i]; if (malloc_mutex_init(&bin->lock, "arena_bin", - WITNESS_RANK_ARENA_BIN)) + WITNESS_RANK_ARENA_BIN)) { goto label_error; + } bin->slabcur = NULL; extent_heap_new(&bin->slabs_nonfull); extent_init(&bin->slabs_full, arena, NULL, 0, 0, 0, false, false, false, false); - if (config_stats) + if (config_stats) { memset(&bin->stats, 0, sizeof(malloc_bin_stats_t)); + } } arena->base = base; return (arena); label_error: - if (ind != 0) + if (ind != 0) { base_delete(base); + } return (NULL); } void -arena_boot(void) -{ +arena_boot(void) { arena_decay_time_default_set(opt_decay_time); } void -arena_prefork0(tsdn_t *tsdn, arena_t *arena) -{ +arena_prefork0(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_prefork(tsdn, &arena->lock); } void -arena_prefork1(tsdn_t *tsdn, arena_t *arena) -{ +arena_prefork1(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_prefork(tsdn, &arena->extents_mtx); } void -arena_prefork2(tsdn_t *tsdn, arena_t *arena) -{ +arena_prefork2(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_prefork(tsdn, &arena->extent_cache_mtx); } void -arena_prefork3(tsdn_t *tsdn, arena_t *arena) -{ +arena_prefork3(tsdn_t *tsdn, arena_t *arena) { unsigned i; base_prefork(tsdn, arena->base); - for (i = 0; i < NBINS; i++) + for (i = 0; i < NBINS; i++) { malloc_mutex_prefork(tsdn, &arena->bins[i].lock); + } malloc_mutex_prefork(tsdn, &arena->large_mtx); } void -arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) -{ +arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) { unsigned i; malloc_mutex_postfork_parent(tsdn, &arena->large_mtx); - for (i = 0; i < NBINS; i++) + for (i = 0; i < NBINS; i++) { malloc_mutex_postfork_parent(tsdn, &arena->bins[i].lock); + } base_postfork_parent(tsdn, arena->base); malloc_mutex_postfork_parent(tsdn, &arena->extent_cache_mtx); malloc_mutex_postfork_parent(tsdn, &arena->extents_mtx); @@ -1834,13 +1816,13 @@ arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) } void -arena_postfork_child(tsdn_t *tsdn, arena_t *arena) -{ +arena_postfork_child(tsdn_t *tsdn, arena_t *arena) { unsigned i; malloc_mutex_postfork_child(tsdn, &arena->large_mtx); - for (i = 0; i < NBINS; i++) + for (i = 0; i < NBINS; i++) { malloc_mutex_postfork_child(tsdn, &arena->bins[i].lock); + } base_postfork_child(tsdn, arena->base); malloc_mutex_postfork_child(tsdn, &arena->extent_cache_mtx); malloc_mutex_postfork_child(tsdn, &arena->extents_mtx); diff --git a/src/base.c b/src/base.c index 7c0ef2c1..ee964faa 100644 --- a/src/base.c +++ b/src/base.c @@ -9,17 +9,16 @@ static base_t *b0; /******************************************************************************/ static void * -base_map(extent_hooks_t *extent_hooks, unsigned ind, size_t size) -{ +base_map(extent_hooks_t *extent_hooks, unsigned ind, size_t size) { void *addr; bool zero = true; bool commit = true; assert(size == HUGEPAGE_CEILING(size)); - if (extent_hooks == &extent_hooks_default) + if (extent_hooks == &extent_hooks_default) { addr = extent_alloc_mmap(NULL, size, PAGE, &zero, &commit); - else { + } else { addr = extent_hooks->alloc(extent_hooks, NULL, size, PAGE, &zero, &commit, ind); } @@ -28,8 +27,8 @@ base_map(extent_hooks_t *extent_hooks, unsigned ind, size_t size) } static void -base_unmap(extent_hooks_t *extent_hooks, unsigned ind, void *addr, size_t size) -{ +base_unmap(extent_hooks_t *extent_hooks, unsigned ind, void *addr, + size_t size) { /* * Cascade through dalloc, decommit, purge_lazy, and purge_forced, * stopping at first success. This cascade is performed for consistency @@ -41,40 +40,48 @@ base_unmap(extent_hooks_t *extent_hooks, unsigned ind, void *addr, size_t size) * some consistent-but-allocated state. */ if (extent_hooks == &extent_hooks_default) { - if (!extent_dalloc_mmap(addr, size)) + if (!extent_dalloc_mmap(addr, size)) { return; - if (!pages_decommit(addr, size)) + } + if (!pages_decommit(addr, size)) { return; - if (!pages_purge_lazy(addr, size)) + } + if (!pages_purge_lazy(addr, size)) { return; - if (!pages_purge_forced(addr, size)) + } + if (!pages_purge_forced(addr, size)) { return; + } /* Nothing worked. This should never happen. */ not_reached(); } else { if (extent_hooks->dalloc != NULL && - !extent_hooks->dalloc(extent_hooks, addr, size, true, ind)) + !extent_hooks->dalloc(extent_hooks, addr, size, true, + ind)) { return; + } if (extent_hooks->decommit != NULL && !extent_hooks->decommit(extent_hooks, addr, size, 0, size, - ind)) + ind)) { return; + } if (extent_hooks->purge_lazy != NULL && !extent_hooks->purge_lazy(extent_hooks, addr, size, 0, size, - ind)) + ind)) { return; + } if (extent_hooks->purge_forced != NULL && !extent_hooks->purge_forced(extent_hooks, addr, size, 0, - size, ind)) + size, ind)) { return; + } /* Nothing worked. That's the application's problem. */ } } static void base_extent_init(size_t *extent_sn_next, extent_t *extent, void *addr, - size_t size) -{ + size_t size) { size_t sn; sn = *extent_sn_next; @@ -85,8 +92,7 @@ base_extent_init(size_t *extent_sn_next, extent_t *extent, void *addr, static void * base_extent_bump_alloc_helper(extent_t *extent, size_t *gap_size, size_t size, - size_t alignment) -{ + size_t alignment) { void *ret; assert(alignment == ALIGNMENT_CEILING(alignment, QUANTUM)); @@ -104,8 +110,7 @@ base_extent_bump_alloc_helper(extent_t *extent, size_t *gap_size, size_t size, static void base_extent_bump_alloc_post(tsdn_t *tsdn, base_t *base, extent_t *extent, - size_t gap_size, void *addr, size_t size) -{ + size_t gap_size, void *addr, size_t size) { if (extent_size_get(extent) > 0) { /* * Compute the index for the largest size class that does not @@ -131,8 +136,7 @@ base_extent_bump_alloc_post(tsdn_t *tsdn, base_t *base, extent_t *extent, static void * base_extent_bump_alloc(tsdn_t *tsdn, base_t *base, extent_t *extent, - size_t size, size_t alignment) -{ + size_t size, size_t alignment) { void *ret; size_t gap_size; @@ -148,8 +152,7 @@ base_extent_bump_alloc(tsdn_t *tsdn, base_t *base, extent_t *extent, */ static base_block_t * base_block_alloc(extent_hooks_t *extent_hooks, unsigned ind, - size_t *extent_sn_next, size_t size, size_t alignment) -{ + size_t *extent_sn_next, size_t size, size_t alignment) { base_block_t *block; size_t usize, header_size, gap_size, block_size; @@ -159,8 +162,9 @@ base_block_alloc(extent_hooks_t *extent_hooks, unsigned ind, gap_size = ALIGNMENT_CEILING(header_size, alignment) - header_size; block_size = HUGEPAGE_CEILING(header_size + gap_size + usize); block = (base_block_t *)base_map(extent_hooks, ind, block_size); - if (block == NULL) + if (block == NULL) { return (NULL); + } block->size = block_size; block->next = NULL; assert(block_size >= header_size); @@ -174,8 +178,7 @@ base_block_alloc(extent_hooks_t *extent_hooks, unsigned ind, * specified alignment. */ static extent_t * -base_extent_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) -{ +base_extent_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) { extent_hooks_t *extent_hooks = base_extent_hooks_get(base); base_block_t *block; @@ -183,8 +186,9 @@ base_extent_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) block = base_block_alloc(extent_hooks, base_ind_get(base), &base->extent_sn_next, size, alignment); - if (block == NULL) + if (block == NULL) { return (NULL); + } block->next = base->blocks; base->blocks = block; if (config_stats) { @@ -198,14 +202,12 @@ base_extent_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) } base_t * -b0get(void) -{ +b0get(void) { return (b0); } base_t * -base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) -{ +base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { base_t *base; size_t extent_sn_next, base_alignment, base_size, gap_size; base_block_t *block; @@ -214,8 +216,9 @@ base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) extent_sn_next = 0; block = base_block_alloc(extent_hooks, ind, &extent_sn_next, sizeof(base_t), QUANTUM); - if (block == NULL) + if (block == NULL) { return (NULL); + } base_alignment = CACHELINE; base_size = ALIGNMENT_CEILING(sizeof(base_t), base_alignment); @@ -229,8 +232,9 @@ base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) } base->extent_sn_next = extent_sn_next; base->blocks = block; - for (i = 0; i < NSIZES; i++) + for (i = 0; i < NSIZES; i++) { extent_heap_new(&base->avail[i]); + } if (config_stats) { base->allocated = sizeof(base_block_t); base->resident = PAGE_CEILING(sizeof(base_block_t)); @@ -245,8 +249,7 @@ base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) } void -base_delete(base_t *base) -{ +base_delete(base_t *base) { extent_hooks_t *extent_hooks = base_extent_hooks_get(base); base_block_t *next = base->blocks; do { @@ -258,14 +261,12 @@ base_delete(base_t *base) } extent_hooks_t * -base_extent_hooks_get(base_t *base) -{ +base_extent_hooks_get(base_t *base) { return ((extent_hooks_t *)atomic_read_p(&base->extent_hooks_pun)); } extent_hooks_t * -base_extent_hooks_set(base_t *base, extent_hooks_t *extent_hooks) -{ +base_extent_hooks_set(base_t *base, extent_hooks_t *extent_hooks) { extent_hooks_t *old_extent_hooks = base_extent_hooks_get(base); union { extent_hooks_t **h; @@ -287,8 +288,7 @@ base_extent_hooks_set(base_t *base, extent_hooks_t *extent_hooks) * sharing. */ void * -base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) -{ +base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) { void *ret; size_t usize, asize; szind_t i; @@ -324,8 +324,7 @@ label_return: void base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated, size_t *resident, - size_t *mapped) -{ + size_t *mapped) { cassert(config_stats); malloc_mutex_lock(tsdn, &base->mtx); @@ -338,26 +337,22 @@ base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated, size_t *resident, } void -base_prefork(tsdn_t *tsdn, base_t *base) -{ +base_prefork(tsdn_t *tsdn, base_t *base) { malloc_mutex_prefork(tsdn, &base->mtx); } void -base_postfork_parent(tsdn_t *tsdn, base_t *base) -{ +base_postfork_parent(tsdn_t *tsdn, base_t *base) { malloc_mutex_postfork_parent(tsdn, &base->mtx); } void -base_postfork_child(tsdn_t *tsdn, base_t *base) -{ +base_postfork_child(tsdn_t *tsdn, base_t *base) { malloc_mutex_postfork_child(tsdn, &base->mtx); } bool -base_boot(tsdn_t *tsdn) -{ +base_boot(tsdn_t *tsdn) { b0 = base_new(tsdn, 0, (extent_hooks_t *)&extent_hooks_default); return (b0 == NULL); } diff --git a/src/bitmap.c b/src/bitmap.c index 3d27f059..7cbc7d45 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -6,8 +6,7 @@ #ifdef BITMAP_USE_TREE void -bitmap_info_init(bitmap_info_t *binfo, size_t nbits) -{ +bitmap_info_init(bitmap_info_t *binfo, size_t nbits) { unsigned i; size_t group_count; @@ -35,14 +34,12 @@ bitmap_info_init(bitmap_info_t *binfo, size_t nbits) } static size_t -bitmap_info_ngroups(const bitmap_info_t *binfo) -{ +bitmap_info_ngroups(const bitmap_info_t *binfo) { return (binfo->levels[binfo->nlevels].group_offset); } void -bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo) -{ +bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo) { size_t extra; unsigned i; @@ -56,23 +53,24 @@ bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo) memset(bitmap, 0xffU, bitmap_size(binfo)); extra = (BITMAP_GROUP_NBITS - (binfo->nbits & BITMAP_GROUP_NBITS_MASK)) & BITMAP_GROUP_NBITS_MASK; - if (extra != 0) + if (extra != 0) { bitmap[binfo->levels[1].group_offset - 1] >>= extra; + } for (i = 1; i < binfo->nlevels; i++) { size_t group_count = binfo->levels[i].group_offset - binfo->levels[i-1].group_offset; extra = (BITMAP_GROUP_NBITS - (group_count & BITMAP_GROUP_NBITS_MASK)) & BITMAP_GROUP_NBITS_MASK; - if (extra != 0) + if (extra != 0) { bitmap[binfo->levels[i+1].group_offset - 1] >>= extra; + } } } #else /* BITMAP_USE_TREE */ void -bitmap_info_init(bitmap_info_t *binfo, size_t nbits) -{ +bitmap_info_init(bitmap_info_t *binfo, size_t nbits) { assert(nbits > 0); assert(nbits <= (ZU(1) << LG_BITMAP_MAXBITS)); @@ -81,27 +79,25 @@ bitmap_info_init(bitmap_info_t *binfo, size_t nbits) } static size_t -bitmap_info_ngroups(const bitmap_info_t *binfo) -{ +bitmap_info_ngroups(const bitmap_info_t *binfo) { return (binfo->ngroups); } void -bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo) -{ +bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo) { size_t extra; memset(bitmap, 0xffU, bitmap_size(binfo)); extra = (BITMAP_GROUP_NBITS - (binfo->nbits & BITMAP_GROUP_NBITS_MASK)) & BITMAP_GROUP_NBITS_MASK; - if (extra != 0) + if (extra != 0) { bitmap[binfo->ngroups - 1] >>= extra; + } } #endif /* BITMAP_USE_TREE */ size_t -bitmap_size(const bitmap_info_t *binfo) -{ +bitmap_size(const bitmap_info_t *binfo) { return (bitmap_info_ngroups(binfo) << LG_SIZEOF_BITMAP); } diff --git a/src/ckh.c b/src/ckh.c index fe79862c..0deaf809 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -50,15 +50,15 @@ static void ckh_shrink(tsd_t *tsd, ckh_t *ckh); * otherwise. */ JEMALLOC_INLINE_C size_t -ckh_bucket_search(ckh_t *ckh, size_t bucket, const void *key) -{ +ckh_bucket_search(ckh_t *ckh, size_t bucket, const void *key) { ckhc_t *cell; unsigned i; for (i = 0; i < (ZU(1) << LG_CKH_BUCKET_CELLS); i++) { cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + i]; - if (cell->key != NULL && ckh->keycomp(key, cell->key)) + if (cell->key != NULL && ckh->keycomp(key, cell->key)) { return ((bucket << LG_CKH_BUCKET_CELLS) + i); + } } return (SIZE_T_MAX); @@ -68,8 +68,7 @@ ckh_bucket_search(ckh_t *ckh, size_t bucket, const void *key) * Search table for key and return cell number if found; SIZE_T_MAX otherwise. */ JEMALLOC_INLINE_C size_t -ckh_isearch(ckh_t *ckh, const void *key) -{ +ckh_isearch(ckh_t *ckh, const void *key) { size_t hashes[2], bucket, cell; assert(ckh != NULL); @@ -79,8 +78,9 @@ ckh_isearch(ckh_t *ckh, const void *key) /* Search primary bucket. */ bucket = hashes[0] & ((ZU(1) << ckh->lg_curbuckets) - 1); cell = ckh_bucket_search(ckh, bucket, key); - if (cell != SIZE_T_MAX) + if (cell != SIZE_T_MAX) { return (cell); + } /* Search secondary bucket. */ bucket = hashes[1] & ((ZU(1) << ckh->lg_curbuckets) - 1); @@ -90,8 +90,7 @@ ckh_isearch(ckh_t *ckh, const void *key) JEMALLOC_INLINE_C bool ckh_try_bucket_insert(ckh_t *ckh, size_t bucket, const void *key, - const void *data) -{ + const void *data) { ckhc_t *cell; unsigned offset, i; @@ -123,8 +122,7 @@ ckh_try_bucket_insert(ckh_t *ckh, size_t bucket, const void *key, */ JEMALLOC_INLINE_C bool ckh_evict_reloc_insert(ckh_t *ckh, size_t argbucket, void const **argkey, - void const **argdata) -{ + void const **argdata) { const void *key, *data, *tkey, *tdata; ckhc_t *cell; size_t hashes[2], bucket, tbucket; @@ -187,14 +185,14 @@ ckh_evict_reloc_insert(ckh_t *ckh, size_t argbucket, void const **argkey, } bucket = tbucket; - if (!ckh_try_bucket_insert(ckh, bucket, key, data)) + if (!ckh_try_bucket_insert(ckh, bucket, key, data)) { return (false); + } } } JEMALLOC_INLINE_C bool -ckh_try_insert(ckh_t *ckh, void const**argkey, void const**argdata) -{ +ckh_try_insert(ckh_t *ckh, void const**argkey, void const**argdata) { size_t hashes[2], bucket; const void *key = *argkey; const void *data = *argdata; @@ -203,13 +201,15 @@ ckh_try_insert(ckh_t *ckh, void const**argkey, void const**argdata) /* Try to insert in primary bucket. */ bucket = hashes[0] & ((ZU(1) << ckh->lg_curbuckets) - 1); - if (!ckh_try_bucket_insert(ckh, bucket, key, data)) + if (!ckh_try_bucket_insert(ckh, bucket, key, data)) { return (false); + } /* Try to insert in secondary bucket. */ bucket = hashes[1] & ((ZU(1) << ckh->lg_curbuckets) - 1); - if (!ckh_try_bucket_insert(ckh, bucket, key, data)) + if (!ckh_try_bucket_insert(ckh, bucket, key, data)) { return (false); + } /* * Try to find a place for this item via iterative eviction/relocation. @@ -222,8 +222,7 @@ ckh_try_insert(ckh_t *ckh, void const**argkey, void const**argdata) * old table into the new. */ JEMALLOC_INLINE_C bool -ckh_rebuild(ckh_t *ckh, ckhc_t *aTab) -{ +ckh_rebuild(ckh_t *ckh, ckhc_t *aTab) { size_t count, i, nins; const void *key, *data; @@ -245,8 +244,7 @@ ckh_rebuild(ckh_t *ckh, ckhc_t *aTab) } static bool -ckh_grow(tsd_t *tsd, ckh_t *ckh) -{ +ckh_grow(tsd_t *tsd, ckh_t *ckh) { bool ret; ckhc_t *tab, *ttab; unsigned lg_prevbuckets, lg_curcells; @@ -302,8 +300,7 @@ label_return: } static void -ckh_shrink(tsd_t *tsd, ckh_t *ckh) -{ +ckh_shrink(tsd_t *tsd, ckh_t *ckh) { ckhc_t *tab, *ttab; size_t usize; unsigned lg_prevbuckets, lg_curcells; @@ -315,8 +312,9 @@ ckh_shrink(tsd_t *tsd, ckh_t *ckh) lg_prevbuckets = ckh->lg_curbuckets; lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 1; usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); - if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { return; + } tab = (ckhc_t *)ipallocztm(tsd_tsdn(tsd), usize, CACHELINE, true, NULL, true, arena_ichoose(tsd, NULL)); if (tab == NULL) { @@ -353,8 +351,7 @@ ckh_shrink(tsd_t *tsd, ckh_t *ckh) bool ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, - ckh_keycomp_t *keycomp) -{ + ckh_keycomp_t *keycomp) { bool ret; size_t mincells, usize; unsigned lg_mincells; @@ -384,8 +381,9 @@ ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, mincells = ((minitems + (3 - (minitems % 3))) / 3) << 2; for (lg_mincells = LG_CKH_BUCKET_CELLS; (ZU(1) << lg_mincells) < mincells; - lg_mincells++) - ; /* Do nothing. */ + lg_mincells++) { + /* Do nothing. */ + } ckh->lg_minbuckets = lg_mincells - LG_CKH_BUCKET_CELLS; ckh->lg_curbuckets = lg_mincells - LG_CKH_BUCKET_CELLS; ckh->hash = hash; @@ -409,8 +407,7 @@ label_return: } void -ckh_delete(tsd_t *tsd, ckh_t *ckh) -{ +ckh_delete(tsd_t *tsd, ckh_t *ckh) { assert(ckh != NULL); #ifdef CKH_VERBOSE @@ -427,30 +424,31 @@ ckh_delete(tsd_t *tsd, ckh_t *ckh) idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), ckh->tab), ckh->tab, NULL, true, true); - if (config_debug) + if (config_debug) { memset(ckh, JEMALLOC_FREE_JUNK, sizeof(ckh_t)); + } } size_t -ckh_count(ckh_t *ckh) -{ +ckh_count(ckh_t *ckh) { assert(ckh != NULL); return (ckh->count); } bool -ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data) -{ +ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data) { size_t i, ncells; for (i = *tabind, ncells = (ZU(1) << (ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS)); i < ncells; i++) { if (ckh->tab[i].key != NULL) { - if (key != NULL) + if (key != NULL) { *key = (void *)ckh->tab[i].key; - if (data != NULL) + } + if (data != NULL) { *data = (void *)ckh->tab[i].data; + } *tabind = i + 1; return (false); } @@ -460,8 +458,7 @@ ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data) } bool -ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data) -{ +ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data) { bool ret; assert(ckh != NULL); @@ -485,18 +482,19 @@ label_return: bool ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key, - void **data) -{ + void **data) { size_t cell; assert(ckh != NULL); cell = ckh_isearch(ckh, searchkey); if (cell != SIZE_T_MAX) { - if (key != NULL) + if (key != NULL) { *key = (void *)ckh->tab[cell].key; - if (data != NULL) + } + if (data != NULL) { *data = (void *)ckh->tab[cell].data; + } ckh->tab[cell].key = NULL; ckh->tab[cell].data = NULL; /* Not necessary. */ @@ -516,18 +514,19 @@ ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key, } bool -ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data) -{ +ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data) { size_t cell; assert(ckh != NULL); cell = ckh_isearch(ckh, searchkey); if (cell != SIZE_T_MAX) { - if (key != NULL) + if (key != NULL) { *key = (void *)ckh->tab[cell].key; - if (data != NULL) + } + if (data != NULL) { *data = (void *)ckh->tab[cell].data; + } return (false); } @@ -535,14 +534,12 @@ ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data) } void -ckh_string_hash(const void *key, size_t r_hash[2]) -{ +ckh_string_hash(const void *key, size_t r_hash[2]) { hash(key, strlen((const char *)key), 0x94122f33U, r_hash); } bool -ckh_string_keycomp(const void *k1, const void *k2) -{ +ckh_string_keycomp(const void *k1, const void *k2) { assert(k1 != NULL); assert(k2 != NULL); @@ -550,8 +547,7 @@ ckh_string_keycomp(const void *k1, const void *k2) } void -ckh_pointer_hash(const void *key, size_t r_hash[2]) -{ +ckh_pointer_hash(const void *key, size_t r_hash[2]) { union { const void *v; size_t i; @@ -563,7 +559,6 @@ ckh_pointer_hash(const void *key, size_t r_hash[2]) } bool -ckh_pointer_keycomp(const void *k1, const void *k2) -{ +ckh_pointer_keycomp(const void *k1, const void *k2) { return ((k1 == k2) ? true : false); } diff --git a/src/ctl.c b/src/ctl.c index b19c9d31..929176f2 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -17,22 +17,19 @@ static ctl_arenas_t *ctl_arenas; /* Helpers for named and indexed nodes. */ JEMALLOC_INLINE_C const ctl_named_node_t * -ctl_named_node(const ctl_node_t *node) -{ +ctl_named_node(const ctl_node_t *node) { return ((node->named) ? (const ctl_named_node_t *)node : NULL); } JEMALLOC_INLINE_C const ctl_named_node_t * -ctl_named_children(const ctl_named_node_t *node, size_t index) -{ +ctl_named_children(const ctl_named_node_t *node, size_t index) { const ctl_named_node_t *children = ctl_named_node(node->children); return (children ? &children[index] : NULL); } JEMALLOC_INLINE_C const ctl_indexed_node_t * -ctl_indexed_node(const ctl_node_t *node) -{ +ctl_indexed_node(const ctl_node_t *node) { return (!node->named ? (const ctl_indexed_node_t *)node : NULL); } @@ -433,8 +430,7 @@ static const ctl_named_node_t super_root_node[] = { /******************************************************************************/ static unsigned -arenas_i2a_impl(size_t i, bool compat, bool validate) -{ +arenas_i2a_impl(size_t i, bool compat, bool validate) { unsigned a; switch (i) { @@ -453,9 +449,9 @@ arenas_i2a_impl(size_t i, bool compat, bool validate) * removal in 6.0.0. */ a = 0; - } else if (validate && i >= ctl_arenas->narenas) + } else if (validate && i >= ctl_arenas->narenas) { a = UINT_MAX; - else { + } else { /* * This function should never be called for an index * more than one past the range of indices that have @@ -472,14 +468,12 @@ arenas_i2a_impl(size_t i, bool compat, bool validate) } static unsigned -arenas_i2a(size_t i) -{ +arenas_i2a(size_t i) { return (arenas_i2a_impl(i, true, false)); } static ctl_arena_t * -arenas_i_impl(tsdn_t *tsdn, size_t i, bool compat, bool init) -{ +arenas_i_impl(tsdn_t *tsdn, size_t i, bool compat, bool init) { ctl_arena_t *ret; assert(!compat || !init); @@ -515,16 +509,14 @@ arenas_i_impl(tsdn_t *tsdn, size_t i, bool compat, bool init) } static ctl_arena_t * -arenas_i(size_t i) -{ +arenas_i(size_t i) { ctl_arena_t *ret = arenas_i_impl(TSDN_NULL, i, true, false); assert(ret != NULL); return (ret); } static void -ctl_arena_clear(ctl_arena_t *ctl_arena) -{ +ctl_arena_clear(ctl_arena_t *ctl_arena) { ctl_arena->nthreads = 0; ctl_arena->dss = dss_prec_names[dss_prec_limit]; ctl_arena->decay_time = -1; @@ -544,8 +536,7 @@ ctl_arena_clear(ctl_arena_t *ctl_arena) } static void -ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_t *ctl_arena, arena_t *arena) -{ +ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_t *ctl_arena, arena_t *arena) { unsigned i; if (config_stats) { @@ -575,8 +566,7 @@ ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_t *ctl_arena, arena_t *arena) static void ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, - bool destroyed) -{ + bool destroyed) { unsigned i; if (!destroyed) { @@ -605,13 +595,15 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, sdstats->astats.base += astats->astats.base; sdstats->astats.internal += astats->astats.internal; sdstats->astats.resident += astats->astats.resident; - } else + } else { assert(astats->astats.internal == 0); + } - if (!destroyed) + if (!destroyed) { sdstats->allocated_small += astats->allocated_small; - else + } else { assert(astats->allocated_small == 0); + } sdstats->nmalloc_small += astats->nmalloc_small; sdstats->ndalloc_small += astats->ndalloc_small; sdstats->nrequests_small += astats->nrequests_small; @@ -619,8 +611,9 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, if (!destroyed) { sdstats->astats.allocated_large += astats->astats.allocated_large; - } else + } else { assert(astats->astats.allocated_large == 0); + } sdstats->astats.nmalloc_large += astats->astats.nmalloc_large; sdstats->astats.ndalloc_large += astats->astats.ndalloc_large; sdstats->astats.nrequests_large += @@ -639,8 +632,9 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, if (!destroyed) { sdstats->bstats[i].curregs += astats->bstats[i].curregs; - } else + } else { assert(astats->bstats[i].curregs == 0); + } if (config_tcache) { sdstats->bstats[i].nfills += astats->bstats[i].nfills; @@ -652,8 +646,9 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, if (!destroyed) { sdstats->bstats[i].curslabs += astats->bstats[i].curslabs; - } else + } else { assert(astats->bstats[i].curslabs == 0); + } } for (i = 0; i < NSIZES - NBINS; i++) { @@ -664,16 +659,16 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, if (!destroyed) { sdstats->lstats[i].curlextents += astats->lstats[i].curlextents; - } else + } else { assert(astats->lstats[i].curlextents == 0); + } } } } static void ctl_arena_refresh(tsdn_t *tsdn, arena_t *arena, ctl_arena_t *ctl_sdarena, - unsigned i, bool destroyed) -{ + unsigned i, bool destroyed) { ctl_arena_t *ctl_arena = arenas_i(i); ctl_arena_clear(ctl_arena); @@ -683,8 +678,7 @@ ctl_arena_refresh(tsdn_t *tsdn, arena_t *arena, ctl_arena_t *ctl_sdarena, } static unsigned -ctl_arena_init(tsdn_t *tsdn, extent_hooks_t *extent_hooks) -{ +ctl_arena_init(tsdn_t *tsdn, extent_hooks_t *extent_hooks) { unsigned arena_ind; ctl_arena_t *ctl_arena; @@ -692,26 +686,29 @@ ctl_arena_init(tsdn_t *tsdn, extent_hooks_t *extent_hooks) NULL) { ql_remove(&ctl_arenas->destroyed, ctl_arena, destroyed_link); arena_ind = ctl_arena->arena_ind; - } else + } else { arena_ind = ctl_arenas->narenas; + } /* Trigger stats allocation. */ - if (arenas_i_impl(tsdn, arena_ind, false, true) == NULL) + if (arenas_i_impl(tsdn, arena_ind, false, true) == NULL) { return (UINT_MAX); + } /* Initialize new arena. */ - if (arena_init(tsdn, arena_ind, extent_hooks) == NULL) + if (arena_init(tsdn, arena_ind, extent_hooks) == NULL) { return (UINT_MAX); + } - if (arena_ind == ctl_arenas->narenas) + if (arena_ind == ctl_arenas->narenas) { ctl_arenas->narenas++; + } return (arena_ind); } static void -ctl_refresh(tsdn_t *tsdn) -{ +ctl_refresh(tsdn_t *tsdn) { unsigned i; ctl_arena_t *ctl_sarena = arenas_i(MALLCTL_ARENAS_ALL); VARIABLE_ARRAY(arena_t *, tarenas, ctl_arenas->narenas); @@ -751,8 +748,7 @@ ctl_refresh(tsdn_t *tsdn) } static bool -ctl_init(tsdn_t *tsdn) -{ +ctl_init(tsdn_t *tsdn) { bool ret; malloc_mutex_lock(tsdn, &ctl_mtx); @@ -828,8 +824,7 @@ label_return: static int ctl_lookup(tsdn_t *tsdn, const char *name, ctl_node_t const **nodesp, - size_t *mibp, size_t *depthp) -{ + size_t *mibp, size_t *depthp) { int ret; const char *elm, *tdot, *dot; size_t elen, i, j; @@ -857,9 +852,10 @@ ctl_lookup(tsdn_t *tsdn, const char *name, ctl_node_t const **nodesp, if (strlen(child->name) == elen && strncmp(elm, child->name, elen) == 0) { node = child; - if (nodesp != NULL) + if (nodesp != NULL) { nodesp[i] = (const ctl_node_t *)node; + } mibp[i] = j; break; } @@ -886,8 +882,9 @@ ctl_lookup(tsdn_t *tsdn, const char *name, ctl_node_t const **nodesp, goto label_return; } - if (nodesp != NULL) + if (nodesp != NULL) { nodesp[i] = (const ctl_node_t *)node; + } mibp[i] = (size_t)index; } @@ -925,8 +922,7 @@ label_return: int ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp, - void *newp, size_t newlen) -{ + void *newp, size_t newlen) { int ret; size_t depth; ctl_node_t const *nodes[CTL_MAX_DEPTH]; @@ -940,12 +936,14 @@ ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp, depth = CTL_MAX_DEPTH; ret = ctl_lookup(tsd_tsdn(tsd), name, nodes, mib, &depth); - if (ret != 0) + if (ret != 0) { goto label_return; + } node = ctl_named_node(nodes[depth-1]); - if (node != NULL && node->ctl) + if (node != NULL && node->ctl) { ret = node->ctl(tsd, mib, depth, oldp, oldlenp, newp, newlen); + } else { /* The name refers to a partial path through the ctl tree. */ ret = ENOENT; @@ -956,8 +954,7 @@ label_return: } int -ctl_nametomib(tsdn_t *tsdn, const char *name, size_t *mibp, size_t *miblenp) -{ +ctl_nametomib(tsdn_t *tsdn, const char *name, size_t *mibp, size_t *miblenp) { int ret; if (!ctl_initialized && ctl_init(tsdn)) { @@ -972,8 +969,7 @@ label_return: int ctl_bymib(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; const ctl_named_node_t *node; size_t i; @@ -1009,9 +1005,9 @@ ctl_bymib(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, } /* Call the ctl function. */ - if (node && node->ctl) + if (node && node->ctl) { ret = node->ctl(tsd, mib, miblen, oldp, oldlenp, newp, newlen); - else { + } else { /* Partial MIB. */ ret = ENOENT; } @@ -1021,10 +1017,10 @@ label_return: } bool -ctl_boot(void) -{ - if (malloc_mutex_init(&ctl_mtx, "ctl", WITNESS_RANK_CTL)) +ctl_boot(void) { + if (malloc_mutex_init(&ctl_mtx, "ctl", WITNESS_RANK_CTL)) { return (true); + } ctl_initialized = false; @@ -1032,20 +1028,17 @@ ctl_boot(void) } void -ctl_prefork(tsdn_t *tsdn) -{ +ctl_prefork(tsdn_t *tsdn) { malloc_mutex_prefork(tsdn, &ctl_mtx); } void -ctl_postfork_parent(tsdn_t *tsdn) -{ +ctl_postfork_parent(tsdn_t *tsdn) { malloc_mutex_postfork_parent(tsdn, &ctl_mtx); } void -ctl_postfork_child(tsdn_t *tsdn) -{ +ctl_postfork_child(tsdn_t *tsdn) { malloc_mutex_postfork_child(tsdn, &ctl_mtx); } @@ -1112,36 +1105,38 @@ ctl_postfork_child(tsdn_t *tsdn) #define CTL_RO_CLGEN(c, l, n, v, t) \ static int \ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ - size_t *oldlenp, void *newp, size_t newlen) \ -{ \ + size_t *oldlenp, void *newp, size_t newlen) { \ int ret; \ t oldval; \ \ - if (!(c)) \ + if (!(c)) { \ return (ENOENT); \ - if (l) \ + } \ + if (l) { \ malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); \ + } \ READONLY(); \ oldval = (v); \ READ(oldval, t); \ \ ret = 0; \ label_return: \ - if (l) \ + if (l) { \ malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); \ + } \ return (ret); \ } #define CTL_RO_CGEN(c, n, v, t) \ static int \ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ - size_t *oldlenp, void *newp, size_t newlen) \ -{ \ + size_t *oldlenp, void *newp, size_t newlen) { \ int ret; \ t oldval; \ \ - if (!(c)) \ + if (!(c)) { \ return (ENOENT); \ + } \ malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); \ READONLY(); \ oldval = (v); \ @@ -1156,8 +1151,7 @@ label_return: \ #define CTL_RO_GEN(n, v, t) \ static int \ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ - size_t *oldlenp, void *newp, size_t newlen) \ -{ \ + size_t *oldlenp, void *newp, size_t newlen) { \ int ret; \ t oldval; \ \ @@ -1179,13 +1173,13 @@ label_return: \ #define CTL_RO_NL_CGEN(c, n, v, t) \ static int \ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ - size_t *oldlenp, void *newp, size_t newlen) \ -{ \ + size_t *oldlenp, void *newp, size_t newlen) { \ int ret; \ t oldval; \ \ - if (!(c)) \ + if (!(c)) { \ return (ENOENT); \ + } \ READONLY(); \ oldval = (v); \ READ(oldval, t); \ @@ -1198,8 +1192,7 @@ label_return: \ #define CTL_RO_NL_GEN(n, v, t) \ static int \ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ - size_t *oldlenp, void *newp, size_t newlen) \ -{ \ + size_t *oldlenp, void *newp, size_t newlen) { \ int ret; \ t oldval; \ \ @@ -1215,13 +1208,13 @@ label_return: \ #define CTL_TSD_RO_NL_CGEN(c, n, m, t) \ static int \ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ - size_t *oldlenp, void *newp, size_t newlen) \ -{ \ + size_t *oldlenp, void *newp, size_t newlen) { \ int ret; \ t oldval; \ \ - if (!(c)) \ + if (!(c)) { \ return (ENOENT); \ + } \ READONLY(); \ oldval = (m(tsd)); \ READ(oldval, t); \ @@ -1234,8 +1227,7 @@ label_return: \ #define CTL_RO_CONFIG_GEN(n, t) \ static int \ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ - size_t *oldlenp, void *newp, size_t newlen) \ -{ \ + size_t *oldlenp, void *newp, size_t newlen) { \ int ret; \ t oldval; \ \ @@ -1254,15 +1246,15 @@ CTL_RO_NL_GEN(version, JEMALLOC_VERSION, const char *) static int epoch_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; UNUSED uint64_t newval; malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); WRITE(newval, uint64_t); - if (newp != NULL) + if (newp != NULL) { ctl_refresh(tsd_tsdn(tsd)); + } READ(ctl_arenas->epoch, uint64_t); ret = 0; @@ -1317,15 +1309,15 @@ CTL_RO_NL_CGEN(config_prof, opt_prof_leak, opt_prof_leak, bool) static int thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; arena_t *oldarena; unsigned newind, oldind; oldarena = arena_choose(tsd, NULL); - if (oldarena == NULL) + if (oldarena == NULL) { return (EAGAIN); + } newind = oldind = arena_ind_get(oldarena); WRITE(newind, unsigned); @@ -1372,13 +1364,13 @@ CTL_TSD_RO_NL_CGEN(config_stats, thread_deallocatedp, static int thread_tcache_enabled_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, - void *oldp, size_t *oldlenp, void *newp, size_t newlen) -{ + void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; bool oldval; - if (!config_tcache) + if (!config_tcache) { return (ENOENT); + } oldval = tcache_enabled_get(); if (newp != NULL) { @@ -1397,12 +1389,12 @@ label_return: static int thread_tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, - void *oldp, size_t *oldlenp, void *newp, size_t newlen) -{ + void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; - if (!config_tcache) + if (!config_tcache) { return (ENOENT); + } READONLY(); WRITEONLY(); @@ -1416,12 +1408,12 @@ label_return: static int thread_prof_name_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; - if (!config_prof) + if (!config_prof) { return (ENOENT); + } READ_XOR_WRITE(); @@ -1432,8 +1424,9 @@ thread_prof_name_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, } if ((ret = prof_thread_name_set(tsd, *(const char **)newp)) != - 0) + 0) { goto label_return; + } } else { const char *oldname = prof_thread_name_get(tsd); READ(oldname, const char *); @@ -1446,13 +1439,13 @@ label_return: static int thread_prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; bool oldval; - if (!config_prof) + if (!config_prof) { return (ENOENT); + } oldval = prof_thread_active_get(tsd); if (newp != NULL) { @@ -1476,13 +1469,13 @@ label_return: static int tcache_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; unsigned tcache_ind; - if (!config_tcache) + if (!config_tcache) { return (ENOENT); + } malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); READONLY(); @@ -1500,13 +1493,13 @@ label_return: static int tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; unsigned tcache_ind; - if (!config_tcache) + if (!config_tcache) { return (ENOENT); + } WRITEONLY(); tcache_ind = UINT_MAX; @@ -1524,13 +1517,13 @@ label_return: static int tcache_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; unsigned tcache_ind; - if (!config_tcache) + if (!config_tcache) { return (ENOENT); + } WRITEONLY(); tcache_ind = UINT_MAX; @@ -1550,8 +1543,7 @@ label_return: static int arena_i_initialized_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, - void *oldp, size_t *oldlenp, void *newp, size_t newlen) -{ + void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; tsdn_t *tsdn = tsd_tsdn(tsd); unsigned arena_ind; @@ -1572,8 +1564,7 @@ label_return: } static void -arena_i_purge(tsdn_t *tsdn, unsigned arena_ind, bool all) -{ +arena_i_purge(tsdn_t *tsdn, unsigned arena_ind, bool all) { malloc_mutex_lock(tsdn, &ctl_mtx); { unsigned narenas = ctl_arenas->narenas; @@ -1586,8 +1577,9 @@ arena_i_purge(tsdn_t *tsdn, unsigned arena_ind, bool all) unsigned i; VARIABLE_ARRAY(arena_t *, tarenas, narenas); - for (i = 0; i < narenas; i++) + for (i = 0; i < narenas; i++) { tarenas[i] = arena_get(tsdn, i, false); + } /* * No further need to hold ctl_mtx, since narenas and @@ -1596,8 +1588,9 @@ arena_i_purge(tsdn_t *tsdn, unsigned arena_ind, bool all) malloc_mutex_unlock(tsdn, &ctl_mtx); for (i = 0; i < narenas; i++) { - if (tarenas[i] != NULL) + if (tarenas[i] != NULL) { arena_purge(tsdn, tarenas[i], all); + } } } else { arena_t *tarena; @@ -1609,16 +1602,16 @@ arena_i_purge(tsdn_t *tsdn, unsigned arena_ind, bool all) /* No further need to hold ctl_mtx. */ malloc_mutex_unlock(tsdn, &ctl_mtx); - if (tarena != NULL) + if (tarena != NULL) { arena_purge(tsdn, tarena, all); + } } } } static int arena_i_purge_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; unsigned arena_ind; @@ -1634,8 +1627,7 @@ label_return: static int arena_i_decay_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; unsigned arena_ind; @@ -1652,8 +1644,7 @@ label_return: static int arena_i_reset_destroy_helper(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen, unsigned *arena_ind, - arena_t **arena) -{ + arena_t **arena) { int ret; READONLY(); @@ -1678,16 +1669,16 @@ label_return: static int arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; unsigned arena_ind; arena_t *arena; ret = arena_i_reset_destroy_helper(tsd, mib, miblen, oldp, oldlenp, newp, newlen, &arena_ind, &arena); - if (ret != 0) + if (ret != 0) { return (ret); + } arena_reset(tsd, arena); @@ -1696,8 +1687,7 @@ arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, static int arena_i_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; unsigned arena_ind; arena_t *arena; @@ -1705,8 +1695,9 @@ arena_i_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = arena_i_reset_destroy_helper(tsd, mib, miblen, oldp, oldlenp, newp, newlen, &arena_ind, &arena); - if (ret != 0) + if (ret != 0) { goto label_return; + } if (arena_nthreads_get(arena, false) != 0 || arena_nthreads_get(arena, true) != 0) { @@ -1735,8 +1726,7 @@ label_return: static int arena_i_dss_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; const char *dss = NULL; unsigned arena_ind; @@ -1797,8 +1787,7 @@ label_return: static int arena_i_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; unsigned arena_ind; arena_t *arena; @@ -1833,8 +1822,7 @@ label_return: static int arena_i_extent_hooks_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, - void *oldp, size_t *oldlenp, void *newp, size_t newlen) -{ + void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; unsigned arena_ind; arena_t *arena; @@ -1867,8 +1855,7 @@ label_return: } static const ctl_named_node_t * -arena_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) -{ +arena_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { const ctl_named_node_t *ret; malloc_mutex_lock(tsdn, &ctl_mtx); @@ -1894,8 +1881,7 @@ label_return: static int arenas_narenas_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; unsigned narenas; @@ -1916,8 +1902,7 @@ label_return: static int arenas_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; if (oldp != NULL && oldlenp != NULL) { @@ -1949,27 +1934,27 @@ CTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[2]].reg_size, size_t) CTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t) CTL_RO_NL_GEN(arenas_bin_i_slab_size, arena_bin_info[mib[2]].slab_size, size_t) static const ctl_named_node_t * -arenas_bin_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) -{ - if (i > NBINS) +arenas_bin_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { + if (i > NBINS) { return (NULL); + } return (super_arenas_bin_i_node); } CTL_RO_NL_GEN(arenas_nlextents, NSIZES - NBINS, unsigned) CTL_RO_NL_GEN(arenas_lextent_i_size, index2size(NBINS+(szind_t)mib[2]), size_t) static const ctl_named_node_t * -arenas_lextent_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) -{ - if (i > NSIZES - NBINS) +arenas_lextent_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, + size_t i) { + if (i > NSIZES - NBINS) { return (NULL); + } return (super_arenas_lextent_i_node); } static int arenas_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; extent_hooks_t *extent_hooks; unsigned arena_ind; @@ -1995,13 +1980,13 @@ label_return: static int prof_thread_active_init_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, - void *oldp, size_t *oldlenp, void *newp, size_t newlen) -{ + void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; bool oldval; - if (!config_prof) + if (!config_prof) { return (ENOENT); + } if (newp != NULL) { if (newlen != sizeof(bool)) { @@ -2010,8 +1995,9 @@ prof_thread_active_init_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, } oldval = prof_thread_active_init_set(tsd_tsdn(tsd), *(bool *)newp); - } else + } else { oldval = prof_thread_active_init_get(tsd_tsdn(tsd)); + } READ(oldval, bool); ret = 0; @@ -2021,13 +2007,13 @@ label_return: static int prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; bool oldval; - if (!config_prof) + if (!config_prof) { return (ENOENT); + } if (newp != NULL) { if (newlen != sizeof(bool)) { @@ -2035,8 +2021,9 @@ prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, goto label_return; } oldval = prof_active_set(tsd_tsdn(tsd), *(bool *)newp); - } else + } else { oldval = prof_active_get(tsd_tsdn(tsd)); + } READ(oldval, bool); ret = 0; @@ -2046,13 +2033,13 @@ label_return: static int prof_dump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; const char *filename = NULL; - if (!config_prof) + if (!config_prof) { return (ENOENT); + } WRITEONLY(); WRITE(filename, const char *); @@ -2069,13 +2056,13 @@ label_return: static int prof_gdump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; bool oldval; - if (!config_prof) + if (!config_prof) { return (ENOENT); + } if (newp != NULL) { if (newlen != sizeof(bool)) { @@ -2083,8 +2070,9 @@ prof_gdump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, goto label_return; } oldval = prof_gdump_set(tsd_tsdn(tsd), *(bool *)newp); - } else + } else { oldval = prof_gdump_get(tsd_tsdn(tsd)); + } READ(oldval, bool); ret = 0; @@ -2094,18 +2082,19 @@ label_return: static int prof_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) -{ + size_t *oldlenp, void *newp, size_t newlen) { int ret; size_t lg_sample = lg_prof_sample; - if (!config_prof) + if (!config_prof) { return (ENOENT); + } WRITEONLY(); WRITE(lg_sample, size_t); - if (lg_sample >= (sizeof(uint64_t) << 3)) + if (lg_sample >= (sizeof(uint64_t) << 3)) { lg_sample = (sizeof(uint64_t) << 3) - 1; + } prof_reset(tsd, lg_sample); @@ -2189,10 +2178,10 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curslabs, static const ctl_named_node_t * stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, - size_t j) -{ - if (j > NBINS) + size_t j) { + if (j > NBINS) { return (NULL); + } return (super_stats_arenas_i_bins_j_node); } @@ -2207,16 +2196,15 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_curlextents, static const ctl_named_node_t * stats_arenas_i_lextents_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, - size_t j) -{ - if (j > NSIZES - NBINS) + size_t j) { + if (j > NSIZES - NBINS) { return (NULL); + } return (super_stats_arenas_i_lextents_j_node); } static const ctl_named_node_t * -stats_arenas_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) -{ +stats_arenas_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { const ctl_named_node_t *ret; size_t a; diff --git a/src/extent.c b/src/extent.c index be40aaad..5cf2e25c 100644 --- a/src/extent.c +++ b/src/extent.c @@ -75,8 +75,7 @@ static void extent_record(tsdn_t *tsdn, arena_t *arena, /******************************************************************************/ extent_t * -extent_alloc(tsdn_t *tsdn, arena_t *arena) -{ +extent_alloc(tsdn_t *tsdn, arena_t *arena) { extent_t *extent; malloc_mutex_lock(tsdn, &arena->extent_cache_mtx); @@ -92,8 +91,7 @@ extent_alloc(tsdn_t *tsdn, arena_t *arena) } void -extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) -{ +extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { malloc_mutex_lock(tsdn, &arena->extent_cache_mtx); ql_elm_new(extent, ql_link); ql_tail_insert(&arena->extent_cache, extent, ql_link); @@ -101,22 +99,21 @@ extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) } extent_hooks_t * -extent_hooks_get(arena_t *arena) -{ +extent_hooks_get(arena_t *arena) { return (base_extent_hooks_get(arena->base)); } extent_hooks_t * -extent_hooks_set(arena_t *arena, extent_hooks_t *extent_hooks) -{ +extent_hooks_set(arena_t *arena, extent_hooks_t *extent_hooks) { return (base_extent_hooks_set(arena->base, extent_hooks)); } static void -extent_hooks_assure_initialized(arena_t *arena, extent_hooks_t **r_extent_hooks) -{ - if (*r_extent_hooks == EXTENT_HOOKS_INITIALIZER) +extent_hooks_assure_initialized(arena_t *arena, + extent_hooks_t **r_extent_hooks) { + if (*r_extent_hooks == EXTENT_HOOKS_INITIALIZER) { *r_extent_hooks = extent_hooks_get(arena); + } } #ifdef JEMALLOC_JET @@ -124,8 +121,7 @@ extent_hooks_assure_initialized(arena_t *arena, extent_hooks_t **r_extent_hooks) #define extent_size_quantize_floor JEMALLOC_N(n_extent_size_quantize_floor) #endif size_t -extent_size_quantize_floor(size_t size) -{ +extent_size_quantize_floor(size_t size) { size_t ret; pszind_t pind; @@ -161,8 +157,7 @@ extent_size_quantize_t *extent_size_quantize_floor = #define extent_size_quantize_ceil JEMALLOC_N(n_extent_size_quantize_ceil) #endif size_t -extent_size_quantize_ceil(size_t size) -{ +extent_size_quantize_ceil(size_t size) { size_t ret; assert(size > 0); @@ -195,8 +190,7 @@ ph_gen(, extent_heap_, extent_heap_t, extent_t, ph_link, extent_snad_comp) static void extent_heaps_insert(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES+1], - extent_t *extent) -{ + extent_t *extent) { size_t psz = extent_size_quantize_floor(extent_size_get(extent)); pszind_t pind = psz2ind(psz); @@ -207,8 +201,7 @@ extent_heaps_insert(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES+1], static void extent_heaps_remove(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES+1], - extent_t *extent) -{ + extent_t *extent) { size_t psz = extent_size_quantize_floor(extent_size_get(extent)); pszind_t pind = psz2ind(psz); @@ -220,12 +213,12 @@ extent_heaps_remove(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES+1], static bool extent_rtree_acquire(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, const extent_t *extent, bool dependent, bool init_missing, - rtree_elm_t **r_elm_a, rtree_elm_t **r_elm_b) -{ + rtree_elm_t **r_elm_a, rtree_elm_t **r_elm_b) { *r_elm_a = rtree_elm_acquire(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_base_get(extent), dependent, init_missing); - if (!dependent && *r_elm_a == NULL) + if (!dependent && *r_elm_a == NULL) { return (true); + } assert(*r_elm_a != NULL); if (extent_size_get(extent) > PAGE) { @@ -237,33 +230,33 @@ extent_rtree_acquire(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, return (true); } assert(*r_elm_b != NULL); - } else + } else { *r_elm_b = NULL; + } return (false); } static void extent_rtree_write_acquired(tsdn_t *tsdn, rtree_elm_t *elm_a, - rtree_elm_t *elm_b, const extent_t *extent) -{ + rtree_elm_t *elm_b, const extent_t *extent) { rtree_elm_write_acquired(tsdn, &extents_rtree, elm_a, extent); - if (elm_b != NULL) + if (elm_b != NULL) { rtree_elm_write_acquired(tsdn, &extents_rtree, elm_b, extent); + } } static void -extent_rtree_release(tsdn_t *tsdn, rtree_elm_t *elm_a, rtree_elm_t *elm_b) -{ +extent_rtree_release(tsdn_t *tsdn, rtree_elm_t *elm_a, rtree_elm_t *elm_b) { rtree_elm_release(tsdn, &extents_rtree, elm_a); - if (elm_b != NULL) + if (elm_b != NULL) { rtree_elm_release(tsdn, &extents_rtree, elm_b); + } } static void extent_interior_register(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, - const extent_t *extent) -{ + const extent_t *extent) { size_t i; assert(extent_slab_get(extent)); @@ -276,8 +269,7 @@ extent_interior_register(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, } static void -extent_gprof_add(tsdn_t *tsdn, const extent_t *extent) -{ +extent_gprof_add(tsdn_t *tsdn, const extent_t *extent) { cassert(config_prof); if (opt_prof && extent_active_get(extent)) { @@ -291,14 +283,14 @@ extent_gprof_add(tsdn_t *tsdn, const extent_t *extent) */ high = atomic_read_zu(&highpages); } - if (cur > high && prof_gdump_get_unlocked()) + if (cur > high && prof_gdump_get_unlocked()) { prof_gdump(tsdn); + } } } static void -extent_gprof_sub(tsdn_t *tsdn, const extent_t *extent) -{ +extent_gprof_sub(tsdn_t *tsdn, const extent_t *extent) { cassert(config_prof); if (opt_prof && extent_active_get(extent)) { @@ -309,37 +301,37 @@ extent_gprof_sub(tsdn_t *tsdn, const extent_t *extent) } static bool -extent_register(tsdn_t *tsdn, const extent_t *extent) -{ +extent_register(tsdn_t *tsdn, const extent_t *extent) { rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_elm_t *elm_a, *elm_b; if (extent_rtree_acquire(tsdn, rtree_ctx, extent, false, true, &elm_a, - &elm_b)) + &elm_b)) { return (true); + } extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent); - if (extent_slab_get(extent)) + if (extent_slab_get(extent)) { extent_interior_register(tsdn, rtree_ctx, extent); + } extent_rtree_release(tsdn, elm_a, elm_b); - if (config_prof) + if (config_prof) { extent_gprof_add(tsdn, extent); + } return (false); } static void -extent_reregister(tsdn_t *tsdn, const extent_t *extent) -{ +extent_reregister(tsdn_t *tsdn, const extent_t *extent) { bool err = extent_register(tsdn, extent); assert(!err); } static void extent_interior_deregister(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, - const extent_t *extent) -{ + const extent_t *extent) { size_t i; assert(extent_slab_get(extent)); @@ -352,8 +344,7 @@ extent_interior_deregister(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, } static void -extent_deregister(tsdn_t *tsdn, extent_t *extent) -{ +extent_deregister(tsdn_t *tsdn, extent_t *extent) { rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_elm_t *elm_a, *elm_b; @@ -367,8 +358,9 @@ extent_deregister(tsdn_t *tsdn, extent_t *extent) } extent_rtree_release(tsdn, elm_a, elm_b); - if (config_prof) + if (config_prof) { extent_gprof_sub(tsdn, extent); + } } /* @@ -377,8 +369,7 @@ extent_deregister(tsdn_t *tsdn, extent_t *extent) */ static extent_t * extent_first_best_fit(tsdn_t *tsdn, arena_t *arena, - extent_heap_t extent_heaps[NPSIZES+1], size_t size) -{ + extent_heap_t extent_heaps[NPSIZES+1], size_t size) { pszind_t pind, i; malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); @@ -386,8 +377,9 @@ extent_first_best_fit(tsdn_t *tsdn, arena_t *arena, pind = psz2ind(extent_size_quantize_ceil(size)); for (i = pind; i < NPSIZES+1; i++) { extent_t *extent = extent_heap_first(&extent_heaps[i]); - if (extent != NULL) + if (extent != NULL) { return (extent); + } } return (NULL); @@ -395,8 +387,7 @@ extent_first_best_fit(tsdn_t *tsdn, arena_t *arena, static void extent_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - bool cache, extent_t *extent) -{ + bool cache, extent_t *extent) { /* * Leak extent after making sure its pages have already been purged, so * that this is only a virtual memory leak. @@ -415,15 +406,15 @@ static extent_t * extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_heap_t extent_heaps[NPSIZES+1], bool locked, bool cache, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, - bool *commit, bool slab) -{ + bool *commit, bool slab) { extent_t *extent; rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); size_t size, alloc_size, leadsize, trailsize; - if (locked) + if (locked) { malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); + } assert(new_addr == NULL || !slab); assert(pad == 0 || !slab); assert(alignment > 0); @@ -452,10 +443,12 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, size = usize + pad; alloc_size = size + PAGE_CEILING(alignment) - PAGE; /* Beware size_t wrap-around. */ - if (alloc_size < usize) + if (alloc_size < usize) { return (NULL); - if (!locked) + } + if (!locked) { malloc_mutex_lock(tsdn, &arena->extents_mtx); + } extent_hooks_assure_initialized(arena, r_extent_hooks); if (new_addr != NULL) { rtree_elm_t *elm; @@ -470,19 +463,22 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, if (extent_arena_get(extent) != arena || extent_size_get(extent) < size || extent_active_get(extent) || - extent_retained_get(extent) == cache) + extent_retained_get(extent) == cache) { extent = NULL; + } } rtree_elm_release(tsdn, &extents_rtree, elm); - } else + } else { extent = NULL; + } } else { extent = extent_first_best_fit(tsdn, arena, extent_heaps, alloc_size); } if (extent == NULL) { - if (!locked) + if (!locked) { malloc_mutex_unlock(tsdn, &arena->extents_mtx); + } return (NULL); } extent_heaps_remove(tsdn, extent_heaps, extent); @@ -493,10 +489,12 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, assert(new_addr == NULL || leadsize == 0); assert(extent_size_get(extent) >= leadsize + size); trailsize = extent_size_get(extent) - leadsize - size; - if (extent_zeroed_get(extent)) + if (extent_zeroed_get(extent)) { *zero = true; - if (extent_committed_get(extent)) + } + if (extent_committed_get(extent)) { *commit = true; + } /* Split the lead. */ if (leadsize != 0) { @@ -507,8 +505,9 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, if (extent == NULL) { extent_deregister(tsdn, lead); extent_leak(tsdn, arena, r_extent_hooks, cache, lead); - if (!locked) + if (!locked) { malloc_mutex_unlock(tsdn, &arena->extents_mtx); + } return (NULL); } extent_heaps_insert(tsdn, extent_heaps, lead); @@ -523,8 +522,9 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_deregister(tsdn, extent); extent_leak(tsdn, arena, r_extent_hooks, cache, extent); - if (!locked) + if (!locked) { malloc_mutex_unlock(tsdn, &arena->extents_mtx); + } return (NULL); } extent_heaps_insert(tsdn, extent_heaps, trail); @@ -540,8 +540,9 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, if (*commit && !extent_committed_get(extent)) { if (extent_commit_wrapper(tsdn, arena, r_extent_hooks, extent, 0, extent_size_get(extent))) { - if (!locked) + if (!locked) { malloc_mutex_unlock(tsdn, &arena->extents_mtx); + } extent_record(tsdn, arena, r_extent_hooks, extent_heaps, cache, extent); return (NULL); @@ -549,16 +550,18 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_zeroed_set(extent, true); } - if (pad != 0) + if (pad != 0) { extent_addr_randomize(tsdn, extent, alignment); + } extent_active_set(extent, true); if (slab) { extent_slab_set(extent, slab); extent_interior_register(tsdn, rtree_ctx, extent); } - if (!locked) + if (!locked) { malloc_mutex_unlock(tsdn, &arena->extents_mtx); + } if (*zero) { if (!extent_zeroed_get(extent)) { @@ -569,8 +572,9 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, size_t *p = (size_t *)(uintptr_t) extent_addr_get(extent); - for (i = 0; i < usize / sizeof(size_t); i++) + for (i = 0; i < usize / sizeof(size_t); i++) { assert(p[i] == 0); + } } } return (extent); @@ -584,8 +588,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, */ static void * extent_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, - size_t alignment, bool *zero, bool *commit, dss_prec_t dss_prec) -{ + size_t alignment, bool *zero, bool *commit, dss_prec_t dss_prec) { void *ret; assert(size != 0); @@ -594,17 +597,20 @@ extent_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, /* "primary" dss. */ if (have_dss && dss_prec == dss_prec_primary && (ret = extent_alloc_dss(tsdn, arena, new_addr, size, alignment, zero, - commit)) != NULL) + commit)) != NULL) { return (ret); + } /* mmap. */ if ((ret = extent_alloc_mmap(new_addr, size, alignment, zero, commit)) - != NULL) + != NULL) { return (ret); + } /* "secondary" dss. */ if (have_dss && dss_prec == dss_prec_secondary && (ret = extent_alloc_dss(tsdn, arena, new_addr, size, alignment, zero, - commit)) != NULL) + commit)) != NULL) { return (ret); + } /* All strategies for allocation failed. */ return (NULL); @@ -613,8 +619,7 @@ extent_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, static extent_t * extent_alloc_cache_impl(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, bool locked, void *new_addr, size_t usize, - size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) -{ + size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) { extent_t *extent; assert(usize + pad != 0); @@ -629,8 +634,7 @@ extent_alloc_cache_impl(tsdn_t *tsdn, arena_t *arena, extent_t * extent_alloc_cache_locked(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) -{ + size_t alignment, bool *zero, bool *commit, bool slab) { malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); return (extent_alloc_cache_impl(tsdn, arena, r_extent_hooks, true, @@ -640,16 +644,14 @@ extent_alloc_cache_locked(tsdn_t *tsdn, arena_t *arena, extent_t * extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) -{ + size_t alignment, bool *zero, bool *commit, bool slab) { return (extent_alloc_cache_impl(tsdn, arena, r_extent_hooks, false, new_addr, usize, pad, alignment, zero, commit, slab)); } static void * extent_alloc_default_impl(tsdn_t *tsdn, arena_t *arena, void *new_addr, - size_t size, size_t alignment, bool *zero, bool *commit) -{ + size_t size, size_t alignment, bool *zero, bool *commit) { void *ret; ret = extent_alloc_core(tsdn, arena, new_addr, size, alignment, zero, @@ -659,8 +661,7 @@ extent_alloc_default_impl(tsdn_t *tsdn, arena_t *arena, void *new_addr, static void * extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, size_t size, - size_t alignment, bool *zero, bool *commit, unsigned arena_ind) -{ + size_t alignment, bool *zero, bool *commit, unsigned arena_ind) { tsdn_t *tsdn; arena_t *arena; @@ -680,10 +681,10 @@ extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, size_t size, static void extent_retain(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extent_t *extent) -{ - if (config_stats) + extent_t *extent) { + if (config_stats) { arena->stats.retained += extent_size_get(extent); + } extent_record(tsdn, arena, r_extent_hooks, arena->extents_retained, false, extent); } @@ -696,8 +697,7 @@ extent_retain(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, static extent_t * extent_grow_retained(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) -{ + size_t alignment, bool *zero, bool *commit, bool slab) { extent_t *extent; void *ptr; size_t size, alloc_size, alloc_size_min, leadsize, trailsize; @@ -713,13 +713,16 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, alloc_size = pind2sz(arena->extent_grow_next); alloc_size_min = size + PAGE_CEILING(alignment) - PAGE; /* Beware size_t wrap-around. */ - if (alloc_size_min < usize) + if (alloc_size_min < usize) { return (NULL); - if (alloc_size < alloc_size_min) + } + if (alloc_size < alloc_size_min) { return (NULL); + } extent = extent_alloc(tsdn, arena); - if (extent == NULL) + if (extent == NULL) { return (NULL); + } zeroed = false; committed = false; ptr = extent_alloc_core(tsdn, arena, new_addr, alloc_size, PAGE, @@ -741,10 +744,12 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, assert(new_addr == NULL || leadsize == 0); assert(alloc_size >= leadsize + size); trailsize = alloc_size - leadsize - size; - if (extent_zeroed_get(extent)) + if (extent_zeroed_get(extent)) { *zero = true; - if (extent_committed_get(extent)) + } + if (extent_committed_get(extent)) { *commit = true; + } /* Split the lead. */ if (leadsize != 0) { @@ -790,8 +795,9 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, /* Adjust gprof stats now that extent is final size. */ extent_gprof_add(tsdn, extent); } - if (pad != 0) + if (pad != 0) { extent_addr_randomize(tsdn, extent, alignment); + } if (slab) { rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, @@ -800,18 +806,19 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, extent_slab_set(extent, true); extent_interior_register(tsdn, rtree_ctx, extent); } - if (*zero && !extent_zeroed_get(extent)) + if (*zero && !extent_zeroed_get(extent)) { memset(extent_addr_get(extent), 0, extent_usize_get(extent)); - if (arena->extent_grow_next + 1 < NPSIZES) + } + if (arena->extent_grow_next + 1 < NPSIZES) { arena->extent_grow_next++; + } return (extent); } static extent_t * extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) -{ + size_t alignment, bool *zero, bool *commit, bool slab) { extent_t *extent; assert(usize != 0); @@ -825,8 +832,9 @@ extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, size_t size = usize + pad; arena->stats.retained -= size; } - if (config_prof) + if (config_prof) { extent_gprof_add(tsdn, extent); + } } if (!config_munmap && extent == NULL) { extent = extent_grow_retained(tsdn, arena, r_extent_hooks, @@ -839,16 +847,16 @@ extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, static extent_t * extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) -{ + size_t alignment, bool *zero, bool *commit, bool slab) { extent_t *extent; size_t size; void *addr; size = usize + pad; extent = extent_alloc(tsdn, arena); - if (extent == NULL) + if (extent == NULL) { return (NULL); + } if (*r_extent_hooks == &extent_hooks_default) { /* Call directly to propagate tsdn. */ addr = extent_alloc_default_impl(tsdn, arena, new_addr, size, @@ -863,8 +871,9 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, } extent_init(extent, arena, addr, size, usize, arena_extent_sn_next(arena), true, zero, commit, slab); - if (pad != 0) + if (pad != 0) { extent_addr_randomize(tsdn, extent, alignment); + } if (extent_register(tsdn, extent)) { extent_leak(tsdn, arena, r_extent_hooks, false, extent); return (NULL); @@ -876,8 +885,7 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, extent_t * extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) -{ + size_t alignment, bool *zero, bool *commit, bool slab) { extent_t *extent; extent_hooks_assure_initialized(arena, r_extent_hooks); @@ -893,16 +901,19 @@ extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, } static bool -extent_can_coalesce(const extent_t *a, const extent_t *b) -{ - if (extent_arena_get(a) != extent_arena_get(b)) +extent_can_coalesce(const extent_t *a, const extent_t *b) { + if (extent_arena_get(a) != extent_arena_get(b)) { return (false); - if (extent_active_get(a) != extent_active_get(b)) + } + if (extent_active_get(a) != extent_active_get(b)) { return (false); - if (extent_committed_get(a) != extent_committed_get(b)) + } + if (extent_committed_get(a) != extent_committed_get(b)) { return (false); - if (extent_retained_get(a) != extent_retained_get(b)) + } + if (extent_retained_get(a) != extent_retained_get(b)) { return (false); + } return (true); } @@ -910,10 +921,10 @@ extent_can_coalesce(const extent_t *a, const extent_t *b) static void extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b, - extent_heap_t extent_heaps[NPSIZES+1], bool cache) -{ - if (!extent_can_coalesce(a, b)) + extent_heap_t extent_heaps[NPSIZES+1], bool cache) { + if (!extent_can_coalesce(a, b)) { return; + } extent_heaps_remove(tsdn, extent_heaps, a); extent_heaps_remove(tsdn, extent_heaps, b); @@ -937,8 +948,7 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, static void extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extent_heap_t extent_heaps[NPSIZES+1], bool cache, extent_t *extent) -{ + extent_heap_t extent_heaps[NPSIZES+1], bool cache, extent_t *extent) { extent_t *prev, *next; rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); @@ -980,8 +990,7 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, } void -extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent) -{ +extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; if (extent_register(tsdn, extent)) { @@ -993,8 +1002,7 @@ extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent) void extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent) -{ + extent_hooks_t **r_extent_hooks, extent_t *extent) { assert(extent_base_get(extent) != NULL); assert(extent_size_get(extent) != 0); @@ -1006,17 +1014,16 @@ extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, } static bool -extent_dalloc_default_impl(void *addr, size_t size) -{ - if (!have_dss || !extent_in_dss(addr)) +extent_dalloc_default_impl(void *addr, size_t size) { + if (!have_dss || !extent_in_dss(addr)) { return (extent_dalloc_mmap(addr, size)); + } return (true); } static bool extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, size_t size, - bool committed, unsigned arena_ind) -{ + bool committed, unsigned arena_ind) { assert(extent_hooks == &extent_hooks_default); return (extent_dalloc_default_impl(addr, size)); @@ -1024,8 +1031,7 @@ extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, size_t size, bool extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent) -{ + extent_hooks_t **r_extent_hooks, extent_t *extent) { bool err; assert(extent_base_get(extent) != NULL); @@ -1050,46 +1056,50 @@ extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, extent_committed_get(extent), arena_ind_get(arena))); } - if (!err) + if (!err) { extent_dalloc(tsdn, arena, extent); + } return (err); } void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent) -{ + extent_hooks_t **r_extent_hooks, extent_t *extent) { bool zeroed; - if (!extent_dalloc_wrapper_try(tsdn, arena, r_extent_hooks, extent)) + if (!extent_dalloc_wrapper_try(tsdn, arena, r_extent_hooks, extent)) { return; + } extent_reregister(tsdn, extent); /* Try to decommit; purge if that fails. */ - if (!extent_committed_get(extent)) + if (!extent_committed_get(extent)) { zeroed = true; - else if (!extent_decommit_wrapper(tsdn, arena, r_extent_hooks, extent, - 0, extent_size_get(extent))) + } else if (!extent_decommit_wrapper(tsdn, arena, r_extent_hooks, extent, + 0, extent_size_get(extent))) { zeroed = true; - else if ((*r_extent_hooks)->purge_lazy != NULL && + } else if ((*r_extent_hooks)->purge_lazy != NULL && !(*r_extent_hooks)->purge_lazy(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), 0, - extent_size_get(extent), arena_ind_get(arena))) + extent_size_get(extent), arena_ind_get(arena))) { zeroed = false; - else if ((*r_extent_hooks)->purge_forced != NULL && + } else if ((*r_extent_hooks)->purge_forced != NULL && !(*r_extent_hooks)->purge_forced(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), 0, - extent_size_get(extent), arena_ind_get(arena))) + extent_size_get(extent), arena_ind_get(arena))) { zeroed = true; - else + } else { zeroed = false; + } extent_zeroed_set(extent, zeroed); - if (config_stats) + if (config_stats) { arena->stats.retained += extent_size_get(extent); - if (config_prof) + } + if (config_prof) { extent_gprof_sub(tsdn, extent); + } extent_record(tsdn, arena, r_extent_hooks, arena->extents_retained, false, extent); @@ -1097,8 +1107,7 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, static bool extent_commit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t offset, size_t length, unsigned arena_ind) -{ + size_t offset, size_t length, unsigned arena_ind) { assert(extent_hooks == &extent_hooks_default); return (pages_commit((void *)((uintptr_t)addr + (uintptr_t)offset), @@ -1108,8 +1117,7 @@ extent_commit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, bool extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, - size_t length) -{ + size_t length) { bool err; extent_hooks_assure_initialized(arena, r_extent_hooks); @@ -1122,8 +1130,7 @@ extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, static bool extent_decommit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t offset, size_t length, unsigned arena_ind) -{ + size_t offset, size_t length, unsigned arena_ind) { assert(extent_hooks == &extent_hooks_default); return (pages_decommit((void *)((uintptr_t)addr + (uintptr_t)offset), @@ -1133,8 +1140,7 @@ extent_decommit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, bool extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, - size_t length) -{ + size_t length) { bool err; extent_hooks_assure_initialized(arena, r_extent_hooks); @@ -1150,8 +1156,7 @@ extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, #ifdef PAGES_CAN_PURGE_LAZY static bool extent_purge_lazy_default(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t offset, size_t length, unsigned arena_ind) -{ + size_t offset, size_t length, unsigned arena_ind) { assert(extent_hooks == &extent_hooks_default); assert(addr != NULL); assert((offset & PAGE_MASK) == 0); @@ -1166,8 +1171,7 @@ extent_purge_lazy_default(extent_hooks_t *extent_hooks, void *addr, size_t size, bool extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, - size_t length) -{ + size_t length) { extent_hooks_assure_initialized(arena, r_extent_hooks); return ((*r_extent_hooks)->purge_lazy == NULL || (*r_extent_hooks)->purge_lazy(*r_extent_hooks, @@ -1178,8 +1182,7 @@ extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, #ifdef PAGES_CAN_PURGE_FORCED static bool extent_purge_forced_default(extent_hooks_t *extent_hooks, void *addr, - size_t size, size_t offset, size_t length, unsigned arena_ind) -{ + size_t size, size_t offset, size_t length, unsigned arena_ind) { assert(extent_hooks == &extent_hooks_default); assert(addr != NULL); assert((offset & PAGE_MASK) == 0); @@ -1194,8 +1197,7 @@ extent_purge_forced_default(extent_hooks_t *extent_hooks, void *addr, bool extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, - size_t length) -{ + size_t length) { extent_hooks_assure_initialized(arena, r_extent_hooks); return ((*r_extent_hooks)->purge_forced == NULL || (*r_extent_hooks)->purge_forced(*r_extent_hooks, @@ -1206,12 +1208,12 @@ extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, #ifdef JEMALLOC_MAPS_COALESCE static bool extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t size_a, size_t size_b, bool committed, unsigned arena_ind) -{ + size_t size_a, size_t size_b, bool committed, unsigned arena_ind) { assert(extent_hooks == &extent_hooks_default); - if (!maps_coalesce) + if (!maps_coalesce) { return (true); + } return (false); } #endif @@ -1219,8 +1221,7 @@ extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size, extent_t * extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a, - size_t usize_a, size_t size_b, size_t usize_b) -{ + size_t usize_a, size_t size_b, size_t usize_b) { extent_t *trail; rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); @@ -1230,12 +1231,14 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_assure_initialized(arena, r_extent_hooks); - if ((*r_extent_hooks)->split == NULL) + if ((*r_extent_hooks)->split == NULL) { return (NULL); + } trail = extent_alloc(tsdn, arena); - if (trail == NULL) + if (trail == NULL) { goto label_error_a; + } { extent_t lead; @@ -1246,8 +1249,9 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_slab_get(extent)); if (extent_rtree_acquire(tsdn, rtree_ctx, &lead, false, true, - &lead_elm_a, &lead_elm_b)) + &lead_elm_a, &lead_elm_b)) { goto label_error_b; + } } extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) + @@ -1255,13 +1259,15 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_active_get(extent), extent_zeroed_get(extent), extent_committed_get(extent), extent_slab_get(extent)); if (extent_rtree_acquire(tsdn, rtree_ctx, trail, false, true, - &trail_elm_a, &trail_elm_b)) + &trail_elm_a, &trail_elm_b)) { goto label_error_c; + } if ((*r_extent_hooks)->split(*r_extent_hooks, extent_base_get(extent), size_a + size_b, size_a, size_b, extent_committed_get(extent), - arena_ind_get(arena))) + arena_ind_get(arena))) { goto label_error_d; + } extent_size_set(extent, size_a); extent_usize_set(extent, usize_a); @@ -1284,12 +1290,13 @@ label_error_a: } static bool -extent_merge_default_impl(void *addr_a, void *addr_b) -{ - if (!maps_coalesce) +extent_merge_default_impl(void *addr_a, void *addr_b) { + if (!maps_coalesce) { return (true); - if (have_dss && !extent_dss_mergeable(addr_a, addr_b)) + } + if (have_dss && !extent_dss_mergeable(addr_a, addr_b)) { return (true); + } return (false); } @@ -1297,8 +1304,7 @@ extent_merge_default_impl(void *addr_a, void *addr_b) #ifdef JEMALLOC_MAPS_COALESCE static bool extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, - void *addr_b, size_t size_b, bool committed, unsigned arena_ind) -{ + void *addr_b, size_t size_b, bool committed, unsigned arena_ind) { assert(extent_hooks == &extent_hooks_default); return (extent_merge_default_impl(addr_a, addr_b)); @@ -1307,8 +1313,7 @@ extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b) -{ + extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b) { bool err; rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); @@ -1316,8 +1321,9 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_assure_initialized(arena, r_extent_hooks); - if ((*r_extent_hooks)->merge == NULL) + if ((*r_extent_hooks)->merge == NULL) { return (true); + } if (*r_extent_hooks == &extent_hooks_default) { /* Call directly to propagate tsdn. */ @@ -1330,8 +1336,9 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, arena_ind_get(arena)); } - if (err) + if (err) { return (true); + } /* * The rtree writes must happen while all the relevant elements are @@ -1350,8 +1357,9 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, if (b_elm_b != NULL) { rtree_elm_write_acquired(tsdn, &extents_rtree, b_elm_a, NULL); rtree_elm_release(tsdn, &extents_rtree, b_elm_a); - } else + } else { b_elm_b = b_elm_a; + } extent_size_set(a, extent_size_get(a) + extent_size_get(b)); extent_usize_set(a, extent_usize_get(a) + extent_usize_get(b)); @@ -1368,14 +1376,15 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, } bool -extent_boot(void) -{ +extent_boot(void) { if (rtree_new(&extents_rtree, (unsigned)((ZU(1) << (LG_SIZEOF_PTR+3)) - - LG_PAGE))) + LG_PAGE))) { return (true); + } - if (have_dss) + if (have_dss) { extent_dss_boot(); + } return (false); } diff --git a/src/extent_dss.c b/src/extent_dss.c index 5aa95b1c..d61d5464 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -30,8 +30,7 @@ static void *dss_max; /******************************************************************************/ static void * -extent_dss_sbrk(intptr_t increment) -{ +extent_dss_sbrk(intptr_t increment) { #ifdef JEMALLOC_DSS return (sbrk(increment)); #else @@ -41,28 +40,27 @@ extent_dss_sbrk(intptr_t increment) } dss_prec_t -extent_dss_prec_get(void) -{ +extent_dss_prec_get(void) { dss_prec_t ret; - if (!have_dss) + if (!have_dss) { return (dss_prec_disabled); + } ret = (dss_prec_t)atomic_read_u(&dss_prec_default); return (ret); } bool -extent_dss_prec_set(dss_prec_t dss_prec) -{ - if (!have_dss) +extent_dss_prec_set(dss_prec_t dss_prec) { + if (!have_dss) { return (dss_prec != dss_prec_disabled); + } atomic_write_u(&dss_prec_default, (unsigned)dss_prec); return (false); } static void * -extent_dss_max_update(void *new_addr) -{ +extent_dss_max_update(void *new_addr) { void *max_cur; spin_t spinner; @@ -83,20 +81,21 @@ extent_dss_max_update(void *new_addr) spin_adaptive(&spinner); continue; } - if (!atomic_cas_p(&dss_max, max_prev, max_cur)) + if (!atomic_cas_p(&dss_max, max_prev, max_cur)) { break; + } } /* Fixed new_addr can only be supported if it is at the edge of DSS. */ - if (new_addr != NULL && max_cur != new_addr) + if (new_addr != NULL && max_cur != new_addr) { return (NULL); + } return (max_cur); } void * extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, - size_t alignment, bool *zero, bool *commit) -{ + size_t alignment, bool *zero, bool *commit) { extent_t *gap; cassert(have_dss); @@ -107,12 +106,14 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, * sbrk() uses a signed increment argument, so take care not to * interpret a large allocation request as a negative increment. */ - if ((intptr_t)size < 0) + if ((intptr_t)size < 0) { return (NULL); + } gap = extent_alloc(tsdn, arena); - if (gap == NULL) + if (gap == NULL) { return (NULL); + } if (!atomic_read_u(&dss_exhausted)) { /* @@ -126,8 +127,9 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, intptr_t incr; max_cur = extent_dss_max_update(new_addr); - if (max_cur == NULL) + if (max_cur == NULL) { goto label_oom; + } /* * Compute how much gap space (if any) is necessary to @@ -145,8 +147,9 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, } dss_next = (void *)((uintptr_t)ret + size); if ((uintptr_t)ret < (uintptr_t)max_cur || - (uintptr_t)dss_next < (uintptr_t)max_cur) + (uintptr_t)dss_next < (uintptr_t)max_cur) { goto label_oom; /* Wrap-around. */ + } incr = gap_size + size; /* @@ -155,19 +158,22 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, * DSS while dss_max is greater than the current DSS * max reported by sbrk(0). */ - if (atomic_cas_p(&dss_max, max_cur, dss_next)) + if (atomic_cas_p(&dss_max, max_cur, dss_next)) { continue; + } /* Try to allocate. */ dss_prev = extent_dss_sbrk(incr); if (dss_prev == max_cur) { /* Success. */ - if (gap_size != 0) + if (gap_size != 0) { extent_dalloc_gap(tsdn, arena, gap); - else + } else { extent_dalloc(tsdn, arena, gap); - if (!*commit) + } + if (!*commit) { *commit = pages_decommit(ret, size); + } if (*zero && *commit) { extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; @@ -177,8 +183,9 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, size, 0, true, false, true, false); if (extent_purge_forced_wrapper(tsdn, arena, &extent_hooks, &extent, 0, - size)) + size)) { memset(ret, 0, size); + } } return (ret); } @@ -204,30 +211,28 @@ label_oom: } static bool -extent_in_dss_helper(void *addr, void *max) -{ +extent_in_dss_helper(void *addr, void *max) { return ((uintptr_t)addr >= (uintptr_t)dss_base && (uintptr_t)addr < (uintptr_t)max); } bool -extent_in_dss(void *addr) -{ +extent_in_dss(void *addr) { cassert(have_dss); return (extent_in_dss_helper(addr, atomic_read_p(&dss_max))); } bool -extent_dss_mergeable(void *addr_a, void *addr_b) -{ +extent_dss_mergeable(void *addr_a, void *addr_b) { void *max; cassert(have_dss); if ((uintptr_t)addr_a < (uintptr_t)dss_base && (uintptr_t)addr_b < - (uintptr_t)dss_base) + (uintptr_t)dss_base) { return (true); + } max = atomic_read_p(&dss_max); return (extent_in_dss_helper(addr_a, max) == @@ -235,8 +240,7 @@ extent_dss_mergeable(void *addr_a, void *addr_b) } void -extent_dss_boot(void) -{ +extent_dss_boot(void) { cassert(have_dss); dss_base = extent_dss_sbrk(0); diff --git a/src/extent_mmap.c b/src/extent_mmap.c index e685a45b..2c00b588 100644 --- a/src/extent_mmap.c +++ b/src/extent_mmap.c @@ -4,21 +4,23 @@ /******************************************************************************/ static void * -extent_alloc_mmap_slow(size_t size, size_t alignment, bool *zero, bool *commit) -{ +extent_alloc_mmap_slow(size_t size, size_t alignment, bool *zero, + bool *commit) { void *ret; size_t alloc_size; alloc_size = size + alignment - PAGE; /* Beware size_t wrap-around. */ - if (alloc_size < size) + if (alloc_size < size) { return (NULL); + } do { void *pages; size_t leadsize; pages = pages_map(NULL, alloc_size, commit); - if (pages == NULL) + if (pages == NULL) { return (NULL); + } leadsize = ALIGNMENT_CEILING((uintptr_t)pages, alignment) - (uintptr_t)pages; ret = pages_trim(pages, alloc_size, leadsize, size, commit); @@ -31,8 +33,7 @@ extent_alloc_mmap_slow(size_t size, size_t alignment, bool *zero, bool *commit) void * extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, - bool *commit) -{ + bool *commit) { void *ret; size_t offset; @@ -52,8 +53,9 @@ extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, assert(alignment != 0); ret = pages_map(new_addr, size, commit); - if (ret == NULL || ret == new_addr) + if (ret == NULL || ret == new_addr) { return (ret); + } assert(new_addr == NULL); offset = ALIGNMENT_ADDR2OFFSET(ret, alignment); if (offset != 0) { @@ -67,9 +69,9 @@ extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, } bool -extent_dalloc_mmap(void *addr, size_t size) -{ - if (config_munmap) +extent_dalloc_mmap(void *addr, size_t size) { + if (config_munmap) { pages_unmap(addr, size); + } return (!config_munmap); } diff --git a/src/jemalloc.c b/src/jemalloc.c index af2a53a2..2de42c3e 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -209,8 +209,7 @@ static bool init_lock_initialized = false; JEMALLOC_ATTR(constructor) static void WINAPI -_init_init_lock(void) -{ +_init_init_lock(void) { /* * If another constructor in the same binary is using mallctl to e.g. * set up extent hooks, it may end up running before this one, and @@ -221,8 +220,9 @@ _init_init_lock(void) * the process creation, before any separate thread normally starts * doing anything. */ - if (!init_lock_initialized) + if (!init_lock_initialized) { malloc_mutex_init(&init_lock, "init", WITNESS_RANK_INIT); + } init_lock_initialized = true; } @@ -273,24 +273,23 @@ static bool malloc_init_hard(void); */ JEMALLOC_ALWAYS_INLINE_C bool -malloc_initialized(void) -{ +malloc_initialized(void) { return (malloc_init_state == malloc_init_initialized); } JEMALLOC_ALWAYS_INLINE_C bool -malloc_init_a0(void) -{ - if (unlikely(malloc_init_state == malloc_init_uninitialized)) +malloc_init_a0(void) { + if (unlikely(malloc_init_state == malloc_init_uninitialized)) { return (malloc_init_hard_a0()); + } return (false); } JEMALLOC_ALWAYS_INLINE_C bool -malloc_init(void) -{ - if (unlikely(!malloc_initialized()) && malloc_init_hard()) +malloc_init(void) { + if (unlikely(!malloc_initialized()) && malloc_init_hard()) { return (true); + } return (false); } @@ -300,30 +299,27 @@ malloc_init(void) */ static void * -a0ialloc(size_t size, bool zero, bool is_internal) -{ - if (unlikely(malloc_init_a0())) +a0ialloc(size_t size, bool zero, bool is_internal) { + if (unlikely(malloc_init_a0())) { return (NULL); + } return (iallocztm(TSDN_NULL, size, size2index(size), zero, NULL, is_internal, arena_get(TSDN_NULL, 0, true), true)); } static void -a0idalloc(extent_t *extent, void *ptr, bool is_internal) -{ +a0idalloc(extent_t *extent, void *ptr, bool is_internal) { idalloctm(TSDN_NULL, extent, ptr, false, is_internal, true); } void * -a0malloc(size_t size) -{ +a0malloc(size_t size) { return (a0ialloc(size, false, true)); } void -a0dalloc(void *ptr) -{ +a0dalloc(void *ptr) { a0idalloc(iealloc(NULL, ptr), ptr, true); } @@ -334,17 +330,16 @@ a0dalloc(void *ptr) */ void * -bootstrap_malloc(size_t size) -{ - if (unlikely(size == 0)) +bootstrap_malloc(size_t size) { + if (unlikely(size == 0)) { size = 1; + } return (a0ialloc(size, false, false)); } void * -bootstrap_calloc(size_t num, size_t size) -{ +bootstrap_calloc(size_t num, size_t size) { size_t num_size; num_size = num * size; @@ -357,49 +352,46 @@ bootstrap_calloc(size_t num, size_t size) } void -bootstrap_free(void *ptr) -{ - if (unlikely(ptr == NULL)) +bootstrap_free(void *ptr) { + if (unlikely(ptr == NULL)) { return; + } a0idalloc(iealloc(NULL, ptr), ptr, false); } void -arena_set(unsigned ind, arena_t *arena) -{ +arena_set(unsigned ind, arena_t *arena) { atomic_write_p((void **)&arenas[ind], arena); } static void -narenas_total_set(unsigned narenas) -{ +narenas_total_set(unsigned narenas) { atomic_write_u(&narenas_total, narenas); } static void -narenas_total_inc(void) -{ +narenas_total_inc(void) { atomic_add_u(&narenas_total, 1); } unsigned -narenas_total_get(void) -{ +narenas_total_get(void) { return (atomic_read_u(&narenas_total)); } /* Create a new arena and insert it into the arenas array at index ind. */ static arena_t * -arena_init_locked(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) -{ +arena_init_locked(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena_t *arena; assert(ind <= narenas_total_get()); - if (ind > MALLOCX_ARENA_MAX) + if (ind > MALLOCX_ARENA_MAX) { return (NULL); - if (ind == narenas_total_get()) + } + if (ind == narenas_total_get()) { narenas_total_inc(); + } /* * Another thread may have already initialized arenas[ind] if it's an @@ -418,8 +410,7 @@ arena_init_locked(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) } arena_t * -arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) -{ +arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena_t *arena; malloc_mutex_lock(tsdn, &arenas_lock); @@ -429,25 +420,25 @@ arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) } static void -arena_bind(tsd_t *tsd, unsigned ind, bool internal) -{ +arena_bind(tsd_t *tsd, unsigned ind, bool internal) { arena_t *arena; - if (!tsd_nominal(tsd)) + if (!tsd_nominal(tsd)) { return; + } arena = arena_get(tsd_tsdn(tsd), ind, false); arena_nthreads_inc(arena, internal); - if (internal) + if (internal) { tsd_iarena_set(tsd, arena); - else + } else { tsd_arena_set(tsd, arena); + } } void -arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind) -{ +arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind) { arena_t *oldarena, *newarena; oldarena = arena_get(tsd_tsdn(tsd), oldind, false); @@ -458,21 +449,20 @@ arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind) } static void -arena_unbind(tsd_t *tsd, unsigned ind, bool internal) -{ +arena_unbind(tsd_t *tsd, unsigned ind, bool internal) { arena_t *arena; arena = arena_get(tsd_tsdn(tsd), ind, false); arena_nthreads_dec(arena, internal); - if (internal) + if (internal) { tsd_iarena_set(tsd, NULL); - else + } else { tsd_arena_set(tsd, NULL); + } } arena_tdata_t * -arena_tdata_get_hard(tsd_t *tsd, unsigned ind) -{ +arena_tdata_get_hard(tsd_t *tsd, unsigned ind) { arena_tdata_t *tdata, *arenas_tdata_old; arena_tdata_t *arenas_tdata = tsd_arenas_tdata_get(tsd); unsigned narenas_tdata_old, i; @@ -541,15 +531,15 @@ arena_tdata_get_hard(tsd_t *tsd, unsigned ind) /* Read the refreshed tdata array. */ tdata = &arenas_tdata[ind]; label_return: - if (arenas_tdata_old != NULL) + if (arenas_tdata_old != NULL) { a0dalloc(arenas_tdata_old); + } return (tdata); } /* Slow path, called only by arena_choose(). */ arena_t * -arena_choose_hard(tsd_t *tsd, bool internal) -{ +arena_choose_hard(tsd_t *tsd, bool internal) { arena_t *ret JEMALLOC_CC_SILENCE_INIT(NULL); if (narenas_auto > 1) { @@ -563,8 +553,9 @@ arena_choose_hard(tsd_t *tsd, bool internal) * choose[1]: For internal metadata allocation. */ - for (j = 0; j < 2; j++) + for (j = 0; j < 2; j++) { choose[j] = 0; + } first_null = narenas_auto; malloc_mutex_lock(tsd_tsdn(tsd), &arenas_lock); @@ -580,8 +571,9 @@ arena_choose_hard(tsd_t *tsd, bool internal) tsd_tsdn(tsd), i, false), !!j) < arena_nthreads_get(arena_get( tsd_tsdn(tsd), choose[j], false), - !!j)) + !!j)) { choose[j] = i; + } } } else if (first_null == narenas_auto) { /* @@ -622,8 +614,9 @@ arena_choose_hard(tsd_t *tsd, bool internal) &arenas_lock); return (NULL); } - if (!!j == internal) + if (!!j == internal) { ret = arena; + } } arena_bind(tsd, choose[j], !!j); } @@ -638,28 +631,27 @@ arena_choose_hard(tsd_t *tsd, bool internal) } void -iarena_cleanup(tsd_t *tsd) -{ +iarena_cleanup(tsd_t *tsd) { arena_t *iarena; iarena = tsd_iarena_get(tsd); - if (iarena != NULL) + if (iarena != NULL) { arena_unbind(tsd, arena_ind_get(iarena), true); + } } void -arena_cleanup(tsd_t *tsd) -{ +arena_cleanup(tsd_t *tsd) { arena_t *arena; arena = tsd_arena_get(tsd); - if (arena != NULL) + if (arena != NULL) { arena_unbind(tsd, arena_ind_get(arena), false); + } } void -arenas_tdata_cleanup(tsd_t *tsd) -{ +arenas_tdata_cleanup(tsd_t *tsd) { arena_tdata_t *arenas_tdata; /* Prevent tsd->arenas_tdata from being (re)created. */ @@ -673,8 +665,7 @@ arenas_tdata_cleanup(tsd_t *tsd) } static void -stats_print_atexit(void) -{ +stats_print_atexit(void) { if (config_tcache && config_stats) { tsdn_t *tsdn; unsigned narenas, i; @@ -720,19 +711,18 @@ stats_print_atexit(void) #ifndef JEMALLOC_HAVE_SECURE_GETENV static char * -secure_getenv(const char *name) -{ +secure_getenv(const char *name) { # ifdef JEMALLOC_HAVE_ISSETUGID - if (issetugid() != 0) + if (issetugid() != 0) { return (NULL); + } # endif return (getenv(name)); } #endif static unsigned -malloc_ncpus(void) -{ +malloc_ncpus(void) { long result; #ifdef _WIN32 @@ -761,8 +751,7 @@ malloc_ncpus(void) static bool malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p, - char const **v_p, size_t *vlen_p) -{ + char const **v_p, size_t *vlen_p) { bool accept; const char *opts = *opts_p; @@ -837,15 +826,13 @@ malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p, static void malloc_conf_error(const char *msg, const char *k, size_t klen, const char *v, - size_t vlen) -{ + size_t vlen) { malloc_printf(": %s: %.*s:%.*s\n", msg, (int)klen, k, (int)vlen, v); } static void -malloc_slow_flag_init(void) -{ +malloc_slow_flag_init(void) { /* * Combine the runtime options into malloc_slow for fast path. Called * after processing all the options. @@ -860,8 +847,7 @@ malloc_slow_flag_init(void) } static void -malloc_conf_init(void) -{ +malloc_conf_init(void) { unsigned i; char buf[PATH_MAX + 1]; const char *opts, *k, *v; @@ -948,17 +934,18 @@ malloc_conf_init(void) (sizeof(n)-1 == vlen && strncmp(n, v, vlen) == 0) #define CONF_HANDLE_BOOL(o, n, cont) \ if (CONF_MATCH(n)) { \ - if (CONF_MATCH_VALUE("true")) \ + if (CONF_MATCH_VALUE("true")) { \ o = true; \ - else if (CONF_MATCH_VALUE("false")) \ + } else if (CONF_MATCH_VALUE("false")) { \ o = false; \ - else { \ + } else { \ malloc_conf_error( \ "Invalid conf value", \ k, klen, v, vlen); \ } \ - if (cont) \ + if (cont) { \ continue; \ + } \ } #define CONF_MIN_no(um, min) false #define CONF_MIN_yes(um, min) ((um) < (min)) @@ -978,13 +965,15 @@ malloc_conf_init(void) k, klen, v, vlen); \ } else if (clip) { \ if (CONF_MIN_##check_min(um, \ - (min))) \ + (min))) { \ o = (t)(min); \ - else if (CONF_MAX_##check_max( \ - um, (max))) \ + } else if ( \ + CONF_MAX_##check_max(um, \ + (max))) { \ o = (t)(max); \ - else \ + } else { \ o = (t)um; \ + } \ } else { \ if (CONF_MIN_##check_min(um, \ (min)) || \ @@ -994,8 +983,9 @@ malloc_conf_init(void) "Out-of-range " \ "conf value", \ k, klen, v, vlen); \ - } else \ + } else { \ o = (t)um; \ + } \ } \ continue; \ } @@ -1023,8 +1013,9 @@ malloc_conf_init(void) malloc_conf_error( \ "Out-of-range conf value", \ k, klen, v, vlen); \ - } else \ + } else { \ o = l; \ + } \ continue; \ } #define CONF_HANDLE_CHAR_P(o, n, d) \ @@ -1148,8 +1139,7 @@ malloc_conf_init(void) } static bool -malloc_init_hard_needed(void) -{ +malloc_init_hard_needed(void) { if (malloc_initialized() || (IS_INITIALIZER && malloc_init_state == malloc_init_recursible)) { /* @@ -1177,35 +1167,42 @@ malloc_init_hard_needed(void) } static bool -malloc_init_hard_a0_locked() -{ +malloc_init_hard_a0_locked() { malloc_initializer = INITIALIZER; - if (config_prof) + if (config_prof) { prof_boot0(); + } malloc_conf_init(); if (opt_stats_print) { /* Print statistics at exit. */ if (atexit(stats_print_atexit) != 0) { malloc_write(": Error in atexit()\n"); - if (opt_abort) + if (opt_abort) { abort(); + } } } pages_boot(); - if (base_boot(TSDN_NULL)) + if (base_boot(TSDN_NULL)) { return (true); - if (extent_boot()) + } + if (extent_boot()) { return (true); - if (ctl_boot()) + } + if (ctl_boot()) { return (true); - if (config_prof) + } + if (config_prof) { prof_boot1(); + } arena_boot(); - if (config_tcache && tcache_boot(TSDN_NULL)) + if (config_tcache && tcache_boot(TSDN_NULL)) { return (true); - if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS)) + } + if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS)) { return (true); + } /* * Create enough scaffolding to allow recursive allocation in * malloc_ncpus(). @@ -1218,9 +1215,10 @@ malloc_init_hard_a0_locked() * Initialize one arena here. The rest are lazily created in * arena_choose_hard(). */ - if (arena_init(TSDN_NULL, 0, (extent_hooks_t *)&extent_hooks_default) == - NULL) + if (arena_init(TSDN_NULL, 0, (extent_hooks_t *)&extent_hooks_default) + == NULL) { return (true); + } malloc_init_state = malloc_init_a0_initialized; @@ -1228,8 +1226,7 @@ malloc_init_hard_a0_locked() } static bool -malloc_init_hard_a0(void) -{ +malloc_init_hard_a0(void) { bool ret; malloc_mutex_lock(TSDN_NULL, &init_lock); @@ -1240,8 +1237,7 @@ malloc_init_hard_a0(void) /* Initialize data structures which may trigger recursive allocation. */ static bool -malloc_init_hard_recursible(void) -{ +malloc_init_hard_recursible(void) { malloc_init_state = malloc_init_recursible; ncpus = malloc_ncpus(); @@ -1253,8 +1249,9 @@ malloc_init_hard_recursible(void) if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent, jemalloc_postfork_child) != 0) { malloc_write(": Error in pthread_atfork()\n"); - if (opt_abort) + if (opt_abort) { abort(); + } return (true); } #endif @@ -1263,20 +1260,21 @@ malloc_init_hard_recursible(void) } static bool -malloc_init_hard_finish(tsdn_t *tsdn) -{ - if (malloc_mutex_boot()) +malloc_init_hard_finish(tsdn_t *tsdn) { + if (malloc_mutex_boot()) { return (true); + } if (opt_narenas == 0) { /* * For SMP systems, create more than one arena per CPU by * default. */ - if (ncpus > 1) + if (ncpus > 1) { opt_narenas = ncpus << 2; - else + } else { opt_narenas = 1; + } } narenas_auto = opt_narenas; /* @@ -1292,8 +1290,9 @@ malloc_init_hard_finish(tsdn_t *tsdn) /* Allocate and initialize arenas. */ arenas = (arena_t **)base_alloc(tsdn, a0->base, sizeof(arena_t *) * (MALLOCX_ARENA_MAX+1), CACHELINE); - if (arenas == NULL) + if (arenas == NULL) { return (true); + } /* Copy the pointer to the one arena that was already initialized. */ arena_set(0, a0); @@ -1304,8 +1303,7 @@ malloc_init_hard_finish(tsdn_t *tsdn) } static bool -malloc_init_hard(void) -{ +malloc_init_hard(void) { tsd_t *tsd; #if defined(_WIN32) && _WIN32_WINNT < 0x0600 @@ -1326,10 +1324,12 @@ malloc_init_hard(void) malloc_mutex_unlock(TSDN_NULL, &init_lock); /* Recursive allocation relies on functional tsd. */ tsd = malloc_tsd_boot0(); - if (tsd == NULL) + if (tsd == NULL) { return (true); - if (malloc_init_hard_recursible()) + } + if (malloc_init_hard_recursible()) { return (true); + } malloc_mutex_lock(tsd_tsdn(tsd), &init_lock); if (config_prof && prof_boot2(tsd)) { @@ -1616,7 +1616,6 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); - /* If profiling is on, get our profiling context. */ if (config_prof && opt_prof) { /* @@ -1755,8 +1754,7 @@ imalloc(static_opts_t *sopts, dynamic_opts_t *dopts) { JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN void JEMALLOC_NOTHROW * JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1) -je_malloc(size_t size) -{ +je_malloc(size_t size) { void *ret; static_opts_t sopts; dynamic_opts_t dopts; @@ -1780,8 +1778,7 @@ je_malloc(size_t size) JEMALLOC_EXPORT int JEMALLOC_NOTHROW JEMALLOC_ATTR(nonnull(1)) -je_posix_memalign(void **memptr, size_t alignment, size_t size) -{ +je_posix_memalign(void **memptr, size_t alignment, size_t size) { int ret; static_opts_t sopts; dynamic_opts_t dopts; @@ -1808,8 +1805,7 @@ je_posix_memalign(void **memptr, size_t alignment, size_t size) JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN void JEMALLOC_NOTHROW * JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(2) -je_aligned_alloc(size_t alignment, size_t size) -{ +je_aligned_alloc(size_t alignment, size_t size) { void *ret; static_opts_t sopts; @@ -1839,8 +1835,7 @@ je_aligned_alloc(size_t alignment, size_t size) JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN void JEMALLOC_NOTHROW * JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE2(1, 2) -je_calloc(size_t num, size_t size) -{ +je_calloc(size_t num, size_t size) { void *ret; static_opts_t sopts; dynamic_opts_t dopts; @@ -1865,29 +1860,30 @@ je_calloc(size_t num, size_t size) static void * irealloc_prof_sample(tsd_t *tsd, extent_t *extent, void *old_ptr, - size_t old_usize, size_t usize, prof_tctx_t *tctx) -{ + size_t old_usize, size_t usize, prof_tctx_t *tctx) { void *p; - if (tctx == NULL) + if (tctx == NULL) { return (NULL); + } if (usize <= SMALL_MAXCLASS) { p = iralloc(tsd, extent, old_ptr, old_usize, LARGE_MINCLASS, 0, false); - if (p == NULL) + if (p == NULL) { return (NULL); + } arena_prof_promote(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, usize); - } else + } else { p = iralloc(tsd, extent, old_ptr, old_usize, usize, 0, false); + } return (p); } JEMALLOC_ALWAYS_INLINE_C void * irealloc_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, - size_t usize) -{ + size_t usize) { void *p; extent_t *extent; bool prof_active; @@ -1915,8 +1911,7 @@ irealloc_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, } JEMALLOC_INLINE_C void -ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) -{ +ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { extent_t *extent; size_t usize; @@ -1929,42 +1924,46 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) if (config_prof && opt_prof) { usize = isalloc(tsd_tsdn(tsd), extent, ptr); prof_free(tsd, extent, ptr, usize); - } else if (config_stats) + } else if (config_stats) { usize = isalloc(tsd_tsdn(tsd), extent, ptr); - if (config_stats) + } + if (config_stats) { *tsd_thread_deallocatedp_get(tsd) += usize; + } - if (likely(!slow_path)) + if (likely(!slow_path)) { idalloctm(tsd_tsdn(tsd), extent, ptr, tcache, false, false); - else + } else { idalloctm(tsd_tsdn(tsd), extent, ptr, tcache, false, true); + } } JEMALLOC_INLINE_C void isfree(tsd_t *tsd, extent_t *extent, void *ptr, size_t usize, tcache_t *tcache, - bool slow_path) -{ + bool slow_path) { witness_assert_lockless(tsd_tsdn(tsd)); assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); - if (config_prof && opt_prof) + if (config_prof && opt_prof) { prof_free(tsd, extent, ptr, usize); - if (config_stats) + } + if (config_stats) { *tsd_thread_deallocatedp_get(tsd) += usize; + } - if (likely(!slow_path)) + if (likely(!slow_path)) { isdalloct(tsd_tsdn(tsd), extent, ptr, usize, tcache, false); - else + } else { isdalloct(tsd_tsdn(tsd), extent, ptr, usize, tcache, true); + } } JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN void JEMALLOC_NOTHROW * JEMALLOC_ALLOC_SIZE(2) -je_realloc(void *ptr, size_t size) -{ +je_realloc(void *ptr, size_t size) { void *ret; tsdn_t *tsdn JEMALLOC_CC_SILENCE_INIT(NULL); size_t usize JEMALLOC_CC_SILENCE_INIT(0); @@ -2000,8 +1999,9 @@ je_realloc(void *ptr, size_t size) NULL : irealloc_prof(tsd, extent, ptr, old_usize, usize); } else { - if (config_stats) + if (config_stats) { usize = s2u(size); + } ret = iralloc(tsd, extent, ptr, old_usize, size, 0, false); } @@ -2033,16 +2033,16 @@ je_realloc(void *ptr, size_t size) } JEMALLOC_EXPORT void JEMALLOC_NOTHROW -je_free(void *ptr) -{ +je_free(void *ptr) { UTRACE(ptr, 0, 0); if (likely(ptr != NULL)) { tsd_t *tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); - if (likely(!malloc_slow)) + if (likely(!malloc_slow)) { ifree(tsd, ptr, tcache_get(tsd, false), false); - else + } else { ifree(tsd, ptr, tcache_get(tsd, false), true); + } witness_assert_lockless(tsd_tsdn(tsd)); } } @@ -2059,8 +2059,7 @@ je_free(void *ptr) JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN void JEMALLOC_NOTHROW * JEMALLOC_ATTR(malloc) -je_memalign(size_t alignment, size_t size) -{ +je_memalign(size_t alignment, size_t size) { void *ret; static_opts_t sopts; dynamic_opts_t dopts; @@ -2090,8 +2089,7 @@ je_memalign(size_t alignment, size_t size) JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN void JEMALLOC_NOTHROW * JEMALLOC_ATTR(malloc) -je_valloc(size_t size) -{ +je_valloc(size_t size) { void *ret; static_opts_t sopts; @@ -2180,8 +2178,7 @@ int __posix_memalign(void** r, size_t a, size_t s) JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN void JEMALLOC_NOTHROW * JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1) -je_mallocx(size_t size, int flags) -{ +je_mallocx(size_t size, int flags) { void *ret; static_opts_t sopts; dynamic_opts_t dopts; @@ -2225,17 +2222,18 @@ je_mallocx(size_t size, int flags) static void * irallocx_prof_sample(tsdn_t *tsdn, extent_t *extent, void *old_ptr, size_t old_usize, size_t usize, size_t alignment, bool zero, - tcache_t *tcache, arena_t *arena, prof_tctx_t *tctx) -{ + tcache_t *tcache, arena_t *arena, prof_tctx_t *tctx) { void *p; - if (tctx == NULL) + if (tctx == NULL) { return (NULL); + } if (usize <= SMALL_MAXCLASS) { p = iralloct(tsdn, extent, old_ptr, old_usize, LARGE_MINCLASS, alignment, zero, tcache, arena); - if (p == NULL) + if (p == NULL) { return (NULL); + } arena_prof_promote(tsdn, iealloc(tsdn, p), p, usize); } else { p = iralloct(tsdn, extent, old_ptr, old_usize, usize, alignment, @@ -2248,8 +2246,7 @@ irallocx_prof_sample(tsdn_t *tsdn, extent_t *extent, void *old_ptr, JEMALLOC_ALWAYS_INLINE_C void * irallocx_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, size_t size, size_t alignment, size_t *usize, bool zero, tcache_t *tcache, - arena_t *arena) -{ + arena_t *arena) { void *p; extent_t *extent; bool prof_active; @@ -2281,8 +2278,9 @@ irallocx_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, */ extent = old_extent; *usize = isalloc(tsd_tsdn(tsd), extent, p); - } else + } else { extent = iealloc(tsd_tsdn(tsd), p); + } prof_realloc(tsd, extent, p, *usize, tctx, prof_active, false, old_extent, old_ptr, old_usize, old_tctx); @@ -2292,8 +2290,7 @@ irallocx_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN void JEMALLOC_NOTHROW * JEMALLOC_ALLOC_SIZE(2) -je_rallocx(void *ptr, size_t size, int flags) -{ +je_rallocx(void *ptr, size_t size, int flags) { void *p; tsd_t *tsd; extent_t *extent; @@ -2314,34 +2311,41 @@ je_rallocx(void *ptr, size_t size, int flags) if (unlikely((flags & MALLOCX_ARENA_MASK) != 0)) { unsigned arena_ind = MALLOCX_ARENA_GET(flags); arena = arena_get(tsd_tsdn(tsd), arena_ind, true); - if (unlikely(arena == NULL)) + if (unlikely(arena == NULL)) { goto label_oom; - } else + } + } else { arena = NULL; + } if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { - if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) + if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) { tcache = NULL; - else + } else { tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags)); - } else + } + } else { tcache = tcache_get(tsd, true); + } old_usize = isalloc(tsd_tsdn(tsd), extent, ptr); if (config_prof && opt_prof) { usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment); - if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { goto label_oom; + } p = irallocx_prof(tsd, extent, ptr, old_usize, size, alignment, &usize, zero, tcache, arena); - if (unlikely(p == NULL)) + if (unlikely(p == NULL)) { goto label_oom; + } } else { p = iralloct(tsd_tsdn(tsd), extent, ptr, old_usize, size, alignment, zero, tcache, arena); - if (unlikely(p == NULL)) + if (unlikely(p == NULL)) { goto label_oom; + } if (config_stats) { usize = isalloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p); @@ -2368,12 +2372,13 @@ label_oom: JEMALLOC_ALWAYS_INLINE_C size_t ixallocx_helper(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t old_usize, - size_t size, size_t extra, size_t alignment, bool zero) -{ + size_t size, size_t extra, size_t alignment, bool zero) { size_t usize; - if (ixalloc(tsdn, extent, ptr, old_usize, size, extra, alignment, zero)) + if (ixalloc(tsdn, extent, ptr, old_usize, size, extra, alignment, + zero)) { return (old_usize); + } usize = isalloc(tsdn, extent, ptr); return (usize); @@ -2382,12 +2387,12 @@ ixallocx_helper(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t old_usize, static size_t ixallocx_prof_sample(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t old_usize, size_t size, size_t extra, size_t alignment, bool zero, - prof_tctx_t *tctx) -{ + prof_tctx_t *tctx) { size_t usize; - if (tctx == NULL) + if (tctx == NULL) { return (old_usize); + } usize = ixallocx_helper(tsdn, extent, ptr, old_usize, size, extra, alignment, zero); @@ -2396,8 +2401,7 @@ ixallocx_prof_sample(tsdn_t *tsdn, extent_t *extent, void *ptr, JEMALLOC_ALWAYS_INLINE_C size_t ixallocx_prof(tsd_t *tsd, extent_t *extent, void *ptr, size_t old_usize, - size_t size, size_t extra, size_t alignment, bool zero) -{ + size_t size, size_t extra, size_t alignment, bool zero) { size_t usize_max, usize; bool prof_active; prof_tctx_t *old_tctx, *tctx; @@ -2445,8 +2449,7 @@ ixallocx_prof(tsd_t *tsd, extent_t *extent, void *ptr, size_t old_usize, } JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW -je_xallocx(void *ptr, size_t size, size_t extra, int flags) -{ +je_xallocx(void *ptr, size_t size, size_t extra, int flags) { tsd_t *tsd; extent_t *extent; size_t usize, old_usize; @@ -2476,8 +2479,9 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) usize = old_usize; goto label_not_resized; } - if (unlikely(LARGE_MAXCLASS - size < extra)) + if (unlikely(LARGE_MAXCLASS - size < extra)) { extra = LARGE_MAXCLASS - size; + } if (config_prof && opt_prof) { usize = ixallocx_prof(tsd, extent, ptr, old_usize, size, extra, @@ -2486,8 +2490,9 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) usize = ixallocx_helper(tsd_tsdn(tsd), extent, ptr, old_usize, size, extra, alignment, zero); } - if (unlikely(usize == old_usize)) + if (unlikely(usize == old_usize)) { goto label_not_resized; + } if (config_stats) { *tsd_thread_allocatedp_get(tsd) += usize; @@ -2501,8 +2506,7 @@ label_not_resized: JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW JEMALLOC_ATTR(pure) -je_sallocx(const void *ptr, int flags) -{ +je_sallocx(const void *ptr, int flags) { size_t usize; tsdn_t *tsdn; @@ -2511,18 +2515,18 @@ je_sallocx(const void *ptr, int flags) tsdn = tsdn_fetch(); witness_assert_lockless(tsdn); - if (config_ivsalloc) + if (config_ivsalloc) { usize = ivsalloc(tsdn, ptr); - else + } else { usize = isalloc(tsdn, iealloc(tsdn, ptr), ptr); + } witness_assert_lockless(tsdn); return (usize); } JEMALLOC_EXPORT void JEMALLOC_NOTHROW -je_dallocx(void *ptr, int flags) -{ +je_dallocx(void *ptr, int flags) { tsd_t *tsd; tcache_t *tcache; @@ -2532,39 +2536,41 @@ je_dallocx(void *ptr, int flags) tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { - if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) + if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) { tcache = NULL; - else + } else { tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags)); - } else + } + } else { tcache = tcache_get(tsd, false); + } UTRACE(ptr, 0, 0); - if (likely(!malloc_slow)) + if (likely(!malloc_slow)) { ifree(tsd, ptr, tcache, false); - else + } else { ifree(tsd, ptr, tcache, true); + } witness_assert_lockless(tsd_tsdn(tsd)); } JEMALLOC_ALWAYS_INLINE_C size_t -inallocx(tsdn_t *tsdn, size_t size, int flags) -{ +inallocx(tsdn_t *tsdn, size_t size, int flags) { size_t usize; witness_assert_lockless(tsdn); - if (likely((flags & MALLOCX_LG_ALIGN_MASK) == 0)) + if (likely((flags & MALLOCX_LG_ALIGN_MASK) == 0)) { usize = s2u(size); - else + } else { usize = sa2u(size, MALLOCX_ALIGN_GET_SPECIFIED(flags)); + } witness_assert_lockless(tsdn); return (usize); } JEMALLOC_EXPORT void JEMALLOC_NOTHROW -je_sdallocx(void *ptr, size_t size, int flags) -{ +je_sdallocx(void *ptr, size_t size, int flags) { tsd_t *tsd; extent_t *extent; size_t usize; @@ -2579,39 +2585,43 @@ je_sdallocx(void *ptr, size_t size, int flags) witness_assert_lockless(tsd_tsdn(tsd)); if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { - if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) + if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) { tcache = NULL; - else + } else { tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags)); - } else + } + } else { tcache = tcache_get(tsd, false); + } UTRACE(ptr, 0, 0); - if (likely(!malloc_slow)) + if (likely(!malloc_slow)) { isfree(tsd, extent, ptr, usize, tcache, false); - else + } else { isfree(tsd, extent, ptr, usize, tcache, true); + } witness_assert_lockless(tsd_tsdn(tsd)); } JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW JEMALLOC_ATTR(pure) -je_nallocx(size_t size, int flags) -{ +je_nallocx(size_t size, int flags) { size_t usize; tsdn_t *tsdn; assert(size != 0); - if (unlikely(malloc_init())) + if (unlikely(malloc_init())) { return (0); + } tsdn = tsdn_fetch(); witness_assert_lockless(tsdn); usize = inallocx(tsdn, size, flags); - if (unlikely(usize > LARGE_MAXCLASS)) + if (unlikely(usize > LARGE_MAXCLASS)) { return (0); + } witness_assert_lockless(tsdn); return (usize); @@ -2619,13 +2629,13 @@ je_nallocx(size_t size, int flags) JEMALLOC_EXPORT int JEMALLOC_NOTHROW je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, - size_t newlen) -{ + size_t newlen) { int ret; tsd_t *tsd; - if (unlikely(malloc_init())) + if (unlikely(malloc_init())) { return (EAGAIN); + } tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); @@ -2635,13 +2645,13 @@ je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, } JEMALLOC_EXPORT int JEMALLOC_NOTHROW -je_mallctlnametomib(const char *name, size_t *mibp, size_t *miblenp) -{ +je_mallctlnametomib(const char *name, size_t *mibp, size_t *miblenp) { int ret; tsdn_t *tsdn; - if (unlikely(malloc_init())) + if (unlikely(malloc_init())) { return (EAGAIN); + } tsdn = tsdn_fetch(); witness_assert_lockless(tsdn); @@ -2652,13 +2662,13 @@ je_mallctlnametomib(const char *name, size_t *mibp, size_t *miblenp) JEMALLOC_EXPORT int JEMALLOC_NOTHROW je_mallctlbymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, - void *newp, size_t newlen) -{ + void *newp, size_t newlen) { int ret; tsd_t *tsd; - if (unlikely(malloc_init())) + if (unlikely(malloc_init())) { return (EAGAIN); + } tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); @@ -2669,8 +2679,7 @@ je_mallctlbymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, JEMALLOC_EXPORT void JEMALLOC_NOTHROW je_malloc_stats_print(void (*write_cb)(void *, const char *), void *cbopaque, - const char *opts) -{ + const char *opts) { tsdn_t *tsdn; tsdn = tsdn_fetch(); @@ -2680,8 +2689,7 @@ je_malloc_stats_print(void (*write_cb)(void *, const char *), void *cbopaque, } JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW -je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) -{ +je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) { size_t ret; tsdn_t *tsdn; @@ -2690,9 +2698,9 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) tsdn = tsdn_fetch(); witness_assert_lockless(tsdn); - if (config_ivsalloc) + if (config_ivsalloc) { ret = ivsalloc(tsdn, ptr); - else { + } else { ret = (ptr == NULL) ? 0 : isalloc(tsdn, iealloc(tsdn, ptr), ptr); } @@ -2726,8 +2734,7 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) #ifndef JEMALLOC_JET JEMALLOC_ATTR(constructor) static void -jemalloc_constructor(void) -{ +jemalloc_constructor(void) { malloc_init(); } #endif @@ -2745,8 +2752,9 @@ _malloc_prefork(void) arena_t *arena; #ifdef JEMALLOC_MUTEX_INIT_CB - if (!malloc_initialized()) + if (!malloc_initialized()) { return; + } #endif assert(malloc_initialized()); @@ -2779,8 +2787,9 @@ _malloc_prefork(void) } } for (i = 0; i < narenas; i++) { - if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) + if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) { arena_prefork3(tsd_tsdn(tsd), arena); + } } prof_prefork1(tsd_tsdn(tsd)); } @@ -2797,8 +2806,9 @@ _malloc_postfork(void) unsigned i, narenas; #ifdef JEMALLOC_MUTEX_INIT_CB - if (!malloc_initialized()) + if (!malloc_initialized()) { return; + } #endif assert(malloc_initialized()); @@ -2809,8 +2819,9 @@ _malloc_postfork(void) for (i = 0, narenas = narenas_total_get(); i < narenas; i++) { arena_t *arena; - if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) + if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) { arena_postfork_parent(tsd_tsdn(tsd), arena); + } } prof_postfork_parent(tsd_tsdn(tsd)); malloc_mutex_postfork_parent(tsd_tsdn(tsd), &arenas_lock); @@ -2818,8 +2829,7 @@ _malloc_postfork(void) } void -jemalloc_postfork_child(void) -{ +jemalloc_postfork_child(void) { tsd_t *tsd; unsigned i, narenas; @@ -2832,8 +2842,9 @@ jemalloc_postfork_child(void) for (i = 0, narenas = narenas_total_get(); i < narenas; i++) { arena_t *arena; - if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) + if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) { arena_postfork_child(tsd_tsdn(tsd), arena); + } } prof_postfork_child(tsd_tsdn(tsd)); malloc_mutex_postfork_child(tsd_tsdn(tsd), &arenas_lock); diff --git a/src/jemalloc_cpp.cpp b/src/jemalloc_cpp.cpp index 984c944b..030ff995 100644 --- a/src/jemalloc_cpp.cpp +++ b/src/jemalloc_cpp.cpp @@ -33,8 +33,7 @@ void operator delete[](void *ptr, std::size_t size) noexcept; template JEMALLOC_INLINE void * -newImpl(std::size_t size) noexcept(IsNoExcept) -{ +newImpl(std::size_t size) noexcept(IsNoExcept) { void *ptr = je_malloc(size); if (likely(ptr != nullptr)) return (ptr); @@ -67,65 +66,55 @@ newImpl(std::size_t size) noexcept(IsNoExcept) } void * -operator new(std::size_t size) -{ +operator new(std::size_t size) { return (newImpl(size)); } void * -operator new[](std::size_t size) -{ +operator new[](std::size_t size) { return (newImpl(size)); } void * -operator new(std::size_t size, const std::nothrow_t &) noexcept -{ +operator new(std::size_t size, const std::nothrow_t &) noexcept { return (newImpl(size)); } void * -operator new[](std::size_t size, const std::nothrow_t &) noexcept -{ +operator new[](std::size_t size, const std::nothrow_t &) noexcept { return (newImpl(size)); } void -operator delete(void *ptr) noexcept -{ +operator delete(void *ptr) noexcept { je_free(ptr); } void -operator delete[](void *ptr) noexcept -{ +operator delete[](void *ptr) noexcept { je_free(ptr); } void -operator delete(void *ptr, const std::nothrow_t &) noexcept -{ +operator delete(void *ptr, const std::nothrow_t &) noexcept { je_free(ptr); } -void operator delete[](void *ptr, const std::nothrow_t &) noexcept -{ +void operator delete[](void *ptr, const std::nothrow_t &) noexcept { je_free(ptr); } #if __cpp_sized_deallocation >= 201309 void -operator delete(void *ptr, std::size_t size) noexcept -{ +operator delete(void *ptr, std::size_t size) noexcept { if (unlikely(ptr == nullptr)) { return; } je_sdallocx(ptr, size, /*flags=*/0); } -void operator delete[](void *ptr, std::size_t size) noexcept -{ +void operator delete[](void *ptr, std::size_t size) noexcept { if (unlikely(ptr == nullptr)) { return; } diff --git a/src/large.c b/src/large.c index 9936b236..0f2f1763 100644 --- a/src/large.c +++ b/src/large.c @@ -4,8 +4,7 @@ /******************************************************************************/ void * -large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero) -{ +large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero) { assert(usize == s2u(usize)); return (large_palloc(tsdn, arena, usize, CACHELINE, zero)); @@ -13,8 +12,7 @@ large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero) void * large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, - bool zero) -{ + bool zero) { size_t ausize; extent_t *extent; bool is_zeroed; @@ -23,27 +21,31 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, assert(!tsdn_null(tsdn) || arena != NULL); ausize = sa2u(usize, alignment); - if (unlikely(ausize == 0 || ausize > LARGE_MAXCLASS)) + if (unlikely(ausize == 0 || ausize > LARGE_MAXCLASS)) { return (NULL); + } /* * Copy zero into is_zeroed and pass the copy to extent_alloc(), so that * it is possible to make correct junk/zero fill decisions below. */ is_zeroed = zero; - if (likely(!tsdn_null(tsdn))) + if (likely(!tsdn_null(tsdn))) { arena = arena_choose(tsdn_tsd(tsdn), arena); + } if (unlikely(arena == NULL) || (extent = arena_extent_alloc_large(tsdn, - arena, usize, alignment, &is_zeroed)) == NULL) + arena, usize, alignment, &is_zeroed)) == NULL) { return (NULL); + } /* Insert extent into large. */ malloc_mutex_lock(tsdn, &arena->large_mtx); ql_elm_new(extent, ql_link); ql_tail_insert(&arena->large, extent, ql_link); malloc_mutex_unlock(tsdn, &arena->large_mtx); - if (config_prof && arena_prof_accum(tsdn, arena, usize)) + if (config_prof && arena_prof_accum(tsdn, arena, usize)) { prof_idump(tsdn); + } if (zero || (config_fill && unlikely(opt_zero))) { if (!is_zeroed) { @@ -64,8 +66,7 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, #define large_dalloc_junk JEMALLOC_N(n_large_dalloc_junk) #endif void -large_dalloc_junk(void *ptr, size_t usize) -{ +large_dalloc_junk(void *ptr, size_t usize) { memset(ptr, JEMALLOC_FREE_JUNK, usize); } #ifdef JEMALLOC_JET @@ -79,15 +80,15 @@ large_dalloc_junk_t *large_dalloc_junk = JEMALLOC_N(n_large_dalloc_junk); #define large_dalloc_maybe_junk JEMALLOC_N(n_large_dalloc_maybe_junk) #endif void -large_dalloc_maybe_junk(void *ptr, size_t usize) -{ +large_dalloc_maybe_junk(void *ptr, size_t usize) { if (config_fill && have_dss && unlikely(opt_junk_free)) { /* * Only bother junk filling if the extent isn't about to be * unmapped. */ - if (!config_munmap || (have_dss && extent_in_dss(ptr))) + if (!config_munmap || (have_dss && extent_in_dss(ptr))) { large_dalloc_junk(ptr, usize); + } } } #ifdef JEMALLOC_JET @@ -98,8 +99,7 @@ large_dalloc_maybe_junk_t *large_dalloc_maybe_junk = #endif static bool -large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) -{ +large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { arena_t *arena = extent_arena_get(extent); size_t oldusize = extent_usize_get(extent); extent_hooks_t *extent_hooks = extent_hooks_get(arena); @@ -107,16 +107,18 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) assert(oldusize > usize); - if (extent_hooks->split == NULL) + if (extent_hooks->split == NULL) { return (true); + } /* Split excess pages. */ if (diff != 0) { extent_t *trail = extent_split_wrapper(tsdn, arena, &extent_hooks, extent, usize + large_pad, usize, diff, diff); - if (trail == NULL) + if (trail == NULL) { return (true); + } if (config_fill && unlikely(opt_junk_free)) { large_dalloc_maybe_junk(extent_addr_get(trail), @@ -133,8 +135,7 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) static bool large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, - bool zero) -{ + bool zero) { arena_t *arena = extent_arena_get(extent); size_t oldusize = extent_usize_get(extent); bool is_zeroed_trail = false; @@ -142,8 +143,9 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, size_t trailsize = usize - extent_usize_get(extent); extent_t *trail; - if (extent_hooks->merge == NULL) + if (extent_hooks->merge == NULL) { return (true); + } if ((trail = arena_extent_cache_alloc(tsdn, arena, &extent_hooks, extent_past_get(extent), trailsize, CACHELINE, &is_zeroed_trail)) == @@ -151,8 +153,9 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, bool commit = true; if ((trail = extent_alloc_wrapper(tsdn, arena, &extent_hooks, extent_past_get(extent), trailsize, 0, CACHELINE, - &is_zeroed_trail, &commit, false)) == NULL) + &is_zeroed_trail, &commit, false)) == NULL) { return (true); + } } if (extent_merge_wrapper(tsdn, arena, &extent_hooks, extent, trail)) { @@ -193,8 +196,7 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, bool large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, - size_t usize_max, bool zero) -{ + size_t usize_max, bool zero) { assert(s2u(extent_usize_get(extent)) == extent_usize_get(extent)); /* The following should have been caught by callers. */ assert(usize_min > 0 && usize_max <= LARGE_MAXCLASS); @@ -241,17 +243,16 @@ large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, static void * large_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, - size_t alignment, bool zero) -{ - if (alignment <= CACHELINE) + size_t alignment, bool zero) { + if (alignment <= CACHELINE) { return (large_malloc(tsdn, arena, usize, zero)); + } return (large_palloc(tsdn, arena, usize, alignment, zero)); } void * large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, - size_t alignment, bool zero, tcache_t *tcache) -{ + size_t alignment, bool zero, tcache_t *tcache) { void *ret; size_t copysize; @@ -262,8 +263,9 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, LARGE_MINCLASS); /* Try to avoid moving the allocation. */ - if (!large_ralloc_no_move(tsdn, extent, usize, usize, zero)) + if (!large_ralloc_no_move(tsdn, extent, usize, usize, zero)) { return (extent_addr_get(extent)); + } /* * usize and old size are different enough that we need to use a @@ -271,8 +273,9 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, * space and copying. */ ret = large_ralloc_move_helper(tsdn, arena, usize, alignment, zero); - if (ret == NULL) + if (ret == NULL) { return (NULL); + } copysize = (usize < extent_usize_get(extent)) ? usize : extent_usize_get(extent); @@ -288,8 +291,7 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, * independent of these considerations. */ static void -large_dalloc_impl(tsdn_t *tsdn, extent_t *extent, bool junked_locked) -{ +large_dalloc_impl(tsdn_t *tsdn, extent_t *extent, bool junked_locked) { arena_t *arena; arena = extent_arena_get(extent); @@ -302,42 +304,37 @@ large_dalloc_impl(tsdn_t *tsdn, extent_t *extent, bool junked_locked) } arena_extent_dalloc_large(tsdn, arena, extent, junked_locked); - if (!junked_locked) + if (!junked_locked) { arena_decay_tick(tsdn, arena); + } } void -large_dalloc_junked_locked(tsdn_t *tsdn, extent_t *extent) -{ +large_dalloc_junked_locked(tsdn_t *tsdn, extent_t *extent) { large_dalloc_impl(tsdn, extent, true); } void -large_dalloc(tsdn_t *tsdn, extent_t *extent) -{ +large_dalloc(tsdn_t *tsdn, extent_t *extent) { large_dalloc_impl(tsdn, extent, false); } size_t -large_salloc(tsdn_t *tsdn, const extent_t *extent) -{ +large_salloc(tsdn_t *tsdn, const extent_t *extent) { return (extent_usize_get(extent)); } prof_tctx_t * -large_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent) -{ +large_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent) { return (extent_prof_tctx_get(extent)); } void -large_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx) -{ +large_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx) { extent_prof_tctx_set(extent, tctx); } void -large_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent) -{ +large_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent) { large_prof_tctx_set(tsdn, extent, (prof_tctx_t *)(uintptr_t)1U); } diff --git a/src/mutex.c b/src/mutex.c index bde536de..bc0869f8 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -35,8 +35,7 @@ static int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *, void *(*)(void *), void *__restrict); static void -pthread_create_once(void) -{ +pthread_create_once(void) { pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create"); if (pthread_create_fptr == NULL) { malloc_write(": Error in dlsym(RTLD_NEXT, " @@ -50,8 +49,7 @@ pthread_create_once(void) JEMALLOC_EXPORT int pthread_create(pthread_t *__restrict thread, const pthread_attr_t *__restrict attr, void *(*start_routine)(void *), - void *__restrict arg) -{ + void *__restrict arg) { static pthread_once_t once_control = PTHREAD_ONCE_INIT; pthread_once(&once_control, pthread_create_once); @@ -68,15 +66,16 @@ JEMALLOC_EXPORT int _pthread_mutex_init_calloc_cb(pthread_mutex_t *mutex, #endif bool -malloc_mutex_init(malloc_mutex_t *mutex, const char *name, witness_rank_t rank) -{ +malloc_mutex_init(malloc_mutex_t *mutex, const char *name, + witness_rank_t rank) { #ifdef _WIN32 # if _WIN32_WINNT >= 0x0600 InitializeSRWLock(&mutex->lock); # else if (!InitializeCriticalSectionAndSpinCount(&mutex->lock, - _CRT_SPINCOUNT)) + _CRT_SPINCOUNT)) { return (true); + } # endif #elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) mutex->lock = OS_UNFAIR_LOCK_INIT; @@ -88,14 +87,16 @@ malloc_mutex_init(malloc_mutex_t *mutex, const char *name, witness_rank_t rank) postponed_mutexes = mutex; } else { if (_pthread_mutex_init_calloc_cb(&mutex->lock, - bootstrap_calloc) != 0) + bootstrap_calloc) != 0) { return (true); + } } #else pthread_mutexattr_t attr; - if (pthread_mutexattr_init(&attr) != 0) + if (pthread_mutexattr_init(&attr) != 0) { return (true); + } pthread_mutexattr_settype(&attr, MALLOC_MUTEX_TYPE); if (pthread_mutex_init(&mutex->lock, &attr) != 0) { pthread_mutexattr_destroy(&attr); @@ -103,26 +104,24 @@ malloc_mutex_init(malloc_mutex_t *mutex, const char *name, witness_rank_t rank) } pthread_mutexattr_destroy(&attr); #endif - if (config_debug) + if (config_debug) { witness_init(&mutex->witness, name, rank, NULL, NULL); + } return (false); } void -malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex) -{ +malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex) { malloc_mutex_lock(tsdn, mutex); } void -malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex) -{ +malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex) { malloc_mutex_unlock(tsdn, mutex); } void -malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex) -{ +malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex) { #ifdef JEMALLOC_MUTEX_INIT_CB malloc_mutex_unlock(tsdn, mutex); #else @@ -130,21 +129,22 @@ malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex) mutex->witness.rank)) { malloc_printf(": Error re-initializing mutex in " "child\n"); - if (opt_abort) + if (opt_abort) { abort(); + } } #endif } bool -malloc_mutex_boot(void) -{ +malloc_mutex_boot(void) { #ifdef JEMALLOC_MUTEX_INIT_CB postpone_init = false; while (postponed_mutexes != NULL) { if (_pthread_mutex_init_calloc_cb(&postponed_mutexes->lock, - bootstrap_calloc) != 0) + bootstrap_calloc) != 0) { return (true); + } postponed_mutexes = postponed_mutexes->postponed_next; } #endif diff --git a/src/nstime.c b/src/nstime.c index 57ebf2e0..66989a07 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -3,66 +3,56 @@ #define BILLION UINT64_C(1000000000) void -nstime_init(nstime_t *time, uint64_t ns) -{ +nstime_init(nstime_t *time, uint64_t ns) { time->ns = ns; } void -nstime_init2(nstime_t *time, uint64_t sec, uint64_t nsec) -{ +nstime_init2(nstime_t *time, uint64_t sec, uint64_t nsec) { time->ns = sec * BILLION + nsec; } uint64_t -nstime_ns(const nstime_t *time) -{ +nstime_ns(const nstime_t *time) { return (time->ns); } uint64_t -nstime_sec(const nstime_t *time) -{ +nstime_sec(const nstime_t *time) { return (time->ns / BILLION); } uint64_t -nstime_nsec(const nstime_t *time) -{ +nstime_nsec(const nstime_t *time) { return (time->ns % BILLION); } void -nstime_copy(nstime_t *time, const nstime_t *source) -{ +nstime_copy(nstime_t *time, const nstime_t *source) { *time = *source; } int -nstime_compare(const nstime_t *a, const nstime_t *b) -{ +nstime_compare(const nstime_t *a, const nstime_t *b) { return ((a->ns > b->ns) - (a->ns < b->ns)); } void -nstime_add(nstime_t *time, const nstime_t *addend) -{ +nstime_add(nstime_t *time, const nstime_t *addend) { assert(UINT64_MAX - time->ns >= addend->ns); time->ns += addend->ns; } void -nstime_subtract(nstime_t *time, const nstime_t *subtrahend) -{ +nstime_subtract(nstime_t *time, const nstime_t *subtrahend) { assert(nstime_compare(time, subtrahend) >= 0); time->ns -= subtrahend->ns; } void -nstime_imultiply(nstime_t *time, uint64_t multiplier) -{ +nstime_imultiply(nstime_t *time, uint64_t multiplier) { assert((((time->ns | multiplier) & (UINT64_MAX << (sizeof(uint64_t) << 2))) == 0) || ((time->ns * multiplier) / multiplier == time->ns)); @@ -70,16 +60,14 @@ nstime_imultiply(nstime_t *time, uint64_t multiplier) } void -nstime_idivide(nstime_t *time, uint64_t divisor) -{ +nstime_idivide(nstime_t *time, uint64_t divisor) { assert(divisor != 0); time->ns /= divisor; } uint64_t -nstime_divide(const nstime_t *time, const nstime_t *divisor) -{ +nstime_divide(const nstime_t *time, const nstime_t *divisor) { assert(divisor->ns != 0); return (time->ns / divisor->ns); @@ -88,8 +76,7 @@ nstime_divide(const nstime_t *time, const nstime_t *divisor) #ifdef _WIN32 # define NSTIME_MONOTONIC true static void -nstime_get(nstime_t *time) -{ +nstime_get(nstime_t *time) { FILETIME ft; uint64_t ticks_100ns; @@ -101,8 +88,7 @@ nstime_get(nstime_t *time) #elif JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE # define NSTIME_MONOTONIC true static void -nstime_get(nstime_t *time) -{ +nstime_get(nstime_t *time) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); @@ -111,8 +97,7 @@ nstime_get(nstime_t *time) #elif JEMALLOC_HAVE_CLOCK_MONOTONIC # define NSTIME_MONOTONIC true static void -nstime_get(nstime_t *time) -{ +nstime_get(nstime_t *time) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -121,15 +106,13 @@ nstime_get(nstime_t *time) #elif JEMALLOC_HAVE_MACH_ABSOLUTE_TIME # define NSTIME_MONOTONIC true static void -nstime_get(nstime_t *time) -{ +nstime_get(nstime_t *time) { nstime_init(time, mach_absolute_time()); } #else # define NSTIME_MONOTONIC false static void -nstime_get(nstime_t *time) -{ +nstime_get(nstime_t *time) { struct timeval tv; gettimeofday(&tv, NULL); @@ -142,8 +125,7 @@ nstime_get(nstime_t *time) #define nstime_monotonic JEMALLOC_N(n_nstime_monotonic) #endif bool -nstime_monotonic(void) -{ +nstime_monotonic(void) { return (NSTIME_MONOTONIC); #undef NSTIME_MONOTONIC } @@ -158,8 +140,7 @@ nstime_monotonic_t *nstime_monotonic = JEMALLOC_N(n_nstime_monotonic); #define nstime_update JEMALLOC_N(n_nstime_update) #endif bool -nstime_update(nstime_t *time) -{ +nstime_update(nstime_t *time) { nstime_t old_time; nstime_copy(&old_time, time); diff --git a/src/pages.c b/src/pages.c index 7c26a28a..c23dccd7 100644 --- a/src/pages.c +++ b/src/pages.c @@ -18,14 +18,14 @@ static bool os_overcommits; /******************************************************************************/ void * -pages_map(void *addr, size_t size, bool *commit) -{ +pages_map(void *addr, size_t size, bool *commit) { void *ret; assert(size != 0); - if (os_overcommits) + if (os_overcommits) { *commit = true; + } #ifdef _WIN32 /* @@ -46,9 +46,9 @@ pages_map(void *addr, size_t size, bool *commit) } assert(ret != NULL); - if (ret == MAP_FAILED) + if (ret == MAP_FAILED) { ret = NULL; - else if (addr != NULL && ret != addr) { + } else if (addr != NULL && ret != addr) { /* * We succeeded in mapping memory, but not in the right place. */ @@ -62,8 +62,7 @@ pages_map(void *addr, size_t size, bool *commit) } void -pages_unmap(void *addr, size_t size) -{ +pages_unmap(void *addr, size_t size) { #ifdef _WIN32 if (VirtualFree(addr, 0, MEM_RELEASE) == 0) #else @@ -80,15 +79,15 @@ pages_unmap(void *addr, size_t size) "munmap" #endif "(): %s\n", buf); - if (opt_abort) + if (opt_abort) { abort(); + } } } void * pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size, - bool *commit) -{ + bool *commit) { void *ret = (void *)((uintptr_t)addr + leadsize); assert(alloc_size >= leadsize + size); @@ -98,30 +97,34 @@ pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size, pages_unmap(addr, alloc_size); new_addr = pages_map(ret, size, commit); - if (new_addr == ret) + if (new_addr == ret) { return (ret); - if (new_addr) + } + if (new_addr) { pages_unmap(new_addr, size); + } return (NULL); } #else { size_t trailsize = alloc_size - leadsize - size; - if (leadsize != 0) + if (leadsize != 0) { pages_unmap(addr, leadsize); - if (trailsize != 0) + } + if (trailsize != 0) { pages_unmap((void *)((uintptr_t)ret + size), trailsize); + } return (ret); } #endif } static bool -pages_commit_impl(void *addr, size_t size, bool commit) -{ - if (os_overcommits) +pages_commit_impl(void *addr, size_t size, bool commit) { + if (os_overcommits) { return (true); + } #ifdef _WIN32 return (commit ? (addr != VirtualAlloc(addr, size, MEM_COMMIT, @@ -131,8 +134,9 @@ pages_commit_impl(void *addr, size_t size, bool commit) int prot = commit ? PAGES_PROT_COMMIT : PAGES_PROT_DECOMMIT; void *result = mmap(addr, size, prot, mmap_flags | MAP_FIXED, -1, 0); - if (result == MAP_FAILED) + if (result == MAP_FAILED) { return (true); + } if (result != addr) { /* * We succeeded in mapping memory, but not in the right @@ -147,22 +151,20 @@ pages_commit_impl(void *addr, size_t size, bool commit) } bool -pages_commit(void *addr, size_t size) -{ +pages_commit(void *addr, size_t size) { return (pages_commit_impl(addr, size, true)); } bool -pages_decommit(void *addr, size_t size) -{ +pages_decommit(void *addr, size_t size) { return (pages_commit_impl(addr, size, false)); } bool -pages_purge_lazy(void *addr, size_t size) -{ - if (!pages_can_purge_lazy) +pages_purge_lazy(void *addr, size_t size) { + if (!pages_can_purge_lazy) { return (true); + } #ifdef _WIN32 VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE); @@ -175,10 +177,10 @@ pages_purge_lazy(void *addr, size_t size) } bool -pages_purge_forced(void *addr, size_t size) -{ - if (!pages_can_purge_forced) +pages_purge_forced(void *addr, size_t size) { + if (!pages_can_purge_forced) { return (true); + } #if defined(JEMALLOC_PURGE_MADVISE_DONTNEED) return (madvise(addr, size, MADV_DONTNEED) != 0); @@ -188,8 +190,7 @@ pages_purge_forced(void *addr, size_t size) } bool -pages_huge(void *addr, size_t size) -{ +pages_huge(void *addr, size_t size) { assert(HUGEPAGE_ADDR2BASE(addr) == addr); assert(HUGEPAGE_CEILING(size) == size); @@ -201,8 +202,7 @@ pages_huge(void *addr, size_t size) } bool -pages_nohuge(void *addr, size_t size) -{ +pages_nohuge(void *addr, size_t size) { assert(HUGEPAGE_ADDR2BASE(addr) == addr); assert(HUGEPAGE_CEILING(size) == size); @@ -215,14 +215,14 @@ pages_nohuge(void *addr, size_t size) #ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT static bool -os_overcommits_sysctl(void) -{ +os_overcommits_sysctl(void) { int vm_overcommit; size_t sz; sz = sizeof(vm_overcommit); - if (sysctlbyname("vm.overcommit", &vm_overcommit, &sz, NULL, 0) != 0) + if (sysctlbyname("vm.overcommit", &vm_overcommit, &sz, NULL, 0) != 0) { return (false); /* Error. */ + } return ((vm_overcommit & 0x3) == 0); } @@ -235,8 +235,7 @@ os_overcommits_sysctl(void) * wrappers. */ static bool -os_overcommits_proc(void) -{ +os_overcommits_proc(void) { int fd; char buf[1]; ssize_t nread; @@ -246,8 +245,9 @@ os_overcommits_proc(void) #else fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY); #endif - if (fd == -1) + if (fd == -1) { return (false); /* Error. */ + } #if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_read) nread = (ssize_t)syscall(SYS_read, fd, &buf, sizeof(buf)); @@ -261,8 +261,9 @@ os_overcommits_proc(void) close(fd); #endif - if (nread < 1) + if (nread < 1) { return (false); /* Error. */ + } /* * /proc/sys/vm/overcommit_memory meanings: * 0: Heuristic overcommit. @@ -274,8 +275,7 @@ os_overcommits_proc(void) #endif void -pages_boot(void) -{ +pages_boot(void) { #ifndef _WIN32 mmap_flags = MAP_PRIVATE | MAP_ANON; #endif @@ -285,8 +285,9 @@ pages_boot(void) #elif defined(JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY) os_overcommits = os_overcommits_proc(); # ifdef MAP_NORESERVE - if (os_overcommits) + if (os_overcommits) { mmap_flags |= MAP_NORESERVE; + } # endif #else os_overcommits = false; diff --git a/src/prof.c b/src/prof.c index b161acfb..ca01d8b1 100644 --- a/src/prof.c +++ b/src/prof.c @@ -133,8 +133,7 @@ static char *prof_thread_name_alloc(tsdn_t *tsdn, const char *thread_name); /* Red-black trees. */ JEMALLOC_INLINE_C int -prof_tctx_comp(const prof_tctx_t *a, const prof_tctx_t *b) -{ +prof_tctx_comp(const prof_tctx_t *a, const prof_tctx_t *b) { uint64_t a_thr_uid = a->thr_uid; uint64_t b_thr_uid = b->thr_uid; int ret = (a_thr_uid > b_thr_uid) - (a_thr_uid < b_thr_uid); @@ -157,14 +156,14 @@ rb_gen(static UNUSED, tctx_tree_, prof_tctx_tree_t, prof_tctx_t, tctx_link, prof_tctx_comp) JEMALLOC_INLINE_C int -prof_gctx_comp(const prof_gctx_t *a, const prof_gctx_t *b) -{ +prof_gctx_comp(const prof_gctx_t *a, const prof_gctx_t *b) { unsigned a_len = a->bt.len; unsigned b_len = b->bt.len; unsigned comp_len = (a_len < b_len) ? a_len : b_len; int ret = memcmp(a->bt.vec, b->bt.vec, comp_len * sizeof(void *)); - if (ret == 0) + if (ret == 0) { ret = (a_len > b_len) - (a_len < b_len); + } return (ret); } @@ -172,8 +171,7 @@ rb_gen(static UNUSED, gctx_tree_, prof_gctx_tree_t, prof_gctx_t, dump_link, prof_gctx_comp) JEMALLOC_INLINE_C int -prof_tdata_comp(const prof_tdata_t *a, const prof_tdata_t *b) -{ +prof_tdata_comp(const prof_tdata_t *a, const prof_tdata_t *b) { int ret; uint64_t a_uid = a->thr_uid; uint64_t b_uid = b->thr_uid; @@ -194,8 +192,7 @@ rb_gen(static UNUSED, tdata_tree_, prof_tdata_tree_t, prof_tdata_t, tdata_link, /******************************************************************************/ void -prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated) -{ +prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated) { prof_tdata_t *tdata; cassert(config_prof); @@ -208,24 +205,25 @@ prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated) * programs. */ tdata = prof_tdata_get(tsd, true); - if (tdata != NULL) + if (tdata != NULL) { prof_sample_threshold_update(tdata); + } } if ((uintptr_t)tctx > (uintptr_t)1U) { malloc_mutex_lock(tsd_tsdn(tsd), tctx->tdata->lock); tctx->prepared = false; - if (prof_tctx_should_destroy(tsd_tsdn(tsd), tctx)) + if (prof_tctx_should_destroy(tsd_tsdn(tsd), tctx)) { prof_tctx_destroy(tsd, tctx); - else + } else { malloc_mutex_unlock(tsd_tsdn(tsd), tctx->tdata->lock); + } } } void prof_malloc_sample_object(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize, prof_tctx_t *tctx) -{ + size_t usize, prof_tctx_t *tctx) { prof_tctx_set(tsdn, extent, ptr, usize, tctx); malloc_mutex_lock(tsdn, tctx->tdata->lock); @@ -240,23 +238,22 @@ prof_malloc_sample_object(tsdn_t *tsdn, extent_t *extent, const void *ptr, } void -prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_tctx_t *tctx) -{ +prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_tctx_t *tctx) { malloc_mutex_lock(tsd_tsdn(tsd), tctx->tdata->lock); assert(tctx->cnts.curobjs > 0); assert(tctx->cnts.curbytes >= usize); tctx->cnts.curobjs--; tctx->cnts.curbytes -= usize; - if (prof_tctx_should_destroy(tsd_tsdn(tsd), tctx)) + if (prof_tctx_should_destroy(tsd_tsdn(tsd), tctx)) { prof_tctx_destroy(tsd, tctx); - else + } else { malloc_mutex_unlock(tsd_tsdn(tsd), tctx->tdata->lock); + } } void -bt_init(prof_bt_t *bt, void **vec) -{ +bt_init(prof_bt_t *bt, void **vec) { cassert(config_prof); bt->vec = vec; @@ -264,8 +261,7 @@ bt_init(prof_bt_t *bt, void **vec) } JEMALLOC_INLINE_C void -prof_enter(tsd_t *tsd, prof_tdata_t *tdata) -{ +prof_enter(tsd_t *tsd, prof_tdata_t *tdata) { cassert(config_prof); assert(tdata == prof_tdata_get(tsd, false)); @@ -278,8 +274,7 @@ prof_enter(tsd_t *tsd, prof_tdata_t *tdata) } JEMALLOC_INLINE_C void -prof_leave(tsd_t *tsd, prof_tdata_t *tdata) -{ +prof_leave(tsd_t *tsd, prof_tdata_t *tdata) { cassert(config_prof); assert(tdata == prof_tdata_get(tsd, false)); @@ -295,17 +290,18 @@ prof_leave(tsd_t *tsd, prof_tdata_t *tdata) gdump = tdata->enq_gdump; tdata->enq_gdump = false; - if (idump) + if (idump) { prof_idump(tsd_tsdn(tsd)); - if (gdump) + } + if (gdump) { prof_gdump(tsd_tsdn(tsd)); + } } } #ifdef JEMALLOC_PROF_LIBUNWIND void -prof_backtrace(prof_bt_t *bt) -{ +prof_backtrace(prof_bt_t *bt) { int nframes; cassert(config_prof); @@ -313,41 +309,41 @@ prof_backtrace(prof_bt_t *bt) assert(bt->vec != NULL); nframes = unw_backtrace(bt->vec, PROF_BT_MAX); - if (nframes <= 0) + if (nframes <= 0) { return; + } bt->len = nframes; } #elif (defined(JEMALLOC_PROF_LIBGCC)) static _Unwind_Reason_Code -prof_unwind_init_callback(struct _Unwind_Context *context, void *arg) -{ +prof_unwind_init_callback(struct _Unwind_Context *context, void *arg) { cassert(config_prof); return (_URC_NO_REASON); } static _Unwind_Reason_Code -prof_unwind_callback(struct _Unwind_Context *context, void *arg) -{ +prof_unwind_callback(struct _Unwind_Context *context, void *arg) { prof_unwind_data_t *data = (prof_unwind_data_t *)arg; void *ip; cassert(config_prof); ip = (void *)_Unwind_GetIP(context); - if (ip == NULL) + if (ip == NULL) { return (_URC_END_OF_STACK); + } data->bt->vec[data->bt->len] = ip; data->bt->len++; - if (data->bt->len == data->max) + if (data->bt->len == data->max) { return (_URC_END_OF_STACK); + } return (_URC_NO_REASON); } void -prof_backtrace(prof_bt_t *bt) -{ +prof_backtrace(prof_bt_t *bt) { prof_unwind_data_t data = {bt, PROF_BT_MAX}; cassert(config_prof); @@ -356,20 +352,22 @@ prof_backtrace(prof_bt_t *bt) } #elif (defined(JEMALLOC_PROF_GCC)) void -prof_backtrace(prof_bt_t *bt) -{ +prof_backtrace(prof_bt_t *bt) { #define BT_FRAME(i) \ if ((i) < PROF_BT_MAX) { \ void *p; \ - if (__builtin_frame_address(i) == 0) \ + if (__builtin_frame_address(i) == 0) { \ return; \ + } \ p = __builtin_return_address(i); \ - if (p == NULL) \ + if (p == NULL) { \ return; \ + } \ bt->vec[(i)] = p; \ bt->len = (i) + 1; \ - } else \ - return; + } else { \ + return; \ + } cassert(config_prof); @@ -517,30 +515,26 @@ prof_backtrace(prof_bt_t *bt) } #else void -prof_backtrace(prof_bt_t *bt) -{ +prof_backtrace(prof_bt_t *bt) { cassert(config_prof); not_reached(); } #endif static malloc_mutex_t * -prof_gctx_mutex_choose(void) -{ +prof_gctx_mutex_choose(void) { unsigned ngctxs = atomic_add_u(&cum_gctxs, 1); return (&gctx_locks[(ngctxs - 1) % PROF_NCTX_LOCKS]); } static malloc_mutex_t * -prof_tdata_mutex_choose(uint64_t thr_uid) -{ +prof_tdata_mutex_choose(uint64_t thr_uid) { return (&tdata_locks[thr_uid % PROF_NTDATA_LOCKS]); } static prof_gctx_t * -prof_gctx_create(tsdn_t *tsdn, prof_bt_t *bt) -{ +prof_gctx_create(tsdn_t *tsdn, prof_bt_t *bt) { /* * Create a single allocation that has space for vec of length bt->len. */ @@ -548,8 +542,9 @@ prof_gctx_create(tsdn_t *tsdn, prof_bt_t *bt) prof_gctx_t *gctx = (prof_gctx_t *)iallocztm(tsdn, size, size2index(size), false, NULL, true, arena_get(TSDN_NULL, 0, true), true); - if (gctx == NULL) + if (gctx == NULL) { return (NULL); + } gctx->lock = prof_gctx_mutex_choose(); /* * Set nlimbo to 1, in order to avoid a race condition with @@ -566,8 +561,7 @@ prof_gctx_create(tsdn_t *tsdn, prof_bt_t *bt) static void prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self, prof_gctx_t *gctx, - prof_tdata_t *tdata) -{ + prof_tdata_t *tdata) { cassert(config_prof); /* @@ -582,8 +576,9 @@ prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self, prof_gctx_t *gctx, assert(gctx->nlimbo != 0); if (tctx_tree_empty(&gctx->tctxs) && gctx->nlimbo == 1) { /* Remove gctx from bt2gctx. */ - if (ckh_remove(tsd, &bt2gctx, &gctx->bt, NULL, NULL)) + if (ckh_remove(tsd, &bt2gctx, &gctx->bt, NULL, NULL)) { not_reached(); + } prof_leave(tsd, tdata_self); /* Destroy gctx. */ malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock); @@ -601,34 +596,37 @@ prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self, prof_gctx_t *gctx, } static bool -prof_tctx_should_destroy(tsdn_t *tsdn, prof_tctx_t *tctx) -{ +prof_tctx_should_destroy(tsdn_t *tsdn, prof_tctx_t *tctx) { malloc_mutex_assert_owner(tsdn, tctx->tdata->lock); - if (opt_prof_accum) + if (opt_prof_accum) { return (false); - if (tctx->cnts.curobjs != 0) + } + if (tctx->cnts.curobjs != 0) { return (false); - if (tctx->prepared) + } + if (tctx->prepared) { return (false); + } return (true); } static bool -prof_gctx_should_destroy(prof_gctx_t *gctx) -{ - if (opt_prof_accum) +prof_gctx_should_destroy(prof_gctx_t *gctx) { + if (opt_prof_accum) { return (false); - if (!tctx_tree_empty(&gctx->tctxs)) + } + if (!tctx_tree_empty(&gctx->tctxs)) { return (false); - if (gctx->nlimbo != 0) + } + if (gctx->nlimbo != 0) { return (false); + } return (true); } static void -prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) -{ +prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) { prof_tdata_t *tdata = tctx->tdata; prof_gctx_t *gctx = tctx->gctx; bool destroy_tdata, destroy_tctx, destroy_gctx; @@ -667,8 +665,9 @@ prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) */ gctx->nlimbo++; destroy_gctx = true; - } else + } else { destroy_gctx = false; + } break; case prof_tctx_state_dumping: /* @@ -693,18 +692,19 @@ prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) malloc_mutex_assert_not_owner(tsd_tsdn(tsd), tctx->tdata->lock); - if (destroy_tdata) + if (destroy_tdata) { prof_tdata_destroy(tsd, tdata, false); + } - if (destroy_tctx) + if (destroy_tctx) { idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tctx), tctx, NULL, true, true); + } } static bool prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, - void **p_btkey, prof_gctx_t **p_gctx, bool *p_new_gctx) -{ + void **p_btkey, prof_gctx_t **p_gctx, bool *p_new_gctx) { union { prof_gctx_t *p; void *v; @@ -751,8 +751,7 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, } prof_tctx_t * -prof_lookup(tsd_t *tsd, prof_bt_t *bt) -{ +prof_lookup(tsd_t *tsd, prof_bt_t *bt) { union { prof_tctx_t *p; void *v; @@ -763,13 +762,15 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) cassert(config_prof); tdata = prof_tdata_get(tsd, false); - if (tdata == NULL) + if (tdata == NULL) { return (NULL); + } malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock); not_found = ckh_search(&tdata->bt2tctx, bt, NULL, &ret.v); - if (!not_found) /* Note double negative! */ + if (!not_found) { /* Note double negative! */ ret.p->prepared = true; + } malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); if (not_found) { void *btkey; @@ -781,16 +782,18 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) * cache. */ if (prof_lookup_global(tsd, bt, tdata, &btkey, &gctx, - &new_gctx)) + &new_gctx)) { return (NULL); + } /* Link a prof_tctx_t into gctx for this thread. */ ret.v = iallocztm(tsd_tsdn(tsd), sizeof(prof_tctx_t), size2index(sizeof(prof_tctx_t)), false, NULL, true, arena_ichoose(tsd, NULL), true); if (ret.p == NULL) { - if (new_gctx) + if (new_gctx) { prof_gctx_try_destroy(tsd, tdata, gctx, tdata); + } return (NULL); } ret.p->tdata = tdata; @@ -805,8 +808,9 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) error = ckh_insert(tsd, &tdata->bt2tctx, btkey, ret.v); malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); if (error) { - if (new_gctx) + if (new_gctx) { prof_gctx_try_destroy(tsd, tdata, gctx, tdata); + } idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), ret.v), ret.v, NULL, true, true); return (NULL); @@ -835,14 +839,14 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) * -mno-sse) in order for the workaround to be complete. */ void -prof_sample_threshold_update(prof_tdata_t *tdata) -{ +prof_sample_threshold_update(prof_tdata_t *tdata) { #ifdef JEMALLOC_PROF uint64_t r; double u; - if (!config_prof) + if (!config_prof) { return; + } if (lg_prof_sample == 0) { tdata->bytes_until_sample = 0; @@ -877,8 +881,8 @@ prof_sample_threshold_update(prof_tdata_t *tdata) #ifdef JEMALLOC_JET static prof_tdata_t * -prof_tdata_count_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, void *arg) -{ +prof_tdata_count_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, + void *arg) { size_t *tdata_count = (size_t *)arg; (*tdata_count)++; @@ -887,8 +891,7 @@ prof_tdata_count_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, void *arg) } size_t -prof_tdata_count(void) -{ +prof_tdata_count(void) { size_t tdata_count = 0; tsdn_t *tsdn; @@ -904,16 +907,16 @@ prof_tdata_count(void) #ifdef JEMALLOC_JET size_t -prof_bt_count(void) -{ +prof_bt_count(void) { size_t bt_count; tsd_t *tsd; prof_tdata_t *tdata; tsd = tsd_fetch(); tdata = prof_tdata_get(tsd, false); - if (tdata == NULL) + if (tdata == NULL) { return (0); + } malloc_mutex_lock(tsd_tsdn(tsd), &bt2gctx_mtx); bt_count = ckh_count(&bt2gctx); @@ -928,16 +931,16 @@ prof_bt_count(void) #define prof_dump_open JEMALLOC_N(prof_dump_open_impl) #endif static int -prof_dump_open(bool propagate_err, const char *filename) -{ +prof_dump_open(bool propagate_err, const char *filename) { int fd; fd = creat(filename, 0644); if (fd == -1 && !propagate_err) { malloc_printf(": creat(\"%s\"), 0644) failed\n", filename); - if (opt_abort) + if (opt_abort) { abort(); + } } return (fd); @@ -949,8 +952,7 @@ prof_dump_open_t *prof_dump_open = JEMALLOC_N(prof_dump_open_impl); #endif static bool -prof_dump_flush(bool propagate_err) -{ +prof_dump_flush(bool propagate_err) { bool ret = false; ssize_t err; @@ -961,8 +963,9 @@ prof_dump_flush(bool propagate_err) if (!propagate_err) { malloc_write(": write() failed during heap " "profile flush\n"); - if (opt_abort) + if (opt_abort) { abort(); + } } ret = true; } @@ -972,8 +975,7 @@ prof_dump_flush(bool propagate_err) } static bool -prof_dump_close(bool propagate_err) -{ +prof_dump_close(bool propagate_err) { bool ret; assert(prof_dump_fd != -1); @@ -985,8 +987,7 @@ prof_dump_close(bool propagate_err) } static bool -prof_dump_write(bool propagate_err, const char *s) -{ +prof_dump_write(bool propagate_err, const char *s) { size_t i, slen, n; cassert(config_prof); @@ -995,9 +996,11 @@ prof_dump_write(bool propagate_err, const char *s) slen = strlen(s); while (i < slen) { /* Flush the buffer if it is full. */ - if (prof_dump_buf_end == PROF_DUMP_BUFSIZE) - if (prof_dump_flush(propagate_err) && propagate_err) + if (prof_dump_buf_end == PROF_DUMP_BUFSIZE) { + if (prof_dump_flush(propagate_err) && propagate_err) { return (true); + } + } if (prof_dump_buf_end + slen <= PROF_DUMP_BUFSIZE) { /* Finish writing. */ @@ -1016,8 +1019,7 @@ prof_dump_write(bool propagate_err, const char *s) JEMALLOC_FORMAT_PRINTF(2, 3) static bool -prof_dump_printf(bool propagate_err, const char *format, ...) -{ +prof_dump_printf(bool propagate_err, const char *format, ...) { bool ret; va_list ap; char buf[PROF_PRINTF_BUFSIZE]; @@ -1031,8 +1033,7 @@ prof_dump_printf(bool propagate_err, const char *format, ...) } static void -prof_tctx_merge_tdata(tsdn_t *tsdn, prof_tctx_t *tctx, prof_tdata_t *tdata) -{ +prof_tctx_merge_tdata(tsdn_t *tsdn, prof_tctx_t *tctx, prof_tdata_t *tdata) { malloc_mutex_assert_owner(tsdn, tctx->tdata->lock); malloc_mutex_lock(tsdn, tctx->gctx->lock); @@ -1063,8 +1064,7 @@ prof_tctx_merge_tdata(tsdn_t *tsdn, prof_tctx_t *tctx, prof_tdata_t *tdata) } static void -prof_tctx_merge_gctx(tsdn_t *tsdn, prof_tctx_t *tctx, prof_gctx_t *gctx) -{ +prof_tctx_merge_gctx(tsdn_t *tsdn, prof_tctx_t *tctx, prof_gctx_t *gctx) { malloc_mutex_assert_owner(tsdn, gctx->lock); gctx->cnt_summed.curobjs += tctx->dump_cnts.curobjs; @@ -1076,8 +1076,7 @@ prof_tctx_merge_gctx(tsdn_t *tsdn, prof_tctx_t *tctx, prof_gctx_t *gctx) } static prof_tctx_t * -prof_tctx_merge_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) -{ +prof_tctx_merge_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) { tsdn_t *tsdn = (tsdn_t *)arg; malloc_mutex_assert_owner(tsdn, tctx->gctx->lock); @@ -1103,8 +1102,7 @@ struct prof_tctx_dump_iter_arg_s { }; static prof_tctx_t * -prof_tctx_dump_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *opaque) -{ +prof_tctx_dump_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *opaque) { struct prof_tctx_dump_iter_arg_s *arg = (struct prof_tctx_dump_iter_arg_s *)opaque; @@ -1121,8 +1119,9 @@ prof_tctx_dump_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *opaque) " t%"FMTu64": %"FMTu64": %"FMTu64" [%"FMTu64": " "%"FMTu64"]\n", tctx->thr_uid, tctx->dump_cnts.curobjs, tctx->dump_cnts.curbytes, tctx->dump_cnts.accumobjs, - tctx->dump_cnts.accumbytes)) + tctx->dump_cnts.accumbytes)) { return (tctx); + } break; default: not_reached(); @@ -1131,8 +1130,7 @@ prof_tctx_dump_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *opaque) } static prof_tctx_t * -prof_tctx_finish_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) -{ +prof_tctx_finish_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) { tsdn_t *tsdn = (tsdn_t *)arg; prof_tctx_t *ret; @@ -1158,8 +1156,7 @@ label_return: } static void -prof_dump_gctx_prep(tsdn_t *tsdn, prof_gctx_t *gctx, prof_gctx_tree_t *gctxs) -{ +prof_dump_gctx_prep(tsdn_t *tsdn, prof_gctx_t *gctx, prof_gctx_tree_t *gctxs) { cassert(config_prof); malloc_mutex_lock(tsdn, gctx->lock); @@ -1183,24 +1180,23 @@ struct prof_gctx_merge_iter_arg_s { }; static prof_gctx_t * -prof_gctx_merge_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *opaque) -{ +prof_gctx_merge_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *opaque) { struct prof_gctx_merge_iter_arg_s *arg = (struct prof_gctx_merge_iter_arg_s *)opaque; malloc_mutex_lock(arg->tsdn, gctx->lock); tctx_tree_iter(&gctx->tctxs, NULL, prof_tctx_merge_iter, (void *)arg->tsdn); - if (gctx->cnt_summed.curobjs != 0) + if (gctx->cnt_summed.curobjs != 0) { arg->leak_ngctx++; + } malloc_mutex_unlock(arg->tsdn, gctx->lock); return (NULL); } static void -prof_gctx_finish(tsd_t *tsd, prof_gctx_tree_t *gctxs) -{ +prof_gctx_finish(tsd_t *tsd, prof_gctx_tree_t *gctxs) { prof_tdata_t *tdata = prof_tdata_get(tsd, false); prof_gctx_t *gctx; @@ -1230,8 +1226,9 @@ prof_gctx_finish(tsd_t *tsd, prof_gctx_tree_t *gctxs) idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), to_destroy), to_destroy, NULL, true, true); - } else + } else { next = NULL; + } } while (next != NULL); } gctx->nlimbo--; @@ -1239,8 +1236,9 @@ prof_gctx_finish(tsd_t *tsd, prof_gctx_tree_t *gctxs) gctx->nlimbo++; malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock); prof_gctx_try_destroy(tsd, tdata, gctx, tdata); - } else + } else { malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock); + } } } @@ -1251,8 +1249,7 @@ struct prof_tdata_merge_iter_arg_s { static prof_tdata_t * prof_tdata_merge_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, - void *opaque) -{ + void *opaque) { struct prof_tdata_merge_iter_arg_s *arg = (struct prof_tdata_merge_iter_arg_s *)opaque; @@ -1267,8 +1264,9 @@ prof_tdata_merge_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, tdata->dumping = true; memset(&tdata->cnt_summed, 0, sizeof(prof_cnt_t)); for (tabind = 0; !ckh_iter(&tdata->bt2tctx, &tabind, NULL, - &tctx.v);) + &tctx.v);) { prof_tctx_merge_tdata(arg->tsdn, tctx.p, tdata); + } arg->cnt_all.curobjs += tdata->cnt_summed.curobjs; arg->cnt_all.curbytes += tdata->cnt_summed.curbytes; @@ -1276,20 +1274,22 @@ prof_tdata_merge_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, arg->cnt_all.accumobjs += tdata->cnt_summed.accumobjs; arg->cnt_all.accumbytes += tdata->cnt_summed.accumbytes; } - } else + } else { tdata->dumping = false; + } malloc_mutex_unlock(arg->tsdn, tdata->lock); return (NULL); } static prof_tdata_t * -prof_tdata_dump_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, void *arg) -{ +prof_tdata_dump_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, + void *arg) { bool propagate_err = *(bool *)arg; - if (!tdata->dumping) + if (!tdata->dumping) { return (NULL); + } if (prof_dump_printf(propagate_err, " t%"FMTu64": %"FMTu64": %"FMTu64" [%"FMTu64": %"FMTu64"]%s%s\n", @@ -1297,8 +1297,9 @@ prof_tdata_dump_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, void *arg) tdata->cnt_summed.curbytes, tdata->cnt_summed.accumobjs, tdata->cnt_summed.accumbytes, (tdata->thread_name != NULL) ? " " : "", - (tdata->thread_name != NULL) ? tdata->thread_name : "")) + (tdata->thread_name != NULL) ? tdata->thread_name : "")) { return (tdata); + } return (NULL); } @@ -1307,16 +1308,16 @@ prof_tdata_dump_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, void *arg) #define prof_dump_header JEMALLOC_N(prof_dump_header_impl) #endif static bool -prof_dump_header(tsdn_t *tsdn, bool propagate_err, const prof_cnt_t *cnt_all) -{ +prof_dump_header(tsdn_t *tsdn, bool propagate_err, const prof_cnt_t *cnt_all) { bool ret; if (prof_dump_printf(propagate_err, "heap_v2/%"FMTu64"\n" " t*: %"FMTu64": %"FMTu64" [%"FMTu64": %"FMTu64"]\n", ((uint64_t)1U << lg_prof_sample), cnt_all->curobjs, - cnt_all->curbytes, cnt_all->accumobjs, cnt_all->accumbytes)) + cnt_all->curbytes, cnt_all->accumobjs, cnt_all->accumbytes)) { return (true); + } malloc_mutex_lock(tsdn, &tdatas_mtx); ret = (tdata_tree_iter(&tdatas, NULL, prof_tdata_dump_iter, @@ -1332,8 +1333,7 @@ prof_dump_header_t *prof_dump_header = JEMALLOC_N(prof_dump_header_impl); static bool prof_dump_gctx(tsdn_t *tsdn, bool propagate_err, prof_gctx_t *gctx, - const prof_bt_t *bt, prof_gctx_tree_t *gctxs) -{ + const prof_bt_t *bt, prof_gctx_tree_t *gctxs) { bool ret; unsigned i; struct prof_tctx_dump_iter_arg_s prof_tctx_dump_iter_arg; @@ -1389,8 +1389,7 @@ label_return: #ifndef _WIN32 JEMALLOC_FORMAT_PRINTF(1, 2) static int -prof_open_maps(const char *format, ...) -{ +prof_open_maps(const char *format, ...) { int mfd; va_list ap; char filename[PATH_MAX + 1]; @@ -1405,8 +1404,7 @@ prof_open_maps(const char *format, ...) #endif static int -prof_getpid(void) -{ +prof_getpid(void) { #ifdef _WIN32 return (GetCurrentProcessId()); #else @@ -1415,8 +1413,7 @@ prof_getpid(void) } static bool -prof_dump_maps(bool propagate_err) -{ +prof_dump_maps(bool propagate_err) { bool ret; int mfd; @@ -1430,8 +1427,9 @@ prof_dump_maps(bool propagate_err) int pid = prof_getpid(); mfd = prof_open_maps("/proc/%d/task/%d/maps", pid, pid); - if (mfd == -1) + if (mfd == -1) { mfd = prof_open_maps("/proc/%d/maps", pid); + } } #endif if (mfd != -1) { @@ -1463,8 +1461,9 @@ prof_dump_maps(bool propagate_err) ret = false; label_return: - if (mfd != -1) + if (mfd != -1) { close(mfd); + } return (ret); } @@ -1474,8 +1473,7 @@ label_return: */ static void prof_leakcheck(const prof_cnt_t *cnt_all, size_t leak_ngctx, - const char *filename) -{ + const char *filename) { #ifdef JEMALLOC_PROF /* * Scaling is equivalent AdjustSamples() in jeprof, but the result may @@ -1510,8 +1508,7 @@ struct prof_gctx_dump_iter_arg_s { }; static prof_gctx_t * -prof_gctx_dump_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *opaque) -{ +prof_gctx_dump_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *opaque) { prof_gctx_t *ret; struct prof_gctx_dump_iter_arg_s *arg = (struct prof_gctx_dump_iter_arg_s *)opaque; @@ -1534,8 +1531,7 @@ static void prof_dump_prep(tsd_t *tsd, prof_tdata_t *tdata, struct prof_tdata_merge_iter_arg_s *prof_tdata_merge_iter_arg, struct prof_gctx_merge_iter_arg_s *prof_gctx_merge_iter_arg, - prof_gctx_tree_t *gctxs) -{ + prof_gctx_tree_t *gctxs) { size_t tabind; union { prof_gctx_t *p; @@ -1579,8 +1575,7 @@ prof_dump_file(tsd_t *tsd, bool propagate_err, const char *filename, struct prof_tdata_merge_iter_arg_s *prof_tdata_merge_iter_arg, struct prof_gctx_merge_iter_arg_s *prof_gctx_merge_iter_arg, struct prof_gctx_dump_iter_arg_s *prof_gctx_dump_iter_arg, - prof_gctx_tree_t *gctxs) -{ + prof_gctx_tree_t *gctxs) { /* Create dump file. */ if ((prof_dump_fd = prof_dump_open(propagate_err, filename)) == -1) { return true; @@ -1616,8 +1611,8 @@ label_write_error: } static bool -prof_dump(tsd_t *tsd, bool propagate_err, const char *filename, bool leakcheck) -{ +prof_dump(tsd_t *tsd, bool propagate_err, const char *filename, + bool leakcheck) { prof_tdata_t *tdata; struct prof_tdata_merge_iter_arg_s prof_tdata_merge_iter_arg; struct prof_gctx_merge_iter_arg_s prof_gctx_merge_iter_arg; @@ -1657,8 +1652,7 @@ prof_dump(tsd_t *tsd, bool propagate_err, const char *filename, bool leakcheck) #ifdef JEMALLOC_JET void prof_cnt_all(uint64_t *curobjs, uint64_t *curbytes, uint64_t *accumobjs, - uint64_t *accumbytes) -{ + uint64_t *accumbytes) { tsd_t *tsd; prof_tdata_t *tdata; struct prof_tdata_merge_iter_arg_s prof_tdata_merge_iter_arg; @@ -1705,8 +1699,7 @@ prof_cnt_all(uint64_t *curobjs, uint64_t *curbytes, uint64_t *accumobjs, #define DUMP_FILENAME_BUFSIZE (PATH_MAX + 1) #define VSEQ_INVALID UINT64_C(0xffffffffffffffff) static void -prof_dump_filename(char *filename, char v, uint64_t vseq) -{ +prof_dump_filename(char *filename, char v, uint64_t vseq) { cassert(config_prof); if (vseq != VSEQ_INVALID) { @@ -1724,8 +1717,7 @@ prof_dump_filename(char *filename, char v, uint64_t vseq) } static void -prof_fdump(void) -{ +prof_fdump(void) { tsd_t *tsd; char filename[DUMP_FILENAME_BUFSIZE]; @@ -1733,8 +1725,9 @@ prof_fdump(void) assert(opt_prof_final); assert(opt_prof_prefix[0] != '\0'); - if (!prof_booted) + if (!prof_booted) { return; + } tsd = tsd_fetch(); malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_seq_mtx); @@ -1744,19 +1737,20 @@ prof_fdump(void) } void -prof_idump(tsdn_t *tsdn) -{ +prof_idump(tsdn_t *tsdn) { tsd_t *tsd; prof_tdata_t *tdata; cassert(config_prof); - if (!prof_booted || tsdn_null(tsdn)) + if (!prof_booted || tsdn_null(tsdn)) { return; + } tsd = tsdn_tsd(tsdn); tdata = prof_tdata_get(tsd, false); - if (tdata == NULL) + if (tdata == NULL) { return; + } if (tdata->enq) { tdata->enq_idump = true; return; @@ -1773,19 +1767,20 @@ prof_idump(tsdn_t *tsdn) } bool -prof_mdump(tsd_t *tsd, const char *filename) -{ +prof_mdump(tsd_t *tsd, const char *filename) { char filename_buf[DUMP_FILENAME_BUFSIZE]; cassert(config_prof); - if (!opt_prof || !prof_booted) + if (!opt_prof || !prof_booted) { return (true); + } if (filename == NULL) { /* No filename specified, so automatically generate one. */ - if (opt_prof_prefix[0] == '\0') + if (opt_prof_prefix[0] == '\0') { return (true); + } malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_seq_mtx); prof_dump_filename(filename_buf, 'm', prof_dump_mseq); prof_dump_mseq++; @@ -1796,19 +1791,20 @@ prof_mdump(tsd_t *tsd, const char *filename) } void -prof_gdump(tsdn_t *tsdn) -{ +prof_gdump(tsdn_t *tsdn) { tsd_t *tsd; prof_tdata_t *tdata; cassert(config_prof); - if (!prof_booted || tsdn_null(tsdn)) + if (!prof_booted || tsdn_null(tsdn)) { return; + } tsd = tsdn_tsd(tsdn); tdata = prof_tdata_get(tsd, false); - if (tdata == NULL) + if (tdata == NULL) { return; + } if (tdata->enq) { tdata->enq_gdump = true; return; @@ -1825,8 +1821,7 @@ prof_gdump(tsdn_t *tsdn) } static void -prof_bt_hash(const void *key, size_t r_hash[2]) -{ +prof_bt_hash(const void *key, size_t r_hash[2]) { prof_bt_t *bt = (prof_bt_t *)key; cassert(config_prof); @@ -1835,21 +1830,20 @@ prof_bt_hash(const void *key, size_t r_hash[2]) } static bool -prof_bt_keycomp(const void *k1, const void *k2) -{ +prof_bt_keycomp(const void *k1, const void *k2) { const prof_bt_t *bt1 = (prof_bt_t *)k1; const prof_bt_t *bt2 = (prof_bt_t *)k2; cassert(config_prof); - if (bt1->len != bt2->len) + if (bt1->len != bt2->len) { return (false); + } return (memcmp(bt1->vec, bt2->vec, bt1->len * sizeof(void *)) == 0); } JEMALLOC_INLINE_C uint64_t -prof_thr_uid_alloc(tsdn_t *tsdn) -{ +prof_thr_uid_alloc(tsdn_t *tsdn) { uint64_t thr_uid; malloc_mutex_lock(tsdn, &next_thr_uid_mtx); @@ -1862,8 +1856,7 @@ prof_thr_uid_alloc(tsdn_t *tsdn) static prof_tdata_t * prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim, - char *thread_name, bool active) -{ + char *thread_name, bool active) { prof_tdata_t *tdata; cassert(config_prof); @@ -1872,8 +1865,9 @@ prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim, tdata = (prof_tdata_t *)iallocztm(tsd_tsdn(tsd), sizeof(prof_tdata_t), size2index(sizeof(prof_tdata_t)), false, NULL, true, arena_get(TSDN_NULL, 0, true), true); - if (tdata == NULL) + if (tdata == NULL) { return (NULL); + } tdata->lock = prof_tdata_mutex_choose(thr_uid); tdata->thr_uid = thr_uid; @@ -1908,26 +1902,25 @@ prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim, } prof_tdata_t * -prof_tdata_init(tsd_t *tsd) -{ +prof_tdata_init(tsd_t *tsd) { return (prof_tdata_init_impl(tsd, prof_thr_uid_alloc(tsd_tsdn(tsd)), 0, NULL, prof_thread_active_init_get(tsd_tsdn(tsd)))); } static bool -prof_tdata_should_destroy_unlocked(prof_tdata_t *tdata, bool even_if_attached) -{ - if (tdata->attached && !even_if_attached) +prof_tdata_should_destroy_unlocked(prof_tdata_t *tdata, bool even_if_attached) { + if (tdata->attached && !even_if_attached) { return (false); - if (ckh_count(&tdata->bt2tctx) != 0) + } + if (ckh_count(&tdata->bt2tctx) != 0) { return (false); + } return (true); } static bool prof_tdata_should_destroy(tsdn_t *tsdn, prof_tdata_t *tdata, - bool even_if_attached) -{ + bool even_if_attached) { malloc_mutex_assert_owner(tsdn, tdata->lock); return (prof_tdata_should_destroy_unlocked(tdata, even_if_attached)); @@ -1935,8 +1928,7 @@ prof_tdata_should_destroy(tsdn_t *tsdn, prof_tdata_t *tdata, static void prof_tdata_destroy_locked(tsd_t *tsd, prof_tdata_t *tdata, - bool even_if_attached) -{ + bool even_if_attached) { malloc_mutex_assert_owner(tsd_tsdn(tsd), &tdatas_mtx); tdata_tree_remove(&tdatas, tdata); @@ -1953,16 +1945,14 @@ prof_tdata_destroy_locked(tsd_t *tsd, prof_tdata_t *tdata, } static void -prof_tdata_destroy(tsd_t *tsd, prof_tdata_t *tdata, bool even_if_attached) -{ +prof_tdata_destroy(tsd_t *tsd, prof_tdata_t *tdata, bool even_if_attached) { malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx); prof_tdata_destroy_locked(tsd, tdata, even_if_attached); malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx); } static void -prof_tdata_detach(tsd_t *tsd, prof_tdata_t *tdata) -{ +prof_tdata_detach(tsd_t *tsd, prof_tdata_t *tdata) { bool destroy_tdata; malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock); @@ -1973,19 +1963,21 @@ prof_tdata_detach(tsd_t *tsd, prof_tdata_t *tdata) * Only detach if !destroy_tdata, because detaching would allow * another thread to win the race to destroy tdata. */ - if (!destroy_tdata) + if (!destroy_tdata) { tdata->attached = false; + } tsd_prof_tdata_set(tsd, NULL); - } else + } else { destroy_tdata = false; + } malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); - if (destroy_tdata) + if (destroy_tdata) { prof_tdata_destroy(tsd, tdata, true); + } } prof_tdata_t * -prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata) -{ +prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata) { uint64_t thr_uid = tdata->thr_uid; uint64_t thr_discrim = tdata->thr_discrim + 1; char *thread_name = (tdata->thread_name != NULL) ? @@ -1998,8 +1990,7 @@ prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata) } static bool -prof_tdata_expire(tsdn_t *tsdn, prof_tdata_t *tdata) -{ +prof_tdata_expire(tsdn_t *tsdn, prof_tdata_t *tdata) { bool destroy_tdata; malloc_mutex_lock(tsdn, tdata->lock); @@ -2007,24 +1998,24 @@ prof_tdata_expire(tsdn_t *tsdn, prof_tdata_t *tdata) tdata->expired = true; destroy_tdata = tdata->attached ? false : prof_tdata_should_destroy(tsdn, tdata, false); - } else + } else { destroy_tdata = false; + } malloc_mutex_unlock(tsdn, tdata->lock); return (destroy_tdata); } static prof_tdata_t * -prof_tdata_reset_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, void *arg) -{ +prof_tdata_reset_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, + void *arg) { tsdn_t *tsdn = (tsdn_t *)arg; return (prof_tdata_expire(tsdn, tdata) ? tdata : NULL); } void -prof_reset(tsd_t *tsd, size_t lg_sample) -{ +prof_reset(tsd_t *tsd, size_t lg_sample) { prof_tdata_t *next; assert(lg_sample < (sizeof(uint64_t) << 3)); @@ -2041,8 +2032,9 @@ prof_reset(tsd_t *tsd, size_t lg_sample) if (to_destroy != NULL) { next = tdata_tree_next(&tdatas, to_destroy); prof_tdata_destroy_locked(tsd, to_destroy, false); - } else + } else { next = NULL; + } } while (next != NULL); malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx); @@ -2050,21 +2042,21 @@ prof_reset(tsd_t *tsd, size_t lg_sample) } void -prof_tdata_cleanup(tsd_t *tsd) -{ +prof_tdata_cleanup(tsd_t *tsd) { prof_tdata_t *tdata; - if (!config_prof) + if (!config_prof) { return; + } tdata = tsd_prof_tdata_get(tsd); - if (tdata != NULL) + if (tdata != NULL) { prof_tdata_detach(tsd, tdata); + } } bool -prof_active_get(tsdn_t *tsdn) -{ +prof_active_get(tsdn_t *tsdn) { bool prof_active_current; malloc_mutex_lock(tsdn, &prof_active_mtx); @@ -2074,8 +2066,7 @@ prof_active_get(tsdn_t *tsdn) } bool -prof_active_set(tsdn_t *tsdn, bool active) -{ +prof_active_set(tsdn_t *tsdn, bool active) { bool prof_active_old; malloc_mutex_lock(tsdn, &prof_active_mtx); @@ -2086,97 +2077,102 @@ prof_active_set(tsdn_t *tsdn, bool active) } const char * -prof_thread_name_get(tsd_t *tsd) -{ +prof_thread_name_get(tsd_t *tsd) { prof_tdata_t *tdata; tdata = prof_tdata_get(tsd, true); - if (tdata == NULL) + if (tdata == NULL) { return (""); + } return (tdata->thread_name != NULL ? tdata->thread_name : ""); } static char * -prof_thread_name_alloc(tsdn_t *tsdn, const char *thread_name) -{ +prof_thread_name_alloc(tsdn_t *tsdn, const char *thread_name) { char *ret; size_t size; - if (thread_name == NULL) + if (thread_name == NULL) { return (NULL); + } size = strlen(thread_name) + 1; - if (size == 1) + if (size == 1) { return (""); + } ret = iallocztm(tsdn, size, size2index(size), false, NULL, true, arena_get(TSDN_NULL, 0, true), true); - if (ret == NULL) + if (ret == NULL) { return (NULL); + } memcpy(ret, thread_name, size); return (ret); } int -prof_thread_name_set(tsd_t *tsd, const char *thread_name) -{ +prof_thread_name_set(tsd_t *tsd, const char *thread_name) { prof_tdata_t *tdata; unsigned i; char *s; tdata = prof_tdata_get(tsd, true); - if (tdata == NULL) + if (tdata == NULL) { return (EAGAIN); + } /* Validate input. */ - if (thread_name == NULL) + if (thread_name == NULL) { return (EFAULT); + } for (i = 0; thread_name[i] != '\0'; i++) { char c = thread_name[i]; - if (!isgraph(c) && !isblank(c)) + if (!isgraph(c) && !isblank(c)) { return (EFAULT); + } } s = prof_thread_name_alloc(tsd_tsdn(tsd), thread_name); - if (s == NULL) + if (s == NULL) { return (EAGAIN); + } if (tdata->thread_name != NULL) { idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tdata->thread_name), tdata->thread_name, NULL, true, true); tdata->thread_name = NULL; } - if (strlen(s) > 0) + if (strlen(s) > 0) { tdata->thread_name = s; + } return (0); } bool -prof_thread_active_get(tsd_t *tsd) -{ +prof_thread_active_get(tsd_t *tsd) { prof_tdata_t *tdata; tdata = prof_tdata_get(tsd, true); - if (tdata == NULL) + if (tdata == NULL) { return (false); + } return (tdata->active); } bool -prof_thread_active_set(tsd_t *tsd, bool active) -{ +prof_thread_active_set(tsd_t *tsd, bool active) { prof_tdata_t *tdata; tdata = prof_tdata_get(tsd, true); - if (tdata == NULL) + if (tdata == NULL) { return (true); + } tdata->active = active; return (false); } bool -prof_thread_active_init_get(tsdn_t *tsdn) -{ +prof_thread_active_init_get(tsdn_t *tsdn) { bool active_init; malloc_mutex_lock(tsdn, &prof_thread_active_init_mtx); @@ -2186,8 +2182,7 @@ prof_thread_active_init_get(tsdn_t *tsdn) } bool -prof_thread_active_init_set(tsdn_t *tsdn, bool active_init) -{ +prof_thread_active_init_set(tsdn_t *tsdn, bool active_init) { bool active_init_old; malloc_mutex_lock(tsdn, &prof_thread_active_init_mtx); @@ -2198,8 +2193,7 @@ prof_thread_active_init_set(tsdn_t *tsdn, bool active_init) } bool -prof_gdump_get(tsdn_t *tsdn) -{ +prof_gdump_get(tsdn_t *tsdn) { bool prof_gdump_current; malloc_mutex_lock(tsdn, &prof_gdump_mtx); @@ -2209,8 +2203,7 @@ prof_gdump_get(tsdn_t *tsdn) } bool -prof_gdump_set(tsdn_t *tsdn, bool gdump) -{ +prof_gdump_set(tsdn_t *tsdn, bool gdump) { bool prof_gdump_old; malloc_mutex_lock(tsdn, &prof_gdump_mtx); @@ -2221,8 +2214,7 @@ prof_gdump_set(tsdn_t *tsdn, bool gdump) } void -prof_boot0(void) -{ +prof_boot0(void) { cassert(config_prof); memcpy(opt_prof_prefix, PROF_PREFIX_DEFAULT, @@ -2230,8 +2222,7 @@ prof_boot0(void) } void -prof_boot1(void) -{ +prof_boot1(void) { cassert(config_prof); /* @@ -2255,8 +2246,7 @@ prof_boot1(void) } bool -prof_boot2(tsd_t *tsd) -{ +prof_boot2(tsd_t *tsd) { cassert(config_prof); if (opt_prof) { @@ -2266,71 +2256,85 @@ prof_boot2(tsd_t *tsd) prof_active = opt_prof_active; if (malloc_mutex_init(&prof_active_mtx, "prof_active", - WITNESS_RANK_PROF_ACTIVE)) + WITNESS_RANK_PROF_ACTIVE)) { return (true); + } prof_gdump_val = opt_prof_gdump; if (malloc_mutex_init(&prof_gdump_mtx, "prof_gdump", - WITNESS_RANK_PROF_GDUMP)) + WITNESS_RANK_PROF_GDUMP)) { return (true); + } prof_thread_active_init = opt_prof_thread_active_init; if (malloc_mutex_init(&prof_thread_active_init_mtx, "prof_thread_active_init", - WITNESS_RANK_PROF_THREAD_ACTIVE_INIT)) + WITNESS_RANK_PROF_THREAD_ACTIVE_INIT)) { return (true); + } if (ckh_new(tsd, &bt2gctx, PROF_CKH_MINITEMS, prof_bt_hash, - prof_bt_keycomp)) + prof_bt_keycomp)) { return (true); + } if (malloc_mutex_init(&bt2gctx_mtx, "prof_bt2gctx", - WITNESS_RANK_PROF_BT2GCTX)) + WITNESS_RANK_PROF_BT2GCTX)) { return (true); + } tdata_tree_new(&tdatas); if (malloc_mutex_init(&tdatas_mtx, "prof_tdatas", - WITNESS_RANK_PROF_TDATAS)) + WITNESS_RANK_PROF_TDATAS)) { return (true); + } next_thr_uid = 0; if (malloc_mutex_init(&next_thr_uid_mtx, "prof_next_thr_uid", - WITNESS_RANK_PROF_NEXT_THR_UID)) + WITNESS_RANK_PROF_NEXT_THR_UID)) { return (true); + } if (malloc_mutex_init(&prof_dump_seq_mtx, "prof_dump_seq", - WITNESS_RANK_PROF_DUMP_SEQ)) + WITNESS_RANK_PROF_DUMP_SEQ)) { return (true); + } if (malloc_mutex_init(&prof_dump_mtx, "prof_dump", - WITNESS_RANK_PROF_DUMP)) + WITNESS_RANK_PROF_DUMP)) { return (true); + } if (opt_prof_final && opt_prof_prefix[0] != '\0' && atexit(prof_fdump) != 0) { malloc_write(": Error in atexit()\n"); - if (opt_abort) + if (opt_abort) { abort(); + } } gctx_locks = (malloc_mutex_t *)base_alloc(tsd_tsdn(tsd), b0get(), PROF_NCTX_LOCKS * sizeof(malloc_mutex_t), CACHELINE); - if (gctx_locks == NULL) + if (gctx_locks == NULL) { return (true); + } for (i = 0; i < PROF_NCTX_LOCKS; i++) { if (malloc_mutex_init(&gctx_locks[i], "prof_gctx", - WITNESS_RANK_PROF_GCTX)) + WITNESS_RANK_PROF_GCTX)) { return (true); + } } tdata_locks = (malloc_mutex_t *)base_alloc(tsd_tsdn(tsd), b0get(), PROF_NTDATA_LOCKS * sizeof(malloc_mutex_t), CACHELINE); - if (tdata_locks == NULL) + if (tdata_locks == NULL) { return (true); + } for (i = 0; i < PROF_NTDATA_LOCKS; i++) { if (malloc_mutex_init(&tdata_locks[i], "prof_tdata", - WITNESS_RANK_PROF_TDATA)) + WITNESS_RANK_PROF_TDATA)) { return (true); + } } } @@ -2348,24 +2352,24 @@ prof_boot2(tsd_t *tsd) } void -prof_prefork0(tsdn_t *tsdn) -{ +prof_prefork0(tsdn_t *tsdn) { if (opt_prof) { unsigned i; malloc_mutex_prefork(tsdn, &prof_dump_mtx); malloc_mutex_prefork(tsdn, &bt2gctx_mtx); malloc_mutex_prefork(tsdn, &tdatas_mtx); - for (i = 0; i < PROF_NTDATA_LOCKS; i++) + for (i = 0; i < PROF_NTDATA_LOCKS; i++) { malloc_mutex_prefork(tsdn, &tdata_locks[i]); - for (i = 0; i < PROF_NCTX_LOCKS; i++) + } + for (i = 0; i < PROF_NCTX_LOCKS; i++) { malloc_mutex_prefork(tsdn, &gctx_locks[i]); + } } } void -prof_prefork1(tsdn_t *tsdn) -{ +prof_prefork1(tsdn_t *tsdn) { if (opt_prof) { malloc_mutex_prefork(tsdn, &prof_active_mtx); malloc_mutex_prefork(tsdn, &prof_dump_seq_mtx); @@ -2376,8 +2380,7 @@ prof_prefork1(tsdn_t *tsdn) } void -prof_postfork_parent(tsdn_t *tsdn) -{ +prof_postfork_parent(tsdn_t *tsdn) { if (opt_prof) { unsigned i; @@ -2387,10 +2390,12 @@ prof_postfork_parent(tsdn_t *tsdn) malloc_mutex_postfork_parent(tsdn, &prof_gdump_mtx); malloc_mutex_postfork_parent(tsdn, &prof_dump_seq_mtx); malloc_mutex_postfork_parent(tsdn, &prof_active_mtx); - for (i = 0; i < PROF_NCTX_LOCKS; i++) + for (i = 0; i < PROF_NCTX_LOCKS; i++) { malloc_mutex_postfork_parent(tsdn, &gctx_locks[i]); - for (i = 0; i < PROF_NTDATA_LOCKS; i++) + } + for (i = 0; i < PROF_NTDATA_LOCKS; i++) { malloc_mutex_postfork_parent(tsdn, &tdata_locks[i]); + } malloc_mutex_postfork_parent(tsdn, &tdatas_mtx); malloc_mutex_postfork_parent(tsdn, &bt2gctx_mtx); malloc_mutex_postfork_parent(tsdn, &prof_dump_mtx); @@ -2398,8 +2403,7 @@ prof_postfork_parent(tsdn_t *tsdn) } void -prof_postfork_child(tsdn_t *tsdn) -{ +prof_postfork_child(tsdn_t *tsdn) { if (opt_prof) { unsigned i; @@ -2408,10 +2412,12 @@ prof_postfork_child(tsdn_t *tsdn) malloc_mutex_postfork_child(tsdn, &prof_gdump_mtx); malloc_mutex_postfork_child(tsdn, &prof_dump_seq_mtx); malloc_mutex_postfork_child(tsdn, &prof_active_mtx); - for (i = 0; i < PROF_NCTX_LOCKS; i++) + for (i = 0; i < PROF_NCTX_LOCKS; i++) { malloc_mutex_postfork_child(tsdn, &gctx_locks[i]); - for (i = 0; i < PROF_NTDATA_LOCKS; i++) + } + for (i = 0; i < PROF_NTDATA_LOCKS; i++) { malloc_mutex_postfork_child(tsdn, &tdata_locks[i]); + } malloc_mutex_postfork_child(tsdn, &tdatas_mtx); malloc_mutex_postfork_child(tsdn, &bt2gctx_mtx); malloc_mutex_postfork_child(tsdn, &prof_dump_mtx); diff --git a/src/rtree.c b/src/rtree.c index 43f21652..de3e5962 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -2,8 +2,7 @@ #include "jemalloc/internal/jemalloc_internal.h" static unsigned -hmin(unsigned ha, unsigned hb) -{ +hmin(unsigned ha, unsigned hb) { return (ha < hb ? ha : hb); } @@ -12,8 +11,7 @@ hmin(unsigned ha, unsigned hb) * used. */ bool -rtree_new(rtree_t *rtree, unsigned bits) -{ +rtree_new(rtree_t *rtree, unsigned bits) { unsigned bits_in_leaf, height, i; assert(RTREE_HEIGHT_MAX == ((ZU(1) << (LG_SIZEOF_PTR+3)) / @@ -24,10 +22,12 @@ rtree_new(rtree_t *rtree, unsigned bits) : (bits % RTREE_BITS_PER_LEVEL); if (bits > bits_in_leaf) { height = 1 + (bits - bits_in_leaf) / RTREE_BITS_PER_LEVEL; - if ((height-1) * RTREE_BITS_PER_LEVEL + bits_in_leaf != bits) + if ((height-1) * RTREE_BITS_PER_LEVEL + bits_in_leaf != bits) { height++; - } else + } + } else { height = 1; + } assert((height-1) * RTREE_BITS_PER_LEVEL + bits_in_leaf == bits); rtree->height = height; @@ -68,8 +68,7 @@ rtree_new(rtree_t *rtree, unsigned bits) #define rtree_node_alloc JEMALLOC_N(rtree_node_alloc_impl) #endif static rtree_elm_t * -rtree_node_alloc(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) -{ +rtree_node_alloc(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { return ((rtree_elm_t *)base_alloc(tsdn, b0get(), nelms * sizeof(rtree_elm_t), CACHELINE)); } @@ -84,8 +83,7 @@ rtree_node_alloc_t *rtree_node_alloc = JEMALLOC_N(rtree_node_alloc_impl); #define rtree_node_dalloc JEMALLOC_N(rtree_node_dalloc_impl) #endif UNUSED static void -rtree_node_dalloc(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) -{ +rtree_node_dalloc(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) { /* Nodes are never deleted during normal operation. */ not_reached(); } @@ -98,8 +96,7 @@ rtree_node_dalloc_t *rtree_node_dalloc = JEMALLOC_N(rtree_node_dalloc_impl); #ifdef JEMALLOC_JET static void rtree_delete_subtree(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node, - unsigned level) -{ + unsigned level) { if (level + 1 < rtree->height) { size_t nchildren, i; @@ -116,22 +113,21 @@ rtree_delete_subtree(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node, } void -rtree_delete(tsdn_t *tsdn, rtree_t *rtree) -{ +rtree_delete(tsdn_t *tsdn, rtree_t *rtree) { unsigned i; for (i = 0; i < rtree->height; i++) { rtree_elm_t *subtree = rtree->levels[i].subtree; - if (subtree != NULL) + if (subtree != NULL) { rtree_delete_subtree(tsdn, rtree, subtree, i); + } } } #endif static rtree_elm_t * rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level, - rtree_elm_t **elmp) -{ + rtree_elm_t **elmp) { rtree_elm_t *node; malloc_mutex_lock(tsdn, &rtree->init_lock); @@ -151,23 +147,20 @@ rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level, } rtree_elm_t * -rtree_subtree_read_hard(tsdn_t *tsdn, rtree_t *rtree, unsigned level) -{ +rtree_subtree_read_hard(tsdn_t *tsdn, rtree_t *rtree, unsigned level) { return (rtree_node_init(tsdn, rtree, level, &rtree->levels[level].subtree)); } rtree_elm_t * rtree_child_read_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, - unsigned level) -{ + unsigned level) { return (rtree_node_init(tsdn, rtree, level+1, &elm->child)); } static int rtree_elm_witness_comp(const witness_t *a, void *oa, const witness_t *b, - void *ob) -{ + void *ob) { uintptr_t ka = (uintptr_t)oa; uintptr_t kb = (uintptr_t)ob; @@ -178,8 +171,7 @@ rtree_elm_witness_comp(const witness_t *a, void *oa, const witness_t *b, } static witness_t * -rtree_elm_witness_alloc(tsd_t *tsd, uintptr_t key, const rtree_elm_t *elm) -{ +rtree_elm_witness_alloc(tsd_t *tsd, uintptr_t key, const rtree_elm_t *elm) { witness_t *witness; size_t i; rtree_elm_witness_tsd_t *witnesses = tsd_rtree_elm_witnessesp_get(tsd); @@ -204,8 +196,7 @@ rtree_elm_witness_alloc(tsd_t *tsd, uintptr_t key, const rtree_elm_t *elm) } static witness_t * -rtree_elm_witness_find(tsd_t *tsd, const rtree_elm_t *elm) -{ +rtree_elm_witness_find(tsd_t *tsd, const rtree_elm_t *elm) { size_t i; rtree_elm_witness_tsd_t *witnesses = tsd_rtree_elm_witnessesp_get(tsd); @@ -213,15 +204,16 @@ rtree_elm_witness_find(tsd_t *tsd, const rtree_elm_t *elm) i++) { rtree_elm_witness_t *rew = &witnesses->witnesses[i]; - if (rew->elm == elm) + if (rew->elm == elm) { return (&rew->witness); + } } not_reached(); } static void -rtree_elm_witness_dalloc(tsd_t *tsd, witness_t *witness, const rtree_elm_t *elm) -{ +rtree_elm_witness_dalloc(tsd_t *tsd, witness_t *witness, + const rtree_elm_t *elm) { size_t i; rtree_elm_witness_tsd_t *witnesses = tsd_rtree_elm_witnessesp_get(tsd); @@ -242,12 +234,12 @@ rtree_elm_witness_dalloc(tsd_t *tsd, witness_t *witness, const rtree_elm_t *elm) void rtree_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, uintptr_t key, - const rtree_elm_t *elm) -{ + const rtree_elm_t *elm) { witness_t *witness; - if (tsdn_null(tsdn)) + if (tsdn_null(tsdn)) { return; + } witness = rtree_elm_witness_alloc(tsdn_tsd(tsdn), key, elm); witness_lock(tsdn, witness); @@ -255,12 +247,12 @@ rtree_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, uintptr_t key, void rtree_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, - const rtree_elm_t *elm) -{ + const rtree_elm_t *elm) { witness_t *witness; - if (tsdn_null(tsdn)) + if (tsdn_null(tsdn)) { return; + } witness = rtree_elm_witness_find(tsdn_tsd(tsdn), elm); witness_assert_owner(tsdn, witness); @@ -268,12 +260,12 @@ rtree_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, void rtree_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, - const rtree_elm_t *elm) -{ + const rtree_elm_t *elm) { witness_t *witness; - if (tsdn_null(tsdn)) + if (tsdn_null(tsdn)) { return; + } witness = rtree_elm_witness_find(tsdn_tsd(tsdn), elm); witness_unlock(tsdn, witness); diff --git a/src/stats.c b/src/stats.c index 020d56bd..b0a7fca2 100644 --- a/src/stats.c +++ b/src/stats.c @@ -34,8 +34,7 @@ bool opt_stats_print = false; static void stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, - bool json, bool large, unsigned i) -{ + bool json, bool large, unsigned i) { size_t page; bool in_gap, in_gap_prev; unsigned nbins, j; @@ -144,8 +143,9 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, } else if (milli < 1000) { malloc_snprintf(util, sizeof(util), "0.%zu", milli); - } else + } else { malloc_snprintf(util, sizeof(util), "1"); + } if (config_tcache) { malloc_cprintf(write_cb, cbopaque, @@ -183,8 +183,7 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, static void stats_arena_lextents_print(void (*write_cb)(void *, const char *), - void *cbopaque, bool json, unsigned i) -{ + void *cbopaque, bool json, unsigned i) { unsigned nbins, nlextents, j; bool in_gap, in_gap_prev; @@ -248,8 +247,7 @@ stats_arena_lextents_print(void (*write_cb)(void *, const char *), static void stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, - bool json, unsigned i, bool bins, bool large) -{ + bool json, unsigned i, bool bins, bool large) { unsigned nthreads; const char *dss; ssize_t decay_time; @@ -290,8 +288,9 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, if (decay_time >= 0) { malloc_cprintf(write_cb, cbopaque, "decay time: %zd\n", decay_time); - } else + } else { malloc_cprintf(write_cb, cbopaque, "decay time: N/A\n"); + } } CTL_M2_GET("stats.arenas.0.pactive", i, &pactive, size_t); @@ -445,16 +444,17 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, "resident: %12zu\n", resident); } - if (bins) + if (bins) { stats_arena_bins_print(write_cb, cbopaque, json, large, i); - if (large) + } + if (large) { stats_arena_lextents_print(write_cb, cbopaque, json, i); + } } static void stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, - bool json, bool more) -{ + bool json, bool more) { const char *cpv; bool bv; unsigned uv; @@ -473,8 +473,9 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t\"version\": \"%s\",\n", cpv); - } else + } else { malloc_cprintf(write_cb, cbopaque, "Version: %s\n", cpv); + } /* config. */ #define CONFIG_WRITE_BOOL_JSON(n, c) \ @@ -655,8 +656,9 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t\t\"narenas\": %u,\n", uv); - } else + } else { malloc_cprintf(write_cb, cbopaque, "Arenas: %u\n", uv); + } CTL_GET("arenas.decay_time", &ssv, ssize_t); if (json) { @@ -672,15 +674,17 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t\t\"quantum\": %zu,\n", sv); - } else + } else { malloc_cprintf(write_cb, cbopaque, "Quantum size: %zu\n", sv); + } CTL_GET("arenas.page", &sv, size_t); if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t\t\"page\": %zu,\n", sv); - } else + } else { malloc_cprintf(write_cb, cbopaque, "Page size: %zu\n", sv); + } if (je_mallctl("arenas.tcache_max", (void *)&sv, &ssz, NULL, 0) == 0) { if (json) { @@ -787,8 +791,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, static void stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, bool json, bool merged, bool destroyed, bool unmerged, bool bins, - bool large) -{ + bool large) { size_t allocated, active, metadata, resident, mapped, retained; CTL_GET("stats.allocated", &allocated, size_t); @@ -846,8 +849,9 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, sz = sizeof(bool); xmallctlbymib(mib, miblen, &initialized[i], &sz, NULL, 0); - if (initialized[i]) + if (initialized[i]) { ninitialized++; + } } mib[1] = MALLCTL_ARENAS_DESTROYED; sz = sizeof(bool); @@ -934,8 +938,7 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, void stats_print(void (*write_cb)(void *, const char *), void *cbopaque, - const char *opts) -{ + const char *opts) { int err; uint64_t epoch; size_t u64sz; diff --git a/src/tcache.c b/src/tcache.c index d1323418..bb6a5a75 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -24,14 +24,12 @@ static tcaches_t *tcaches_avail; /******************************************************************************/ size_t -tcache_salloc(tsdn_t *tsdn, const void *ptr) -{ +tcache_salloc(tsdn_t *tsdn, const void *ptr) { return (arena_salloc(tsdn, iealloc(tsdn, ptr), ptr)); } void -tcache_event_hard(tsd_t *tsd, tcache_t *tcache) -{ +tcache_event_hard(tsd_t *tsd, tcache_t *tcache) { szind_t binind = tcache->next_gc_bin; tcache_bin_t *tbin = &tcache->tbins[binind]; tcache_bin_info_t *tbin_info = &tcache_bin_info[binind]; @@ -52,33 +50,36 @@ tcache_event_hard(tsd_t *tsd, tcache_t *tcache) * Reduce fill count by 2X. Limit lg_fill_div such that the * fill count is always at least 1. */ - if ((tbin_info->ncached_max >> (tbin->lg_fill_div+1)) >= 1) + if ((tbin_info->ncached_max >> (tbin->lg_fill_div+1)) >= 1) { tbin->lg_fill_div++; + } } else if (tbin->low_water < 0) { /* * Increase fill count by 2X. Make sure lg_fill_div stays * greater than 0. */ - if (tbin->lg_fill_div > 1) + if (tbin->lg_fill_div > 1) { tbin->lg_fill_div--; + } } tbin->low_water = tbin->ncached; tcache->next_gc_bin++; - if (tcache->next_gc_bin == nhbins) + if (tcache->next_gc_bin == nhbins) { tcache->next_gc_bin = 0; + } } void * tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, - tcache_bin_t *tbin, szind_t binind, bool *tcache_success) -{ + tcache_bin_t *tbin, szind_t binind, bool *tcache_success) { void *ret; arena_tcache_fill_small(tsdn, arena, tbin, binind, config_prof ? tcache->prof_accumbytes : 0); - if (config_prof) + if (config_prof) { tcache->prof_accumbytes = 0; + } ret = tcache_alloc_easy(tbin, tcache_success); return (ret); @@ -86,8 +87,7 @@ tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, void tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, - szind_t binind, unsigned rem) -{ + szind_t binind, unsigned rem) { arena_t *arena; void *ptr; unsigned i, nflush, ndeferred; @@ -106,8 +106,9 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, if (config_prof && bin_arena == arena) { if (arena_prof_accum(tsd_tsdn(tsd), arena, - tcache->prof_accumbytes)) + tcache->prof_accumbytes)) { prof_idump(tsd_tsdn(tsd)); + } tcache->prof_accumbytes = 0; } @@ -158,14 +159,14 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, memmove(tbin->avail - rem, tbin->avail - tbin->ncached, rem * sizeof(void *)); tbin->ncached = rem; - if ((int)tbin->ncached < tbin->low_water) + if ((int)tbin->ncached < tbin->low_water) { tbin->low_water = tbin->ncached; + } } void tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, - unsigned rem, tcache_t *tcache) -{ + unsigned rem, tcache_t *tcache) { arena_t *arena; void *ptr; unsigned i, nflush, ndeferred; @@ -182,8 +183,9 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, arena_t *locked_arena = extent_arena_get(extent); UNUSED bool idump; - if (config_prof) + if (config_prof) { idump = false; + } malloc_mutex_lock(tsd_tsdn(tsd), &locked_arena->lock); if ((config_prof || config_stats) && locked_arena == arena) { if (config_prof) { @@ -220,8 +222,9 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, } } malloc_mutex_unlock(tsd_tsdn(tsd), &locked_arena->lock); - if (config_prof && idump) + if (config_prof && idump) { prof_idump(tsd_tsdn(tsd)); + } arena_decay_ticks(tsd_tsdn(tsd), locked_arena, nflush - ndeferred); } @@ -241,13 +244,13 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, memmove(tbin->avail - rem, tbin->avail - tbin->ncached, rem * sizeof(void *)); tbin->ncached = rem; - if ((int)tbin->ncached < tbin->low_water) + if ((int)tbin->ncached < tbin->low_water) { tbin->low_water = tbin->ncached; + } } static void -tcache_arena_associate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) -{ +tcache_arena_associate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { if (config_stats) { /* Link into list of extant tcaches. */ malloc_mutex_lock(tsdn, &arena->lock); @@ -258,8 +261,7 @@ tcache_arena_associate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) } static void -tcache_arena_dissociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) -{ +tcache_arena_dissociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { if (config_stats) { /* Unlink from list of extant tcaches. */ malloc_mutex_lock(tsdn, &arena->lock); @@ -282,31 +284,30 @@ tcache_arena_dissociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) void tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *oldarena, - arena_t *newarena) -{ + arena_t *newarena) { tcache_arena_dissociate(tsdn, tcache, oldarena); tcache_arena_associate(tsdn, tcache, newarena); } tcache_t * -tcache_get_hard(tsd_t *tsd) -{ +tcache_get_hard(tsd_t *tsd) { arena_t *arena; if (!tcache_enabled_get()) { - if (tsd_nominal(tsd)) + if (tsd_nominal(tsd)) { tcache_enabled_set(false); /* Memoize. */ + } return (NULL); } arena = arena_choose(tsd, NULL); - if (unlikely(arena == NULL)) + if (unlikely(arena == NULL)) { return (NULL); + } return (tcache_create(tsd_tsdn(tsd), arena)); } tcache_t * -tcache_create(tsdn_t *tsdn, arena_t *arena) -{ +tcache_create(tsdn_t *tsdn, arena_t *arena) { tcache_t *tcache; size_t size, stack_offset; unsigned i; @@ -321,8 +322,9 @@ tcache_create(tsdn_t *tsdn, arena_t *arena) tcache = ipallocztm(tsdn, size, CACHELINE, true, NULL, true, arena_get(TSDN_NULL, 0, true)); - if (tcache == NULL) + if (tcache == NULL) { return (NULL); + } tcache_arena_associate(tsdn, tcache, arena); @@ -345,8 +347,7 @@ tcache_create(tsdn_t *tsdn, arena_t *arena) } static void -tcache_destroy(tsd_t *tsd, tcache_t *tcache) -{ +tcache_destroy(tsd_t *tsd, tcache_t *tcache) { arena_t *arena; unsigned i; @@ -372,20 +373,21 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache) } if (config_prof && tcache->prof_accumbytes > 0 && - arena_prof_accum(tsd_tsdn(tsd), arena, tcache->prof_accumbytes)) + arena_prof_accum(tsd_tsdn(tsd), arena, tcache->prof_accumbytes)) { prof_idump(tsd_tsdn(tsd)); + } idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tcache), tcache, NULL, true, true); } void -tcache_cleanup(tsd_t *tsd) -{ +tcache_cleanup(tsd_t *tsd) { tcache_t *tcache; - if (!config_tcache) + if (!config_tcache) { return; + } if ((tcache = tsd_tcache_get(tsd)) != NULL) { tcache_destroy(tsd, tcache); @@ -394,8 +396,7 @@ tcache_cleanup(tsd_t *tsd) } void -tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) -{ +tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { unsigned i; cassert(config_stats); @@ -422,8 +423,7 @@ tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) } bool -tcaches_create(tsd_t *tsd, unsigned *r_ind) -{ +tcaches_create(tsd_t *tsd, unsigned *r_ind) { arena_t *arena; tcache_t *tcache; tcaches_t *elm; @@ -431,18 +431,22 @@ tcaches_create(tsd_t *tsd, unsigned *r_ind) if (tcaches == NULL) { tcaches = base_alloc(tsd_tsdn(tsd), b0get(), sizeof(tcache_t *) * (MALLOCX_TCACHE_MAX+1), CACHELINE); - if (tcaches == NULL) + if (tcaches == NULL) { return (true); + } } - if (tcaches_avail == NULL && tcaches_past > MALLOCX_TCACHE_MAX) + if (tcaches_avail == NULL && tcaches_past > MALLOCX_TCACHE_MAX) { return (true); + } arena = arena_ichoose(tsd, NULL); - if (unlikely(arena == NULL)) + if (unlikely(arena == NULL)) { return (true); + } tcache = tcache_create(tsd_tsdn(tsd), arena); - if (tcache == NULL) + if (tcache == NULL) { return (true); + } if (tcaches_avail != NULL) { elm = tcaches_avail; @@ -460,23 +464,21 @@ tcaches_create(tsd_t *tsd, unsigned *r_ind) } static void -tcaches_elm_flush(tsd_t *tsd, tcaches_t *elm) -{ - if (elm->tcache == NULL) +tcaches_elm_flush(tsd_t *tsd, tcaches_t *elm) { + if (elm->tcache == NULL) { return; + } tcache_destroy(tsd, elm->tcache); elm->tcache = NULL; } void -tcaches_flush(tsd_t *tsd, unsigned ind) -{ +tcaches_flush(tsd_t *tsd, unsigned ind) { tcaches_elm_flush(tsd, &tcaches[ind]); } void -tcaches_destroy(tsd_t *tsd, unsigned ind) -{ +tcaches_destroy(tsd_t *tsd, unsigned ind) { tcaches_t *elm = &tcaches[ind]; tcaches_elm_flush(tsd, elm); elm->next = tcaches_avail; @@ -484,23 +486,25 @@ tcaches_destroy(tsd_t *tsd, unsigned ind) } bool -tcache_boot(tsdn_t *tsdn) -{ +tcache_boot(tsdn_t *tsdn) { unsigned i; /* If necessary, clamp opt_lg_tcache_max. */ - if (opt_lg_tcache_max < 0 || (ZU(1) << opt_lg_tcache_max) < SMALL_MAXCLASS) + if (opt_lg_tcache_max < 0 || (ZU(1) << opt_lg_tcache_max) < + SMALL_MAXCLASS) { tcache_maxclass = SMALL_MAXCLASS; - else + } else { tcache_maxclass = (ZU(1) << opt_lg_tcache_max); + } nhbins = size2index(tcache_maxclass) + 1; /* Initialize tcache_bin_info. */ tcache_bin_info = (tcache_bin_info_t *)base_alloc(tsdn, b0get(), nhbins * sizeof(tcache_bin_info_t), CACHELINE); - if (tcache_bin_info == NULL) + if (tcache_bin_info == NULL) { return (true); + } stack_nelms = 0; for (i = 0; i < NBINS; i++) { if ((arena_bin_info[i].nregs << 1) <= TCACHE_NSLOTS_SMALL_MIN) { diff --git a/src/tsd.c b/src/tsd.c index b4d7e795..f02fc28e 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -12,20 +12,17 @@ malloc_tsd_data(, , tsd_t, TSD_INITIALIZER) /******************************************************************************/ void * -malloc_tsd_malloc(size_t size) -{ +malloc_tsd_malloc(size_t size) { return (a0malloc(CACHELINE_CEILING(size))); } void -malloc_tsd_dalloc(void *wrapper) -{ +malloc_tsd_dalloc(void *wrapper) { a0dalloc(wrapper); } void -malloc_tsd_no_cleanup(void *arg) -{ +malloc_tsd_no_cleanup(void *arg) { not_reached(); } @@ -34,21 +31,22 @@ malloc_tsd_no_cleanup(void *arg) JEMALLOC_EXPORT #endif void -_malloc_thread_cleanup(void) -{ +_malloc_thread_cleanup(void) { bool pending[MALLOC_TSD_CLEANUPS_MAX], again; unsigned i; - for (i = 0; i < ncleanups; i++) + for (i = 0; i < ncleanups; i++) { pending[i] = true; + } do { again = false; for (i = 0; i < ncleanups; i++) { if (pending[i]) { pending[i] = cleanups[i](); - if (pending[i]) + if (pending[i]) { again = true; + } } } } while (again); @@ -56,16 +54,14 @@ _malloc_thread_cleanup(void) #endif void -malloc_tsd_cleanup_register(bool (*f)(void)) -{ +malloc_tsd_cleanup_register(bool (*f)(void)) { assert(ncleanups < MALLOC_TSD_CLEANUPS_MAX); cleanups[ncleanups] = f; ncleanups++; } void -tsd_cleanup(void *arg) -{ +tsd_cleanup(void *arg) { tsd_t *tsd = (tsd_t *)arg; switch (tsd->state) { @@ -108,29 +104,27 @@ MALLOC_TSD } tsd_t * -malloc_tsd_boot0(void) -{ +malloc_tsd_boot0(void) { tsd_t *tsd; ncleanups = 0; - if (tsd_boot0()) + if (tsd_boot0()) { return (NULL); + } tsd = tsd_fetch(); *tsd_arenas_tdata_bypassp_get(tsd) = true; return (tsd); } void -malloc_tsd_boot1(void) -{ +malloc_tsd_boot1(void) { tsd_boot1(); *tsd_arenas_tdata_bypassp_get(tsd_fetch()) = false; } #ifdef _WIN32 static BOOL WINAPI -_tls_callback(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ +_tls_callback(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { #ifdef JEMALLOC_LAZY_LOCK case DLL_THREAD_ATTACH: @@ -164,8 +158,7 @@ BOOL (WINAPI *const tls_callback)(HINSTANCE hinstDLL, #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ !defined(_WIN32)) void * -tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block) -{ +tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block) { pthread_t self = pthread_self(); tsd_init_block_t *iter; @@ -186,8 +179,7 @@ tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block) } void -tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block) -{ +tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block) { malloc_mutex_lock(TSDN_NULL, &head->lock); ql_remove(&head->blocks, block, link); malloc_mutex_unlock(TSDN_NULL, &head->lock); diff --git a/src/util.c b/src/util.c index c6ac4e11..a9595397 100644 --- a/src/util.c +++ b/src/util.c @@ -46,8 +46,7 @@ static char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, /* malloc_message() setup. */ static void -wrtmessage(void *cbopaque, const char *s) -{ +wrtmessage(void *cbopaque, const char *s) { #if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_write) /* * Use syscall(2) rather than write(2) when possible in order to avoid @@ -71,12 +70,12 @@ JEMALLOC_EXPORT void (*je_malloc_message)(void *, const char *s); * je_malloc_message(...) throughout the code. */ void -malloc_write(const char *s) -{ - if (je_malloc_message != NULL) +malloc_write(const char *s) { + if (je_malloc_message != NULL) { je_malloc_message(NULL, s); - else + } else { wrtmessage(NULL, s); + } } /* @@ -84,8 +83,7 @@ malloc_write(const char *s) * provide a wrapper. */ int -buferror(int err, char *buf, size_t buflen) -{ +buferror(int err, char *buf, size_t buflen) { #ifdef _WIN32 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, (LPSTR)buf, (DWORD)buflen, NULL); @@ -103,8 +101,7 @@ buferror(int err, char *buf, size_t buflen) } uintmax_t -malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base) -{ +malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base) { uintmax_t ret, digit; unsigned b; bool neg; @@ -149,10 +146,12 @@ malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base) switch (p[1]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': - if (b == 0) + if (b == 0) { b = 8; - if (b == 8) + } + if (b == 8) { p++; + } break; case 'X': case 'x': switch (p[2]) { @@ -162,10 +161,12 @@ malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base) case 'F': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - if (b == 0) + if (b == 0) { b = 16; - if (b == 16) + } + if (b == 16) { p += 2; + } break; default: break; @@ -177,8 +178,9 @@ malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base) goto label_return; } } - if (b == 0) + if (b == 0) { b = 10; + } /* Convert. */ ret = 0; @@ -196,8 +198,9 @@ malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base) } p++; } - if (neg) + if (neg) { ret = (uintmax_t)(-((intmax_t)ret)); + } if (p == ns) { /* No conversion performed. */ @@ -211,15 +214,15 @@ label_return: if (p == ns) { /* No characters were converted. */ *endptr = (char *)nptr; - } else + } else { *endptr = (char *)p; + } } return (ret); } static char * -u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p) -{ +u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p) { unsigned i; i = U2S_BUFSIZE - 1; @@ -261,19 +264,21 @@ u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p) } static char * -d2s(intmax_t x, char sign, char *s, size_t *slen_p) -{ +d2s(intmax_t x, char sign, char *s, size_t *slen_p) { bool neg; - if ((neg = (x < 0))) + if ((neg = (x < 0))) { x = -x; + } s = u2s(x, 10, false, s, slen_p); - if (neg) + if (neg) { sign = '-'; + } switch (sign) { case '-': - if (!neg) + if (!neg) { break; + } /* Fall through. */ case ' ': case '+': @@ -287,8 +292,7 @@ d2s(intmax_t x, char sign, char *s, size_t *slen_p) } static char * -o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p) -{ +o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p) { s = u2s(x, 8, false, s, slen_p); if (alt_form && *s != '0') { s--; @@ -299,8 +303,7 @@ o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p) } static char * -x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p) -{ +x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p) { s = u2s(x, 16, uppercase, s, slen_p); if (alt_form) { s -= 2; @@ -311,14 +314,14 @@ x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p) } size_t -malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) -{ +malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) { size_t i; const char *f; #define APPEND_C(c) do { \ - if (i < size) \ + if (i < size) { \ str[i] = (c); \ + } \ i++; \ } while (0) #define APPEND_S(s, slen) do { \ @@ -334,16 +337,18 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) (size_t)width - slen : 0); \ if (!left_justify && pad_len != 0) { \ size_t j; \ - for (j = 0; j < pad_len; j++) \ + for (j = 0; j < pad_len; j++) { \ APPEND_C(' '); \ + } \ } \ /* Value. */ \ APPEND_S(s, slen); \ /* Right padding. */ \ if (left_justify && pad_len != 0) { \ size_t j; \ - for (j = 0; j < pad_len; j++) \ + for (j = 0; j < pad_len; j++) { \ APPEND_C(' '); \ + } \ } \ } while (0) #define GET_ARG_NUMERIC(val, len) do { \ @@ -454,10 +459,11 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) break; } /* Width/precision separator. */ - if (*f == '.') + if (*f == '.') { f++; - else + } else { goto label_length; + } /* Precision. */ switch (*f) { case '*': @@ -484,8 +490,9 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) if (*f == 'l') { len = 'q'; f++; - } else + } else { len = 'l'; + } break; case 'q': case 'j': case 't': case 'z': len = *f; @@ -576,10 +583,11 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) }} } label_out: - if (i < size) + if (i < size) { str[i] = '\0'; - else + } else { str[size - 1] = '\0'; + } #undef APPEND_C #undef APPEND_S @@ -590,8 +598,7 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) JEMALLOC_FORMAT_PRINTF(3, 4) size_t -malloc_snprintf(char *str, size_t size, const char *format, ...) -{ +malloc_snprintf(char *str, size_t size, const char *format, ...) { size_t ret; va_list ap; @@ -604,8 +611,7 @@ malloc_snprintf(char *str, size_t size, const char *format, ...) void malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque, - const char *format, va_list ap) -{ + const char *format, va_list ap) { char buf[MALLOC_PRINTF_BUFSIZE]; if (write_cb == NULL) { @@ -630,8 +636,7 @@ malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque, JEMALLOC_FORMAT_PRINTF(3, 4) void malloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque, - const char *format, ...) -{ + const char *format, ...) { va_list ap; va_start(ap, format); @@ -642,8 +647,7 @@ malloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque, /* Print to stderr in such a way as to avoid memory allocation. */ JEMALLOC_FORMAT_PRINTF(1, 2) void -malloc_printf(const char *format, ...) -{ +malloc_printf(const char *format, ...) { va_list ap; va_start(ap, format); diff --git a/src/witness.c b/src/witness.c index ffc7e247..f8d66217 100644 --- a/src/witness.c +++ b/src/witness.c @@ -3,8 +3,7 @@ void witness_init(witness_t *witness, const char *name, witness_rank_t rank, - witness_comp_t *comp, void *opaque) -{ + witness_comp_t *comp, void *opaque) { witness->name = name; witness->rank = rank; witness->comp = comp; @@ -16,8 +15,7 @@ witness_init(witness_t *witness, const char *name, witness_rank_t rank, #define witness_lock_error JEMALLOC_N(n_witness_lock_error) #endif void -witness_lock_error(const witness_list_t *witnesses, const witness_t *witness) -{ +witness_lock_error(const witness_list_t *witnesses, const witness_t *witness) { witness_t *w; malloc_printf(": Lock rank order reversal:"); @@ -38,8 +36,7 @@ witness_lock_error_t *witness_lock_error = JEMALLOC_N(n_witness_lock_error); #define witness_owner_error JEMALLOC_N(n_witness_owner_error) #endif void -witness_owner_error(const witness_t *witness) -{ +witness_owner_error(const witness_t *witness) { malloc_printf(": Should own %s(%u)\n", witness->name, witness->rank); abort(); @@ -55,8 +52,7 @@ witness_owner_error_t *witness_owner_error = JEMALLOC_N(n_witness_owner_error); #define witness_not_owner_error JEMALLOC_N(n_witness_not_owner_error) #endif void -witness_not_owner_error(const witness_t *witness) -{ +witness_not_owner_error(const witness_t *witness) { malloc_printf(": Should not own %s(%u)\n", witness->name, witness->rank); abort(); @@ -73,8 +69,7 @@ witness_not_owner_error_t *witness_not_owner_error = #define witness_lockless_error JEMALLOC_N(n_witness_lockless_error) #endif void -witness_lockless_error(const witness_list_t *witnesses) -{ +witness_lockless_error(const witness_list_t *witnesses) { witness_t *w; malloc_printf(": Should not own any locks:"); @@ -92,28 +87,24 @@ witness_lockless_error_t *witness_lockless_error = #endif void -witnesses_cleanup(tsd_t *tsd) -{ +witnesses_cleanup(tsd_t *tsd) { witness_assert_lockless(tsd_tsdn(tsd)); /* Do nothing. */ } void -witness_prefork(tsd_t *tsd) -{ +witness_prefork(tsd_t *tsd) { tsd_witness_fork_set(tsd, true); } void -witness_postfork_parent(tsd_t *tsd) -{ +witness_postfork_parent(tsd_t *tsd) { tsd_witness_fork_set(tsd, false); } void -witness_postfork_child(tsd_t *tsd) -{ +witness_postfork_child(tsd_t *tsd) { #ifndef JEMALLOC_MUTEX_INIT_CB witness_list_t *witnesses; diff --git a/src/zone.c b/src/zone.c index c54f4a4f..8e106632 100644 --- a/src/zone.c +++ b/src/zone.c @@ -125,8 +125,7 @@ static void zone_reinit_lock(malloc_zone_t *zone); */ static size_t -zone_size(malloc_zone_t *zone, const void *ptr) -{ +zone_size(malloc_zone_t *zone, const void *ptr) { /* * There appear to be places within Darwin (such as setenv(3)) that * cause calls to this function with pointers that *no* zone owns. If @@ -140,20 +139,17 @@ zone_size(malloc_zone_t *zone, const void *ptr) } static void * -zone_malloc(malloc_zone_t *zone, size_t size) -{ +zone_malloc(malloc_zone_t *zone, size_t size) { return (je_malloc(size)); } static void * -zone_calloc(malloc_zone_t *zone, size_t num, size_t size) -{ +zone_calloc(malloc_zone_t *zone, size_t num, size_t size) { return (je_calloc(num, size)); } static void * -zone_valloc(malloc_zone_t *zone, size_t size) -{ +zone_valloc(malloc_zone_t *zone, size_t size) { void *ret = NULL; /* Assignment avoids useless compiler warning. */ je_posix_memalign(&ret, PAGE, size); @@ -162,8 +158,7 @@ zone_valloc(malloc_zone_t *zone, size_t size) } static void -zone_free(malloc_zone_t *zone, void *ptr) -{ +zone_free(malloc_zone_t *zone, void *ptr) { if (ivsalloc(tsdn_fetch(), ptr) != 0) { je_free(ptr); return; @@ -173,17 +168,16 @@ zone_free(malloc_zone_t *zone, void *ptr) } static void * -zone_realloc(malloc_zone_t *zone, void *ptr, size_t size) -{ - if (ivsalloc(tsdn_fetch(), ptr) != 0) +zone_realloc(malloc_zone_t *zone, void *ptr, size_t size) { + if (ivsalloc(tsdn_fetch(), ptr) != 0) { return (je_realloc(ptr, size)); + } return (realloc(ptr, size)); } static void * -zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size) -{ +zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size) { void *ret = NULL; /* Assignment avoids useless compiler warning. */ je_posix_memalign(&ret, alignment, size); @@ -192,8 +186,7 @@ zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size) } static void -zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size) -{ +zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size) { size_t alloc_size; alloc_size = ivsalloc(tsdn_fetch(), ptr); @@ -207,16 +200,14 @@ zone_free_definite_size(malloc_zone_t *zone, void *ptr, size_t size) } static void -zone_destroy(malloc_zone_t *zone) -{ +zone_destroy(malloc_zone_t *zone) { /* This function should never be called. */ not_reached(); } static unsigned zone_batch_malloc(struct _malloc_zone_t *zone, size_t size, void **results, - unsigned num_requested) -{ + unsigned num_requested) { unsigned i; for (i = 0; i < num_requested; i++) { @@ -230,8 +221,7 @@ zone_batch_malloc(struct _malloc_zone_t *zone, size_t size, void **results, static void zone_batch_free(struct _malloc_zone_t *zone, void **to_be_freed, - unsigned num_to_be_freed) -{ + unsigned num_to_be_freed) { unsigned i; for (i = 0; i < num_to_be_freed; i++) { @@ -241,53 +231,47 @@ zone_batch_free(struct _malloc_zone_t *zone, void **to_be_freed, } static size_t -zone_pressure_relief(struct _malloc_zone_t *zone, size_t goal) -{ +zone_pressure_relief(struct _malloc_zone_t *zone, size_t goal) { return 0; } static size_t -zone_good_size(malloc_zone_t *zone, size_t size) -{ - if (size == 0) +zone_good_size(malloc_zone_t *zone, size_t size) { + if (size == 0) { size = 1; + } return (s2u(size)); } static kern_return_t zone_enumerator(task_t task, void *data, unsigned type_mask, vm_address_t zone_address, memory_reader_t reader, - vm_range_recorder_t recorder) -{ + vm_range_recorder_t recorder) { return KERN_SUCCESS; } static boolean_t -zone_check(malloc_zone_t *zone) -{ +zone_check(malloc_zone_t *zone) { return true; } static void -zone_print(malloc_zone_t *zone, boolean_t verbose) -{ +zone_print(malloc_zone_t *zone, boolean_t verbose) { } static void -zone_log(malloc_zone_t *zone, void *address) -{ +zone_log(malloc_zone_t *zone, void *address) { } static void -zone_force_lock(malloc_zone_t *zone) -{ - if (isthreaded) +zone_force_lock(malloc_zone_t *zone) { + if (isthreaded) { jemalloc_prefork(); + } } static void -zone_force_unlock(malloc_zone_t *zone) -{ +zone_force_unlock(malloc_zone_t *zone) { /* * Call jemalloc_postfork_child() rather than * jemalloc_postfork_parent(), because this function is executed by both @@ -295,13 +279,13 @@ zone_force_unlock(malloc_zone_t *zone) * reinitialized, but the child cannot unlock mutexes that were locked * by the parent. */ - if (isthreaded) + if (isthreaded) { jemalloc_postfork_child(); + } } static void -zone_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) -{ +zone_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) { /* We make no effort to actually fill the values */ stats->blocks_in_use = 0; stats->size_in_use = 0; @@ -310,23 +294,20 @@ zone_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) } static boolean_t -zone_locked(malloc_zone_t *zone) -{ +zone_locked(malloc_zone_t *zone) { /* Pretend no lock is being held */ return false; } static void -zone_reinit_lock(malloc_zone_t *zone) -{ +zone_reinit_lock(malloc_zone_t *zone) { /* As of OSX 10.12, this function is only used when force_unlock would * be used if the zone version were < 9. So just use force_unlock. */ zone_force_unlock(zone); } static void -zone_init(void) -{ +zone_init(void) { jemalloc_zone.size = zone_size; jemalloc_zone.malloc = zone_malloc; jemalloc_zone.calloc = zone_calloc; @@ -364,8 +345,7 @@ zone_init(void) } static malloc_zone_t * -zone_default_get(void) -{ +zone_default_get(void) { malloc_zone_t **zones = NULL; unsigned int num_zones = 0; @@ -387,16 +367,16 @@ zone_default_get(void) num_zones = 0; } - if (num_zones) + if (num_zones) { return (zones[0]); + } return (malloc_default_zone()); } /* As written, this function can only promote jemalloc_zone. */ static void -zone_promote(void) -{ +zone_promote(void) { malloc_zone_t *zone; do { @@ -433,16 +413,16 @@ zone_promote(void) JEMALLOC_ATTR(constructor) void -zone_register(void) -{ +zone_register(void) { /* * If something else replaced the system default zone allocator, don't * register jemalloc's. */ default_zone = zone_default_get(); if (!default_zone->zone_name || strcmp(default_zone->zone_name, - "DefaultMallocZone") != 0) + "DefaultMallocZone") != 0) { return; + } /* * The default purgeable zone is created lazily by OSX's libc. It uses diff --git a/test/include/test/SFMT.h b/test/include/test/SFMT.h index 09c1607d..4ad7484a 100644 --- a/test/include/test/SFMT.h +++ b/test/include/test/SFMT.h @@ -97,75 +97,65 @@ double genrand_res53_mix(sfmt_t *ctx); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(SFMT_C_)) /* These real versions are due to Isaku Wada */ /** generates a random number on [0,1]-real-interval */ -JEMALLOC_INLINE double to_real1(uint32_t v) -{ +JEMALLOC_INLINE double to_real1(uint32_t v) { return v * (1.0/4294967295.0); /* divided by 2^32-1 */ } /** generates a random number on [0,1]-real-interval */ -JEMALLOC_INLINE double genrand_real1(sfmt_t *ctx) -{ +JEMALLOC_INLINE double genrand_real1(sfmt_t *ctx) { return to_real1(gen_rand32(ctx)); } /** generates a random number on [0,1)-real-interval */ -JEMALLOC_INLINE double to_real2(uint32_t v) -{ +JEMALLOC_INLINE double to_real2(uint32_t v) { return v * (1.0/4294967296.0); /* divided by 2^32 */ } /** generates a random number on [0,1)-real-interval */ -JEMALLOC_INLINE double genrand_real2(sfmt_t *ctx) -{ +JEMALLOC_INLINE double genrand_real2(sfmt_t *ctx) { return to_real2(gen_rand32(ctx)); } /** generates a random number on (0,1)-real-interval */ -JEMALLOC_INLINE double to_real3(uint32_t v) -{ +JEMALLOC_INLINE double to_real3(uint32_t v) { return (((double)v) + 0.5)*(1.0/4294967296.0); /* divided by 2^32 */ } /** generates a random number on (0,1)-real-interval */ -JEMALLOC_INLINE double genrand_real3(sfmt_t *ctx) -{ +JEMALLOC_INLINE double genrand_real3(sfmt_t *ctx) { return to_real3(gen_rand32(ctx)); } /** These real versions are due to Isaku Wada */ /** generates a random number on [0,1) with 53-bit resolution*/ -JEMALLOC_INLINE double to_res53(uint64_t v) -{ +JEMALLOC_INLINE double to_res53(uint64_t v) { return v * (1.0/18446744073709551616.0L); } /** generates a random number on [0,1) with 53-bit resolution from two * 32 bit integers */ -JEMALLOC_INLINE double to_res53_mix(uint32_t x, uint32_t y) -{ +JEMALLOC_INLINE double to_res53_mix(uint32_t x, uint32_t y) { return to_res53(x | ((uint64_t)y << 32)); } /** generates a random number on [0,1) with 53-bit resolution */ -JEMALLOC_INLINE double genrand_res53(sfmt_t *ctx) -{ +JEMALLOC_INLINE double genrand_res53(sfmt_t *ctx) { return to_res53(gen_rand64(ctx)); -} +} /** generates a random number on [0,1) with 53-bit resolution using 32bit integer. */ -JEMALLOC_INLINE double genrand_res53_mix(sfmt_t *ctx) -{ +JEMALLOC_INLINE double genrand_res53_mix(sfmt_t *ctx) { uint32_t x, y; x = gen_rand32(ctx); y = gen_rand32(ctx); return to_res53_mix(x, y); -} +} #endif #endif diff --git a/test/include/test/btalloc.h b/test/include/test/btalloc.h index c3f9d4df..98366afe 100644 --- a/test/include/test/btalloc.h +++ b/test/include/test/btalloc.h @@ -8,13 +8,12 @@ btalloc_n_proto(1) #define btalloc_n_gen(n) \ void * \ -btalloc_##n(size_t size, unsigned bits) \ -{ \ +btalloc_##n(size_t size, unsigned bits) { \ void *p; \ \ - if (bits == 0) \ + if (bits == 0) { \ p = mallocx(size, 0); \ - else { \ + } else { \ switch (bits & 0x1U) { \ case 0: \ p = (btalloc_0(size, bits >> 1)); \ diff --git a/test/include/test/extent_hooks.h b/test/include/test/extent_hooks.h index f50747d0..a664c433 100644 --- a/test/include/test/extent_hooks.h +++ b/test/include/test/extent_hooks.h @@ -73,8 +73,7 @@ static bool did_merge; static void * extent_alloc_hook(extent_hooks_t *extent_hooks, void *new_addr, size_t size, - size_t alignment, bool *zero, bool *commit, unsigned arena_ind) -{ + size_t alignment, bool *zero, bool *commit, unsigned arena_ind) { void *ret; TRACE_HOOK("%s(extent_hooks=%p, new_addr=%p, size=%zu, alignment=%zu, " @@ -86,8 +85,9 @@ extent_alloc_hook(extent_hooks_t *extent_hooks, void *new_addr, size_t size, assert_ptr_eq(extent_hooks->alloc, extent_alloc_hook, "Wrong hook function"); called_alloc = true; - if (!try_alloc) + if (!try_alloc) { return (NULL); + } ret = default_hooks->alloc(default_hooks, new_addr, size, alignment, zero, commit, 0); did_alloc = (ret != NULL); @@ -96,8 +96,7 @@ extent_alloc_hook(extent_hooks_t *extent_hooks, void *new_addr, size_t size, static bool extent_dalloc_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, - bool committed, unsigned arena_ind) -{ + bool committed, unsigned arena_ind) { bool err; TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, " @@ -108,8 +107,9 @@ extent_dalloc_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, assert_ptr_eq(extent_hooks->dalloc, extent_dalloc_hook, "Wrong hook function"); called_dalloc = true; - if (!try_dalloc) + if (!try_dalloc) { return (true); + } err = default_hooks->dalloc(default_hooks, addr, size, committed, 0); did_dalloc = !err; return (err); @@ -117,8 +117,7 @@ extent_dalloc_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, static bool extent_commit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t offset, size_t length, unsigned arena_ind) -{ + size_t offset, size_t length, unsigned arena_ind) { bool err; TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " @@ -129,8 +128,9 @@ extent_commit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, assert_ptr_eq(extent_hooks->commit, extent_commit_hook, "Wrong hook function"); called_commit = true; - if (!try_commit) + if (!try_commit) { return (true); + } err = default_hooks->commit(default_hooks, addr, size, offset, length, 0); did_commit = !err; @@ -139,8 +139,7 @@ extent_commit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, static bool extent_decommit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t offset, size_t length, unsigned arena_ind) -{ + size_t offset, size_t length, unsigned arena_ind) { bool err; TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " @@ -151,8 +150,9 @@ extent_decommit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, assert_ptr_eq(extent_hooks->decommit, extent_decommit_hook, "Wrong hook function"); called_decommit = true; - if (!try_decommit) + if (!try_decommit) { return (true); + } err = default_hooks->decommit(default_hooks, addr, size, offset, length, 0); did_decommit = !err; @@ -161,8 +161,7 @@ extent_decommit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, static bool extent_purge_lazy_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t offset, size_t length, unsigned arena_ind) -{ + size_t offset, size_t length, unsigned arena_ind) { bool err; TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " @@ -173,8 +172,9 @@ extent_purge_lazy_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, assert_ptr_eq(extent_hooks->purge_lazy, extent_purge_lazy_hook, "Wrong hook function"); called_purge_lazy = true; - if (!try_purge_lazy) + if (!try_purge_lazy) { return (true); + } err = default_hooks->purge_lazy == NULL || default_hooks->purge_lazy(default_hooks, addr, size, offset, length, 0); @@ -184,8 +184,7 @@ extent_purge_lazy_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, static bool extent_purge_forced_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t offset, size_t length, unsigned arena_ind) -{ + size_t offset, size_t length, unsigned arena_ind) { bool err; TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, offset=%zu, " @@ -196,8 +195,9 @@ extent_purge_forced_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, assert_ptr_eq(extent_hooks->purge_forced, extent_purge_forced_hook, "Wrong hook function"); called_purge_forced = true; - if (!try_purge_forced) + if (!try_purge_forced) { return (true); + } err = default_hooks->purge_forced == NULL || default_hooks->purge_forced(default_hooks, addr, size, offset, length, 0); @@ -207,8 +207,7 @@ extent_purge_forced_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, static bool extent_split_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, - size_t size_a, size_t size_b, bool committed, unsigned arena_ind) -{ + size_t size_a, size_t size_b, bool committed, unsigned arena_ind) { bool err; TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, size_a=%zu, " @@ -220,8 +219,9 @@ extent_split_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, assert_ptr_eq(extent_hooks->split, extent_split_hook, "Wrong hook function"); called_split = true; - if (!try_split) + if (!try_split) { return (true); + } err = (default_hooks->split == NULL || default_hooks->split(default_hooks, addr, size, size_a, size_b, committed, 0)); @@ -231,8 +231,7 @@ extent_split_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, static bool extent_merge_hook(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, - void *addr_b, size_t size_b, bool committed, unsigned arena_ind) -{ + void *addr_b, size_t size_b, bool committed, unsigned arena_ind) { bool err; TRACE_HOOK("%s(extent_hooks=%p, addr_a=%p, size_a=%zu, addr_b=%p " @@ -244,8 +243,9 @@ extent_merge_hook(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, assert_ptr_eq(extent_hooks->merge, extent_merge_hook, "Wrong hook function"); called_merge = true; - if (!try_merge) + if (!try_merge) { return (true); + } err = (default_hooks->merge == NULL || default_hooks->merge(default_hooks, addr_a, size_a, addr_b, size_b, committed, 0)); @@ -254,8 +254,7 @@ extent_merge_hook(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, } static void -extent_hooks_prep(void) -{ +extent_hooks_prep(void) { size_t sz; sz = sizeof(default_hooks); diff --git a/test/include/test/jemalloc_test.h.in b/test/include/test/jemalloc_test.h.in index 2dd0cdea..a0b94747 100644 --- a/test/include/test/jemalloc_test.h.in +++ b/test/include/test/jemalloc_test.h.in @@ -159,8 +159,9 @@ static const bool config_debug = } while (0) #define assert_not_implemented(e) do { \ - if (!(e)) \ + if (!(e)) { \ not_implemented(); \ + } \ } while (0) #ifdef __cplusplus diff --git a/test/include/test/math.h b/test/include/test/math.h index 1728d60f..08be69f8 100644 --- a/test/include/test/math.h +++ b/test/include/test/math.h @@ -16,8 +16,7 @@ double pt_gamma(double p, double shape, double scale, double ln_gamma_shape); * [S14]. Communications of the ACM 9(9):684. */ JEMALLOC_INLINE double -ln_gamma(double x) -{ +ln_gamma(double x) { double f, z; assert(x > 0.0); @@ -31,8 +30,9 @@ ln_gamma(double x) } x = z; f = -log(f); - } else + } else { f = 0.0; + } z = 1.0 / (x * x); @@ -51,8 +51,7 @@ ln_gamma(double x) * Applied Statistics 19:285-287. */ JEMALLOC_INLINE double -i_gamma(double x, double p, double ln_gamma_p) -{ +i_gamma(double x, double p, double ln_gamma_p) { double acu, factor, oflo, gin, term, rn, a, b, an, dif; double pn[6]; unsigned i; @@ -60,8 +59,9 @@ i_gamma(double x, double p, double ln_gamma_p) assert(p > 0.0); assert(x >= 0.0); - if (x == 0.0) + if (x == 0.0) { return (0.0); + } acu = 1.0e-10; oflo = 1.0e30; @@ -99,8 +99,9 @@ i_gamma(double x, double p, double ln_gamma_p) b += 2.0; term += 1.0; an = a * term; - for (i = 0; i < 2; i++) + for (i = 0; i < 2; i++) { pn[i+4] = b * pn[i+2] - an * pn[i]; + } if (pn[5] != 0.0) { rn = pn[4] / pn[5]; dif = fabs(gin - rn); @@ -110,12 +111,14 @@ i_gamma(double x, double p, double ln_gamma_p) } gin = rn; } - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { pn[i] = pn[i+2]; + } if (fabs(pn[4]) >= oflo) { - for (i = 0; i < 4; i++) + for (i = 0; i < 4; i++) { pn[i] /= oflo; + } } } } @@ -132,8 +135,7 @@ i_gamma(double x, double p, double ln_gamma_p) * distribution. Applied Statistics 37(3):477-484. */ JEMALLOC_INLINE double -pt_norm(double p) -{ +pt_norm(double p) { double q, r, ret; assert(p > 0.0 && p < 1.0); @@ -153,10 +155,11 @@ pt_norm(double p) r + 6.8718700749205790830e2) * r + 4.2313330701600911252e1) * r + 1.0)); } else { - if (q < 0.0) + if (q < 0.0) { r = p; - else + } else { r = 1.0 - p; + } assert(r > 0.0); r = sqrt(-log(r)); @@ -198,8 +201,9 @@ pt_norm(double p) 5.99832206555887937690e-1) * r + 1.0)); } - if (q < 0.0) + if (q < 0.0) { ret = -ret; + } return (ret); } } @@ -219,8 +223,7 @@ pt_norm(double p) * points of the Chi^2 distribution. Applied Statistics 40(1):233-235. */ JEMALLOC_INLINE double -pt_chi2(double p, double df, double ln_gamma_df_2) -{ +pt_chi2(double p, double df, double ln_gamma_df_2) { double e, aa, xx, c, ch, a, q, p1, p2, t, x, b, s1, s2, s3, s4, s5, s6; unsigned i; @@ -236,8 +239,9 @@ pt_chi2(double p, double df, double ln_gamma_df_2) if (df < -1.24 * log(p)) { /* Starting approximation for small Chi^2. */ ch = pow(p * xx * exp(ln_gamma_df_2 + xx * aa), 1.0 / xx); - if (ch - e < 0.0) + if (ch - e < 0.0) { return (ch); + } } else { if (df > 0.32) { x = pt_norm(p); @@ -263,8 +267,9 @@ pt_chi2(double p, double df, double ln_gamma_df_2) * (13.32 + 3.0 * ch)) / p2; ch -= (1.0 - exp(a + ln_gamma_df_2 + 0.5 * ch + c * aa) * p2 / p1) / t; - if (fabs(q / ch - 1.0) - 0.01 <= 0.0) + if (fabs(q / ch - 1.0) - 0.01 <= 0.0) { break; + } } } } @@ -273,8 +278,9 @@ pt_chi2(double p, double df, double ln_gamma_df_2) /* Calculation of seven-term Taylor series. */ q = ch; p1 = 0.5 * ch; - if (p1 < 0.0) + if (p1 < 0.0) { return (-1.0); + } p2 = p - i_gamma(p1, xx, ln_gamma_df_2); t = p2 * exp(xx * aa + ln_gamma_df_2 + p1 - c * log(ch)); b = t / ch; @@ -290,8 +296,9 @@ pt_chi2(double p, double df, double ln_gamma_df_2) s6 = (120.0 + c * (346.0 + 127.0 * c)) / 5040.0; ch += t * (1.0 + 0.5 * t * s1 - b * c * (s1 - b * (s2 - b * (s3 - b * (s4 - b * (s5 - b * s6)))))); - if (fabs(q / ch - 1.0) <= e) + if (fabs(q / ch - 1.0) <= e) { break; + } } return (ch); @@ -303,8 +310,7 @@ pt_chi2(double p, double df, double ln_gamma_df_2) * p. */ JEMALLOC_INLINE double -pt_gamma(double p, double shape, double scale, double ln_gamma_shape) -{ +pt_gamma(double p, double shape, double scale, double ln_gamma_shape) { return (pt_chi2(p, shape * 2.0, ln_gamma_shape) * 0.5 * scale); } #endif diff --git a/test/include/test/mq.h b/test/include/test/mq.h index a974eb90..fd66de95 100644 --- a/test/include/test/mq.h +++ b/test/include/test/mq.h @@ -37,20 +37,19 @@ typedef struct { \ a_attr bool \ a_prefix##init(a_mq_type *mq) { \ \ - if (mtx_init(&mq->lock)) \ + if (mtx_init(&mq->lock)) { \ return (true); \ + } \ ql_new(&mq->msgs); \ mq->count = 0; \ return (false); \ } \ a_attr void \ -a_prefix##fini(a_mq_type *mq) \ -{ \ +a_prefix##fini(a_mq_type *mq) { \ mtx_fini(&mq->lock); \ } \ a_attr unsigned \ -a_prefix##count(a_mq_type *mq) \ -{ \ +a_prefix##count(a_mq_type *mq) { \ unsigned count; \ \ mtx_lock(&mq->lock); \ @@ -59,8 +58,7 @@ a_prefix##count(a_mq_type *mq) \ return (count); \ } \ a_attr a_mq_msg_type * \ -a_prefix##tryget(a_mq_type *mq) \ -{ \ +a_prefix##tryget(a_mq_type *mq) { \ a_mq_msg_type *msg; \ \ mtx_lock(&mq->lock); \ @@ -73,32 +71,33 @@ a_prefix##tryget(a_mq_type *mq) \ return (msg); \ } \ a_attr a_mq_msg_type * \ -a_prefix##get(a_mq_type *mq) \ -{ \ +a_prefix##get(a_mq_type *mq) { \ a_mq_msg_type *msg; \ unsigned ns; \ \ msg = a_prefix##tryget(mq); \ - if (msg != NULL) \ + if (msg != NULL) { \ return (msg); \ + } \ \ ns = 1; \ while (true) { \ mq_nanosleep(ns); \ msg = a_prefix##tryget(mq); \ - if (msg != NULL) \ + if (msg != NULL) { \ return (msg); \ + } \ if (ns < 1000*1000*1000) { \ /* Double sleep time, up to max 1 second. */ \ ns <<= 1; \ - if (ns > 1000*1000*1000) \ + if (ns > 1000*1000*1000) { \ ns = 1000*1000*1000; \ + } \ } \ } \ } \ a_attr void \ -a_prefix##put(a_mq_type *mq, a_mq_msg_type *msg) \ -{ \ +a_prefix##put(a_mq_type *mq, a_mq_msg_type *msg) { \ \ mtx_lock(&mq->lock); \ ql_elm_new(msg, a_field); \ diff --git a/test/include/test/test.h b/test/include/test/test.h index 8c69fc2e..a1b6f72a 100644 --- a/test/include/test/test.h +++ b/test/include/test/test.h @@ -298,8 +298,7 @@ typedef void (test_t)(void); #define TEST_BEGIN(f) \ static void \ -f(void) \ -{ \ +f(void) { \ p_test_init(#f); #define TEST_END \ diff --git a/test/integration/MALLOCX_ARENA.c b/test/integration/MALLOCX_ARENA.c index 1d9e423e..f706e5a5 100644 --- a/test/integration/MALLOCX_ARENA.c +++ b/test/integration/MALLOCX_ARENA.c @@ -11,8 +11,7 @@ static bool have_dss = ; void * -thd_start(void *arg) -{ +thd_start(void *arg) { unsigned thread_ind = (unsigned)(uintptr_t)arg; unsigned arena_ind; void *p; @@ -45,8 +44,7 @@ thd_start(void *arg) return (NULL); } -TEST_BEGIN(test_MALLOCX_ARENA) -{ +TEST_BEGIN(test_MALLOCX_ARENA) { thd_t thds[NTHREADS]; unsigned i; @@ -55,14 +53,14 @@ TEST_BEGIN(test_MALLOCX_ARENA) (void *)(uintptr_t)i); } - for (i = 0; i < NTHREADS; i++) + for (i = 0; i < NTHREADS; i++) { thd_join(thds[i], NULL); + } } TEST_END int -main(void) -{ +main(void) { return (test( test_MALLOCX_ARENA)); } diff --git a/test/integration/aligned_alloc.c b/test/integration/aligned_alloc.c index 52b69acb..8a3ad6b9 100644 --- a/test/integration/aligned_alloc.c +++ b/test/integration/aligned_alloc.c @@ -8,14 +8,12 @@ * potential OOM on e.g. 32-bit Windows. */ static void -purge(void) -{ +purge(void) { assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl error"); } -TEST_BEGIN(test_alignment_errors) -{ +TEST_BEGIN(test_alignment_errors) { size_t alignment; void *p; @@ -36,8 +34,7 @@ TEST_BEGIN(test_alignment_errors) } TEST_END -TEST_BEGIN(test_oom_errors) -{ +TEST_BEGIN(test_oom_errors) { size_t alignment, size; void *p; @@ -81,15 +78,15 @@ TEST_BEGIN(test_oom_errors) } TEST_END -TEST_BEGIN(test_alignment_and_size) -{ +TEST_BEGIN(test_alignment_and_size) { #define NITER 4 size_t alignment, size, total; unsigned i; void *ps[NITER]; - for (i = 0; i < NITER; i++) + for (i = 0; i < NITER; i++) { ps[i] = NULL; + } for (alignment = 8; alignment <= MAXALIGN; @@ -110,8 +107,9 @@ TEST_BEGIN(test_alignment_and_size) alignment, size, size, buf); } total += malloc_usable_size(ps[i]); - if (total >= (MAXALIGN << 1)) + if (total >= (MAXALIGN << 1)) { break; + } } for (i = 0; i < NITER; i++) { if (ps[i] != NULL) { @@ -127,8 +125,7 @@ TEST_BEGIN(test_alignment_and_size) TEST_END int -main(void) -{ +main(void) { return (test( test_alignment_errors, test_oom_errors, diff --git a/test/integration/allocated.c b/test/integration/allocated.c index 7570c52f..555d40a9 100644 --- a/test/integration/allocated.c +++ b/test/integration/allocated.c @@ -9,8 +9,7 @@ static const bool config_stats = ; void * -thd_start(void *arg) -{ +thd_start(void *arg) { int err; void *p; uint64_t a0, a1, d0, d1; @@ -19,15 +18,17 @@ thd_start(void *arg) sz = sizeof(a0); if ((err = mallctl("thread.allocated", (void *)&a0, &sz, NULL, 0))) { - if (err == ENOENT) + if (err == ENOENT) { goto label_ENOENT; + } test_fail("%s(): Error in mallctl(): %s", __func__, strerror(err)); } sz = sizeof(ap0); if ((err = mallctl("thread.allocatedp", (void *)&ap0, &sz, NULL, 0))) { - if (err == ENOENT) + if (err == ENOENT) { goto label_ENOENT; + } test_fail("%s(): Error in mallctl(): %s", __func__, strerror(err)); } @@ -37,16 +38,18 @@ thd_start(void *arg) sz = sizeof(d0); if ((err = mallctl("thread.deallocated", (void *)&d0, &sz, NULL, 0))) { - if (err == ENOENT) + if (err == ENOENT) { goto label_ENOENT; + } test_fail("%s(): Error in mallctl(): %s", __func__, strerror(err)); } sz = sizeof(dp0); if ((err = mallctl("thread.deallocatedp", (void *)&dp0, &sz, NULL, 0))) { - if (err == ENOENT) + if (err == ENOENT) { goto label_ENOENT; + } test_fail("%s(): Error in mallctl(): %s", __func__, strerror(err)); } @@ -96,14 +99,12 @@ label_ENOENT: return (NULL); } -TEST_BEGIN(test_main_thread) -{ +TEST_BEGIN(test_main_thread) { thd_start(NULL); } TEST_END -TEST_BEGIN(test_subthread) -{ +TEST_BEGIN(test_subthread) { thd_t thd; thd_create(&thd, thd_start, NULL); @@ -112,8 +113,7 @@ TEST_BEGIN(test_subthread) TEST_END int -main(void) -{ +main(void) { /* Run tests multiple times to check for bad interactions. */ return (test( test_main_thread, diff --git a/test/integration/cpp/basic.cpp b/test/integration/cpp/basic.cpp index b208e1d1..fe8874fa 100644 --- a/test/integration/cpp/basic.cpp +++ b/test/integration/cpp/basic.cpp @@ -1,8 +1,7 @@ #include #include "test/jemalloc_test.h" -TEST_BEGIN(test_basic) -{ +TEST_BEGIN(test_basic) { auto foo = new long(4); assert_ptr_not_null(foo, "Unexpected new[] failure"); delete foo; @@ -20,8 +19,7 @@ TEST_BEGIN(test_basic) TEST_END int -main() -{ +main() { return (test( test_basic)); } diff --git a/test/integration/extent.c b/test/integration/extent.c index 30849b0c..d12c123c 100644 --- a/test/integration/extent.c +++ b/test/integration/extent.c @@ -7,8 +7,7 @@ const char *malloc_conf = "junk:false"; #include "test/extent_hooks.h" static void -test_extent_body(unsigned arena_ind) -{ +test_extent_body(unsigned arena_ind) { void *p; size_t large0, large1, large2, sz; size_t purge_mib[3]; @@ -67,15 +66,17 @@ test_extent_body(unsigned arena_ind) xallocx_success_b = (xallocx(p, large0, 0, flags) == large0); assert_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0), 0, "Unexpected arena.%u.purge error", arena_ind); - if (xallocx_success_b) + if (xallocx_success_b) { assert_true(did_split, "Expected split"); + } xallocx_success_c = (xallocx(p, large0 * 2, 0, flags) == large0 * 2); if (did_split) { assert_b_eq(did_decommit, did_commit, "Expected decommit/commit match"); } - if (xallocx_success_b && xallocx_success_c) + if (xallocx_success_b && xallocx_success_c) { assert_true(did_merge, "Expected merge"); + } dallocx(p, flags); try_dalloc = true; try_decommit = false; @@ -86,8 +87,7 @@ test_extent_body(unsigned arena_ind) dallocx(p, flags); } -TEST_BEGIN(test_extent_manual_hook) -{ +TEST_BEGIN(test_extent_manual_hook) { unsigned arena_ind; size_t old_size, new_size, sz; size_t hooks_mib[3]; @@ -155,8 +155,7 @@ TEST_BEGIN(test_extent_manual_hook) } TEST_END -TEST_BEGIN(test_extent_auto_hook) -{ +TEST_BEGIN(test_extent_auto_hook) { unsigned arena_ind; size_t new_size, sz; extent_hooks_t *new_hooks; @@ -174,8 +173,7 @@ TEST_BEGIN(test_extent_auto_hook) TEST_END int -main(void) -{ +main(void) { return (test( test_extent_manual_hook, test_extent_auto_hook)); diff --git a/test/integration/mallocx.c b/test/integration/mallocx.c index 7617b1b7..ec04c399 100644 --- a/test/integration/mallocx.c +++ b/test/integration/mallocx.c @@ -5,8 +5,7 @@ const char *malloc_conf = "junk:false"; #endif static unsigned -get_nsizes_impl(const char *cmd) -{ +get_nsizes_impl(const char *cmd) { unsigned ret; size_t z; @@ -18,14 +17,12 @@ get_nsizes_impl(const char *cmd) } static unsigned -get_nlarge(void) -{ +get_nlarge(void) { return (get_nsizes_impl("arenas.nlextents")); } static size_t -get_size_impl(const char *cmd, size_t ind) -{ +get_size_impl(const char *cmd, size_t ind) { size_t ret; size_t z; size_t mib[4]; @@ -43,8 +40,7 @@ get_size_impl(const char *cmd, size_t ind) } static size_t -get_large_size(size_t ind) -{ +get_large_size(size_t ind) { return (get_size_impl("arenas.lextent.0.size", ind)); } @@ -54,14 +50,12 @@ get_large_size(size_t ind) * potential OOM on e.g. 32-bit Windows. */ static void -purge(void) -{ +purge(void) { assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl error"); } -TEST_BEGIN(test_overflow) -{ +TEST_BEGIN(test_overflow) { size_t largemax; largemax = get_large_size(get_nlarge()-1); @@ -81,8 +75,7 @@ TEST_BEGIN(test_overflow) } TEST_END -TEST_BEGIN(test_oom) -{ +TEST_BEGIN(test_oom) { size_t largemax; bool oom; void *ptrs[3]; @@ -96,15 +89,17 @@ TEST_BEGIN(test_oom) oom = false; for (i = 0; i < sizeof(ptrs) / sizeof(void *); i++) { ptrs[i] = mallocx(largemax, 0); - if (ptrs[i] == NULL) + if (ptrs[i] == NULL) { oom = true; + } } assert_true(oom, "Expected OOM during series of calls to mallocx(size=%zu, 0)", largemax); for (i = 0; i < sizeof(ptrs) / sizeof(void *); i++) { - if (ptrs[i] != NULL) + if (ptrs[i] != NULL) { dallocx(ptrs[i], 0); + } } purge(); @@ -122,8 +117,7 @@ TEST_BEGIN(test_oom) } TEST_END -TEST_BEGIN(test_basic) -{ +TEST_BEGIN(test_basic) { #define MAXSZ (((size_t)1) << 23) size_t sz; @@ -160,16 +154,16 @@ TEST_BEGIN(test_basic) } TEST_END -TEST_BEGIN(test_alignment_and_size) -{ +TEST_BEGIN(test_alignment_and_size) { #define MAXALIGN (((size_t)1) << 23) #define NITER 4 size_t nsz, rsz, sz, alignment, total; unsigned i; void *ps[NITER]; - for (i = 0; i < NITER; i++) + for (i = 0; i < NITER; i++) { ps[i] = NULL; + } for (alignment = 8; alignment <= MAXALIGN; @@ -202,8 +196,9 @@ TEST_BEGIN(test_alignment_and_size) " alignment=%zu, size=%zu", ps[i], alignment, sz); total += rsz; - if (total >= (MAXALIGN << 1)) + if (total >= (MAXALIGN << 1)) { break; + } } for (i = 0; i < NITER; i++) { if (ps[i] != NULL) { @@ -220,8 +215,7 @@ TEST_BEGIN(test_alignment_and_size) TEST_END int -main(void) -{ +main(void) { return (test( test_overflow, test_oom, diff --git a/test/integration/overflow.c b/test/integration/overflow.c index ad867e7c..a7f4b515 100644 --- a/test/integration/overflow.c +++ b/test/integration/overflow.c @@ -1,7 +1,6 @@ #include "test/jemalloc_test.h" -TEST_BEGIN(test_overflow) -{ +TEST_BEGIN(test_overflow) { unsigned nlextents; size_t mib[4]; size_t sz, miblen, max_size_class; @@ -41,8 +40,7 @@ TEST_BEGIN(test_overflow) TEST_END int -main(void) -{ +main(void) { return (test( test_overflow)); } diff --git a/test/integration/posix_memalign.c b/test/integration/posix_memalign.c index dace10f7..6bbf1839 100644 --- a/test/integration/posix_memalign.c +++ b/test/integration/posix_memalign.c @@ -8,14 +8,12 @@ * potential OOM on e.g. 32-bit Windows. */ static void -purge(void) -{ +purge(void) { assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl error"); } -TEST_BEGIN(test_alignment_errors) -{ +TEST_BEGIN(test_alignment_errors) { size_t alignment; void *p; @@ -34,8 +32,7 @@ TEST_BEGIN(test_alignment_errors) } TEST_END -TEST_BEGIN(test_oom_errors) -{ +TEST_BEGIN(test_oom_errors) { size_t alignment, size; void *p; @@ -73,16 +70,16 @@ TEST_BEGIN(test_oom_errors) } TEST_END -TEST_BEGIN(test_alignment_and_size) -{ +TEST_BEGIN(test_alignment_and_size) { #define NITER 4 size_t alignment, size, total; unsigned i; int err; void *ps[NITER]; - for (i = 0; i < NITER; i++) + for (i = 0; i < NITER; i++) { ps[i] = NULL; + } for (alignment = 8; alignment <= MAXALIGN; @@ -104,8 +101,9 @@ TEST_BEGIN(test_alignment_and_size) alignment, size, size, buf); } total += malloc_usable_size(ps[i]); - if (total >= (MAXALIGN << 1)) + if (total >= (MAXALIGN << 1)) { break; + } } for (i = 0; i < NITER; i++) { if (ps[i] != NULL) { @@ -121,8 +119,7 @@ TEST_BEGIN(test_alignment_and_size) TEST_END int -main(void) -{ +main(void) { return (test( test_alignment_errors, test_oom_errors, diff --git a/test/integration/rallocx.c b/test/integration/rallocx.c index 0a8b50c7..176b9957 100644 --- a/test/integration/rallocx.c +++ b/test/integration/rallocx.c @@ -1,8 +1,7 @@ #include "test/jemalloc_test.h" static unsigned -get_nsizes_impl(const char *cmd) -{ +get_nsizes_impl(const char *cmd) { unsigned ret; size_t z; @@ -14,14 +13,12 @@ get_nsizes_impl(const char *cmd) } static unsigned -get_nlarge(void) -{ +get_nlarge(void) { return (get_nsizes_impl("arenas.nlextents")); } static size_t -get_size_impl(const char *cmd, size_t ind) -{ +get_size_impl(const char *cmd, size_t ind) { size_t ret; size_t z; size_t mib[4]; @@ -39,13 +36,11 @@ get_size_impl(const char *cmd, size_t ind) } static size_t -get_large_size(size_t ind) -{ +get_large_size(size_t ind) { return (get_size_impl("arenas.lextent.0.size", ind)); } -TEST_BEGIN(test_grow_and_shrink) -{ +TEST_BEGIN(test_grow_and_shrink) { void *p, *q; size_t tsz; #define NCYCLES 3 @@ -90,8 +85,7 @@ TEST_BEGIN(test_grow_and_shrink) TEST_END static bool -validate_fill(const void *p, uint8_t c, size_t offset, size_t len) -{ +validate_fill(const void *p, uint8_t c, size_t offset, size_t len) { bool ret = false; const uint8_t *buf = (const uint8_t *)p; size_t i; @@ -109,8 +103,7 @@ validate_fill(const void *p, uint8_t c, size_t offset, size_t len) return (ret); } -TEST_BEGIN(test_zero) -{ +TEST_BEGIN(test_zero) { void *p, *q; size_t psz, qsz, i, j; size_t start_sizes[] = {1, 3*1024, 63*1024, 4095*1024}; @@ -154,8 +147,7 @@ TEST_BEGIN(test_zero) } TEST_END -TEST_BEGIN(test_align) -{ +TEST_BEGIN(test_align) { void *p, *q; size_t align; #define MAX_ALIGN (ZU(1) << 25) @@ -179,8 +171,7 @@ TEST_BEGIN(test_align) } TEST_END -TEST_BEGIN(test_lg_align_and_zero) -{ +TEST_BEGIN(test_lg_align_and_zero) { void *p, *q; unsigned lg_align; size_t sz; @@ -217,8 +208,7 @@ TEST_BEGIN(test_lg_align_and_zero) } TEST_END -TEST_BEGIN(test_overflow) -{ +TEST_BEGIN(test_overflow) { size_t largemax; void *p; @@ -245,8 +235,7 @@ TEST_BEGIN(test_overflow) TEST_END int -main(void) -{ +main(void) { return (test( test_grow_and_shrink, test_zero, diff --git a/test/integration/sdallocx.c b/test/integration/sdallocx.c index 5d0a8f80..bf2fd2c0 100644 --- a/test/integration/sdallocx.c +++ b/test/integration/sdallocx.c @@ -3,21 +3,20 @@ #define MAXALIGN (((size_t)1) << 22) #define NITER 3 -TEST_BEGIN(test_basic) -{ +TEST_BEGIN(test_basic) { void *ptr = mallocx(64, 0); sdallocx(ptr, 64, 0); } TEST_END -TEST_BEGIN(test_alignment_and_size) -{ +TEST_BEGIN(test_alignment_and_size) { size_t nsz, sz, alignment, total; unsigned i; void *ps[NITER]; - for (i = 0; i < NITER; i++) + for (i = 0; i < NITER; i++) { ps[i] = NULL; + } for (alignment = 8; alignment <= MAXALIGN; @@ -32,8 +31,9 @@ TEST_BEGIN(test_alignment_and_size) ps[i] = mallocx(sz, MALLOCX_ALIGN(alignment) | MALLOCX_ZERO); total += nsz; - if (total >= (MAXALIGN << 1)) + if (total >= (MAXALIGN << 1)) { break; + } } for (i = 0; i < NITER; i++) { if (ps[i] != NULL) { @@ -48,8 +48,7 @@ TEST_BEGIN(test_alignment_and_size) TEST_END int -main(void) -{ +main(void) { return (test( test_basic, test_alignment_and_size)); diff --git a/test/integration/thread_arena.c b/test/integration/thread_arena.c index cf8240d1..5adb5ce0 100644 --- a/test/integration/thread_arena.c +++ b/test/integration/thread_arena.c @@ -3,8 +3,7 @@ #define NTHREADS 10 void * -thd_start(void *arg) -{ +thd_start(void *arg) { unsigned main_arena_ind = *(unsigned *)arg; void *p; unsigned arena_ind; @@ -38,8 +37,7 @@ thd_start(void *arg) return (NULL); } -TEST_BEGIN(test_thread_arena) -{ +TEST_BEGIN(test_thread_arena) { void *p; unsigned arena_ind; size_t size; @@ -73,8 +71,7 @@ TEST_BEGIN(test_thread_arena) TEST_END int -main(void) -{ +main(void) { return (test( test_thread_arena)); } diff --git a/test/integration/thread_tcache_enabled.c b/test/integration/thread_tcache_enabled.c index 1394371b..117d06bf 100644 --- a/test/integration/thread_tcache_enabled.c +++ b/test/integration/thread_tcache_enabled.c @@ -9,8 +9,7 @@ static const bool config_tcache = ; void * -thd_start(void *arg) -{ +thd_start(void *arg) { int err; size_t sz; bool e0, e1; @@ -84,14 +83,12 @@ label_ENOENT: return (NULL); } -TEST_BEGIN(test_main_thread) -{ +TEST_BEGIN(test_main_thread) { thd_start(NULL); } TEST_END -TEST_BEGIN(test_subthread) -{ +TEST_BEGIN(test_subthread) { thd_t thd; thd_create(&thd, thd_start, NULL); @@ -100,8 +97,7 @@ TEST_BEGIN(test_subthread) TEST_END int -main(void) -{ +main(void) { /* Run tests multiple times to check for bad interactions. */ return (test( test_main_thread, diff --git a/test/integration/xallocx.c b/test/integration/xallocx.c index 647404a7..9b4b68e0 100644 --- a/test/integration/xallocx.c +++ b/test/integration/xallocx.c @@ -10,8 +10,7 @@ const char *malloc_conf = "junk:false"; * xallocx() would ordinarily be able to extend. */ static unsigned -arena_ind(void) -{ +arena_ind(void) { static unsigned ind = 0; if (ind == 0) { @@ -23,8 +22,7 @@ arena_ind(void) return (ind); } -TEST_BEGIN(test_same_size) -{ +TEST_BEGIN(test_same_size) { void *p; size_t sz, tsz; @@ -39,8 +37,7 @@ TEST_BEGIN(test_same_size) } TEST_END -TEST_BEGIN(test_extra_no_move) -{ +TEST_BEGIN(test_extra_no_move) { void *p; size_t sz, tsz; @@ -55,8 +52,7 @@ TEST_BEGIN(test_extra_no_move) } TEST_END -TEST_BEGIN(test_no_move_fail) -{ +TEST_BEGIN(test_no_move_fail) { void *p; size_t sz, tsz; @@ -72,8 +68,7 @@ TEST_BEGIN(test_no_move_fail) TEST_END static unsigned -get_nsizes_impl(const char *cmd) -{ +get_nsizes_impl(const char *cmd) { unsigned ret; size_t z; @@ -85,20 +80,17 @@ get_nsizes_impl(const char *cmd) } static unsigned -get_nsmall(void) -{ +get_nsmall(void) { return (get_nsizes_impl("arenas.nbins")); } static unsigned -get_nlarge(void) -{ +get_nlarge(void) { return (get_nsizes_impl("arenas.nlextents")); } static size_t -get_size_impl(const char *cmd, size_t ind) -{ +get_size_impl(const char *cmd, size_t ind) { size_t ret; size_t z; size_t mib[4]; @@ -116,19 +108,16 @@ get_size_impl(const char *cmd, size_t ind) } static size_t -get_small_size(size_t ind) -{ +get_small_size(size_t ind) { return (get_size_impl("arenas.bin.0.size", ind)); } static size_t -get_large_size(size_t ind) -{ +get_large_size(size_t ind) { return (get_size_impl("arenas.lextent.0.size", ind)); } -TEST_BEGIN(test_size) -{ +TEST_BEGIN(test_size) { size_t small0, largemax; void *p; @@ -157,8 +146,7 @@ TEST_BEGIN(test_size) } TEST_END -TEST_BEGIN(test_size_extra_overflow) -{ +TEST_BEGIN(test_size_extra_overflow) { size_t small0, largemax; void *p; @@ -189,8 +177,7 @@ TEST_BEGIN(test_size_extra_overflow) } TEST_END -TEST_BEGIN(test_extra_small) -{ +TEST_BEGIN(test_extra_small) { size_t small0, small1, largemax; void *p; @@ -221,8 +208,7 @@ TEST_BEGIN(test_extra_small) } TEST_END -TEST_BEGIN(test_extra_large) -{ +TEST_BEGIN(test_extra_large) { int flags = MALLOCX_ARENA(arena_ind()); size_t smallmax, large1, large2, large3, largemax; void *p; @@ -292,8 +278,7 @@ TEST_BEGIN(test_extra_large) TEST_END static void -print_filled_extents(const void *p, uint8_t c, size_t len) -{ +print_filled_extents(const void *p, uint8_t c, size_t len) { const uint8_t *pc = (const uint8_t *)p; size_t i, range0; uint8_t c0; @@ -312,26 +297,26 @@ print_filled_extents(const void *p, uint8_t c, size_t len) } static bool -validate_fill(const void *p, uint8_t c, size_t offset, size_t len) -{ +validate_fill(const void *p, uint8_t c, size_t offset, size_t len) { const uint8_t *pc = (const uint8_t *)p; bool err; size_t i; for (i = offset, err = false; i < offset+len; i++) { - if (pc[i] != c) + if (pc[i] != c) { err = true; + } } - if (err) + if (err) { print_filled_extents(p, c, offset + len); + } return (err); } static void -test_zero(size_t szmin, size_t szmax) -{ +test_zero(size_t szmin, size_t szmax) { int flags = MALLOCX_ARENA(arena_ind()) | MALLOCX_ZERO; size_t sz, nsz; void *p; @@ -378,8 +363,7 @@ test_zero(size_t szmin, size_t szmax) dallocx(p, flags); } -TEST_BEGIN(test_zero_large) -{ +TEST_BEGIN(test_zero_large) { size_t large0, large1; /* Get size classes. */ @@ -391,8 +375,7 @@ TEST_BEGIN(test_zero_large) TEST_END int -main(void) -{ +main(void) { return (test( test_same_size, test_extra_no_move, diff --git a/test/src/btalloc.c b/test/src/btalloc.c index a78cb89b..bc31f9b8 100644 --- a/test/src/btalloc.c +++ b/test/src/btalloc.c @@ -1,7 +1,6 @@ #include "test/jemalloc_test.h" void * -btalloc(size_t size, unsigned bits) -{ +btalloc(size_t size, unsigned bits) { return (btalloc_0(size, bits)); } diff --git a/test/src/mq.c b/test/src/mq.c index 47f362c0..9b5f672d 100644 --- a/test/src/mq.c +++ b/test/src/mq.c @@ -5,8 +5,7 @@ * time is guaranteed. */ void -mq_nanosleep(unsigned ns) -{ +mq_nanosleep(unsigned ns) { assert(ns <= 1000*1000*1000); #ifdef _WIN32 diff --git a/test/src/mtx.c b/test/src/mtx.c index bbfec4ac..924ba287 100644 --- a/test/src/mtx.c +++ b/test/src/mtx.c @@ -5,11 +5,12 @@ #endif bool -mtx_init(mtx_t *mtx) -{ +mtx_init(mtx_t *mtx) { #ifdef _WIN32 - if (!InitializeCriticalSectionAndSpinCount(&mtx->lock, _CRT_SPINCOUNT)) + if (!InitializeCriticalSectionAndSpinCount(&mtx->lock, + _CRT_SPINCOUNT)) { return (true); + } #elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) mtx->lock = OS_UNFAIR_LOCK_INIT; #elif (defined(JEMALLOC_OSSPIN)) @@ -17,8 +18,9 @@ mtx_init(mtx_t *mtx) #else pthread_mutexattr_t attr; - if (pthread_mutexattr_init(&attr) != 0) + if (pthread_mutexattr_init(&attr) != 0) { return (true); + } pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT); if (pthread_mutex_init(&mtx->lock, &attr) != 0) { pthread_mutexattr_destroy(&attr); @@ -30,8 +32,7 @@ mtx_init(mtx_t *mtx) } void -mtx_fini(mtx_t *mtx) -{ +mtx_fini(mtx_t *mtx) { #ifdef _WIN32 #elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) #elif (defined(JEMALLOC_OSSPIN)) @@ -41,8 +42,7 @@ mtx_fini(mtx_t *mtx) } void -mtx_lock(mtx_t *mtx) -{ +mtx_lock(mtx_t *mtx) { #ifdef _WIN32 EnterCriticalSection(&mtx->lock); #elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) @@ -55,8 +55,7 @@ mtx_lock(mtx_t *mtx) } void -mtx_unlock(mtx_t *mtx) -{ +mtx_unlock(mtx_t *mtx) { #ifdef _WIN32 LeaveCriticalSection(&mtx->lock); #elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) diff --git a/test/src/test.c b/test/src/test.c index 345cc1c1..1155326b 100644 --- a/test/src/test.c +++ b/test/src/test.c @@ -7,8 +7,7 @@ static const char * test_name = ""; JEMALLOC_FORMAT_PRINTF(1, 2) void -test_skip(const char *format, ...) -{ +test_skip(const char *format, ...) { va_list ap; va_start(ap, format); @@ -20,8 +19,7 @@ test_skip(const char *format, ...) JEMALLOC_FORMAT_PRINTF(1, 2) void -test_fail(const char *format, ...) -{ +test_fail(const char *format, ...) { va_list ap; va_start(ap, format); @@ -32,8 +30,7 @@ test_fail(const char *format, ...) } static const char * -test_status_string(test_status_t test_status) -{ +test_status_string(test_status_t test_status) { switch (test_status) { case test_status_pass: return "pass"; case test_status_skip: return "skip"; @@ -43,23 +40,20 @@ test_status_string(test_status_t test_status) } void -p_test_init(const char *name) -{ +p_test_init(const char *name) { test_count++; test_status = test_status_pass; test_name = name; } void -p_test_fini(void) -{ +p_test_fini(void) { test_counts[test_status]++; malloc_printf("%s: %s\n", test_name, test_status_string(test_status)); } static test_status_t -p_test_impl(bool do_malloc_init, test_t *t, va_list ap) -{ +p_test_impl(bool do_malloc_init, test_t *t, va_list ap) { test_status_t ret; if (do_malloc_init) { @@ -78,8 +72,9 @@ p_test_impl(bool do_malloc_init, test_t *t, va_list ap) ret = test_status_pass; for (; t != NULL; t = va_arg(ap, test_t *)) { t(); - if (test_status > ret) + if (test_status > ret) { ret = test_status; + } } malloc_printf("--- %s: %u/%u, %s: %u/%u, %s: %u/%u ---\n", @@ -94,8 +89,7 @@ p_test_impl(bool do_malloc_init, test_t *t, va_list ap) } test_status_t -p_test(test_t *t, ...) -{ +p_test(test_t *t, ...) { test_status_t ret; va_list ap; @@ -108,8 +102,7 @@ p_test(test_t *t, ...) } test_status_t -p_test_no_malloc_init(test_t *t, ...) -{ +p_test_no_malloc_init(test_t *t, ...) { test_status_t ret; va_list ap; @@ -122,8 +115,7 @@ p_test_no_malloc_init(test_t *t, ...) } void -p_test_fail(const char *prefix, const char *message) -{ +p_test_fail(const char *prefix, const char *message) { malloc_cprintf(NULL, NULL, "%s%s\n", prefix, message); test_status = test_status_fail; } diff --git a/test/src/thd.c b/test/src/thd.c index e3167089..9a15eabb 100644 --- a/test/src/thd.c +++ b/test/src/thd.c @@ -2,17 +2,16 @@ #ifdef _WIN32 void -thd_create(thd_t *thd, void *(*proc)(void *), void *arg) -{ +thd_create(thd_t *thd, void *(*proc)(void *), void *arg) { LPTHREAD_START_ROUTINE routine = (LPTHREAD_START_ROUTINE)proc; *thd = CreateThread(NULL, 0, routine, arg, 0, NULL); - if (*thd == NULL) + if (*thd == NULL) { test_fail("Error in CreateThread()\n"); + } } void -thd_join(thd_t thd, void **ret) -{ +thd_join(thd_t thd, void **ret) { if (WaitForSingleObject(thd, INFINITE) == WAIT_OBJECT_0 && ret) { DWORD exit_code; GetExitCodeThread(thd, (LPDWORD) &exit_code); @@ -22,15 +21,14 @@ thd_join(thd_t thd, void **ret) #else void -thd_create(thd_t *thd, void *(*proc)(void *), void *arg) -{ - if (pthread_create(thd, NULL, proc, arg) != 0) +thd_create(thd_t *thd, void *(*proc)(void *), void *arg) { + if (pthread_create(thd, NULL, proc, arg) != 0) { test_fail("Error in pthread_create()\n"); + } } void -thd_join(thd_t thd, void **ret) -{ +thd_join(thd_t thd, void **ret) { pthread_join(thd, ret); } #endif diff --git a/test/src/timer.c b/test/src/timer.c index 82f69d0a..1b186332 100644 --- a/test/src/timer.c +++ b/test/src/timer.c @@ -1,22 +1,19 @@ #include "test/jemalloc_test.h" void -timer_start(timedelta_t *timer) -{ +timer_start(timedelta_t *timer) { nstime_init(&timer->t0, 0); nstime_update(&timer->t0); } void -timer_stop(timedelta_t *timer) -{ +timer_stop(timedelta_t *timer) { nstime_copy(&timer->t1, &timer->t0); nstime_update(&timer->t1); } uint64_t -timer_usec(const timedelta_t *timer) -{ +timer_usec(const timedelta_t *timer) { nstime_t delta; nstime_copy(&delta, &timer->t1); @@ -25,8 +22,7 @@ timer_usec(const timedelta_t *timer) } void -timer_ratio(timedelta_t *a, timedelta_t *b, char *buf, size_t buflen) -{ +timer_ratio(timedelta_t *a, timedelta_t *b, char *buf, size_t buflen) { uint64_t t0 = timer_usec(a); uint64_t t1 = timer_usec(b); uint64_t mult; @@ -36,11 +32,13 @@ timer_ratio(timedelta_t *a, timedelta_t *b, char *buf, size_t buflen) /* Whole. */ n = malloc_snprintf(&buf[i], buflen-i, "%"FMTu64, t0 / t1); i += n; - if (i >= buflen) + if (i >= buflen) { return; + } mult = 1; - for (j = 0; j < n; j++) + for (j = 0; j < n; j++) { mult *= 10; + } /* Decimal. */ n = malloc_snprintf(&buf[i], buflen-i, "."); diff --git a/test/stress/microbench.c b/test/stress/microbench.c index c599d9d3..3b7e9660 100644 --- a/test/stress/microbench.c +++ b/test/stress/microbench.c @@ -2,22 +2,22 @@ JEMALLOC_INLINE_C void time_func(timedelta_t *timer, uint64_t nwarmup, uint64_t niter, - void (*func)(void)) -{ + void (*func)(void)) { uint64_t i; - for (i = 0; i < nwarmup; i++) + for (i = 0; i < nwarmup; i++) { func(); + } timer_start(timer); - for (i = 0; i < niter; i++) + for (i = 0; i < niter; i++) { func(); + } timer_stop(timer); } void compare_funcs(uint64_t nwarmup, uint64_t niter, const char *name_a, - void (*func_a), const char *name_b, void (*func_b)) -{ + void (*func_a), const char *name_b, void (*func_b)) { timedelta_t timer_a, timer_b; char ratio_buf[6]; void *p; @@ -41,8 +41,7 @@ compare_funcs(uint64_t nwarmup, uint64_t niter, const char *name_a, } static void -malloc_free(void) -{ +malloc_free(void) { /* The compiler can optimize away free(malloc(1))! */ void *p = malloc(1); if (p == NULL) { @@ -53,8 +52,7 @@ malloc_free(void) } static void -mallocx_free(void) -{ +mallocx_free(void) { void *p = mallocx(1, 0); if (p == NULL) { test_fail("Unexpected mallocx() failure"); @@ -63,16 +61,14 @@ mallocx_free(void) free(p); } -TEST_BEGIN(test_malloc_vs_mallocx) -{ +TEST_BEGIN(test_malloc_vs_mallocx) { compare_funcs(10*1000*1000, 100*1000*1000, "malloc", malloc_free, "mallocx", mallocx_free); } TEST_END static void -malloc_dallocx(void) -{ +malloc_dallocx(void) { void *p = malloc(1); if (p == NULL) { test_fail("Unexpected malloc() failure"); @@ -82,8 +78,7 @@ malloc_dallocx(void) } static void -malloc_sdallocx(void) -{ +malloc_sdallocx(void) { void *p = malloc(1); if (p == NULL) { test_fail("Unexpected malloc() failure"); @@ -92,23 +87,20 @@ malloc_sdallocx(void) sdallocx(p, 1, 0); } -TEST_BEGIN(test_free_vs_dallocx) -{ +TEST_BEGIN(test_free_vs_dallocx) { compare_funcs(10*1000*1000, 100*1000*1000, "free", malloc_free, "dallocx", malloc_dallocx); } TEST_END -TEST_BEGIN(test_dallocx_vs_sdallocx) -{ +TEST_BEGIN(test_dallocx_vs_sdallocx) { compare_funcs(10*1000*1000, 100*1000*1000, "dallocx", malloc_dallocx, "sdallocx", malloc_sdallocx); } TEST_END static void -malloc_mus_free(void) -{ +malloc_mus_free(void) { void *p; p = malloc(1); @@ -121,8 +113,7 @@ malloc_mus_free(void) } static void -malloc_sallocx_free(void) -{ +malloc_sallocx_free(void) { void *p; p = malloc(1); @@ -130,21 +121,20 @@ malloc_sallocx_free(void) test_fail("Unexpected malloc() failure"); return; } - if (sallocx(p, 0) < 1) + if (sallocx(p, 0) < 1) { test_fail("Unexpected sallocx() failure"); + } free(p); } -TEST_BEGIN(test_mus_vs_sallocx) -{ +TEST_BEGIN(test_mus_vs_sallocx) { compare_funcs(10*1000*1000, 100*1000*1000, "malloc_usable_size", malloc_mus_free, "sallocx", malloc_sallocx_free); } TEST_END static void -malloc_nallocx_free(void) -{ +malloc_nallocx_free(void) { void *p; p = malloc(1); @@ -152,21 +142,20 @@ malloc_nallocx_free(void) test_fail("Unexpected malloc() failure"); return; } - if (nallocx(1, 0) < 1) + if (nallocx(1, 0) < 1) { test_fail("Unexpected nallocx() failure"); + } free(p); } -TEST_BEGIN(test_sallocx_vs_nallocx) -{ +TEST_BEGIN(test_sallocx_vs_nallocx) { compare_funcs(10*1000*1000, 100*1000*1000, "sallocx", malloc_sallocx_free, "nallocx", malloc_nallocx_free); } TEST_END int -main(void) -{ +main(void) { return (test( test_malloc_vs_mallocx, test_free_vs_dallocx, diff --git a/test/unit/SFMT.c b/test/unit/SFMT.c index cf52670b..b1bcf3d3 100644 --- a/test/unit/SFMT.c +++ b/test/unit/SFMT.c @@ -1449,8 +1449,7 @@ static const uint64_t init_by_array_64_expected[] = { KQU(15570163926716513029), KQU(13356980519185762498) }; -TEST_BEGIN(test_gen_rand_32) -{ +TEST_BEGIN(test_gen_rand_32) { uint32_t array32[BLOCK_SIZE] JEMALLOC_ATTR(aligned(16)); uint32_t array32_2[BLOCK_SIZE] JEMALLOC_ATTR(aligned(16)); int i; @@ -1484,8 +1483,7 @@ TEST_BEGIN(test_gen_rand_32) } TEST_END -TEST_BEGIN(test_by_array_32) -{ +TEST_BEGIN(test_by_array_32) { uint32_t array32[BLOCK_SIZE] JEMALLOC_ATTR(aligned(16)); uint32_t array32_2[BLOCK_SIZE] JEMALLOC_ATTR(aligned(16)); int i; @@ -1520,8 +1518,7 @@ TEST_BEGIN(test_by_array_32) } TEST_END -TEST_BEGIN(test_gen_rand_64) -{ +TEST_BEGIN(test_gen_rand_64) { uint64_t array64[BLOCK_SIZE64] JEMALLOC_ATTR(aligned(16)); uint64_t array64_2[BLOCK_SIZE64] JEMALLOC_ATTR(aligned(16)); int i; @@ -1556,8 +1553,7 @@ TEST_BEGIN(test_gen_rand_64) } TEST_END -TEST_BEGIN(test_by_array_64) -{ +TEST_BEGIN(test_by_array_64) { uint64_t array64[BLOCK_SIZE64] JEMALLOC_ATTR(aligned(16)); uint64_t array64_2[BLOCK_SIZE64] JEMALLOC_ATTR(aligned(16)); int i; @@ -1594,8 +1590,7 @@ TEST_BEGIN(test_by_array_64) TEST_END int -main(void) -{ +main(void) { return (test( test_gen_rand_32, test_by_array_32, diff --git a/test/unit/a0.c b/test/unit/a0.c index 87f7e527..c7ce8cfb 100644 --- a/test/unit/a0.c +++ b/test/unit/a0.c @@ -1,7 +1,6 @@ #include "test/jemalloc_test.h" -TEST_BEGIN(test_a0) -{ +TEST_BEGIN(test_a0) { void *p; p = a0malloc(1); @@ -11,8 +10,7 @@ TEST_BEGIN(test_a0) TEST_END int -main(void) -{ +main(void) { return (test_no_malloc_init( test_a0)); } diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 257f9729..710aaf53 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -5,8 +5,7 @@ #include "test/extent_hooks.h" static unsigned -get_nsizes_impl(const char *cmd) -{ +get_nsizes_impl(const char *cmd) { unsigned ret; size_t z; @@ -18,20 +17,17 @@ get_nsizes_impl(const char *cmd) } static unsigned -get_nsmall(void) -{ +get_nsmall(void) { return (get_nsizes_impl("arenas.nbins")); } static unsigned -get_nlarge(void) -{ +get_nlarge(void) { return (get_nsizes_impl("arenas.nlextents")); } static size_t -get_size_impl(const char *cmd, size_t ind) -{ +get_size_impl(const char *cmd, size_t ind) { size_t ret; size_t z; size_t mib[4]; @@ -49,35 +45,33 @@ get_size_impl(const char *cmd, size_t ind) } static size_t -get_small_size(size_t ind) -{ +get_small_size(size_t ind) { return (get_size_impl("arenas.bin.0.size", ind)); } static size_t -get_large_size(size_t ind) -{ +get_large_size(size_t ind) { return (get_size_impl("arenas.lextent.0.size", ind)); } /* Like ivsalloc(), but safe to call on discarded allocations. */ static size_t -vsalloc(tsdn_t *tsdn, const void *ptr) -{ +vsalloc(tsdn_t *tsdn, const void *ptr) { extent_t *extent; extent = extent_lookup(tsdn, ptr, false); - if (extent == NULL) + if (extent == NULL) { return (0); - if (!extent_active_get(extent)) + } + if (!extent_active_get(extent)) { return (0); + } return (isalloc(tsdn, extent, ptr)); } static unsigned -do_arena_create(extent_hooks_t *h) -{ +do_arena_create(extent_hooks_t *h) { unsigned arena_ind; size_t sz = sizeof(unsigned); assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, @@ -87,8 +81,7 @@ do_arena_create(extent_hooks_t *h) } static void -do_arena_reset_pre(unsigned arena_ind, void ***ptrs, unsigned *nptrs) -{ +do_arena_reset_pre(unsigned arena_ind, void ***ptrs, unsigned *nptrs) { #define NLARGE 32 unsigned nsmall, nlarge, i; size_t sz; @@ -127,8 +120,7 @@ do_arena_reset_pre(unsigned arena_ind, void ***ptrs, unsigned *nptrs) } static void -do_arena_reset_post(void **ptrs, unsigned nptrs) -{ +do_arena_reset_post(void **ptrs, unsigned nptrs) { tsdn_t *tsdn; unsigned i; @@ -144,8 +136,7 @@ do_arena_reset_post(void **ptrs, unsigned nptrs) } static void -do_arena_reset_destroy(const char *name, unsigned arena_ind) -{ +do_arena_reset_destroy(const char *name, unsigned arena_ind) { size_t mib[3]; size_t miblen; @@ -158,19 +149,16 @@ do_arena_reset_destroy(const char *name, unsigned arena_ind) } static void -do_arena_reset(unsigned arena_ind) -{ +do_arena_reset(unsigned arena_ind) { do_arena_reset_destroy("arena.0.reset", arena_ind); } static void -do_arena_destroy(unsigned arena_ind) -{ +do_arena_destroy(unsigned arena_ind) { do_arena_reset_destroy("arena.0.destroy", arena_ind); } -TEST_BEGIN(test_arena_reset) -{ +TEST_BEGIN(test_arena_reset) { unsigned arena_ind; void **ptrs; unsigned nptrs; @@ -183,8 +171,7 @@ TEST_BEGIN(test_arena_reset) TEST_END static bool -arena_i_initialized(unsigned arena_ind, bool refresh) -{ +arena_i_initialized(unsigned arena_ind, bool refresh) { bool initialized; size_t mib[3]; size_t miblen, sz; @@ -206,15 +193,13 @@ arena_i_initialized(unsigned arena_ind, bool refresh) return (initialized); } -TEST_BEGIN(test_arena_destroy_initial) -{ +TEST_BEGIN(test_arena_destroy_initial) { assert_false(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false), "Destroyed arena stats should not be initialized"); } TEST_END -TEST_BEGIN(test_arena_destroy_hooks_default) -{ +TEST_BEGIN(test_arena_destroy_hooks_default) { unsigned arena_ind, arena_ind_another, arena_ind_prev; void **ptrs; unsigned nptrs; @@ -260,8 +245,7 @@ TEST_END */ static bool extent_dalloc_unmap(extent_hooks_t *extent_hooks, void *addr, size_t size, - bool committed, unsigned arena_ind) -{ + bool committed, unsigned arena_ind) { TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, " "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ? "true" : "false", arena_ind); @@ -270,8 +254,9 @@ extent_dalloc_unmap(extent_hooks_t *extent_hooks, void *addr, size_t size, assert_ptr_eq(extent_hooks->dalloc, extent_dalloc_unmap, "Wrong hook function"); called_dalloc = true; - if (!try_dalloc) + if (!try_dalloc) { return (true); + } pages_unmap(addr, size); did_dalloc = true; return (false); @@ -290,8 +275,7 @@ static extent_hooks_t hooks_unmap = { extent_merge_hook }; -TEST_BEGIN(test_arena_destroy_hooks_unmap) -{ +TEST_BEGIN(test_arena_destroy_hooks_unmap) { unsigned arena_ind; void **ptrs; unsigned nptrs; @@ -328,8 +312,7 @@ TEST_BEGIN(test_arena_destroy_hooks_unmap) TEST_END int -main(void) -{ +main(void) { return (test( test_arena_reset, test_arena_destroy_initial, diff --git a/test/unit/atomic.c b/test/unit/atomic.c index 1d143689..3e36acd1 100644 --- a/test/unit/atomic.c +++ b/test/unit/atomic.c @@ -66,8 +66,7 @@ typedef struct p##_test_s p##_test_t; } while (0) TEST_STRUCT(u64, uint64_t) -TEST_BEGIN(test_atomic_u64) -{ +TEST_BEGIN(test_atomic_u64) { #if !(LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) test_skip("64-bit atomic operations not supported"); #else @@ -77,36 +76,31 @@ TEST_BEGIN(test_atomic_u64) TEST_END TEST_STRUCT(u32, uint32_t) -TEST_BEGIN(test_atomic_u32) -{ +TEST_BEGIN(test_atomic_u32) { TEST_BODY(u32, uint32_t, uint32_t, u32, "#"FMTx32); } TEST_END TEST_STRUCT(p, void *) -TEST_BEGIN(test_atomic_p) -{ +TEST_BEGIN(test_atomic_p) { TEST_BODY(p, void *, uintptr_t, ptr, "p"); } TEST_END TEST_STRUCT(zu, size_t) -TEST_BEGIN(test_atomic_zu) -{ +TEST_BEGIN(test_atomic_zu) { TEST_BODY(zu, size_t, size_t, zu, "#zx"); } TEST_END TEST_STRUCT(u, unsigned) -TEST_BEGIN(test_atomic_u) -{ +TEST_BEGIN(test_atomic_u) { TEST_BODY(u, unsigned, unsigned, u, "#x"); } TEST_END int -main(void) -{ +main(void) { return (test( test_atomic_u64, test_atomic_u32, diff --git a/test/unit/base.c b/test/unit/base.c index 76e96da8..65cf980b 100644 --- a/test/unit/base.c +++ b/test/unit/base.c @@ -24,8 +24,7 @@ static extent_hooks_t hooks_not_null = { NULL /* merge */ }; -TEST_BEGIN(test_base_hooks_default) -{ +TEST_BEGIN(test_base_hooks_default) { tsdn_t *tsdn; base_t *base; size_t allocated0, allocated1, resident, mapped; @@ -52,8 +51,7 @@ TEST_BEGIN(test_base_hooks_default) } TEST_END -TEST_BEGIN(test_base_hooks_null) -{ +TEST_BEGIN(test_base_hooks_null) { extent_hooks_t hooks_orig; tsdn_t *tsdn; base_t *base; @@ -92,8 +90,7 @@ TEST_BEGIN(test_base_hooks_null) } TEST_END -TEST_BEGIN(test_base_hooks_not_null) -{ +TEST_BEGIN(test_base_hooks_not_null) { extent_hooks_t hooks_orig; tsdn_t *tsdn; base_t *base; @@ -214,8 +211,7 @@ TEST_BEGIN(test_base_hooks_not_null) TEST_END int -main(void) -{ +main(void) { return (test( test_base_hooks_default, test_base_hooks_null, diff --git a/test/unit/bitmap.c b/test/unit/bitmap.c index b502bfea..6dfa72f2 100644 --- a/test/unit/bitmap.c +++ b/test/unit/bitmap.c @@ -93,8 +93,7 @@ NB(16384) \ static void -test_bitmap_initializer_body(const bitmap_info_t *binfo, size_t nbits) -{ +test_bitmap_initializer_body(const bitmap_info_t *binfo, size_t nbits) { bitmap_info_t binfo_dyn; bitmap_info_init(&binfo_dyn, nbits); @@ -124,8 +123,7 @@ test_bitmap_initializer_body(const bitmap_info_t *binfo, size_t nbits) #endif } -TEST_BEGIN(test_bitmap_initializer) -{ +TEST_BEGIN(test_bitmap_initializer) { #define NB(nbits) { \ if (nbits <= BITMAP_MAXBITS) { \ bitmap_info_t binfo = \ @@ -140,8 +138,7 @@ TEST_END static size_t test_bitmap_size_body(const bitmap_info_t *binfo, size_t nbits, - size_t prev_size) -{ + size_t prev_size) { size_t size = bitmap_size(binfo); assert_zu_ge(size, (nbits >> 3), "Bitmap size is smaller than expected"); @@ -149,8 +146,7 @@ test_bitmap_size_body(const bitmap_info_t *binfo, size_t nbits, return (size); } -TEST_BEGIN(test_bitmap_size) -{ +TEST_BEGIN(test_bitmap_size) { size_t nbits, prev_size; prev_size = 0; @@ -171,8 +167,7 @@ TEST_BEGIN(test_bitmap_size) TEST_END static void -test_bitmap_init_body(const bitmap_info_t *binfo, size_t nbits) -{ +test_bitmap_init_body(const bitmap_info_t *binfo, size_t nbits) { size_t i; bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo)); assert_ptr_not_null(bitmap, "Unexpected malloc() failure"); @@ -185,8 +180,7 @@ test_bitmap_init_body(const bitmap_info_t *binfo, size_t nbits) free(bitmap); } -TEST_BEGIN(test_bitmap_init) -{ +TEST_BEGIN(test_bitmap_init) { size_t nbits; for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) { @@ -204,21 +198,20 @@ TEST_BEGIN(test_bitmap_init) TEST_END static void -test_bitmap_set_body(const bitmap_info_t *binfo, size_t nbits) -{ +test_bitmap_set_body(const bitmap_info_t *binfo, size_t nbits) { size_t i; bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo)); assert_ptr_not_null(bitmap, "Unexpected malloc() failure"); bitmap_init(bitmap, binfo); - for (i = 0; i < nbits; i++) + for (i = 0; i < nbits; i++) { bitmap_set(bitmap, binfo, i); + } assert_true(bitmap_full(bitmap, binfo), "All bits should be set"); free(bitmap); } -TEST_BEGIN(test_bitmap_set) -{ +TEST_BEGIN(test_bitmap_set) { size_t nbits; for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) { @@ -236,26 +229,27 @@ TEST_BEGIN(test_bitmap_set) TEST_END static void -test_bitmap_unset_body(const bitmap_info_t *binfo, size_t nbits) -{ +test_bitmap_unset_body(const bitmap_info_t *binfo, size_t nbits) { size_t i; bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo)); assert_ptr_not_null(bitmap, "Unexpected malloc() failure"); bitmap_init(bitmap, binfo); - for (i = 0; i < nbits; i++) + for (i = 0; i < nbits; i++) { bitmap_set(bitmap, binfo, i); + } assert_true(bitmap_full(bitmap, binfo), "All bits should be set"); - for (i = 0; i < nbits; i++) + for (i = 0; i < nbits; i++) { bitmap_unset(bitmap, binfo, i); - for (i = 0; i < nbits; i++) + } + for (i = 0; i < nbits; i++) { bitmap_set(bitmap, binfo, i); + } assert_true(bitmap_full(bitmap, binfo), "All bits should be set"); free(bitmap); } -TEST_BEGIN(test_bitmap_unset) -{ +TEST_BEGIN(test_bitmap_unset) { size_t nbits; for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) { @@ -273,8 +267,7 @@ TEST_BEGIN(test_bitmap_unset) TEST_END static void -test_bitmap_sfu_body(const bitmap_info_t *binfo, size_t nbits) -{ +test_bitmap_sfu_body(const bitmap_info_t *binfo, size_t nbits) { size_t i; bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo)); assert_ptr_not_null(bitmap, "Unexpected malloc() failure"); @@ -317,8 +310,7 @@ test_bitmap_sfu_body(const bitmap_info_t *binfo, size_t nbits) free(bitmap); } -TEST_BEGIN(test_bitmap_sfu) -{ +TEST_BEGIN(test_bitmap_sfu) { size_t nbits; for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) { @@ -336,8 +328,7 @@ TEST_BEGIN(test_bitmap_sfu) TEST_END int -main(void) -{ +main(void) { return (test( test_bitmap_initializer, test_bitmap_size, diff --git a/test/unit/ckh.c b/test/unit/ckh.c index 1f576689..0638cb33 100644 --- a/test/unit/ckh.c +++ b/test/unit/ckh.c @@ -1,7 +1,6 @@ #include "test/jemalloc_test.h" -TEST_BEGIN(test_new_delete) -{ +TEST_BEGIN(test_new_delete) { tsd_t *tsd; ckh_t ckh; @@ -17,8 +16,7 @@ TEST_BEGIN(test_new_delete) } TEST_END -TEST_BEGIN(test_count_insert_search_remove) -{ +TEST_BEGIN(test_count_insert_search_remove) { tsd_t *tsd; ckh_t ckh; const char *strs[] = { @@ -105,8 +103,7 @@ TEST_BEGIN(test_count_insert_search_remove) } TEST_END -TEST_BEGIN(test_insert_iter_remove) -{ +TEST_BEGIN(test_insert_iter_remove) { #define NITEMS ZU(1000) tsd_t *tsd; ckh_t ckh; @@ -174,10 +171,12 @@ TEST_BEGIN(test_insert_iter_remove) } } - for (j = 0; j < i + 1; j++) + for (j = 0; j < i + 1; j++) { assert_true(seen[j], "Item %zu not seen", j); - for (; j < NITEMS; j++) + } + for (; j < NITEMS; j++) { assert_false(seen[j], "Item %zu seen", j); + } } } @@ -204,8 +203,7 @@ TEST_BEGIN(test_insert_iter_remove) TEST_END int -main(void) -{ +main(void) { return (test( test_new_delete, test_count_insert_search_remove, diff --git a/test/unit/decay.c b/test/unit/decay.c index b3b1dd9d..d6334cd2 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -10,22 +10,20 @@ static nstime_t time_mock; static bool monotonic_mock; static bool -nstime_monotonic_mock(void) -{ +nstime_monotonic_mock(void) { return (monotonic_mock); } static bool -nstime_update_mock(nstime_t *time) -{ +nstime_update_mock(nstime_t *time) { nupdates_mock++; - if (monotonic_mock) + if (monotonic_mock) { nstime_copy(time, &time_mock); + } return (!monotonic_mock); } -TEST_BEGIN(test_decay_ticks) -{ +TEST_BEGIN(test_decay_ticks) { ticker_t *decay_ticker; unsigned tick0, tick1; size_t sz, large0; @@ -197,8 +195,7 @@ TEST_BEGIN(test_decay_ticks) } TEST_END -TEST_BEGIN(test_decay_ticker) -{ +TEST_BEGIN(test_decay_ticker) { #define NPS 1024 int flags = (MALLOCX_ARENA(0) | MALLOCX_TCACHE_NONE); void *ps[NPS]; @@ -284,14 +281,14 @@ TEST_BEGIN(test_decay_ticker) nstime_update(&time); } while (nstime_compare(&time, &deadline) <= 0 && npurge1 == npurge0); - if (config_stats) + if (config_stats) { assert_u64_gt(npurge1, npurge0, "Expected purging to occur"); + } #undef NPS } TEST_END -TEST_BEGIN(test_decay_nonmonotonic) -{ +TEST_BEGIN(test_decay_nonmonotonic) { #define NPS (SMOOTHSTEP_NSTEPS + 1) int flags = (MALLOCX_ARENA(0) | MALLOCX_TCACHE_NONE); void *ps[NPS]; @@ -343,8 +340,9 @@ TEST_BEGIN(test_decay_nonmonotonic) assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge1, &sz, NULL, 0), config_stats ? 0 : ENOENT, "Unexpected mallctl result"); - if (config_stats) + if (config_stats) { assert_u64_eq(npurge0, npurge1, "Unexpected purging occurred"); + } nstime_monotonic = nstime_monotonic_orig; nstime_update = nstime_update_orig; @@ -353,8 +351,7 @@ TEST_BEGIN(test_decay_nonmonotonic) TEST_END int -main(void) -{ +main(void) { return (test( test_decay_ticks, test_decay_ticker, diff --git a/test/unit/extent_quantize.c b/test/unit/extent_quantize.c index a5c1b7a0..343d1d8f 100644 --- a/test/unit/extent_quantize.c +++ b/test/unit/extent_quantize.c @@ -1,7 +1,6 @@ #include "test/jemalloc_test.h" -TEST_BEGIN(test_small_extent_size) -{ +TEST_BEGIN(test_small_extent_size) { unsigned nbins, i; size_t sz, extent_size; size_t mib[4]; @@ -35,8 +34,7 @@ TEST_BEGIN(test_small_extent_size) } TEST_END -TEST_BEGIN(test_large_extent_size) -{ +TEST_BEGIN(test_large_extent_size) { bool cache_oblivious; unsigned nlextents, i; size_t sz, extent_size_prev, ceil_prev; @@ -100,8 +98,7 @@ TEST_BEGIN(test_large_extent_size) } TEST_END -TEST_BEGIN(test_monotonic) -{ +TEST_BEGIN(test_monotonic) { #define SZ_MAX ZU(4 * 1024 * 1024) unsigned i; size_t floor_prev, ceil_prev; @@ -136,8 +133,7 @@ TEST_BEGIN(test_monotonic) TEST_END int -main(void) -{ +main(void) { return (test( test_small_extent_size, test_large_extent_size, diff --git a/test/unit/fork.c b/test/unit/fork.c index 58091c66..4880328e 100644 --- a/test/unit/fork.c +++ b/test/unit/fork.c @@ -4,8 +4,7 @@ #include #endif -TEST_BEGIN(test_fork) -{ +TEST_BEGIN(test_fork) { #ifndef _WIN32 void *p; pid_t pid; @@ -32,8 +31,9 @@ TEST_BEGIN(test_fork) /* Parent. */ while (true) { - if (waitpid(pid, &status, 0) == -1) + if (waitpid(pid, &status, 0) == -1) { test_fail("Unexpected waitpid() failure"); + } if (WIFSIGNALED(status)) { test_fail("Unexpected child termination due to " "signal %d", WTERMSIG(status)); @@ -56,8 +56,7 @@ TEST_BEGIN(test_fork) TEST_END int -main(void) -{ +main(void) { return (test( test_fork)); } diff --git a/test/unit/hash.c b/test/unit/hash.c index ff237779..977d058f 100644 --- a/test/unit/hash.c +++ b/test/unit/hash.c @@ -36,8 +36,7 @@ typedef enum { } hash_variant_t; static int -hash_variant_bits(hash_variant_t variant) -{ +hash_variant_bits(hash_variant_t variant) { switch (variant) { case hash_variant_x86_32: return (32); case hash_variant_x86_128: return (128); @@ -47,8 +46,7 @@ hash_variant_bits(hash_variant_t variant) } static const char * -hash_variant_string(hash_variant_t variant) -{ +hash_variant_string(hash_variant_t variant) { switch (variant) { case hash_variant_x86_32: return ("hash_x86_32"); case hash_variant_x86_128: return ("hash_x86_128"); @@ -59,8 +57,7 @@ hash_variant_string(hash_variant_t variant) #define KEY_SIZE 256 static void -hash_variant_verify_key(hash_variant_t variant, uint8_t *key) -{ +hash_variant_verify_key(hash_variant_t variant, uint8_t *key) { const int hashbytes = hash_variant_bits(variant) / 8; const int hashes_size = hashbytes * 256; VARIABLE_ARRAY(uint8_t, hashes, hashes_size); @@ -139,39 +136,35 @@ hash_variant_verify_key(hash_variant_t variant, uint8_t *key) } static void -hash_variant_verify(hash_variant_t variant) -{ +hash_variant_verify(hash_variant_t variant) { #define MAX_ALIGN 16 uint8_t key[KEY_SIZE + (MAX_ALIGN - 1)]; unsigned i; - for (i = 0; i < MAX_ALIGN; i++) + for (i = 0; i < MAX_ALIGN; i++) { hash_variant_verify_key(variant, &key[i]); + } #undef MAX_ALIGN } #undef KEY_SIZE -TEST_BEGIN(test_hash_x86_32) -{ +TEST_BEGIN(test_hash_x86_32) { hash_variant_verify(hash_variant_x86_32); } TEST_END -TEST_BEGIN(test_hash_x86_128) -{ +TEST_BEGIN(test_hash_x86_128) { hash_variant_verify(hash_variant_x86_128); } TEST_END -TEST_BEGIN(test_hash_x64_128) -{ +TEST_BEGIN(test_hash_x64_128) { hash_variant_verify(hash_variant_x64_128); } TEST_END int -main(void) -{ +main(void) { return (test( test_hash_x86_32, test_hash_x86_128, diff --git a/test/unit/junk.c b/test/unit/junk.c index 5f34d051..02f0726d 100644 --- a/test/unit/junk.c +++ b/test/unit/junk.c @@ -15,15 +15,13 @@ static void *watch_for_junking; static bool saw_junking; static void -watch_junking(void *p) -{ +watch_junking(void *p) { watch_for_junking = p; saw_junking = false; } static void -arena_dalloc_junk_small_intercept(void *ptr, const arena_bin_info_t *bin_info) -{ +arena_dalloc_junk_small_intercept(void *ptr, const arena_bin_info_t *bin_info) { size_t i; arena_dalloc_junk_small_orig(ptr, bin_info); @@ -32,13 +30,13 @@ arena_dalloc_junk_small_intercept(void *ptr, const arena_bin_info_t *bin_info) "Missing junk fill for byte %zu/%zu of deallocated region", i, bin_info->reg_size); } - if (ptr == watch_for_junking) + if (ptr == watch_for_junking) { saw_junking = true; + } } static void -large_dalloc_junk_intercept(void *ptr, size_t usize) -{ +large_dalloc_junk_intercept(void *ptr, size_t usize) { size_t i; large_dalloc_junk_orig(ptr, usize); @@ -47,21 +45,21 @@ large_dalloc_junk_intercept(void *ptr, size_t usize) "Missing junk fill for byte %zu/%zu of deallocated region", i, usize); } - if (ptr == watch_for_junking) + if (ptr == watch_for_junking) { saw_junking = true; + } } static void -large_dalloc_maybe_junk_intercept(void *ptr, size_t usize) -{ +large_dalloc_maybe_junk_intercept(void *ptr, size_t usize) { large_dalloc_maybe_junk_orig(ptr, usize); - if (ptr == watch_for_junking) + if (ptr == watch_for_junking) { saw_junking = true; + } } static void -test_junk(size_t sz_min, size_t sz_max) -{ +test_junk(size_t sz_min, size_t sz_max) { uint8_t *s; size_t sz_prev, sz, i; @@ -126,23 +124,20 @@ test_junk(size_t sz_min, size_t sz_max) } } -TEST_BEGIN(test_junk_small) -{ +TEST_BEGIN(test_junk_small) { test_skip_if(!config_fill); test_junk(1, SMALL_MAXCLASS-1); } TEST_END -TEST_BEGIN(test_junk_large) -{ +TEST_BEGIN(test_junk_large) { test_skip_if(!config_fill); test_junk(SMALL_MAXCLASS+1, (1U << (LG_LARGE_MINCLASS+1))); } TEST_END int -main(void) -{ +main(void) { return (test( test_junk_small, test_junk_large)); diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 5b734e1d..a116894b 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -1,7 +1,6 @@ #include "test/jemalloc_test.h" -TEST_BEGIN(test_mallctl_errors) -{ +TEST_BEGIN(test_mallctl_errors) { uint64_t epoch; size_t sz; @@ -28,8 +27,7 @@ TEST_BEGIN(test_mallctl_errors) } TEST_END -TEST_BEGIN(test_mallctlnametomib_errors) -{ +TEST_BEGIN(test_mallctlnametomib_errors) { size_t mib[1]; size_t miblen; @@ -39,8 +37,7 @@ TEST_BEGIN(test_mallctlnametomib_errors) } TEST_END -TEST_BEGIN(test_mallctlbymib_errors) -{ +TEST_BEGIN(test_mallctlbymib_errors) { uint64_t epoch; size_t sz; size_t mib[1]; @@ -76,8 +73,7 @@ TEST_BEGIN(test_mallctlbymib_errors) } TEST_END -TEST_BEGIN(test_mallctl_read_write) -{ +TEST_BEGIN(test_mallctl_read_write) { uint64_t old_epoch, new_epoch; size_t sz = sizeof(old_epoch); @@ -104,8 +100,7 @@ TEST_BEGIN(test_mallctl_read_write) } TEST_END -TEST_BEGIN(test_mallctlnametomib_short_mib) -{ +TEST_BEGIN(test_mallctlnametomib_short_mib) { size_t mib[4]; size_t miblen; @@ -119,8 +114,7 @@ TEST_BEGIN(test_mallctlnametomib_short_mib) } TEST_END -TEST_BEGIN(test_mallctl_config) -{ +TEST_BEGIN(test_mallctl_config) { #define TEST_MALLCTL_CONFIG(config, t) do { \ t oldval; \ size_t sz = sizeof(oldval); \ @@ -149,8 +143,7 @@ TEST_BEGIN(test_mallctl_config) } TEST_END -TEST_BEGIN(test_mallctl_opt) -{ +TEST_BEGIN(test_mallctl_opt) { bool config_always = true; #define TEST_MALLCTL_OPT(t, opt, config) do { \ @@ -189,8 +182,7 @@ TEST_BEGIN(test_mallctl_opt) } TEST_END -TEST_BEGIN(test_manpage_example) -{ +TEST_BEGIN(test_manpage_example) { unsigned nbins, i; size_t mib[4]; size_t len, miblen; @@ -214,8 +206,7 @@ TEST_BEGIN(test_manpage_example) } TEST_END -TEST_BEGIN(test_tcache_none) -{ +TEST_BEGIN(test_tcache_none) { void *p0, *q, *p1; test_skip_if(!config_tcache); @@ -240,8 +231,7 @@ TEST_BEGIN(test_tcache_none) } TEST_END -TEST_BEGIN(test_tcache) -{ +TEST_BEGIN(test_tcache) { #define NTCACHES 10 unsigned tis[NTCACHES]; void *ps[NTCACHES]; @@ -312,11 +302,13 @@ TEST_BEGIN(test_tcache) assert_ptr_eq(qs[i], q0, "Expected rallocx() to allocate cached region, i=%u", i); /* Avoid undefined behavior in case of test failure. */ - if (qs[i] == NULL) + if (qs[i] == NULL) { qs[i] = ps[i]; + } } - for (i = 0; i < NTCACHES; i++) + for (i = 0; i < NTCACHES; i++) { dallocx(qs[i], MALLOCX_TCACHE(tis[i])); + } /* Flush some non-empty tcaches. */ for (i = 0; i < NTCACHES/2; i++) { @@ -334,8 +326,7 @@ TEST_BEGIN(test_tcache) } TEST_END -TEST_BEGIN(test_thread_arena) -{ +TEST_BEGIN(test_thread_arena) { unsigned arena_old, arena_new, narenas; size_t sz = sizeof(unsigned); @@ -353,8 +344,7 @@ TEST_BEGIN(test_thread_arena) } TEST_END -TEST_BEGIN(test_arena_i_initialized) -{ +TEST_BEGIN(test_arena_i_initialized) { unsigned narenas, i; size_t sz; size_t mib[3]; @@ -392,8 +382,7 @@ TEST_BEGIN(test_arena_i_initialized) } TEST_END -TEST_BEGIN(test_arena_i_decay_time) -{ +TEST_BEGIN(test_arena_i_decay_time) { ssize_t decay_time, orig_decay_time, prev_decay_time; size_t sz = sizeof(ssize_t); @@ -423,8 +412,7 @@ TEST_BEGIN(test_arena_i_decay_time) } TEST_END -TEST_BEGIN(test_arena_i_purge) -{ +TEST_BEGIN(test_arena_i_purge) { unsigned narenas; size_t sz = sizeof(unsigned); size_t mib[3]; @@ -447,8 +435,7 @@ TEST_BEGIN(test_arena_i_purge) } TEST_END -TEST_BEGIN(test_arena_i_decay) -{ +TEST_BEGIN(test_arena_i_decay) { unsigned narenas; size_t sz = sizeof(unsigned); size_t mib[3]; @@ -471,8 +458,7 @@ TEST_BEGIN(test_arena_i_decay) } TEST_END -TEST_BEGIN(test_arena_i_dss) -{ +TEST_BEGIN(test_arena_i_dss) { const char *dss_prec_old, *dss_prec_new; size_t sz = sizeof(dss_prec_old); size_t mib[3]; @@ -517,8 +503,7 @@ TEST_BEGIN(test_arena_i_dss) } TEST_END -TEST_BEGIN(test_arenas_decay_time) -{ +TEST_BEGIN(test_arenas_decay_time) { ssize_t decay_time, orig_decay_time, prev_decay_time; size_t sz = sizeof(ssize_t); @@ -548,8 +533,7 @@ TEST_BEGIN(test_arenas_decay_time) } TEST_END -TEST_BEGIN(test_arenas_constants) -{ +TEST_BEGIN(test_arenas_constants) { #define TEST_ARENAS_CONSTANT(t, name, expected) do { \ t name; \ size_t sz = sizeof(t); \ @@ -567,8 +551,7 @@ TEST_BEGIN(test_arenas_constants) } TEST_END -TEST_BEGIN(test_arenas_bin_constants) -{ +TEST_BEGIN(test_arenas_bin_constants) { #define TEST_ARENAS_BIN_CONSTANT(t, name, expected) do { \ t name; \ size_t sz = sizeof(t); \ @@ -586,8 +569,7 @@ TEST_BEGIN(test_arenas_bin_constants) } TEST_END -TEST_BEGIN(test_arenas_lextent_constants) -{ +TEST_BEGIN(test_arenas_lextent_constants) { #define TEST_ARENAS_LEXTENT_CONSTANT(t, name, expected) do { \ t name; \ size_t sz = sizeof(t); \ @@ -602,8 +584,7 @@ TEST_BEGIN(test_arenas_lextent_constants) } TEST_END -TEST_BEGIN(test_arenas_create) -{ +TEST_BEGIN(test_arenas_create) { unsigned narenas_before, arena, narenas_after; size_t sz = sizeof(unsigned); @@ -620,8 +601,7 @@ TEST_BEGIN(test_arenas_create) } TEST_END -TEST_BEGIN(test_stats_arenas) -{ +TEST_BEGIN(test_stats_arenas) { #define TEST_STATS_ARENAS(t, name) do { \ t name; \ size_t sz = sizeof(t); \ @@ -640,8 +620,7 @@ TEST_BEGIN(test_stats_arenas) TEST_END int -main(void) -{ +main(void) { return (test( test_mallctl_errors, test_mallctlnametomib_errors, diff --git a/test/unit/math.c b/test/unit/math.c index 8e5ec61b..15fc7d54 100644 --- a/test/unit/math.c +++ b/test/unit/math.c @@ -14,30 +14,29 @@ #endif static bool -double_eq_rel(double a, double b, double max_rel_err, double max_abs_err) -{ +double_eq_rel(double a, double b, double max_rel_err, double max_abs_err) { double rel_err; - if (fabs(a - b) < max_abs_err) + if (fabs(a - b) < max_abs_err) { return (true); + } rel_err = (fabs(b) > fabs(a)) ? fabs((a-b)/b) : fabs((a-b)/a); return (rel_err < max_rel_err); } static uint64_t -factorial(unsigned x) -{ +factorial(unsigned x) { uint64_t ret = 1; unsigned i; - for (i = 2; i <= x; i++) + for (i = 2; i <= x; i++) { ret *= (uint64_t)i; + } return (ret); } -TEST_BEGIN(test_ln_gamma_factorial) -{ +TEST_BEGIN(test_ln_gamma_factorial) { unsigned x; /* exp(ln_gamma(x)) == (x-1)! for integer x. */ @@ -188,8 +187,7 @@ static const double ln_gamma_misc_expected[] = { 359.13420536957539753 }; -TEST_BEGIN(test_ln_gamma_misc) -{ +TEST_BEGIN(test_ln_gamma_misc) { unsigned i; for (i = 1; i < sizeof(ln_gamma_misc_expected)/sizeof(double); i++) { @@ -239,8 +237,7 @@ static const double pt_norm_expected[] = { 1.88079360815125041, 2.05374891063182208, 2.32634787404084076 }; -TEST_BEGIN(test_pt_norm) -{ +TEST_BEGIN(test_pt_norm) { unsigned i; for (i = 1; i < sizeof(pt_norm_expected)/sizeof(double); i++) { @@ -289,8 +286,7 @@ static const double pt_chi2_expected[] = { 1046.4872561869577, 1063.5717461999654, 1107.0741966053859 }; -TEST_BEGIN(test_pt_chi2) -{ +TEST_BEGIN(test_pt_chi2) { unsigned i, j; unsigned e = 0; @@ -351,8 +347,7 @@ static const double pt_gamma_expected[] = { 4.7230515633946677, 5.6417477865306020, 8.4059469148854635 }; -TEST_BEGIN(test_pt_gamma_shape) -{ +TEST_BEGIN(test_pt_gamma_shape) { unsigned i, j; unsigned e = 0; @@ -371,8 +366,7 @@ TEST_BEGIN(test_pt_gamma_shape) } TEST_END -TEST_BEGIN(test_pt_gamma_scale) -{ +TEST_BEGIN(test_pt_gamma_scale) { double shape = 1.0; double ln_gamma_shape = ln_gamma(shape); @@ -385,8 +379,7 @@ TEST_BEGIN(test_pt_gamma_scale) TEST_END int -main(void) -{ +main(void) { return (test( test_ln_gamma_factorial, test_ln_gamma_misc, diff --git a/test/unit/mq.c b/test/unit/mq.c index bd289c54..95c9c500 100644 --- a/test/unit/mq.c +++ b/test/unit/mq.c @@ -9,8 +9,7 @@ struct mq_msg_s { }; mq_gen(static, mq_, mq_t, mq_msg_t, link) -TEST_BEGIN(test_mq_basic) -{ +TEST_BEGIN(test_mq_basic) { mq_t mq; mq_msg_t msg; @@ -31,8 +30,7 @@ TEST_BEGIN(test_mq_basic) TEST_END static void * -thd_receiver_start(void *arg) -{ +thd_receiver_start(void *arg) { mq_t *mq = (mq_t *)arg; unsigned i; @@ -45,8 +43,7 @@ thd_receiver_start(void *arg) } static void * -thd_sender_start(void *arg) -{ +thd_sender_start(void *arg) { mq_t *mq = (mq_t *)arg; unsigned i; @@ -61,8 +58,7 @@ thd_sender_start(void *arg) return (NULL); } -TEST_BEGIN(test_mq_threaded) -{ +TEST_BEGIN(test_mq_threaded) { mq_t mq; thd_t receiver; thd_t senders[NSENDERS]; @@ -71,20 +67,21 @@ TEST_BEGIN(test_mq_threaded) assert_false(mq_init(&mq), "Unexpected mq_init() failure"); thd_create(&receiver, thd_receiver_start, (void *)&mq); - for (i = 0; i < NSENDERS; i++) + for (i = 0; i < NSENDERS; i++) { thd_create(&senders[i], thd_sender_start, (void *)&mq); + } thd_join(receiver, NULL); - for (i = 0; i < NSENDERS; i++) + for (i = 0; i < NSENDERS; i++) { thd_join(senders[i], NULL); + } mq_fini(&mq); } TEST_END int -main(void) -{ +main(void) { return (test( test_mq_basic, test_mq_threaded)); diff --git a/test/unit/mtx.c b/test/unit/mtx.c index 2eccc98f..0813a699 100644 --- a/test/unit/mtx.c +++ b/test/unit/mtx.c @@ -3,8 +3,7 @@ #define NTHREADS 2 #define NINCRS 2000000 -TEST_BEGIN(test_mtx_basic) -{ +TEST_BEGIN(test_mtx_basic) { mtx_t mtx; assert_false(mtx_init(&mtx), "Unexpected mtx_init() failure"); @@ -20,8 +19,7 @@ typedef struct { } thd_start_arg_t; static void * -thd_start(void *varg) -{ +thd_start(void *varg) { thd_start_arg_t *arg = (thd_start_arg_t *)varg; unsigned i; @@ -33,26 +31,26 @@ thd_start(void *varg) return (NULL); } -TEST_BEGIN(test_mtx_race) -{ +TEST_BEGIN(test_mtx_race) { thd_start_arg_t arg; thd_t thds[NTHREADS]; unsigned i; assert_false(mtx_init(&arg.mtx), "Unexpected mtx_init() failure"); arg.x = 0; - for (i = 0; i < NTHREADS; i++) + for (i = 0; i < NTHREADS; i++) { thd_create(&thds[i], thd_start, (void *)&arg); - for (i = 0; i < NTHREADS; i++) + } + for (i = 0; i < NTHREADS; i++) { thd_join(thds[i], NULL); + } assert_u_eq(arg.x, NTHREADS * NINCRS, "Race-related counter corruption"); } TEST_END int -main(void) -{ +main(void) { return (test( test_mtx_basic, test_mtx_race)); diff --git a/test/unit/nstime.c b/test/unit/nstime.c index 6548ba23..f628a8f3 100644 --- a/test/unit/nstime.c +++ b/test/unit/nstime.c @@ -2,8 +2,7 @@ #define BILLION UINT64_C(1000000000) -TEST_BEGIN(test_nstime_init) -{ +TEST_BEGIN(test_nstime_init) { nstime_t nst; nstime_init(&nst, 42000000043); @@ -13,8 +12,7 @@ TEST_BEGIN(test_nstime_init) } TEST_END -TEST_BEGIN(test_nstime_init2) -{ +TEST_BEGIN(test_nstime_init2) { nstime_t nst; nstime_init2(&nst, 42, 43); @@ -23,8 +21,7 @@ TEST_BEGIN(test_nstime_init2) } TEST_END -TEST_BEGIN(test_nstime_copy) -{ +TEST_BEGIN(test_nstime_copy) { nstime_t nsta, nstb; nstime_init2(&nsta, 42, 43); @@ -35,8 +32,7 @@ TEST_BEGIN(test_nstime_copy) } TEST_END -TEST_BEGIN(test_nstime_compare) -{ +TEST_BEGIN(test_nstime_compare) { nstime_t nsta, nstb; nstime_init2(&nsta, 42, 43); @@ -70,8 +66,7 @@ TEST_BEGIN(test_nstime_compare) } TEST_END -TEST_BEGIN(test_nstime_add) -{ +TEST_BEGIN(test_nstime_add) { nstime_t nsta, nstb; nstime_init2(&nsta, 42, 43); @@ -90,8 +85,7 @@ TEST_BEGIN(test_nstime_add) } TEST_END -TEST_BEGIN(test_nstime_subtract) -{ +TEST_BEGIN(test_nstime_subtract) { nstime_t nsta, nstb; nstime_init2(&nsta, 42, 43); @@ -110,8 +104,7 @@ TEST_BEGIN(test_nstime_subtract) } TEST_END -TEST_BEGIN(test_nstime_imultiply) -{ +TEST_BEGIN(test_nstime_imultiply) { nstime_t nsta, nstb; nstime_init2(&nsta, 42, 43); @@ -128,8 +121,7 @@ TEST_BEGIN(test_nstime_imultiply) } TEST_END -TEST_BEGIN(test_nstime_idivide) -{ +TEST_BEGIN(test_nstime_idivide) { nstime_t nsta, nstb; nstime_init2(&nsta, 42, 43); @@ -148,8 +140,7 @@ TEST_BEGIN(test_nstime_idivide) } TEST_END -TEST_BEGIN(test_nstime_divide) -{ +TEST_BEGIN(test_nstime_divide) { nstime_t nsta, nstb, nstc; nstime_init2(&nsta, 42, 43); @@ -176,14 +167,12 @@ TEST_BEGIN(test_nstime_divide) } TEST_END -TEST_BEGIN(test_nstime_monotonic) -{ +TEST_BEGIN(test_nstime_monotonic) { nstime_monotonic(); } TEST_END -TEST_BEGIN(test_nstime_update) -{ +TEST_BEGIN(test_nstime_update) { nstime_t nst; nstime_init(&nst, 0); @@ -208,8 +197,7 @@ TEST_BEGIN(test_nstime_update) TEST_END int -main(void) -{ +main(void) { return (test( test_nstime_init, test_nstime_init2, diff --git a/test/unit/pack.c b/test/unit/pack.c index 316b6df5..9237ba2e 100644 --- a/test/unit/pack.c +++ b/test/unit/pack.c @@ -20,8 +20,7 @@ const char *malloc_conf = "decay_time:-1"; #define NSLABS 8 static unsigned -binind_compute(void) -{ +binind_compute(void) { size_t sz; unsigned nbins, i; @@ -41,8 +40,9 @@ binind_compute(void) sz = sizeof(size); assert_d_eq(mallctlbymib(mib, miblen, (void *)&size, &sz, NULL, 0), 0, "Unexpected mallctlbymib failure"); - if (size == SZ) + if (size == SZ) { return (i); + } } test_fail("Unable to compute nregs_per_run"); @@ -50,8 +50,7 @@ binind_compute(void) } static size_t -nregs_per_run_compute(void) -{ +nregs_per_run_compute(void) { uint32_t nregs; size_t sz; unsigned binind = binind_compute(); @@ -68,8 +67,7 @@ nregs_per_run_compute(void) } static unsigned -arenas_create_mallctl(void) -{ +arenas_create_mallctl(void) { unsigned arena_ind; size_t sz; @@ -81,8 +79,7 @@ arenas_create_mallctl(void) } static void -arena_reset_mallctl(unsigned arena_ind) -{ +arena_reset_mallctl(unsigned arena_ind) { size_t mib[3]; size_t miblen = sizeof(mib)/sizeof(size_t); @@ -93,8 +90,7 @@ arena_reset_mallctl(unsigned arena_ind) "Unexpected mallctlbymib() failure"); } -TEST_BEGIN(test_pack) -{ +TEST_BEGIN(test_pack) { unsigned arena_ind = arenas_create_mallctl(); size_t nregs_per_run = nregs_per_run_compute(); size_t nregs = nregs_per_run * NSLABS; @@ -125,8 +121,9 @@ TEST_BEGIN(test_pack) i++, offset = (offset + 1) % nregs_per_run) { for (j = 0; j < nregs_per_run; j++) { void *p = ptrs[(i * nregs_per_run) + j]; - if (offset == j) + if (offset == j) { continue; + } dallocx(p, MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE); } @@ -143,8 +140,9 @@ TEST_BEGIN(test_pack) for (j = 0; j < nregs_per_run; j++) { void *p; - if (offset == j) + if (offset == j) { continue; + } p = mallocx(SZ, MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE); assert_ptr_eq(p, ptrs[(i * nregs_per_run) + j], @@ -159,8 +157,7 @@ TEST_BEGIN(test_pack) TEST_END int -main(void) -{ +main(void) { return (test( test_pack)); } diff --git a/test/unit/pages.c b/test/unit/pages.c index 1e6add95..b6092de0 100644 --- a/test/unit/pages.c +++ b/test/unit/pages.c @@ -1,7 +1,6 @@ #include "test/jemalloc_test.h" -TEST_BEGIN(test_pages_huge) -{ +TEST_BEGIN(test_pages_huge) { size_t alloc_size; bool commit; void *pages, *hugepage; @@ -22,8 +21,7 @@ TEST_BEGIN(test_pages_huge) TEST_END int -main(void) -{ +main(void) { return (test( test_pages_huge)); } diff --git a/test/unit/ph.c b/test/unit/ph.c index 10bf99e4..e49a0e78 100644 --- a/test/unit/ph.c +++ b/test/unit/ph.c @@ -10,8 +10,7 @@ struct node_s { }; static int -node_cmp(const node_t *a, const node_t *b) -{ +node_cmp(const node_t *a, const node_t *b) { int ret; ret = (a->key > b->key) - (a->key < b->key); @@ -39,18 +38,19 @@ typedef ph(node_t) heap_t; ph_gen(static, heap_, heap_t, node_t, link, node_cmp_magic); static void -node_print(const node_t *node, unsigned depth) -{ +node_print(const node_t *node, unsigned depth) { unsigned i; node_t *leftmost_child, *sibling; - for (i = 0; i < depth; i++) + for (i = 0; i < depth; i++) { malloc_printf("\t"); + } malloc_printf("%2"FMTu64"\n", node->key); leftmost_child = phn_lchild_get(node_t, link, node); - if (leftmost_child == NULL) + if (leftmost_child == NULL) { return; + } node_print(leftmost_child, depth + 1); for (sibling = phn_next_get(node_t, link, leftmost_child); sibling != @@ -60,13 +60,13 @@ node_print(const node_t *node, unsigned depth) } static void -heap_print(const heap_t *heap) -{ +heap_print(const heap_t *heap) { node_t *auxelm; malloc_printf("vvv heap %p vvv\n", heap); - if (heap->ph_root == NULL) + if (heap->ph_root == NULL) { goto label_return; + } node_print(heap->ph_root, 0); @@ -83,8 +83,7 @@ label_return: } static unsigned -node_validate(const node_t *node, const node_t *parent) -{ +node_validate(const node_t *node, const node_t *parent) { unsigned nnodes = 1; node_t *leftmost_child, *sibling; @@ -94,8 +93,9 @@ node_validate(const node_t *node, const node_t *parent) } leftmost_child = phn_lchild_get(node_t, link, node); - if (leftmost_child == NULL) + if (leftmost_child == NULL) { return (nnodes); + } assert_ptr_eq((void *)phn_prev_get(node_t, link, leftmost_child), (void *)node, "Leftmost child does not link to node"); nnodes += node_validate(leftmost_child, node); @@ -111,13 +111,13 @@ node_validate(const node_t *node, const node_t *parent) } static unsigned -heap_validate(const heap_t *heap) -{ +heap_validate(const heap_t *heap) { unsigned nnodes = 0; node_t *auxelm; - if (heap->ph_root == NULL) + if (heap->ph_root == NULL) { goto label_return; + } nnodes += node_validate(heap->ph_root, NULL); @@ -130,13 +130,13 @@ heap_validate(const heap_t *heap) } label_return: - if (false) + if (false) { heap_print(heap); + } return (nnodes); } -TEST_BEGIN(test_ph_empty) -{ +TEST_BEGIN(test_ph_empty) { heap_t heap; heap_new(&heap); @@ -146,23 +146,20 @@ TEST_BEGIN(test_ph_empty) TEST_END static void -node_remove(heap_t *heap, node_t *node) -{ +node_remove(heap_t *heap, node_t *node) { heap_remove(heap, node); node->magic = 0; } static node_t * -node_remove_first(heap_t *heap) -{ +node_remove_first(heap_t *heap) { node_t *node = heap_remove_first(heap); node->magic = 0; return (node); } -TEST_BEGIN(test_ph_random) -{ +TEST_BEGIN(test_ph_random) { #define NNODES 25 #define NBAGS 250 #define SEED 42 @@ -177,17 +174,20 @@ TEST_BEGIN(test_ph_random) switch (i) { case 0: /* Insert in order. */ - for (j = 0; j < NNODES; j++) + for (j = 0; j < NNODES; j++) { bag[j] = j; + } break; case 1: /* Insert in reverse order. */ - for (j = 0; j < NNODES; j++) + for (j = 0; j < NNODES; j++) { bag[j] = NNODES - j - 1; + } break; default: - for (j = 0; j < NNODES; j++) + for (j = 0; j < NNODES; j++) { bag[j] = gen_rand64_range(sfmt, NNODES); + } } for (j = 1; j <= NNODES; j++) { @@ -280,8 +280,7 @@ TEST_BEGIN(test_ph_random) TEST_END int -main(void) -{ +main(void) { return (test( test_ph_empty, test_ph_random)); diff --git a/test/unit/prng.c b/test/unit/prng.c index f32d82a6..b26da36e 100644 --- a/test/unit/prng.c +++ b/test/unit/prng.c @@ -1,8 +1,7 @@ #include "test/jemalloc_test.h" static void -test_prng_lg_range_u32(bool atomic) -{ +test_prng_lg_range_u32(bool atomic) { uint32_t sa, sb, ra, rb; unsigned lg_range; @@ -38,8 +37,7 @@ test_prng_lg_range_u32(bool atomic) } static void -test_prng_lg_range_u64(void) -{ +test_prng_lg_range_u64(void) { uint64_t sa, sb, ra, rb; unsigned lg_range; @@ -75,8 +73,7 @@ test_prng_lg_range_u64(void) } static void -test_prng_lg_range_zu(bool atomic) -{ +test_prng_lg_range_zu(bool atomic) { size_t sa, sb, ra, rb; unsigned lg_range; @@ -112,39 +109,33 @@ test_prng_lg_range_zu(bool atomic) } } -TEST_BEGIN(test_prng_lg_range_u32_nonatomic) -{ +TEST_BEGIN(test_prng_lg_range_u32_nonatomic) { test_prng_lg_range_u32(false); } TEST_END -TEST_BEGIN(test_prng_lg_range_u32_atomic) -{ +TEST_BEGIN(test_prng_lg_range_u32_atomic) { test_prng_lg_range_u32(true); } TEST_END -TEST_BEGIN(test_prng_lg_range_u64_nonatomic) -{ +TEST_BEGIN(test_prng_lg_range_u64_nonatomic) { test_prng_lg_range_u64(); } TEST_END -TEST_BEGIN(test_prng_lg_range_zu_nonatomic) -{ +TEST_BEGIN(test_prng_lg_range_zu_nonatomic) { test_prng_lg_range_zu(false); } TEST_END -TEST_BEGIN(test_prng_lg_range_zu_atomic) -{ +TEST_BEGIN(test_prng_lg_range_zu_atomic) { test_prng_lg_range_zu(true); } TEST_END static void -test_prng_range_u32(bool atomic) -{ +test_prng_range_u32(bool atomic) { uint32_t range; #define MAX_RANGE 10000000 #define RANGE_STEP 97 @@ -164,8 +155,7 @@ test_prng_range_u32(bool atomic) } static void -test_prng_range_u64(void) -{ +test_prng_range_u64(void) { uint64_t range; #define MAX_RANGE 10000000 #define RANGE_STEP 97 @@ -185,8 +175,7 @@ test_prng_range_u64(void) } static void -test_prng_range_zu(bool atomic) -{ +test_prng_range_zu(bool atomic) { size_t range; #define MAX_RANGE 10000000 #define RANGE_STEP 97 @@ -205,39 +194,33 @@ test_prng_range_zu(bool atomic) } } -TEST_BEGIN(test_prng_range_u32_nonatomic) -{ +TEST_BEGIN(test_prng_range_u32_nonatomic) { test_prng_range_u32(false); } TEST_END -TEST_BEGIN(test_prng_range_u32_atomic) -{ +TEST_BEGIN(test_prng_range_u32_atomic) { test_prng_range_u32(true); } TEST_END -TEST_BEGIN(test_prng_range_u64_nonatomic) -{ +TEST_BEGIN(test_prng_range_u64_nonatomic) { test_prng_range_u64(); } TEST_END -TEST_BEGIN(test_prng_range_zu_nonatomic) -{ +TEST_BEGIN(test_prng_range_zu_nonatomic) { test_prng_range_zu(false); } TEST_END -TEST_BEGIN(test_prng_range_zu_atomic) -{ +TEST_BEGIN(test_prng_range_zu_atomic) { test_prng_range_zu(true); } TEST_END int -main(void) -{ +main(void) { return (test( test_prng_lg_range_u32_nonatomic, test_prng_lg_range_u32_atomic, diff --git a/test/unit/prof_accum.c b/test/unit/prof_accum.c index 41ebeea5..bed0c9a6 100644 --- a/test/unit/prof_accum.c +++ b/test/unit/prof_accum.c @@ -11,8 +11,7 @@ const char *malloc_conf = #endif static int -prof_dump_open_intercept(bool propagate_err, const char *filename) -{ +prof_dump_open_intercept(bool propagate_err, const char *filename) { int fd; fd = open("/dev/null", O_WRONLY); @@ -22,14 +21,12 @@ prof_dump_open_intercept(bool propagate_err, const char *filename) } static void * -alloc_from_permuted_backtrace(unsigned thd_ind, unsigned iteration) -{ +alloc_from_permuted_backtrace(unsigned thd_ind, unsigned iteration) { return (btalloc(1, thd_ind*NALLOCS_PER_THREAD + iteration)); } static void * -thd_start(void *varg) -{ +thd_start(void *varg) { unsigned thd_ind = *(unsigned *)varg; size_t bt_count_prev, bt_count; unsigned i_prev, i; @@ -57,8 +54,7 @@ thd_start(void *varg) return (NULL); } -TEST_BEGIN(test_idump) -{ +TEST_BEGIN(test_idump) { bool active; thd_t thds[NTHREADS]; unsigned thd_args[NTHREADS]; @@ -77,14 +73,14 @@ TEST_BEGIN(test_idump) thd_args[i] = i; thd_create(&thds[i], thd_start, (void *)&thd_args[i]); } - for (i = 0; i < NTHREADS; i++) + for (i = 0; i < NTHREADS; i++) { thd_join(thds[i], NULL); + } } TEST_END int -main(void) -{ +main(void) { return (test( test_idump)); } diff --git a/test/unit/prof_active.c b/test/unit/prof_active.c index d3b341d7..422024f1 100644 --- a/test/unit/prof_active.c +++ b/test/unit/prof_active.c @@ -6,8 +6,7 @@ const char *malloc_conf = #endif static void -mallctl_bool_get(const char *name, bool expected, const char *func, int line) -{ +mallctl_bool_get(const char *name, bool expected, const char *func, int line) { bool old; size_t sz; @@ -20,8 +19,7 @@ mallctl_bool_get(const char *name, bool expected, const char *func, int line) static void mallctl_bool_set(const char *name, bool old_expected, bool val_new, - const char *func, int line) -{ + const char *func, int line) { bool old; size_t sz; @@ -36,8 +34,7 @@ mallctl_bool_set(const char *name, bool old_expected, bool val_new, static void mallctl_prof_active_get_impl(bool prof_active_old_expected, const char *func, - int line) -{ + int line) { mallctl_bool_get("prof.active", prof_active_old_expected, func, line); } #define mallctl_prof_active_get(a) \ @@ -45,8 +42,7 @@ mallctl_prof_active_get_impl(bool prof_active_old_expected, const char *func, static void mallctl_prof_active_set_impl(bool prof_active_old_expected, - bool prof_active_new, const char *func, int line) -{ + bool prof_active_new, const char *func, int line) { mallctl_bool_set("prof.active", prof_active_old_expected, prof_active_new, func, line); } @@ -55,8 +51,7 @@ mallctl_prof_active_set_impl(bool prof_active_old_expected, static void mallctl_thread_prof_active_get_impl(bool thread_prof_active_old_expected, - const char *func, int line) -{ + const char *func, int line) { mallctl_bool_get("thread.prof.active", thread_prof_active_old_expected, func, line); } @@ -65,8 +60,7 @@ mallctl_thread_prof_active_get_impl(bool thread_prof_active_old_expected, static void mallctl_thread_prof_active_set_impl(bool thread_prof_active_old_expected, - bool thread_prof_active_new, const char *func, int line) -{ + bool thread_prof_active_new, const char *func, int line) { mallctl_bool_set("thread.prof.active", thread_prof_active_old_expected, thread_prof_active_new, func, line); } @@ -74,8 +68,7 @@ mallctl_thread_prof_active_set_impl(bool thread_prof_active_old_expected, mallctl_thread_prof_active_set_impl(a, b, __func__, __LINE__) static void -prof_sampling_probe_impl(bool expect_sample, const char *func, int line) -{ +prof_sampling_probe_impl(bool expect_sample, const char *func, int line) { void *p; size_t expected_backtraces = expect_sample ? 1 : 0; @@ -90,8 +83,7 @@ prof_sampling_probe_impl(bool expect_sample, const char *func, int line) #define prof_sampling_probe(a) \ prof_sampling_probe_impl(a, __func__, __LINE__) -TEST_BEGIN(test_prof_active) -{ +TEST_BEGIN(test_prof_active) { test_skip_if(!config_prof); mallctl_prof_active_get(true); @@ -124,8 +116,7 @@ TEST_BEGIN(test_prof_active) TEST_END int -main(void) -{ +main(void) { return (test( test_prof_active)); } diff --git a/test/unit/prof_gdump.c b/test/unit/prof_gdump.c index 53f7cad6..0d8ec71c 100644 --- a/test/unit/prof_gdump.c +++ b/test/unit/prof_gdump.c @@ -7,8 +7,7 @@ const char *malloc_conf = "prof:true,prof_active:false,prof_gdump:true"; static bool did_prof_dump_open; static int -prof_dump_open_intercept(bool propagate_err, const char *filename) -{ +prof_dump_open_intercept(bool propagate_err, const char *filename) { int fd; did_prof_dump_open = true; @@ -19,8 +18,7 @@ prof_dump_open_intercept(bool propagate_err, const char *filename) return (fd); } -TEST_BEGIN(test_gdump) -{ +TEST_BEGIN(test_gdump) { bool active, gdump, gdump_old; void *p, *q, *r, *s; size_t sz; @@ -74,8 +72,7 @@ TEST_BEGIN(test_gdump) TEST_END int -main(void) -{ +main(void) { return (test( test_gdump)); } diff --git a/test/unit/prof_idump.c b/test/unit/prof_idump.c index 43824c6a..393211ea 100644 --- a/test/unit/prof_idump.c +++ b/test/unit/prof_idump.c @@ -16,8 +16,7 @@ const char *malloc_conf = "" static bool did_prof_dump_open; static int -prof_dump_open_intercept(bool propagate_err, const char *filename) -{ +prof_dump_open_intercept(bool propagate_err, const char *filename) { int fd; did_prof_dump_open = true; @@ -28,8 +27,7 @@ prof_dump_open_intercept(bool propagate_err, const char *filename) return (fd); } -TEST_BEGIN(test_idump) -{ +TEST_BEGIN(test_idump) { bool active; void *p; @@ -51,8 +49,7 @@ TEST_BEGIN(test_idump) TEST_END int -main(void) -{ +main(void) { return (test( test_idump)); } diff --git a/test/unit/prof_reset.c b/test/unit/prof_reset.c index cc13e378..463f6893 100644 --- a/test/unit/prof_reset.c +++ b/test/unit/prof_reset.c @@ -6,8 +6,7 @@ const char *malloc_conf = #endif static int -prof_dump_open_intercept(bool propagate_err, const char *filename) -{ +prof_dump_open_intercept(bool propagate_err, const char *filename) { int fd; fd = open("/dev/null", O_WRONLY); @@ -17,15 +16,13 @@ prof_dump_open_intercept(bool propagate_err, const char *filename) } static void -set_prof_active(bool active) -{ +set_prof_active(bool active) { assert_d_eq(mallctl("prof.active", NULL, NULL, (void *)&active, sizeof(active)), 0, "Unexpected mallctl failure"); } static size_t -get_lg_prof_sample(void) -{ +get_lg_prof_sample(void) { size_t lg_prof_sample; size_t sz = sizeof(size_t); @@ -36,8 +33,7 @@ get_lg_prof_sample(void) } static void -do_prof_reset(size_t lg_prof_sample) -{ +do_prof_reset(size_t lg_prof_sample) { assert_d_eq(mallctl("prof.reset", NULL, NULL, (void *)&lg_prof_sample, sizeof(size_t)), 0, "Unexpected mallctl failure while resetting profile data"); @@ -45,8 +41,7 @@ do_prof_reset(size_t lg_prof_sample) "Expected profile sample rate change"); } -TEST_BEGIN(test_prof_reset_basic) -{ +TEST_BEGIN(test_prof_reset_basic) { size_t lg_prof_sample_orig, lg_prof_sample, lg_prof_sample_next; size_t sz; unsigned i; @@ -95,16 +90,14 @@ bool prof_dump_header_intercepted = false; prof_cnt_t cnt_all_copy = {0, 0, 0, 0}; static bool prof_dump_header_intercept(tsdn_t *tsdn, bool propagate_err, - const prof_cnt_t *cnt_all) -{ + const prof_cnt_t *cnt_all) { prof_dump_header_intercepted = true; memcpy(&cnt_all_copy, cnt_all, sizeof(prof_cnt_t)); return (false); } -TEST_BEGIN(test_prof_reset_cleanup) -{ +TEST_BEGIN(test_prof_reset_cleanup) { void *p; prof_dump_header_t *prof_dump_header_orig; @@ -148,8 +141,7 @@ TEST_END #define RESET_INTERVAL (1U << 10) #define DUMP_INTERVAL 3677 static void * -thd_start(void *varg) -{ +thd_start(void *varg) { unsigned thd_ind = *(unsigned *)varg; unsigned i; void *objs[OBJ_RING_BUF_COUNT]; @@ -192,8 +184,7 @@ thd_start(void *varg) return (NULL); } -TEST_BEGIN(test_prof_reset) -{ +TEST_BEGIN(test_prof_reset) { size_t lg_prof_sample_orig; thd_t thds[NTHREADS]; unsigned thd_args[NTHREADS]; @@ -216,8 +207,9 @@ TEST_BEGIN(test_prof_reset) thd_args[i] = i; thd_create(&thds[i], thd_start, (void *)&thd_args[i]); } - for (i = 0; i < NTHREADS; i++) + for (i = 0; i < NTHREADS; i++) { thd_join(thds[i], NULL); + } assert_zu_eq(prof_bt_count(), bt_count, "Unexpected bactrace count change"); @@ -237,8 +229,7 @@ TEST_END /* Test sampling at the same allocation site across resets. */ #define NITER 10 -TEST_BEGIN(test_xallocx) -{ +TEST_BEGIN(test_xallocx) { size_t lg_prof_sample_orig; unsigned i; void *ptrs[NITER]; @@ -288,8 +279,7 @@ TEST_END #undef NITER int -main(void) -{ +main(void) { /* Intercept dumping prior to running any tests. */ prof_dump_open = prof_dump_open_intercept; diff --git a/test/unit/prof_tctx.c b/test/unit/prof_tctx.c index 8f928ebf..2e35b7ec 100644 --- a/test/unit/prof_tctx.c +++ b/test/unit/prof_tctx.c @@ -4,8 +4,7 @@ const char *malloc_conf = "prof:true,lg_prof_sample:0"; #endif -TEST_BEGIN(test_prof_realloc) -{ +TEST_BEGIN(test_prof_realloc) { tsdn_t *tsdn; int flags; void *p, *q; @@ -50,8 +49,7 @@ TEST_BEGIN(test_prof_realloc) TEST_END int -main(void) -{ +main(void) { return test( test_prof_realloc); } diff --git a/test/unit/prof_thread_name.c b/test/unit/prof_thread_name.c index 8699936b..ba86e10e 100644 --- a/test/unit/prof_thread_name.c +++ b/test/unit/prof_thread_name.c @@ -6,8 +6,7 @@ const char *malloc_conf = "prof:true,prof_active:false"; static void mallctl_thread_name_get_impl(const char *thread_name_expected, const char *func, - int line) -{ + int line) { const char *thread_name_old; size_t sz; @@ -24,8 +23,7 @@ mallctl_thread_name_get_impl(const char *thread_name_expected, const char *func, static void mallctl_thread_name_set_impl(const char *thread_name, const char *func, - int line) -{ + int line) { assert_d_eq(mallctl("thread.prof.name", NULL, NULL, (void *)&thread_name, sizeof(thread_name)), 0, "%s():%d: Unexpected mallctl failure reading thread.prof.name", @@ -35,8 +33,7 @@ mallctl_thread_name_set_impl(const char *thread_name, const char *func, #define mallctl_thread_name_set(a) \ mallctl_thread_name_set_impl(a, __func__, __LINE__) -TEST_BEGIN(test_prof_thread_name_validation) -{ +TEST_BEGIN(test_prof_thread_name_validation) { const char *thread_name; test_skip_if(!config_prof); @@ -78,8 +75,7 @@ TEST_END #define NTHREADS 4 #define NRESET 25 static void * -thd_start(void *varg) -{ +thd_start(void *varg) { unsigned thd_ind = *(unsigned *)varg; char thread_name[16] = ""; unsigned i; @@ -101,8 +97,7 @@ thd_start(void *varg) return (NULL); } -TEST_BEGIN(test_prof_thread_name_threaded) -{ +TEST_BEGIN(test_prof_thread_name_threaded) { thd_t thds[NTHREADS]; unsigned thd_args[NTHREADS]; unsigned i; @@ -113,16 +108,16 @@ TEST_BEGIN(test_prof_thread_name_threaded) thd_args[i] = i; thd_create(&thds[i], thd_start, (void *)&thd_args[i]); } - for (i = 0; i < NTHREADS; i++) + for (i = 0; i < NTHREADS; i++) { thd_join(thds[i], NULL); + } } TEST_END #undef NTHREADS #undef NRESET int -main(void) -{ +main(void) { return (test( test_prof_thread_name_validation, test_prof_thread_name_threaded)); diff --git a/test/unit/ql.c b/test/unit/ql.c index 2ebb4502..0bb896cb 100644 --- a/test/unit/ql.c +++ b/test/unit/ql.c @@ -12,8 +12,7 @@ struct list_s { }; static void -test_empty_list(list_head_t *head) -{ +test_empty_list(list_head_t *head) { list_t *t; unsigned i; @@ -34,8 +33,7 @@ test_empty_list(list_head_t *head) assert_u_eq(i, 0, "Unexpected element for empty list"); } -TEST_BEGIN(test_ql_empty) -{ +TEST_BEGIN(test_ql_empty) { list_head_t head; ql_new(&head); @@ -44,8 +42,7 @@ TEST_BEGIN(test_ql_empty) TEST_END static void -init_entries(list_t *entries, unsigned nentries) -{ +init_entries(list_t *entries, unsigned nentries) { unsigned i; for (i = 0; i < nentries; i++) { @@ -55,8 +52,7 @@ init_entries(list_t *entries, unsigned nentries) } static void -test_entries_list(list_head_t *head, list_t *entries, unsigned nentries) -{ +test_entries_list(list_head_t *head, list_t *entries, unsigned nentries) { list_t *t; unsigned i; @@ -91,31 +87,31 @@ test_entries_list(list_head_t *head, list_t *entries, unsigned nentries) } } -TEST_BEGIN(test_ql_tail_insert) -{ +TEST_BEGIN(test_ql_tail_insert) { list_head_t head; list_t entries[NENTRIES]; unsigned i; ql_new(&head); init_entries(entries, sizeof(entries)/sizeof(list_t)); - for (i = 0; i < NENTRIES; i++) + for (i = 0; i < NENTRIES; i++) { ql_tail_insert(&head, &entries[i], link); + } test_entries_list(&head, entries, NENTRIES); } TEST_END -TEST_BEGIN(test_ql_tail_remove) -{ +TEST_BEGIN(test_ql_tail_remove) { list_head_t head; list_t entries[NENTRIES]; unsigned i; ql_new(&head); init_entries(entries, sizeof(entries)/sizeof(list_t)); - for (i = 0; i < NENTRIES; i++) + for (i = 0; i < NENTRIES; i++) { ql_tail_insert(&head, &entries[i], link); + } for (i = 0; i < NENTRIES; i++) { test_entries_list(&head, entries, NENTRIES-i); @@ -125,31 +121,31 @@ TEST_BEGIN(test_ql_tail_remove) } TEST_END -TEST_BEGIN(test_ql_head_insert) -{ +TEST_BEGIN(test_ql_head_insert) { list_head_t head; list_t entries[NENTRIES]; unsigned i; ql_new(&head); init_entries(entries, sizeof(entries)/sizeof(list_t)); - for (i = 0; i < NENTRIES; i++) + for (i = 0; i < NENTRIES; i++) { ql_head_insert(&head, &entries[NENTRIES-i-1], link); + } test_entries_list(&head, entries, NENTRIES); } TEST_END -TEST_BEGIN(test_ql_head_remove) -{ +TEST_BEGIN(test_ql_head_remove) { list_head_t head; list_t entries[NENTRIES]; unsigned i; ql_new(&head); init_entries(entries, sizeof(entries)/sizeof(list_t)); - for (i = 0; i < NENTRIES; i++) + for (i = 0; i < NENTRIES; i++) { ql_head_insert(&head, &entries[NENTRIES-i-1], link); + } for (i = 0; i < NENTRIES; i++) { test_entries_list(&head, &entries[i], NENTRIES-i); @@ -159,8 +155,7 @@ TEST_BEGIN(test_ql_head_remove) } TEST_END -TEST_BEGIN(test_ql_insert) -{ +TEST_BEGIN(test_ql_insert) { list_head_t head; list_t entries[8]; list_t *a, *b, *c, *d, *e, *f, *g, *h; @@ -196,8 +191,7 @@ TEST_BEGIN(test_ql_insert) TEST_END int -main(void) -{ +main(void) { return (test( test_ql_empty, test_ql_tail_insert, diff --git a/test/unit/qr.c b/test/unit/qr.c index 7c9c1029..8061a345 100644 --- a/test/unit/qr.c +++ b/test/unit/qr.c @@ -13,8 +13,7 @@ struct ring_s { }; static void -init_entries(ring_t *entries) -{ +init_entries(ring_t *entries) { unsigned i; for (i = 0; i < NENTRIES; i++) { @@ -24,8 +23,7 @@ init_entries(ring_t *entries) } static void -test_independent_entries(ring_t *entries) -{ +test_independent_entries(ring_t *entries) { ring_t *t; unsigned i, j; @@ -61,8 +59,7 @@ test_independent_entries(ring_t *entries) } } -TEST_BEGIN(test_qr_one) -{ +TEST_BEGIN(test_qr_one) { ring_t entries[NENTRIES]; init_entries(entries); @@ -71,8 +68,7 @@ TEST_BEGIN(test_qr_one) TEST_END static void -test_entries_ring(ring_t *entries) -{ +test_entries_ring(ring_t *entries) { ring_t *t; unsigned i, j; @@ -104,27 +100,27 @@ test_entries_ring(ring_t *entries) } } -TEST_BEGIN(test_qr_after_insert) -{ +TEST_BEGIN(test_qr_after_insert) { ring_t entries[NENTRIES]; unsigned i; init_entries(entries); - for (i = 1; i < NENTRIES; i++) + for (i = 1; i < NENTRIES; i++) { qr_after_insert(&entries[i - 1], &entries[i], link); + } test_entries_ring(entries); } TEST_END -TEST_BEGIN(test_qr_remove) -{ +TEST_BEGIN(test_qr_remove) { ring_t entries[NENTRIES]; ring_t *t; unsigned i, j; init_entries(entries); - for (i = 1; i < NENTRIES; i++) + for (i = 1; i < NENTRIES; i++) { qr_after_insert(&entries[i - 1], &entries[i], link); + } for (i = 0; i < NENTRIES; i++) { j = 0; @@ -145,15 +141,15 @@ TEST_BEGIN(test_qr_remove) } TEST_END -TEST_BEGIN(test_qr_before_insert) -{ +TEST_BEGIN(test_qr_before_insert) { ring_t entries[NENTRIES]; ring_t *t; unsigned i, j; init_entries(entries); - for (i = 1; i < NENTRIES; i++) + for (i = 1; i < NENTRIES; i++) { qr_before_insert(&entries[i - 1], &entries[i], link); + } for (i = 0; i < NENTRIES; i++) { j = 0; qr_foreach(t, &entries[i], link) { @@ -184,8 +180,7 @@ TEST_BEGIN(test_qr_before_insert) TEST_END static void -test_split_entries(ring_t *entries) -{ +test_split_entries(ring_t *entries) { ring_t *t; unsigned i, j; @@ -206,14 +201,14 @@ test_split_entries(ring_t *entries) } } -TEST_BEGIN(test_qr_meld_split) -{ +TEST_BEGIN(test_qr_meld_split) { ring_t entries[NENTRIES]; unsigned i; init_entries(entries); - for (i = 1; i < NENTRIES; i++) + for (i = 1; i < NENTRIES; i++) { qr_after_insert(&entries[i - 1], &entries[i], link); + } qr_split(&entries[0], &entries[SPLIT_INDEX], ring_t, link); test_split_entries(entries); @@ -236,8 +231,7 @@ TEST_BEGIN(test_qr_meld_split) TEST_END int -main(void) -{ +main(void) { return (test( test_qr_one, test_qr_after_insert, diff --git a/test/unit/rb.c b/test/unit/rb.c index 56e00219..dea86c6e 100644 --- a/test/unit/rb.c +++ b/test/unit/rb.c @@ -1,14 +1,14 @@ #include "test/jemalloc_test.h" #define rbtn_black_height(a_type, a_field, a_rbt, r_height) do { \ - a_type *rbp_bh_t; \ - for (rbp_bh_t = (a_rbt)->rbt_root, (r_height) = 0; \ - rbp_bh_t != NULL; \ - rbp_bh_t = rbtn_left_get(a_type, a_field, rbp_bh_t)) { \ - if (!rbtn_red_get(a_type, a_field, rbp_bh_t)) { \ - (r_height)++; \ + a_type *rbp_bh_t; \ + for (rbp_bh_t = (a_rbt)->rbt_root, (r_height) = 0; rbp_bh_t != \ + NULL; rbp_bh_t = rbtn_left_get(a_type, a_field, \ + rbp_bh_t)) { \ + if (!rbtn_red_get(a_type, a_field, rbp_bh_t)) { \ + (r_height)++; \ + } \ } \ - } \ } while (0) typedef struct node_s node_t; @@ -42,8 +42,7 @@ node_cmp(const node_t *a, const node_t *b) { typedef rb_tree(node_t) tree_t; rb_gen(static, tree_, tree_t, node_t, link, node_cmp); -TEST_BEGIN(test_rb_empty) -{ +TEST_BEGIN(test_rb_empty) { tree_t tree; node_t key; @@ -68,52 +67,56 @@ TEST_BEGIN(test_rb_empty) TEST_END static unsigned -tree_recurse(node_t *node, unsigned black_height, unsigned black_depth) -{ +tree_recurse(node_t *node, unsigned black_height, unsigned black_depth) { unsigned ret = 0; node_t *left_node; node_t *right_node; - if (node == NULL) + if (node == NULL) { return (ret); + } left_node = rbtn_left_get(node_t, link, node); right_node = rbtn_right_get(node_t, link, node); - if (!rbtn_red_get(node_t, link, node)) + if (!rbtn_red_get(node_t, link, node)) { black_depth++; + } /* Red nodes must be interleaved with black nodes. */ if (rbtn_red_get(node_t, link, node)) { - if (left_node != NULL) + if (left_node != NULL) { assert_false(rbtn_red_get(node_t, link, left_node), "Node should be black"); - if (right_node != NULL) + } + if (right_node != NULL) { assert_false(rbtn_red_get(node_t, link, right_node), "Node should be black"); + } } /* Self. */ assert_u32_eq(node->magic, NODE_MAGIC, "Bad magic"); /* Left subtree. */ - if (left_node != NULL) + if (left_node != NULL) { ret += tree_recurse(left_node, black_height, black_depth); - else + } else { ret += (black_depth != black_height); + } /* Right subtree. */ - if (right_node != NULL) + if (right_node != NULL) { ret += tree_recurse(right_node, black_height, black_depth); - else + } else { ret += (black_depth != black_height); + } return (ret); } static node_t * -tree_iterate_cb(tree_t *tree, node_t *node, void *data) -{ +tree_iterate_cb(tree_t *tree, node_t *node, void *data) { unsigned *i = (unsigned *)data; node_t *search_node; @@ -140,8 +143,7 @@ tree_iterate_cb(tree_t *tree, node_t *node, void *data) } static unsigned -tree_iterate(tree_t *tree) -{ +tree_iterate(tree_t *tree) { unsigned i; i = 0; @@ -151,8 +153,7 @@ tree_iterate(tree_t *tree) } static unsigned -tree_iterate_reverse(tree_t *tree) -{ +tree_iterate_reverse(tree_t *tree) { unsigned i; i = 0; @@ -162,8 +163,7 @@ tree_iterate_reverse(tree_t *tree) } static void -node_remove(tree_t *tree, node_t *node, unsigned nnodes) -{ +node_remove(tree_t *tree, node_t *node, unsigned nnodes) { node_t *search_node; unsigned black_height, imbalances; @@ -195,8 +195,7 @@ node_remove(tree_t *tree, node_t *node, unsigned nnodes) } static node_t * -remove_iterate_cb(tree_t *tree, node_t *node, void *data) -{ +remove_iterate_cb(tree_t *tree, node_t *node, void *data) { unsigned *nnodes = (unsigned *)data; node_t *ret = tree_next(tree, node); @@ -206,8 +205,7 @@ remove_iterate_cb(tree_t *tree, node_t *node, void *data) } static node_t * -remove_reverse_iterate_cb(tree_t *tree, node_t *node, void *data) -{ +remove_reverse_iterate_cb(tree_t *tree, node_t *node, void *data) { unsigned *nnodes = (unsigned *)data; node_t *ret = tree_prev(tree, node); @@ -217,16 +215,14 @@ remove_reverse_iterate_cb(tree_t *tree, node_t *node, void *data) } static void -destroy_cb(node_t *node, void *data) -{ +destroy_cb(node_t *node, void *data) { unsigned *nnodes = (unsigned *)data; assert_u_gt(*nnodes, 0, "Destruction removed too many nodes"); (*nnodes)--; } -TEST_BEGIN(test_rb_random) -{ +TEST_BEGIN(test_rb_random) { #define NNODES 25 #define NBAGS 250 #define SEED 42 @@ -241,17 +237,20 @@ TEST_BEGIN(test_rb_random) switch (i) { case 0: /* Insert in order. */ - for (j = 0; j < NNODES; j++) + for (j = 0; j < NNODES; j++) { bag[j] = j; + } break; case 1: /* Insert in reverse order. */ - for (j = 0; j < NNODES; j++) + for (j = 0; j < NNODES; j++) { bag[j] = NNODES - j - 1; + } break; default: - for (j = 0; j < NNODES; j++) + for (j = 0; j < NNODES; j++) { bag[j] = gen_rand64_range(sfmt, NNODES); + } } for (j = 1; j <= NNODES; j++) { @@ -292,12 +291,14 @@ TEST_BEGIN(test_rb_random) /* Remove nodes. */ switch (i % 5) { case 0: - for (k = 0; k < j; k++) + for (k = 0; k < j; k++) { node_remove(&tree, &nodes[k], j - k); + } break; case 1: - for (k = j; k > 0; k--) + for (k = j; k > 0; k--) { node_remove(&tree, &nodes[k-1], k); + } break; case 2: { node_t *start; @@ -345,8 +346,7 @@ TEST_BEGIN(test_rb_random) TEST_END int -main(void) -{ +main(void) { return (test( test_rb_empty, test_rb_random)); diff --git a/test/unit/rtree.c b/test/unit/rtree.c index d2f37055..ca99f8a8 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -6,12 +6,12 @@ rtree_node_dalloc_t *rtree_node_dalloc_orig; rtree_t *test_rtree; static rtree_elm_t * -rtree_node_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) -{ +rtree_node_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { rtree_elm_t *node; - if (rtree != test_rtree) + if (rtree != test_rtree) { return rtree_node_alloc_orig(tsdn, rtree, nelms); + } malloc_mutex_unlock(tsdn, &rtree->init_lock); node = (rtree_elm_t *)calloc(nelms, sizeof(rtree_elm_t)); @@ -22,8 +22,7 @@ rtree_node_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) } static void -rtree_node_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) -{ +rtree_node_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) { if (rtree != test_rtree) { rtree_node_dalloc_orig(tsdn, rtree, node); return; @@ -32,8 +31,7 @@ rtree_node_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) free(node); } -TEST_BEGIN(test_rtree_read_empty) -{ +TEST_BEGIN(test_rtree_read_empty) { tsdn_t *tsdn; unsigned i; @@ -65,8 +63,7 @@ typedef struct { } thd_start_arg_t; static void * -thd_start(void *varg) -{ +thd_start(void *varg) { thd_start_arg_t *arg = (thd_start_arg_t *)varg; rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; sfmt_t *sfmt; @@ -98,8 +95,9 @@ thd_start(void *varg) "Unexpected rtree_elm_acquire() failure"); rtree_elm_read_acquired(tsdn, &arg->rtree, elm); rtree_elm_release(tsdn, &arg->rtree, elm); - } else + } else { rtree_read(tsdn, &arg->rtree, &rtree_ctx, key, false); + } } free(extent); @@ -107,8 +105,7 @@ thd_start(void *varg) return (NULL); } -TEST_BEGIN(test_rtree_concurrent) -{ +TEST_BEGIN(test_rtree_concurrent) { thd_start_arg_t arg; thd_t thds[NTHREADS]; sfmt_t *sfmt; @@ -123,10 +120,12 @@ TEST_BEGIN(test_rtree_concurrent) assert_false(rtree_new(&arg.rtree, arg.nbits), "Unexpected rtree_new() failure"); arg.seed = gen_rand32(sfmt); - for (j = 0; j < NTHREADS; j++) + for (j = 0; j < NTHREADS; j++) { thd_create(&thds[j], thd_start, (void *)&arg); - for (j = 0; j < NTHREADS; j++) + } + for (j = 0; j < NTHREADS; j++) { thd_join(thds[j], NULL); + } rtree_delete(tsdn, &arg.rtree); test_rtree = NULL; } @@ -139,8 +138,7 @@ TEST_END #undef NITERS #undef SEED -TEST_BEGIN(test_rtree_extrema) -{ +TEST_BEGIN(test_rtree_extrema) { unsigned i; extent_t extent_a, extent_b; tsdn_t *tsdn; @@ -173,8 +171,7 @@ TEST_BEGIN(test_rtree_extrema) } TEST_END -TEST_BEGIN(test_rtree_bits) -{ +TEST_BEGIN(test_rtree_bits) { tsdn_t *tsdn; unsigned i, j, k; @@ -217,8 +214,7 @@ TEST_BEGIN(test_rtree_bits) } TEST_END -TEST_BEGIN(test_rtree_random) -{ +TEST_BEGIN(test_rtree_random) { unsigned i; sfmt_t *sfmt; tsdn_t *tsdn; @@ -280,8 +276,7 @@ TEST_BEGIN(test_rtree_random) TEST_END int -main(void) -{ +main(void) { rtree_node_alloc_orig = rtree_node_alloc; rtree_node_alloc = rtree_node_alloc_intercept; rtree_node_dalloc_orig = rtree_node_dalloc; diff --git a/test/unit/size_classes.c b/test/unit/size_classes.c index f7c14bc0..38ea9bee 100644 --- a/test/unit/size_classes.c +++ b/test/unit/size_classes.c @@ -1,8 +1,7 @@ #include "test/jemalloc_test.h" static size_t -get_max_size_class(void) -{ +get_max_size_class(void) { unsigned nlextents; size_t mib[4]; size_t sz, miblen, max_size_class; @@ -23,8 +22,7 @@ get_max_size_class(void) return (max_size_class); } -TEST_BEGIN(test_size_classes) -{ +TEST_BEGIN(test_size_classes) { size_t size_class, max_size_class; szind_t index, max_index; @@ -80,8 +78,7 @@ TEST_BEGIN(test_size_classes) } TEST_END -TEST_BEGIN(test_psize_classes) -{ +TEST_BEGIN(test_psize_classes) { size_t size_class, max_psz; pszind_t pind, max_pind; @@ -136,8 +133,7 @@ TEST_BEGIN(test_psize_classes) } TEST_END -TEST_BEGIN(test_overflow) -{ +TEST_BEGIN(test_overflow) { size_t max_size_class, max_psz; max_size_class = get_max_size_class(); @@ -176,8 +172,7 @@ TEST_BEGIN(test_overflow) TEST_END int -main(void) -{ +main(void) { return (test( test_size_classes, test_psize_classes, diff --git a/test/unit/slab.c b/test/unit/slab.c index 7e6a62f5..a5036f59 100644 --- a/test/unit/slab.c +++ b/test/unit/slab.c @@ -1,7 +1,6 @@ #include "test/jemalloc_test.h" -TEST_BEGIN(test_arena_slab_regind) -{ +TEST_BEGIN(test_arena_slab_regind) { szind_t binind; for (binind = 0; binind < NBINS; binind++) { @@ -27,8 +26,7 @@ TEST_BEGIN(test_arena_slab_regind) TEST_END int -main(void) -{ +main(void) { return (test( test_arena_slab_regind)); } diff --git a/test/unit/smoothstep.c b/test/unit/smoothstep.c index 071aede2..ac279159 100644 --- a/test/unit/smoothstep.c +++ b/test/unit/smoothstep.c @@ -7,8 +7,7 @@ static const uint64_t smoothstep_tab[] = { #undef STEP }; -TEST_BEGIN(test_smoothstep_integral) -{ +TEST_BEGIN(test_smoothstep_integral) { uint64_t sum, min, max; unsigned i; @@ -20,8 +19,9 @@ TEST_BEGIN(test_smoothstep_integral) * integral may be off by as much as SMOOTHSTEP_NSTEPS ulps. */ sum = 0; - for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) + for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) { sum += smoothstep_tab[i]; + } max = (KQU(1) << (SMOOTHSTEP_BFP-1)) * (SMOOTHSTEP_NSTEPS+1); min = max - SMOOTHSTEP_NSTEPS; @@ -36,8 +36,7 @@ TEST_BEGIN(test_smoothstep_integral) } TEST_END -TEST_BEGIN(test_smoothstep_monotonic) -{ +TEST_BEGIN(test_smoothstep_monotonic) { uint64_t prev_h; unsigned i; @@ -58,8 +57,7 @@ TEST_BEGIN(test_smoothstep_monotonic) } TEST_END -TEST_BEGIN(test_smoothstep_slope) -{ +TEST_BEGIN(test_smoothstep_slope) { uint64_t prev_h, prev_delta; unsigned i; @@ -96,8 +94,7 @@ TEST_BEGIN(test_smoothstep_slope) TEST_END int -main(void) -{ +main(void) { return (test( test_smoothstep_integral, test_smoothstep_monotonic, diff --git a/test/unit/stats.c b/test/unit/stats.c index 18856f12..98673a8e 100644 --- a/test/unit/stats.c +++ b/test/unit/stats.c @@ -1,7 +1,6 @@ #include "test/jemalloc_test.h" -TEST_BEGIN(test_stats_summary) -{ +TEST_BEGIN(test_stats_summary) { size_t sz, allocated, active, resident, mapped; int expected = config_stats ? 0 : ENOENT; @@ -26,8 +25,7 @@ TEST_BEGIN(test_stats_summary) } TEST_END -TEST_BEGIN(test_stats_large) -{ +TEST_BEGIN(test_stats_large) { void *p; uint64_t epoch; size_t allocated; @@ -67,8 +65,7 @@ TEST_BEGIN(test_stats_large) } TEST_END -TEST_BEGIN(test_stats_arenas_summary) -{ +TEST_BEGIN(test_stats_arenas_summary) { unsigned arena; void *little, *large; uint64_t epoch; @@ -118,22 +115,19 @@ TEST_BEGIN(test_stats_arenas_summary) TEST_END void * -thd_start(void *arg) -{ +thd_start(void *arg) { return (NULL); } static void -no_lazy_lock(void) -{ +no_lazy_lock(void) { thd_t thd; thd_create(&thd, thd_start, NULL); thd_join(thd, NULL); } -TEST_BEGIN(test_stats_arenas_small) -{ +TEST_BEGIN(test_stats_arenas_small) { unsigned arena; void *p; size_t sz, allocated; @@ -183,8 +177,7 @@ TEST_BEGIN(test_stats_arenas_small) } TEST_END -TEST_BEGIN(test_stats_arenas_large) -{ +TEST_BEGIN(test_stats_arenas_large) { unsigned arena; void *p; size_t sz, allocated; @@ -224,8 +217,7 @@ TEST_BEGIN(test_stats_arenas_large) } TEST_END -TEST_BEGIN(test_stats_arenas_bins) -{ +TEST_BEGIN(test_stats_arenas_bins) { unsigned arena; void *p; size_t sz, curslabs, curregs; @@ -299,8 +291,7 @@ TEST_BEGIN(test_stats_arenas_bins) } TEST_END -TEST_BEGIN(test_stats_arenas_lextents) -{ +TEST_BEGIN(test_stats_arenas_lextents) { unsigned arena; void *p; uint64_t epoch, nmalloc, ndalloc; @@ -347,8 +338,7 @@ TEST_BEGIN(test_stats_arenas_lextents) TEST_END int -main(void) -{ +main(void) { return (test( test_stats_summary, test_stats_large, diff --git a/test/unit/stats_print.c b/test/unit/stats_print.c index 5accd8e2..1fb8fe6f 100644 --- a/test/unit/stats_print.c +++ b/test/unit/stats_print.c @@ -39,8 +39,7 @@ struct parser_s { static void token_init(token_t *token, parser_t *parser, token_type_t token_type, - size_t pos, size_t len, size_t line, size_t col) -{ + size_t pos, size_t len, size_t line, size_t col) { token->parser = parser; token->token_type = token_type; token->pos = pos; @@ -50,8 +49,7 @@ token_init(token_t *token, parser_t *parser, token_type_t token_type, } static void -token_error(token_t *token) -{ +token_error(token_t *token) { if (!token->parser->verbose) { return; } @@ -72,8 +70,7 @@ token_error(token_t *token) } static void -parser_init(parser_t *parser, bool verbose) -{ +parser_init(parser_t *parser, bool verbose) { parser->verbose = verbose; parser->buf = NULL; parser->len = 0; @@ -83,16 +80,14 @@ parser_init(parser_t *parser, bool verbose) } static void -parser_fini(parser_t *parser) -{ +parser_fini(parser_t *parser) { if (parser->buf != NULL) { dallocx(parser->buf, MALLOCX_TCACHE_NONE); } } static bool -parser_append(parser_t *parser, const char *str) -{ +parser_append(parser_t *parser, const char *str) { size_t len = strlen(str); char *buf = (parser->buf == NULL) ? mallocx(len + 1, MALLOCX_TCACHE_NONE) : rallocx(parser->buf, parser->len + len + 1, @@ -107,8 +102,7 @@ parser_append(parser_t *parser, const char *str) } static bool -parser_tokenize(parser_t *parser) -{ +parser_tokenize(parser_t *parser) { enum { STATE_START, STATE_EOI, @@ -667,8 +661,7 @@ static bool parser_parse_array(parser_t *parser); static bool parser_parse_object(parser_t *parser); static bool -parser_parse_value(parser_t *parser) -{ +parser_parse_value(parser_t *parser) { switch (parser->token.token_type) { case TOKEN_TYPE_NULL: case TOKEN_TYPE_FALSE: @@ -687,8 +680,7 @@ parser_parse_value(parser_t *parser) } static bool -parser_parse_pair(parser_t *parser) -{ +parser_parse_pair(parser_t *parser) { assert_d_eq(parser->token.token_type, TOKEN_TYPE_STRING, "Pair should start with string"); if (parser_tokenize(parser)) { @@ -706,8 +698,7 @@ parser_parse_pair(parser_t *parser) } static bool -parser_parse_values(parser_t *parser) -{ +parser_parse_values(parser_t *parser) { if (parser_parse_value(parser)) { return true; } @@ -734,8 +725,7 @@ parser_parse_values(parser_t *parser) } static bool -parser_parse_array(parser_t *parser) -{ +parser_parse_array(parser_t *parser) { assert_d_eq(parser->token.token_type, TOKEN_TYPE_LBRACKET, "Array should start with ["); if (parser_tokenize(parser)) { @@ -751,8 +741,7 @@ parser_parse_array(parser_t *parser) } static bool -parser_parse_pairs(parser_t *parser) -{ +parser_parse_pairs(parser_t *parser) { assert_d_eq(parser->token.token_type, TOKEN_TYPE_STRING, "Object should start with string"); if (parser_parse_pair(parser)) { @@ -787,8 +776,7 @@ parser_parse_pairs(parser_t *parser) } static bool -parser_parse_object(parser_t *parser) -{ +parser_parse_object(parser_t *parser) { assert_d_eq(parser->token.token_type, TOKEN_TYPE_LBRACE, "Object should start with {"); if (parser_tokenize(parser)) { @@ -806,8 +794,7 @@ parser_parse_object(parser_t *parser) } static bool -parser_parse(parser_t *parser) -{ +parser_parse(parser_t *parser) { if (parser_tokenize(parser)) { goto label_error; } @@ -831,8 +818,7 @@ label_error: return true; } -TEST_BEGIN(test_json_parser) -{ +TEST_BEGIN(test_json_parser) { size_t i; const char *invalid_inputs[] = { /* Tokenizer error case tests. */ @@ -929,16 +915,14 @@ TEST_BEGIN(test_json_parser) TEST_END void -write_cb(void *opaque, const char *str) -{ +write_cb(void *opaque, const char *str) { parser_t *parser = (parser_t *)opaque; if (parser_append(parser, str)) { test_fail("Unexpected input appending failure"); } } -TEST_BEGIN(test_stats_print_json) -{ +TEST_BEGIN(test_stats_print_json) { const char *opts[] = { "J", "Jg", @@ -998,8 +982,7 @@ TEST_BEGIN(test_stats_print_json) TEST_END int -main(void) -{ +main(void) { return (test( test_json_parser, test_stats_print_json)); diff --git a/test/unit/ticker.c b/test/unit/ticker.c index b8af46c7..be54356f 100644 --- a/test/unit/ticker.c +++ b/test/unit/ticker.c @@ -1,7 +1,6 @@ #include "test/jemalloc_test.h" -TEST_BEGIN(test_ticker_tick) -{ +TEST_BEGIN(test_ticker_tick) { #define NREPS 2 #define NTICKS 3 ticker_t ticker; @@ -26,8 +25,7 @@ TEST_BEGIN(test_ticker_tick) } TEST_END -TEST_BEGIN(test_ticker_ticks) -{ +TEST_BEGIN(test_ticker_ticks) { #define NTICKS 3 ticker_t ticker; @@ -45,8 +43,7 @@ TEST_BEGIN(test_ticker_ticks) } TEST_END -TEST_BEGIN(test_ticker_copy) -{ +TEST_BEGIN(test_ticker_copy) { #define NTICKS 3 ticker_t ta, tb; @@ -66,8 +63,7 @@ TEST_BEGIN(test_ticker_copy) TEST_END int -main(void) -{ +main(void) { return (test( test_ticker_tick, test_ticker_ticks, diff --git a/test/unit/tsd.c b/test/unit/tsd.c index 5313ef88..484dc30b 100644 --- a/test/unit/tsd.c +++ b/test/unit/tsd.c @@ -10,8 +10,7 @@ malloc_tsd_types(data_, data_t) malloc_tsd_protos(, data_, data_t) void -data_cleanup(void *arg) -{ +data_cleanup(void *arg) { data_t *data = (data_t *)arg; if (!data_cleanup_executed) { @@ -53,8 +52,7 @@ malloc_tsd_data(, data_, data_t, DATA_INIT) malloc_tsd_funcs(, data_, data_t, DATA_INIT, data_cleanup) static void * -thd_start(void *arg) -{ +thd_start(void *arg) { data_t d = (data_t)(uintptr_t)arg; void *p; @@ -76,14 +74,12 @@ thd_start(void *arg) return (NULL); } -TEST_BEGIN(test_tsd_main_thread) -{ +TEST_BEGIN(test_tsd_main_thread) { thd_start((void *)(uintptr_t)0xa5f3e329); } TEST_END -TEST_BEGIN(test_tsd_sub_thread) -{ +TEST_BEGIN(test_tsd_sub_thread) { thd_t thd; data_cleanup_executed = false; @@ -95,8 +91,7 @@ TEST_BEGIN(test_tsd_sub_thread) TEST_END int -main(void) -{ +main(void) { /* Core tsd bootstrapping must happen prior to data_tsd_boot(). */ if (nallocx(1, 0) == 0) { malloc_printf("Initialization error"); diff --git a/test/unit/util.c b/test/unit/util.c index b891a199..3d1ecf4e 100644 --- a/test/unit/util.c +++ b/test/unit/util.c @@ -31,26 +31,22 @@ } \ } while (0) -TEST_BEGIN(test_pow2_ceil_u64) -{ +TEST_BEGIN(test_pow2_ceil_u64) { TEST_POW2_CEIL(uint64_t, u64, FMTu64); } TEST_END -TEST_BEGIN(test_pow2_ceil_u32) -{ +TEST_BEGIN(test_pow2_ceil_u32) { TEST_POW2_CEIL(uint32_t, u32, FMTu32); } TEST_END -TEST_BEGIN(test_pow2_ceil_zu) -{ +TEST_BEGIN(test_pow2_ceil_zu) { TEST_POW2_CEIL(size_t, zu, "zu"); } TEST_END -TEST_BEGIN(test_malloc_strtoumax_no_endptr) -{ +TEST_BEGIN(test_malloc_strtoumax_no_endptr) { int err; set_errno(0); @@ -60,8 +56,7 @@ TEST_BEGIN(test_malloc_strtoumax_no_endptr) } TEST_END -TEST_BEGIN(test_malloc_strtoumax) -{ +TEST_BEGIN(test_malloc_strtoumax) { struct test_s { const char *input; const char *expected_remainder; @@ -155,8 +150,7 @@ TEST_BEGIN(test_malloc_strtoumax) } TEST_END -TEST_BEGIN(test_malloc_snprintf_truncated) -{ +TEST_BEGIN(test_malloc_snprintf_truncated) { #define BUFLEN 15 char buf[BUFLEN]; size_t result; @@ -188,8 +182,7 @@ TEST_BEGIN(test_malloc_snprintf_truncated) } TEST_END -TEST_BEGIN(test_malloc_snprintf) -{ +TEST_BEGIN(test_malloc_snprintf) { #define BUFLEN 128 char buf[BUFLEN]; size_t result; @@ -302,8 +295,7 @@ TEST_BEGIN(test_malloc_snprintf) TEST_END int -main(void) -{ +main(void) { return (test( test_pow2_ceil_u64, test_pow2_ceil_u32, diff --git a/test/unit/witness.c b/test/unit/witness.c index 13593989..d75ca482 100644 --- a/test/unit/witness.c +++ b/test/unit/witness.c @@ -12,32 +12,27 @@ static bool saw_lockless_error; static void witness_lock_error_intercept(const witness_list_t *witnesses, - const witness_t *witness) -{ + const witness_t *witness) { saw_lock_error = true; } static void -witness_owner_error_intercept(const witness_t *witness) -{ +witness_owner_error_intercept(const witness_t *witness) { saw_owner_error = true; } static void -witness_not_owner_error_intercept(const witness_t *witness) -{ +witness_not_owner_error_intercept(const witness_t *witness) { saw_not_owner_error = true; } static void -witness_lockless_error_intercept(const witness_list_t *witnesses) -{ +witness_lockless_error_intercept(const witness_list_t *witnesses) { saw_lockless_error = true; } static int -witness_comp(const witness_t *a, void *oa, const witness_t *b, void *ob) -{ +witness_comp(const witness_t *a, void *oa, const witness_t *b, void *ob) { assert_u_eq(a->rank, b->rank, "Witnesses should have equal rank"); assert(oa == (void *)a); @@ -47,8 +42,8 @@ witness_comp(const witness_t *a, void *oa, const witness_t *b, void *ob) } static int -witness_comp_reverse(const witness_t *a, void *oa, const witness_t *b, void *ob) -{ +witness_comp_reverse(const witness_t *a, void *oa, const witness_t *b, + void *ob) { assert_u_eq(a->rank, b->rank, "Witnesses should have equal rank"); assert(oa == (void *)a); @@ -57,8 +52,7 @@ witness_comp_reverse(const witness_t *a, void *oa, const witness_t *b, void *ob) return (-strcmp(a->name, b->name)); } -TEST_BEGIN(test_witness) -{ +TEST_BEGIN(test_witness) { witness_t a, b; tsdn_t *tsdn; @@ -85,8 +79,7 @@ TEST_BEGIN(test_witness) } TEST_END -TEST_BEGIN(test_witness_comp) -{ +TEST_BEGIN(test_witness_comp) { witness_t a, b, c, d; tsdn_t *tsdn; @@ -135,8 +128,7 @@ TEST_BEGIN(test_witness_comp) } TEST_END -TEST_BEGIN(test_witness_reversal) -{ +TEST_BEGIN(test_witness_reversal) { witness_t a, b; tsdn_t *tsdn; @@ -167,8 +159,7 @@ TEST_BEGIN(test_witness_reversal) } TEST_END -TEST_BEGIN(test_witness_recursive) -{ +TEST_BEGIN(test_witness_recursive) { witness_t a; tsdn_t *tsdn; @@ -205,8 +196,7 @@ TEST_BEGIN(test_witness_recursive) } TEST_END -TEST_BEGIN(test_witness_unlock_not_owned) -{ +TEST_BEGIN(test_witness_unlock_not_owned) { witness_t a; tsdn_t *tsdn; @@ -232,8 +222,7 @@ TEST_BEGIN(test_witness_unlock_not_owned) } TEST_END -TEST_BEGIN(test_witness_lockful) -{ +TEST_BEGIN(test_witness_lockful) { witness_t a; tsdn_t *tsdn; @@ -265,8 +254,7 @@ TEST_BEGIN(test_witness_lockful) TEST_END int -main(void) -{ +main(void) { return (test( test_witness, test_witness_comp, diff --git a/test/unit/zero.c b/test/unit/zero.c index c752954c..a802f053 100644 --- a/test/unit/zero.c +++ b/test/unit/zero.c @@ -6,8 +6,7 @@ const char *malloc_conf = #endif static void -test_zero(size_t sz_min, size_t sz_max) -{ +test_zero(size_t sz_min, size_t sz_max) { uint8_t *s; size_t sz_prev, sz, i; #define MAGIC ((uint8_t)0x61) @@ -45,23 +44,20 @@ test_zero(size_t sz_min, size_t sz_max) #undef MAGIC } -TEST_BEGIN(test_zero_small) -{ +TEST_BEGIN(test_zero_small) { test_skip_if(!config_fill); test_zero(1, SMALL_MAXCLASS-1); } TEST_END -TEST_BEGIN(test_zero_large) -{ +TEST_BEGIN(test_zero_large) { test_skip_if(!config_fill); test_zero(SMALL_MAXCLASS+1, (1U << (LG_LARGE_MINCLASS+1))); } TEST_END int -main(void) -{ +main(void) { return (test( test_zero_small, test_zero_large)); -- GitLab From f408643a4c90d51ab8ddc1d68610650d5db87edf Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 19 Jan 2017 18:15:45 -0800 Subject: [PATCH 240/544] Remove extraneous parens around return arguments. This resolves #540. --- configure.ac | 4 +- include/jemalloc/internal/arena_inlines_a.h | 16 +- include/jemalloc/internal/arena_inlines_b.h | 20 +- include/jemalloc/internal/atomic_inlines.h | 120 +++++----- include/jemalloc/internal/base_inlines.h | 2 +- include/jemalloc/internal/bitmap_inlines.h | 8 +- include/jemalloc/internal/extent_inlines.h | 50 ++--- include/jemalloc/internal/hash_inlines.h | 14 +- .../jemalloc/internal/jemalloc_internal.h.in | 124 +++++------ include/jemalloc/internal/ph.h | 8 +- include/jemalloc/internal/prng_inlines.h | 20 +- include/jemalloc/internal/prof_inlines.h | 16 +- include/jemalloc/internal/rb.h | 66 +++--- include/jemalloc/internal/rtree_inlines.h | 38 ++-- include/jemalloc/internal/tcache_inlines.h | 26 +-- include/jemalloc/internal/ticker_inlines.h | 6 +- include/jemalloc/internal/tsd_inlines.h | 24 +- include/jemalloc/internal/tsd_types.h | 68 +++--- include/jemalloc/internal/util_inlines.h | 44 ++-- include/jemalloc/internal/witness_inlines.h | 4 +- include/msvc_compat/strings.h | 16 +- src/arena.c | 124 +++++------ src/base.c | 28 +-- src/bitmap.c | 4 +- src/ckh.c | 50 ++--- src/ctl.c | 144 ++++++------ src/extent.c | 161 +++++++------- src/extent_dss.c | 26 +-- src/extent_mmap.c | 14 +- src/jemalloc.c | 164 +++++++------- src/jemalloc_cpp.cpp | 12 +- src/large.c | 46 ++-- src/mutex.c | 16 +- src/nstime.c | 16 +- src/pages.c | 36 +-- src/prof.c | 210 +++++++++--------- src/rtree.c | 22 +- src/tcache.c | 28 +-- src/tsd.c | 12 +- src/util.c | 20 +- src/zone.c | 20 +- test/include/test/btalloc.h | 2 +- test/include/test/extent_hooks.h | 32 +-- test/include/test/math.h | 24 +- test/include/test/mq.h | 12 +- test/integration/MALLOCX_ARENA.c | 6 +- test/integration/aligned_alloc.c | 4 +- test/integration/allocated.c | 8 +- test/integration/cpp/basic.cpp | 4 +- test/integration/extent.c | 4 +- test/integration/mallocx.c | 12 +- test/integration/overflow.c | 4 +- test/integration/posix_memalign.c | 4 +- test/integration/rallocx.c | 14 +- test/integration/sdallocx.c | 4 +- test/integration/thread_arena.c | 6 +- test/integration/thread_tcache_enabled.c | 8 +- test/integration/xallocx.c | 20 +- test/src/btalloc.c | 2 +- test/src/mtx.c | 8 +- test/src/test.c | 8 +- test/src/timer.c | 2 +- test/stress/microbench.c | 4 +- test/unit/SFMT.c | 4 +- test/unit/a0.c | 4 +- test/unit/arena_reset.c | 30 +-- test/unit/atomic.c | 4 +- test/unit/base.c | 4 +- test/unit/bitmap.c | 6 +- test/unit/ckh.c | 4 +- test/unit/decay.c | 8 +- test/unit/extent_quantize.c | 4 +- test/unit/fork.c | 4 +- test/unit/hash.c | 16 +- test/unit/junk.c | 4 +- test/unit/mallctl.c | 4 +- test/unit/math.c | 8 +- test/unit/mq.c | 8 +- test/unit/mtx.c | 6 +- test/unit/nstime.c | 4 +- test/unit/pack.c | 12 +- test/unit/pages.c | 4 +- test/unit/ph.c | 16 +- test/unit/prng.c | 4 +- test/unit/prof_accum.c | 10 +- test/unit/prof_active.c | 4 +- test/unit/prof_gdump.c | 6 +- test/unit/prof_idump.c | 6 +- test/unit/prof_reset.c | 12 +- test/unit/prof_thread_name.c | 6 +- test/unit/ql.c | 4 +- test/unit/qr.c | 4 +- test/unit/rb.c | 20 +- test/unit/rtree.c | 8 +- test/unit/size_classes.c | 6 +- test/unit/slab.c | 4 +- test/unit/smoothstep.c | 4 +- test/unit/stats.c | 6 +- test/unit/stats_print.c | 4 +- test/unit/ticker.c | 4 +- test/unit/tsd.c | 8 +- test/unit/util.c | 4 +- test/unit/witness.c | 8 +- test/unit/zero.c | 4 +- 104 files changed, 1161 insertions(+), 1168 deletions(-) diff --git a/configure.ac b/configure.ac index 4a1168b0..7530eff7 100644 --- a/configure.ac +++ b/configure.ac @@ -295,7 +295,7 @@ if test "x$enable_cxx" = "x1" ; then ], [[ int *arr = (int *)malloc(sizeof(int) * 42); if (arr == NULL) - return (1); + return 1; ]], [je_cv_libstdcxx]) if test "x${je_cv_libstdcxx}" = "xno" ; then LIBS="${SAVED_LIBS}" @@ -1659,7 +1659,7 @@ JE_COMPILABLE([C11 atomics], [ uint64_t x = 1; volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; uint64_t r = atomic_fetch_add(a, x) + x; - return (r == 0); + return r == 0; ], [je_cv_c11atomics]) if test "x${je_cv_c11atomics}" = "xyes" ; then AC_DEFINE([JEMALLOC_C11ATOMICS]) diff --git a/include/jemalloc/internal/arena_inlines_a.h b/include/jemalloc/internal/arena_inlines_a.h index 3c2b9b0a..a81aaf56 100644 --- a/include/jemalloc/internal/arena_inlines_a.h +++ b/include/jemalloc/internal/arena_inlines_a.h @@ -15,7 +15,7 @@ bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes); JEMALLOC_INLINE unsigned arena_ind_get(const arena_t *arena) { - return (base_ind_get(arena->base)); + return base_ind_get(arena->base); } JEMALLOC_INLINE void @@ -30,7 +30,7 @@ arena_internal_sub(arena_t *arena, size_t size) { JEMALLOC_INLINE size_t arena_internal_get(arena_t *arena) { - return (atomic_read_zu(&arena->stats.internal)); + return atomic_read_zu(&arena->stats.internal); } JEMALLOC_INLINE bool @@ -41,9 +41,9 @@ arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes) { arena->prof_accumbytes += accumbytes; if (arena->prof_accumbytes >= prof_interval) { arena->prof_accumbytes %= prof_interval; - return (true); + return true; } - return (false); + return false; } JEMALLOC_INLINE bool @@ -51,9 +51,9 @@ arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes) { cassert(config_prof); if (likely(prof_interval == 0)) { - return (false); + return false; } - return (arena_prof_accum_impl(arena, accumbytes)); + return arena_prof_accum_impl(arena, accumbytes); } JEMALLOC_INLINE bool @@ -61,7 +61,7 @@ arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) { cassert(config_prof); if (likely(prof_interval == 0)) { - return (false); + return false; } { @@ -70,7 +70,7 @@ arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) { malloc_mutex_lock(tsdn, &arena->lock); ret = arena_prof_accum_impl(arena, accumbytes); malloc_mutex_unlock(tsdn, &arena->lock); - return (ret); + return ret; } } diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 5772781d..a180322b 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -26,7 +26,7 @@ JEMALLOC_INLINE szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin) { szind_t binind = (szind_t)(bin - arena->bins); assert(binind < NBINS); - return (binind); + return binind; } JEMALLOC_INLINE prof_tctx_t * @@ -35,9 +35,9 @@ arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { assert(ptr != NULL); if (unlikely(!extent_slab_get(extent))) { - return (large_prof_tctx_get(tsdn, extent)); + return large_prof_tctx_get(tsdn, extent); } - return ((prof_tctx_t *)(uintptr_t)1U); + return (prof_tctx_t *)(uintptr_t)1U; } JEMALLOC_INLINE void @@ -94,23 +94,23 @@ arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, if (likely(tcache != NULL)) { if (likely(size <= SMALL_MAXCLASS)) { - return (tcache_alloc_small(tsdn_tsd(tsdn), arena, - tcache, size, ind, zero, slow_path)); + return tcache_alloc_small(tsdn_tsd(tsdn), arena, + tcache, size, ind, zero, slow_path); } if (likely(size <= tcache_maxclass)) { - return (tcache_alloc_large(tsdn_tsd(tsdn), arena, - tcache, size, ind, zero, slow_path)); + return tcache_alloc_large(tsdn_tsd(tsdn), arena, + tcache, size, ind, zero, slow_path); } /* (size > tcache_maxclass) case falls through. */ assert(size > tcache_maxclass); } - return (arena_malloc_hard(tsdn, arena, size, ind, zero)); + return arena_malloc_hard(tsdn, arena, size, ind, zero); } JEMALLOC_ALWAYS_INLINE arena_t * arena_aalloc(tsdn_t *tsdn, const void *ptr) { - return (extent_arena_get(iealloc(tsdn, ptr))); + return extent_arena_get(iealloc(tsdn, ptr)); } /* Return the size of the allocation pointed to by ptr. */ @@ -126,7 +126,7 @@ arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { ret = large_salloc(tsdn, extent); } - return (ret); + return ret; } JEMALLOC_ALWAYS_INLINE void diff --git a/include/jemalloc/internal/atomic_inlines.h b/include/jemalloc/internal/atomic_inlines.h index 790a08a2..7c1902f8 100644 --- a/include/jemalloc/internal/atomic_inlines.h +++ b/include/jemalloc/internal/atomic_inlines.h @@ -9,15 +9,15 @@ * operations can be optimized away if the return values aren't used by the * callers. * - * atomic_read_( *p) { return (*p); } - * atomic_add_( *p, x) { return (*p += x); } - * atomic_sub_( *p, x) { return (*p -= x); } + * atomic_read_( *p) { return *p; } + * atomic_add_( *p, x) { return *p += x; } + * atomic_sub_( *p, x) { return *p -= x; } * bool atomic_cas_( *p, c, s) * { * if (*p != c) - * return (true); + * return true; * *p = s; - * return (false); + * return false; * } * void atomic_write_( *p, x) { *p = x; } */ @@ -62,7 +62,7 @@ atomic_add_u64(uint64_t *p, uint64_t x) { : "m" (*p) /* Inputs. */ ); - return (t + x); + return t + x; } JEMALLOC_INLINE uint64_t @@ -77,7 +77,7 @@ atomic_sub_u64(uint64_t *p, uint64_t x) { : "m" (*p) /* Inputs. */ ); - return (t + x); + return t + x; } JEMALLOC_INLINE bool @@ -92,7 +92,7 @@ atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { : "memory" /* Clobbers. */ ); - return (!(bool)success); + return !(bool)success; } JEMALLOC_INLINE void @@ -108,19 +108,19 @@ atomic_write_u64(uint64_t *p, uint64_t x) { JEMALLOC_INLINE uint64_t atomic_add_u64(uint64_t *p, uint64_t x) { volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; - return (atomic_fetch_add(a, x) + x); + return atomic_fetch_add(a, x) + x; } JEMALLOC_INLINE uint64_t atomic_sub_u64(uint64_t *p, uint64_t x) { volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; - return (atomic_fetch_sub(a, x) - x); + return atomic_fetch_sub(a, x) - x; } JEMALLOC_INLINE bool atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; - return (!atomic_compare_exchange_strong(a, &c, s)); + return !atomic_compare_exchange_strong(a, &c, s); } JEMALLOC_INLINE void @@ -137,21 +137,21 @@ atomic_add_u64(uint64_t *p, uint64_t x) { */ assert(sizeof(uint64_t) == sizeof(unsigned long)); - return (atomic_fetchadd_long(p, (unsigned long)x) + x); + return atomic_fetchadd_long(p, (unsigned long)x) + x; } JEMALLOC_INLINE uint64_t atomic_sub_u64(uint64_t *p, uint64_t x) { assert(sizeof(uint64_t) == sizeof(unsigned long)); - return (atomic_fetchadd_long(p, (unsigned long)(-(long)x)) - x); + return atomic_fetchadd_long(p, (unsigned long)(-(long)x)) - x; } JEMALLOC_INLINE bool atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { assert(sizeof(uint64_t) == sizeof(unsigned long)); - return (!atomic_cmpset_long(p, (unsigned long)c, (unsigned long)s)); + return !atomic_cmpset_long(p, (unsigned long)c, (unsigned long)s); } JEMALLOC_INLINE void @@ -163,17 +163,17 @@ atomic_write_u64(uint64_t *p, uint64_t x) { # elif (defined(JEMALLOC_OSATOMIC)) JEMALLOC_INLINE uint64_t atomic_add_u64(uint64_t *p, uint64_t x) { - return (OSAtomicAdd64((int64_t)x, (int64_t *)p)); + return OSAtomicAdd64((int64_t)x, (int64_t *)p); } JEMALLOC_INLINE uint64_t atomic_sub_u64(uint64_t *p, uint64_t x) { - return (OSAtomicAdd64(-((int64_t)x), (int64_t *)p)); + return OSAtomicAdd64(-((int64_t)x), (int64_t *)p); } JEMALLOC_INLINE bool atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { - return (!OSAtomicCompareAndSwap64(c, s, (int64_t *)p)); + return !OSAtomicCompareAndSwap64(c, s, (int64_t *)p); } JEMALLOC_INLINE void @@ -188,12 +188,12 @@ atomic_write_u64(uint64_t *p, uint64_t x) { # elif (defined(_MSC_VER)) JEMALLOC_INLINE uint64_t atomic_add_u64(uint64_t *p, uint64_t x) { - return (InterlockedExchangeAdd64(p, x) + x); + return InterlockedExchangeAdd64(p, x) + x; } JEMALLOC_INLINE uint64_t atomic_sub_u64(uint64_t *p, uint64_t x) { - return (InterlockedExchangeAdd64(p, -((int64_t)x)) - x); + return InterlockedExchangeAdd64(p, -((int64_t)x)) - x; } JEMALLOC_INLINE bool @@ -201,7 +201,7 @@ atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { uint64_t o; o = InterlockedCompareExchange64(p, s, c); - return (o != c); + return o != c; } JEMALLOC_INLINE void @@ -212,17 +212,17 @@ atomic_write_u64(uint64_t *p, uint64_t x) { defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8)) JEMALLOC_INLINE uint64_t atomic_add_u64(uint64_t *p, uint64_t x) { - return (__sync_add_and_fetch(p, x)); + return __sync_add_and_fetch(p, x); } JEMALLOC_INLINE uint64_t atomic_sub_u64(uint64_t *p, uint64_t x) { - return (__sync_sub_and_fetch(p, x)); + return __sync_sub_and_fetch(p, x); } JEMALLOC_INLINE bool atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { - return (!__sync_bool_compare_and_swap(p, c, s)); + return !__sync_bool_compare_and_swap(p, c, s); } JEMALLOC_INLINE void @@ -247,7 +247,7 @@ atomic_add_u32(uint32_t *p, uint32_t x) { : "m" (*p) /* Inputs. */ ); - return (t + x); + return t + x; } JEMALLOC_INLINE uint32_t @@ -262,7 +262,7 @@ atomic_sub_u32(uint32_t *p, uint32_t x) { : "m" (*p) /* Inputs. */ ); - return (t + x); + return t + x; } JEMALLOC_INLINE bool @@ -277,7 +277,7 @@ atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { : "memory" ); - return (!(bool)success); + return !(bool)success; } JEMALLOC_INLINE void @@ -293,19 +293,19 @@ atomic_write_u32(uint32_t *p, uint32_t x) { JEMALLOC_INLINE uint32_t atomic_add_u32(uint32_t *p, uint32_t x) { volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; - return (atomic_fetch_add(a, x) + x); + return atomic_fetch_add(a, x) + x; } JEMALLOC_INLINE uint32_t atomic_sub_u32(uint32_t *p, uint32_t x) { volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; - return (atomic_fetch_sub(a, x) - x); + return atomic_fetch_sub(a, x) - x; } JEMALLOC_INLINE bool atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; - return (!atomic_compare_exchange_strong(a, &c, s)); + return !atomic_compare_exchange_strong(a, &c, s); } JEMALLOC_INLINE void @@ -316,17 +316,17 @@ atomic_write_u32(uint32_t *p, uint32_t x) { #elif (defined(JEMALLOC_ATOMIC9)) JEMALLOC_INLINE uint32_t atomic_add_u32(uint32_t *p, uint32_t x) { - return (atomic_fetchadd_32(p, x) + x); + return atomic_fetchadd_32(p, x) + x; } JEMALLOC_INLINE uint32_t atomic_sub_u32(uint32_t *p, uint32_t x) { - return (atomic_fetchadd_32(p, (uint32_t)(-(int32_t)x)) - x); + return atomic_fetchadd_32(p, (uint32_t)(-(int32_t)x)) - x; } JEMALLOC_INLINE bool atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { - return (!atomic_cmpset_32(p, c, s)); + return !atomic_cmpset_32(p, c, s); } JEMALLOC_INLINE void @@ -336,17 +336,17 @@ atomic_write_u32(uint32_t *p, uint32_t x) { #elif (defined(JEMALLOC_OSATOMIC)) JEMALLOC_INLINE uint32_t atomic_add_u32(uint32_t *p, uint32_t x) { - return (OSAtomicAdd32((int32_t)x, (int32_t *)p)); + return OSAtomicAdd32((int32_t)x, (int32_t *)p); } JEMALLOC_INLINE uint32_t atomic_sub_u32(uint32_t *p, uint32_t x) { - return (OSAtomicAdd32(-((int32_t)x), (int32_t *)p)); + return OSAtomicAdd32(-((int32_t)x), (int32_t *)p); } JEMALLOC_INLINE bool atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { - return (!OSAtomicCompareAndSwap32(c, s, (int32_t *)p)); + return !OSAtomicCompareAndSwap32(c, s, (int32_t *)p); } JEMALLOC_INLINE void @@ -361,12 +361,12 @@ atomic_write_u32(uint32_t *p, uint32_t x) { #elif (defined(_MSC_VER)) JEMALLOC_INLINE uint32_t atomic_add_u32(uint32_t *p, uint32_t x) { - return (InterlockedExchangeAdd(p, x) + x); + return InterlockedExchangeAdd(p, x) + x; } JEMALLOC_INLINE uint32_t atomic_sub_u32(uint32_t *p, uint32_t x) { - return (InterlockedExchangeAdd(p, -((int32_t)x)) - x); + return InterlockedExchangeAdd(p, -((int32_t)x)) - x; } JEMALLOC_INLINE bool @@ -374,7 +374,7 @@ atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { uint32_t o; o = InterlockedCompareExchange(p, s, c); - return (o != c); + return o != c; } JEMALLOC_INLINE void @@ -385,17 +385,17 @@ atomic_write_u32(uint32_t *p, uint32_t x) { defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4)) JEMALLOC_INLINE uint32_t atomic_add_u32(uint32_t *p, uint32_t x) { - return (__sync_add_and_fetch(p, x)); + return __sync_add_and_fetch(p, x); } JEMALLOC_INLINE uint32_t atomic_sub_u32(uint32_t *p, uint32_t x) { - return (__sync_sub_and_fetch(p, x)); + return __sync_sub_and_fetch(p, x); } JEMALLOC_INLINE bool atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { - return (!__sync_bool_compare_and_swap(p, c, s)); + return !__sync_bool_compare_and_swap(p, c, s); } JEMALLOC_INLINE void @@ -411,27 +411,27 @@ atomic_write_u32(uint32_t *p, uint32_t x) { JEMALLOC_INLINE void * atomic_add_p(void **p, void *x) { #if (LG_SIZEOF_PTR == 3) - return ((void *)atomic_add_u64((uint64_t *)p, (uint64_t)x)); + return (void *)atomic_add_u64((uint64_t *)p, (uint64_t)x); #elif (LG_SIZEOF_PTR == 2) - return ((void *)atomic_add_u32((uint32_t *)p, (uint32_t)x)); + return (void *)atomic_add_u32((uint32_t *)p, (uint32_t)x); #endif } JEMALLOC_INLINE void * atomic_sub_p(void **p, void *x) { #if (LG_SIZEOF_PTR == 3) - return ((void *)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x))); + return (void *)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x)); #elif (LG_SIZEOF_PTR == 2) - return ((void *)atomic_add_u32((uint32_t *)p, (uint32_t)-((int32_t)x))); + return (void *)atomic_add_u32((uint32_t *)p, (uint32_t)-((int32_t)x)); #endif } JEMALLOC_INLINE bool atomic_cas_p(void **p, void *c, void *s) { #if (LG_SIZEOF_PTR == 3) - return (atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); + return atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s); #elif (LG_SIZEOF_PTR == 2) - return (atomic_cas_u32((uint32_t *)p, (uint32_t)c, (uint32_t)s)); + return atomic_cas_u32((uint32_t *)p, (uint32_t)c, (uint32_t)s); #endif } @@ -449,27 +449,27 @@ atomic_write_p(void **p, const void *x) { JEMALLOC_INLINE size_t atomic_add_zu(size_t *p, size_t x) { #if (LG_SIZEOF_PTR == 3) - return ((size_t)atomic_add_u64((uint64_t *)p, (uint64_t)x)); + return (size_t)atomic_add_u64((uint64_t *)p, (uint64_t)x); #elif (LG_SIZEOF_PTR == 2) - return ((size_t)atomic_add_u32((uint32_t *)p, (uint32_t)x)); + return (size_t)atomic_add_u32((uint32_t *)p, (uint32_t)x); #endif } JEMALLOC_INLINE size_t atomic_sub_zu(size_t *p, size_t x) { #if (LG_SIZEOF_PTR == 3) - return ((size_t)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x))); + return (size_t)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x)); #elif (LG_SIZEOF_PTR == 2) - return ((size_t)atomic_add_u32((uint32_t *)p, (uint32_t)-((int32_t)x))); + return (size_t)atomic_add_u32((uint32_t *)p, (uint32_t)-((int32_t)x)); #endif } JEMALLOC_INLINE bool atomic_cas_zu(size_t *p, size_t c, size_t s) { #if (LG_SIZEOF_PTR == 3) - return (atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); + return atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s); #elif (LG_SIZEOF_PTR == 2) - return (atomic_cas_u32((uint32_t *)p, (uint32_t)c, (uint32_t)s)); + return atomic_cas_u32((uint32_t *)p, (uint32_t)c, (uint32_t)s); #endif } @@ -487,29 +487,27 @@ atomic_write_zu(size_t *p, size_t x) { JEMALLOC_INLINE unsigned atomic_add_u(unsigned *p, unsigned x) { #if (LG_SIZEOF_INT == 3) - return ((unsigned)atomic_add_u64((uint64_t *)p, (uint64_t)x)); + return (unsigned)atomic_add_u64((uint64_t *)p, (uint64_t)x); #elif (LG_SIZEOF_INT == 2) - return ((unsigned)atomic_add_u32((uint32_t *)p, (uint32_t)x)); + return (unsigned)atomic_add_u32((uint32_t *)p, (uint32_t)x); #endif } JEMALLOC_INLINE unsigned atomic_sub_u(unsigned *p, unsigned x) { #if (LG_SIZEOF_INT == 3) - return ((unsigned)atomic_add_u64((uint64_t *)p, - (uint64_t)-((int64_t)x))); + return (unsigned)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x)); #elif (LG_SIZEOF_INT == 2) - return ((unsigned)atomic_add_u32((uint32_t *)p, - (uint32_t)-((int32_t)x))); + return (unsigned)atomic_add_u32((uint32_t *)p, (uint32_t)-((int32_t)x)); #endif } JEMALLOC_INLINE bool atomic_cas_u(unsigned *p, unsigned c, unsigned s) { #if (LG_SIZEOF_INT == 3) - return (atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s)); + return atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s); #elif (LG_SIZEOF_INT == 2) - return (atomic_cas_u32((uint32_t *)p, (uint32_t)c, (uint32_t)s)); + return atomic_cas_u32((uint32_t *)p, (uint32_t)c, (uint32_t)s); #endif } diff --git a/include/jemalloc/internal/base_inlines.h b/include/jemalloc/internal/base_inlines.h index 94fb1a95..aa8306ac 100644 --- a/include/jemalloc/internal/base_inlines.h +++ b/include/jemalloc/internal/base_inlines.h @@ -8,7 +8,7 @@ unsigned base_ind_get(const base_t *base); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BASE_C_)) JEMALLOC_INLINE unsigned base_ind_get(const base_t *base) { - return (base->ind); + return base->ind; } #endif diff --git a/include/jemalloc/internal/bitmap_inlines.h b/include/jemalloc/internal/bitmap_inlines.h index 1a2411df..df582bbe 100644 --- a/include/jemalloc/internal/bitmap_inlines.h +++ b/include/jemalloc/internal/bitmap_inlines.h @@ -22,10 +22,10 @@ bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) { for (i = 0; i < binfo->ngroups; i++) { if (bitmap[i] != 0) { - return (false); + return false; } } - return (true); + return true; #endif } @@ -37,7 +37,7 @@ bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { assert(bit < binfo->nbits); goff = bit >> LG_BITMAP_GROUP_NBITS; g = bitmap[goff]; - return (!(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK)))); + return !(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); } JEMALLOC_INLINE void @@ -103,7 +103,7 @@ bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) { bit = (i << LG_BITMAP_GROUP_NBITS) + (bit - 1); #endif bitmap_set(bitmap, binfo, bit); - return (bit); + return bit; } JEMALLOC_INLINE void diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index 274e69c6..379dd290 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -47,65 +47,65 @@ extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent) { rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - return (rtree_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, - dependent)); + return rtree_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, + dependent); } JEMALLOC_INLINE arena_t * extent_arena_get(const extent_t *extent) { - return (extent->e_arena); + return extent->e_arena; } JEMALLOC_INLINE void * extent_base_get(const extent_t *extent) { assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || !extent->e_slab); - return (PAGE_ADDR2BASE(extent->e_addr)); + return PAGE_ADDR2BASE(extent->e_addr); } JEMALLOC_INLINE void * extent_addr_get(const extent_t *extent) { assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || !extent->e_slab); - return (extent->e_addr); + return extent->e_addr; } JEMALLOC_INLINE size_t extent_size_get(const extent_t *extent) { - return (extent->e_size); + return extent->e_size; } JEMALLOC_INLINE size_t extent_usize_get(const extent_t *extent) { assert(!extent->e_slab); - return (extent->e_usize); + return extent->e_usize; } JEMALLOC_INLINE void * extent_before_get(const extent_t *extent) { - return ((void *)((uintptr_t)extent_base_get(extent) - PAGE)); + return (void *)((uintptr_t)extent_base_get(extent) - PAGE); } JEMALLOC_INLINE void * extent_last_get(const extent_t *extent) { - return ((void *)((uintptr_t)extent_base_get(extent) + - extent_size_get(extent) - PAGE)); + return (void *)((uintptr_t)extent_base_get(extent) + + extent_size_get(extent) - PAGE); } JEMALLOC_INLINE void * extent_past_get(const extent_t *extent) { - return ((void *)((uintptr_t)extent_base_get(extent) + - extent_size_get(extent))); + return (void *)((uintptr_t)extent_base_get(extent) + + extent_size_get(extent)); } JEMALLOC_INLINE size_t extent_sn_get(const extent_t *extent) { - return (extent->e_sn); + return extent->e_sn; } JEMALLOC_INLINE bool extent_active_get(const extent_t *extent) { - return (extent->e_active); + return extent->e_active; } JEMALLOC_INLINE bool @@ -115,35 +115,35 @@ extent_retained_get(const extent_t *extent) { JEMALLOC_INLINE bool extent_zeroed_get(const extent_t *extent) { - return (extent->e_zeroed); + return extent->e_zeroed; } JEMALLOC_INLINE bool extent_committed_get(const extent_t *extent) { - return (extent->e_committed); + return extent->e_committed; } JEMALLOC_INLINE bool extent_slab_get(const extent_t *extent) { - return (extent->e_slab); + return extent->e_slab; } JEMALLOC_INLINE arena_slab_data_t * extent_slab_data_get(extent_t *extent) { assert(extent->e_slab); - return (&extent->e_slab_data); + return &extent->e_slab_data; } JEMALLOC_INLINE const arena_slab_data_t * extent_slab_data_get_const(const extent_t *extent) { assert(extent->e_slab); - return (&extent->e_slab_data); + return &extent->e_slab_data; } JEMALLOC_INLINE prof_tctx_t * extent_prof_tctx_get(const extent_t *extent) { - return ((prof_tctx_t *)atomic_read_p( - &((extent_t *)extent)->e_prof_tctx_pun)); + return (prof_tctx_t *)atomic_read_p( + &((extent_t *)extent)->e_prof_tctx_pun); } JEMALLOC_INLINE void @@ -251,7 +251,7 @@ extent_sn_comp(const extent_t *a, const extent_t *b) { size_t a_sn = extent_sn_get(a); size_t b_sn = extent_sn_get(b); - return ((a_sn > b_sn) - (a_sn < b_sn)); + return (a_sn > b_sn) - (a_sn < b_sn); } JEMALLOC_INLINE int @@ -259,7 +259,7 @@ extent_ad_comp(const extent_t *a, const extent_t *b) { uintptr_t a_addr = (uintptr_t)extent_addr_get(a); uintptr_t b_addr = (uintptr_t)extent_addr_get(b); - return ((a_addr > b_addr) - (a_addr < b_addr)); + return (a_addr > b_addr) - (a_addr < b_addr); } JEMALLOC_INLINE int @@ -268,11 +268,11 @@ extent_snad_comp(const extent_t *a, const extent_t *b) { ret = extent_sn_comp(a, b); if (ret != 0) { - return (ret); + return ret; } ret = extent_ad_comp(a, b); - return (ret); + return ret; } #endif diff --git a/include/jemalloc/internal/hash_inlines.h b/include/jemalloc/internal/hash_inlines.h index 82ac1f42..b134492a 100644 --- a/include/jemalloc/internal/hash_inlines.h +++ b/include/jemalloc/internal/hash_inlines.h @@ -37,10 +37,10 @@ hash_get_block_32(const uint32_t *p, int i) { uint32_t ret; memcpy(&ret, (uint8_t *)(p + i), sizeof(uint32_t)); - return (ret); + return ret; } - return (p[i]); + return p[i]; } JEMALLOC_INLINE uint64_t @@ -50,10 +50,10 @@ hash_get_block_64(const uint64_t *p, int i) { uint64_t ret; memcpy(&ret, (uint8_t *)(p + i), sizeof(uint64_t)); - return (ret); + return ret; } - return (p[i]); + return p[i]; } JEMALLOC_INLINE uint32_t @@ -64,7 +64,7 @@ hash_fmix_32(uint32_t h) { h *= 0xc2b2ae35; h ^= h >> 16; - return (h); + return h; } JEMALLOC_INLINE uint64_t @@ -75,7 +75,7 @@ hash_fmix_64(uint64_t k) { k *= KQU(0xc4ceb9fe1a85ec53); k ^= k >> 33; - return (k); + return k; } JEMALLOC_INLINE uint32_t @@ -125,7 +125,7 @@ hash_x86_32(const void *key, int len, uint32_t seed) { h1 = hash_fmix_32(h1); - return (h1); + return h1; } UNUSED JEMALLOC_INLINE void diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index c951fab4..03a50a4d 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -552,7 +552,7 @@ ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind); JEMALLOC_ALWAYS_INLINE pszind_t psz2ind(size_t psz) { if (unlikely(psz > LARGE_MAXCLASS)) { - return (NPSIZES); + return NPSIZES; } { pszind_t x = lg_floor((psz<<1)-1); @@ -568,14 +568,14 @@ psz2ind(size_t psz) { ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); pszind_t ind = grp + mod; - return (ind); + return ind; } } JEMALLOC_INLINE size_t pind2sz_compute(pszind_t pind) { if (unlikely(pind == NPSIZES)) { - return (LARGE_MAXCLASS + PAGE); + return LARGE_MAXCLASS + PAGE; } { size_t grp = pind >> LG_SIZE_CLASS_GROUP; @@ -590,7 +590,7 @@ pind2sz_compute(pszind_t pind) { size_t mod_size = (mod+1) << lg_delta; size_t sz = grp_size + mod_size; - return (sz); + return sz; } } @@ -598,19 +598,19 @@ JEMALLOC_INLINE size_t pind2sz_lookup(pszind_t pind) { size_t ret = (size_t)pind2sz_tab[pind]; assert(ret == pind2sz_compute(pind)); - return (ret); + return ret; } JEMALLOC_INLINE size_t pind2sz(pszind_t pind) { assert(pind < NPSIZES+1); - return (pind2sz_lookup(pind)); + return pind2sz_lookup(pind); } JEMALLOC_INLINE size_t psz2u(size_t psz) { if (unlikely(psz > LARGE_MAXCLASS)) { - return (LARGE_MAXCLASS + PAGE); + return LARGE_MAXCLASS + PAGE; } { size_t x = lg_floor((psz<<1)-1); @@ -619,14 +619,14 @@ psz2u(size_t psz) { size_t delta = ZU(1) << lg_delta; size_t delta_mask = delta - 1; size_t usize = (psz + delta_mask) & ~delta_mask; - return (usize); + return usize; } } JEMALLOC_INLINE szind_t size2index_compute(size_t size) { if (unlikely(size > LARGE_MAXCLASS)) { - return (NSIZES); + return NSIZES; } #if (NTBINS != 0) if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { @@ -649,7 +649,7 @@ size2index_compute(size_t size) { ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); szind_t index = NTBINS + grp + mod; - return (index); + return index; } } @@ -659,7 +659,7 @@ size2index_lookup(size_t size) { { szind_t ret = (size2index_tab[(size-1) >> LG_TINY_MIN]); assert(ret == size2index_compute(size)); - return (ret); + return ret; } } @@ -667,9 +667,9 @@ JEMALLOC_ALWAYS_INLINE szind_t size2index(size_t size) { assert(size > 0); if (likely(size <= LOOKUP_MAXCLASS)) { - return (size2index_lookup(size)); + return size2index_lookup(size); } - return (size2index_compute(size)); + return size2index_compute(size); } JEMALLOC_INLINE size_t @@ -694,7 +694,7 @@ index2size_compute(szind_t index) { size_t mod_size = (mod+1) << lg_delta; size_t usize = grp_size + mod_size; - return (usize); + return usize; } } @@ -702,19 +702,19 @@ JEMALLOC_ALWAYS_INLINE size_t index2size_lookup(szind_t index) { size_t ret = (size_t)index2size_tab[index]; assert(ret == index2size_compute(index)); - return (ret); + return ret; } JEMALLOC_ALWAYS_INLINE size_t index2size(szind_t index) { assert(index < NSIZES); - return (index2size_lookup(index)); + return index2size_lookup(index); } JEMALLOC_ALWAYS_INLINE size_t s2u_compute(size_t size) { if (unlikely(size > LARGE_MAXCLASS)) { - return (0); + return 0; } #if (NTBINS > 0) if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { @@ -731,7 +731,7 @@ s2u_compute(size_t size) { size_t delta = ZU(1) << lg_delta; size_t delta_mask = delta - 1; size_t usize = (size + delta_mask) & ~delta_mask; - return (usize); + return usize; } } @@ -740,7 +740,7 @@ s2u_lookup(size_t size) { size_t ret = index2size_lookup(size2index_lookup(size)); assert(ret == s2u_compute(size)); - return (ret); + return ret; } /* @@ -751,9 +751,9 @@ JEMALLOC_ALWAYS_INLINE size_t s2u(size_t size) { assert(size > 0); if (likely(size <= LOOKUP_MAXCLASS)) { - return (s2u_lookup(size)); + return s2u_lookup(size); } - return (s2u_compute(size)); + return s2u_compute(size); } /* @@ -784,14 +784,14 @@ sa2u(size_t size, size_t alignment) { */ usize = s2u(ALIGNMENT_CEILING(size, alignment)); if (usize < LARGE_MINCLASS) { - return (usize); + return usize; } } /* Large size class. Beware of overflow. */ if (unlikely(alignment > LARGE_MAXCLASS)) { - return (0); + return 0; } /* Make sure result is a large size class. */ @@ -801,7 +801,7 @@ sa2u(size_t size, size_t alignment) { usize = s2u(size); if (usize < size) { /* size_t overflow. */ - return (0); + return 0; } } @@ -811,9 +811,9 @@ sa2u(size_t size, size_t alignment) { */ if (usize + large_pad + PAGE_CEILING(alignment) - PAGE < usize) { /* size_t overflow. */ - return (0); + return 0; } - return (usize); + return usize; } /* Choose an arena based on a per-thread value. */ @@ -822,7 +822,7 @@ arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { arena_t *ret; if (arena != NULL) { - return (arena); + return arena; } ret = internal ? tsd_iarena_get(tsd) : tsd_arena_get(tsd); @@ -830,17 +830,17 @@ arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { ret = arena_choose_hard(tsd, internal); } - return (ret); + return ret; } JEMALLOC_INLINE arena_t * arena_choose(tsd_t *tsd, arena_t *arena) { - return (arena_choose_impl(tsd, arena, false)); + return arena_choose_impl(tsd, arena, false); } JEMALLOC_INLINE arena_t * arena_ichoose(tsd_t *tsd, arena_t *arena) { - return (arena_choose_impl(tsd, arena, true)); + return arena_choose_impl(tsd, arena, true); } JEMALLOC_INLINE arena_tdata_t * @@ -850,7 +850,7 @@ arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing) { if (unlikely(arenas_tdata == NULL)) { /* arenas_tdata hasn't been initialized yet. */ - return (arena_tdata_get_hard(tsd, ind)); + return arena_tdata_get_hard(tsd, ind); } if (unlikely(ind >= tsd_narenas_tdata_get(tsd))) { /* @@ -863,9 +863,9 @@ arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing) { tdata = &arenas_tdata[ind]; if (likely(tdata != NULL) || !refresh_if_missing) { - return (tdata); + return tdata; } - return (arena_tdata_get_hard(tsd, ind)); + return arena_tdata_get_hard(tsd, ind); } JEMALLOC_INLINE arena_t * @@ -882,7 +882,7 @@ arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing) { (extent_hooks_t *)&extent_hooks_default); } } - return (ret); + return ret; } JEMALLOC_INLINE ticker_t * @@ -891,9 +891,9 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) { tdata = arena_tdata_get(tsd, ind, true); if (unlikely(tdata == NULL)) { - return (NULL); + return NULL; } - return (&tdata->decay_ticker); + return &tdata->decay_ticker; } #endif @@ -911,7 +911,7 @@ extent_t *iealloc(tsdn_t *tsdn, const void *ptr); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) JEMALLOC_ALWAYS_INLINE extent_t * iealloc(tsdn_t *tsdn, const void *ptr) { - return (extent_lookup(tsdn, ptr, true)); + return extent_lookup(tsdn, ptr, true); } #endif @@ -953,7 +953,7 @@ JEMALLOC_ALWAYS_INLINE arena_t * iaalloc(tsdn_t *tsdn, const void *ptr) { assert(ptr != NULL); - return (arena_aalloc(tsdn, ptr)); + return arena_aalloc(tsdn, ptr); } /* @@ -967,7 +967,7 @@ JEMALLOC_ALWAYS_INLINE size_t isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { assert(ptr != NULL); - return (arena_salloc(tsdn, extent, ptr)); + return arena_salloc(tsdn, extent, ptr); } JEMALLOC_ALWAYS_INLINE void * @@ -985,13 +985,13 @@ iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn, iealloc(tsdn, ret), ret)); } - return (ret); + return ret; } JEMALLOC_ALWAYS_INLINE void * ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, bool slow_path) { - return (iallocztm(tsd_tsdn(tsd), size, ind, zero, tcache_get(tsd, true), - false, NULL, slow_path)); + return iallocztm(tsd_tsdn(tsd), size, ind, zero, tcache_get(tsd, true), + false, NULL, slow_path); } JEMALLOC_ALWAYS_INLINE void * @@ -1011,19 +1011,19 @@ ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn, iealloc(tsdn, ret), ret)); } - return (ret); + return ret; } JEMALLOC_ALWAYS_INLINE void * ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) { - return (ipallocztm(tsdn, usize, alignment, zero, tcache, false, arena)); + return ipallocztm(tsdn, usize, alignment, zero, tcache, false, arena); } JEMALLOC_ALWAYS_INLINE void * ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero) { - return (ipallocztm(tsd_tsdn(tsd), usize, alignment, zero, - tcache_get(tsd, true), false, NULL)); + return ipallocztm(tsd_tsdn(tsd), usize, alignment, zero, + tcache_get(tsd, true), false, NULL); } JEMALLOC_ALWAYS_INLINE size_t @@ -1040,13 +1040,13 @@ ivsalloc(tsdn_t *tsdn, const void *ptr) { * */ extent = extent_lookup(tsdn, ptr, false); if (extent == NULL) { - return (0); + return 0; } assert(extent_active_get(extent)); /* Only slab members should be looked up via interior pointers. */ assert(extent_addr_get(extent) == ptr || extent_slab_get(extent)); - return (isalloc(tsdn, extent, ptr)); + return isalloc(tsdn, extent, ptr); } JEMALLOC_ALWAYS_INLINE void @@ -1085,21 +1085,21 @@ iralloct_realign(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, usize = sa2u(size + extra, alignment); if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { - return (NULL); + return NULL; } p = ipalloct(tsdn, usize, alignment, zero, tcache, arena); if (p == NULL) { if (extra == 0) { - return (NULL); + return NULL; } /* Try again, without extra this time. */ usize = sa2u(size, alignment); if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { - return (NULL); + return NULL; } p = ipalloct(tsdn, usize, alignment, zero, tcache, arena); if (p == NULL) { - return (NULL); + return NULL; } } /* @@ -1109,7 +1109,7 @@ iralloct_realign(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, copysize = (size < oldsize) ? size : oldsize; memcpy(p, ptr, copysize); isdalloct(tsdn, extent, ptr, oldsize, tcache, true); - return (p); + return p; } JEMALLOC_ALWAYS_INLINE void * @@ -1124,19 +1124,19 @@ iralloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, * Existing object alignment is inadequate; allocate new space * and copy. */ - return (iralloct_realign(tsdn, extent, ptr, oldsize, size, 0, - alignment, zero, tcache, arena)); + return iralloct_realign(tsdn, extent, ptr, oldsize, size, 0, + alignment, zero, tcache, arena); } - return (arena_ralloc(tsdn, arena, extent, ptr, oldsize, size, alignment, - zero, tcache)); + return arena_ralloc(tsdn, arena, extent, ptr, oldsize, size, alignment, + zero, tcache); } JEMALLOC_ALWAYS_INLINE void * iralloc(tsd_t *tsd, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero) { - return (iralloct(tsd_tsdn(tsd), extent, ptr, oldsize, size, alignment, - zero, tcache_get(tsd, true), NULL)); + return iralloct(tsd_tsdn(tsd), extent, ptr, oldsize, size, alignment, + zero, tcache_get(tsd, true), NULL); } JEMALLOC_ALWAYS_INLINE bool @@ -1148,11 +1148,11 @@ ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1)) != 0) { /* Existing object alignment is inadequate. */ - return (true); + return true; } - return (arena_ralloc_no_move(tsdn, extent, ptr, oldsize, size, extra, - zero)); + return arena_ralloc_no_move(tsdn, extent, ptr, oldsize, size, extra, + zero); } #endif diff --git a/include/jemalloc/internal/ph.h b/include/jemalloc/internal/ph.h index 61dfdc0b..b8141eff 100644 --- a/include/jemalloc/internal/ph.h +++ b/include/jemalloc/internal/ph.h @@ -218,10 +218,10 @@ a_prefix##empty(a_ph_type *ph) { \ a_attr a_type * \ a_prefix##first(a_ph_type *ph) { \ if (ph->ph_root == NULL) { \ - return (NULL); \ + return NULL; \ } \ ph_merge_aux(a_type, a_field, ph, a_cmp); \ - return (ph->ph_root); \ + return ph->ph_root; \ } \ a_attr void \ a_prefix##insert(a_ph_type *ph, a_type *phn) { \ @@ -255,7 +255,7 @@ a_prefix##remove_first(a_ph_type *ph) { \ a_type *ret; \ \ if (ph->ph_root == NULL) { \ - return (NULL); \ + return NULL; \ } \ ph_merge_aux(a_type, a_field, ph, a_cmp); \ \ @@ -264,7 +264,7 @@ a_prefix##remove_first(a_ph_type *ph) { \ ph_merge_children(a_type, a_field, ph->ph_root, a_cmp, \ ph->ph_root); \ \ - return (ret); \ + return ret; \ } \ a_attr void \ a_prefix##remove(a_ph_type *ph, a_type *phn) { \ diff --git a/include/jemalloc/internal/prng_inlines.h b/include/jemalloc/internal/prng_inlines.h index 124b1baa..646e07b7 100644 --- a/include/jemalloc/internal/prng_inlines.h +++ b/include/jemalloc/internal/prng_inlines.h @@ -19,20 +19,20 @@ size_t prng_range_zu(size_t *state, size_t range, bool atomic); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PRNG_C_)) JEMALLOC_ALWAYS_INLINE uint32_t prng_state_next_u32(uint32_t state) { - return ((state * PRNG_A_32) + PRNG_C_32); + return (state * PRNG_A_32) + PRNG_C_32; } JEMALLOC_ALWAYS_INLINE uint64_t prng_state_next_u64(uint64_t state) { - return ((state * PRNG_A_64) + PRNG_C_64); + return (state * PRNG_A_64) + PRNG_C_64; } JEMALLOC_ALWAYS_INLINE size_t prng_state_next_zu(size_t state) { #if LG_SIZEOF_PTR == 2 - return ((state * PRNG_A_32) + PRNG_C_32); + return (state * PRNG_A_32) + PRNG_C_32; #elif LG_SIZEOF_PTR == 3 - return ((state * PRNG_A_64) + PRNG_C_64); + return (state * PRNG_A_64) + PRNG_C_64; #else #error Unsupported pointer size #endif @@ -58,7 +58,7 @@ prng_lg_range_u32(uint32_t *state, unsigned lg_range, bool atomic) { } ret = state1 >> (32 - lg_range); - return (ret); + return ret; } /* 64-bit atomic operations cannot be supported on all relevant platforms. */ @@ -73,7 +73,7 @@ prng_lg_range_u64(uint64_t *state, unsigned lg_range) { *state = state1; ret = state1 >> (64 - lg_range); - return (ret); + return ret; } JEMALLOC_ALWAYS_INLINE size_t @@ -96,7 +96,7 @@ prng_lg_range_zu(size_t *state, unsigned lg_range, bool atomic) { } ret = state1 >> ((ZU(1) << (3 + LG_SIZEOF_PTR)) - lg_range); - return (ret); + return ret; } JEMALLOC_ALWAYS_INLINE uint32_t @@ -114,7 +114,7 @@ prng_range_u32(uint32_t *state, uint32_t range, bool atomic) { ret = prng_lg_range_u32(state, lg_range, atomic); } while (ret >= range); - return (ret); + return ret; } JEMALLOC_ALWAYS_INLINE uint64_t @@ -132,7 +132,7 @@ prng_range_u64(uint64_t *state, uint64_t range) { ret = prng_lg_range_u64(state, lg_range); } while (ret >= range); - return (ret); + return ret; } JEMALLOC_ALWAYS_INLINE size_t @@ -150,7 +150,7 @@ prng_range_zu(size_t *state, size_t range, bool atomic) { ret = prng_lg_range_zu(state, lg_range, atomic); } while (ret >= range); - return (ret); + return ret; } #endif diff --git a/include/jemalloc/internal/prof_inlines.h b/include/jemalloc/internal/prof_inlines.h index bb9093a8..aba2936a 100644 --- a/include/jemalloc/internal/prof_inlines.h +++ b/include/jemalloc/internal/prof_inlines.h @@ -34,7 +34,7 @@ prof_active_get_unlocked(void) { * prof_active in the fast path, so there are no guarantees regarding * how long it will take for all threads to notice state changes. */ - return (prof_active); + return prof_active; } JEMALLOC_ALWAYS_INLINE bool @@ -44,7 +44,7 @@ prof_gdump_get_unlocked(void) { * there are no guarantees regarding how long it will take for all * threads to notice state changes. */ - return (prof_gdump_val); + return prof_gdump_val; } JEMALLOC_ALWAYS_INLINE prof_tdata_t * @@ -67,7 +67,7 @@ prof_tdata_get(tsd_t *tsd, bool create) { assert(tdata == NULL || tdata->attached); } - return (tdata); + return tdata; } JEMALLOC_ALWAYS_INLINE prof_tctx_t * @@ -75,7 +75,7 @@ prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { cassert(config_prof); assert(ptr != NULL); - return (arena_prof_tctx_get(tsdn, extent, ptr)); + return arena_prof_tctx_get(tsdn, extent, ptr); } JEMALLOC_ALWAYS_INLINE void @@ -113,20 +113,20 @@ prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update, } if (unlikely(tdata == NULL)) { - return (true); + return true; } if (likely(tdata->bytes_until_sample >= usize)) { if (update) { tdata->bytes_until_sample -= usize; } - return (true); + return true; } else { /* Compute new sample threshold. */ if (update) { prof_sample_threshold_update(tdata); } - return (!tdata->active); + return !tdata->active; } } @@ -147,7 +147,7 @@ prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update) { ret = prof_lookup(tsd, &bt); } - return (ret); + return ret; } JEMALLOC_ALWAYS_INLINE void diff --git a/include/jemalloc/internal/rb.h b/include/jemalloc/internal/rb.h index a4b5a65e..7018325f 100644 --- a/include/jemalloc/internal/rb.h +++ b/include/jemalloc/internal/rb.h @@ -348,13 +348,13 @@ a_attr a_type * \ a_prefix##first(a_rbt_type *rbtree) { \ a_type *ret; \ rbtn_first(a_type, a_field, rbtree, rbtree->rbt_root, ret); \ - return (ret); \ + return ret; \ } \ a_attr a_type * \ a_prefix##last(a_rbt_type *rbtree) { \ a_type *ret; \ rbtn_last(a_type, a_field, rbtree, rbtree->rbt_root, ret); \ - return (ret); \ + return ret; \ } \ a_attr a_type * \ a_prefix##next(a_rbt_type *rbtree, a_type *node) { \ @@ -379,7 +379,7 @@ a_prefix##next(a_rbt_type *rbtree, a_type *node) { \ assert(tnode != NULL); \ } \ } \ - return (ret); \ + return ret; \ } \ a_attr a_type * \ a_prefix##prev(a_rbt_type *rbtree, a_type *node) { \ @@ -404,7 +404,7 @@ a_prefix##prev(a_rbt_type *rbtree, a_type *node) { \ assert(tnode != NULL); \ } \ } \ - return (ret); \ + return ret; \ } \ a_attr a_type * \ a_prefix##search(a_rbt_type *rbtree, const a_type *key) { \ @@ -419,7 +419,7 @@ a_prefix##search(a_rbt_type *rbtree, const a_type *key) { \ ret = rbtn_right_get(a_type, a_field, ret); \ } \ } \ - return (ret); \ + return ret; \ } \ a_attr a_type * \ a_prefix##nsearch(a_rbt_type *rbtree, const a_type *key) { \ @@ -438,7 +438,7 @@ a_prefix##nsearch(a_rbt_type *rbtree, const a_type *key) { \ break; \ } \ } \ - return (ret); \ + return ret; \ } \ a_attr a_type * \ a_prefix##psearch(a_rbt_type *rbtree, const a_type *key) { \ @@ -457,7 +457,7 @@ a_prefix##psearch(a_rbt_type *rbtree, const a_type *key) { \ break; \ } \ } \ - return (ret); \ + return ret; \ } \ a_attr void \ a_prefix##insert(a_rbt_type *rbtree, a_type *node) { \ @@ -872,16 +872,16 @@ a_attr a_type * \ a_prefix##iter_recurse(a_rbt_type *rbtree, a_type *node, \ a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \ if (node == NULL) { \ - return (NULL); \ + return NULL; \ } else { \ a_type *ret; \ if ((ret = a_prefix##iter_recurse(rbtree, rbtn_left_get(a_type, \ a_field, node), cb, arg)) != NULL || (ret = cb(rbtree, node, \ arg)) != NULL) { \ - return (ret); \ + return ret; \ } \ - return (a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \ - a_field, node), cb, arg)); \ + return a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \ + a_field, node), cb, arg); \ } \ } \ a_attr a_type * \ @@ -893,20 +893,20 @@ a_prefix##iter_start(a_rbt_type *rbtree, a_type *start, a_type *node, \ if ((ret = a_prefix##iter_start(rbtree, start, \ rbtn_left_get(a_type, a_field, node), cb, arg)) != NULL || \ (ret = cb(rbtree, node, arg)) != NULL) { \ - return (ret); \ + return ret; \ } \ - return (a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \ - a_field, node), cb, arg)); \ + return a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \ + a_field, node), cb, arg); \ } else if (cmp > 0) { \ - return (a_prefix##iter_start(rbtree, start, \ - rbtn_right_get(a_type, a_field, node), cb, arg)); \ + return a_prefix##iter_start(rbtree, start, \ + rbtn_right_get(a_type, a_field, node), cb, arg); \ } else { \ a_type *ret; \ if ((ret = cb(rbtree, node, arg)) != NULL) { \ - return (ret); \ + return ret; \ } \ - return (a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \ - a_field, node), cb, arg)); \ + return a_prefix##iter_recurse(rbtree, rbtn_right_get(a_type, \ + a_field, node), cb, arg); \ } \ } \ a_attr a_type * \ @@ -919,22 +919,22 @@ a_prefix##iter(a_rbt_type *rbtree, a_type *start, a_type *(*cb)( \ } else { \ ret = a_prefix##iter_recurse(rbtree, rbtree->rbt_root, cb, arg);\ } \ - return (ret); \ + return ret; \ } \ a_attr a_type * \ a_prefix##reverse_iter_recurse(a_rbt_type *rbtree, a_type *node, \ a_type *(*cb)(a_rbt_type *, a_type *, void *), void *arg) { \ if (node == NULL) { \ - return (NULL); \ + return NULL; \ } else { \ a_type *ret; \ if ((ret = a_prefix##reverse_iter_recurse(rbtree, \ rbtn_right_get(a_type, a_field, node), cb, arg)) != NULL || \ (ret = cb(rbtree, node, arg)) != NULL) { \ - return (ret); \ + return ret; \ } \ - return (a_prefix##reverse_iter_recurse(rbtree, \ - rbtn_left_get(a_type, a_field, node), cb, arg)); \ + return a_prefix##reverse_iter_recurse(rbtree, \ + rbtn_left_get(a_type, a_field, node), cb, arg); \ } \ } \ a_attr a_type * \ @@ -947,20 +947,20 @@ a_prefix##reverse_iter_start(a_rbt_type *rbtree, a_type *start, \ if ((ret = a_prefix##reverse_iter_start(rbtree, start, \ rbtn_right_get(a_type, a_field, node), cb, arg)) != NULL || \ (ret = cb(rbtree, node, arg)) != NULL) { \ - return (ret); \ + return ret; \ } \ - return (a_prefix##reverse_iter_recurse(rbtree, \ - rbtn_left_get(a_type, a_field, node), cb, arg)); \ + return a_prefix##reverse_iter_recurse(rbtree, \ + rbtn_left_get(a_type, a_field, node), cb, arg); \ } else if (cmp < 0) { \ - return (a_prefix##reverse_iter_start(rbtree, start, \ - rbtn_left_get(a_type, a_field, node), cb, arg)); \ + return a_prefix##reverse_iter_start(rbtree, start, \ + rbtn_left_get(a_type, a_field, node), cb, arg); \ } else { \ a_type *ret; \ if ((ret = cb(rbtree, node, arg)) != NULL) { \ - return (ret); \ + return ret; \ } \ - return (a_prefix##reverse_iter_recurse(rbtree, \ - rbtn_left_get(a_type, a_field, node), cb, arg)); \ + return a_prefix##reverse_iter_recurse(rbtree, \ + rbtn_left_get(a_type, a_field, node), cb, arg); \ } \ } \ a_attr a_type * \ @@ -974,7 +974,7 @@ a_prefix##reverse_iter(a_rbt_type *rbtree, a_type *start, \ ret = a_prefix##reverse_iter_recurse(rbtree, rbtree->rbt_root, \ cb, arg); \ } \ - return (ret); \ + return ret; \ } \ a_attr void \ a_prefix##destroy_recurse(a_rbt_type *rbtree, a_type *node, void (*cb)( \ diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 9e512e9f..c9a06f64 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -41,13 +41,13 @@ rtree_start_level(const rtree_t *rtree, uintptr_t key) { unsigned start_level; if (unlikely(key == 0)) { - return (rtree->height - 1); + return rtree->height - 1; } start_level = rtree->start_level[(lg_floor(key) + 1) >> LG_RTREE_BITS_PER_LEVEL]; assert(start_level < rtree->height); - return (start_level); + return start_level; } JEMALLOC_ALWAYS_INLINE unsigned @@ -67,7 +67,7 @@ rtree_ctx_start_level(const rtree_t *rtree, const rtree_ctx_t *rtree_ctx, start_level = rtree->start_level[(lg_floor(key_diff) + 1) >> LG_RTREE_BITS_PER_LEVEL]; assert(start_level < rtree->height); - return (start_level); + return start_level; } JEMALLOC_ALWAYS_INLINE uintptr_t @@ -92,7 +92,7 @@ rtree_child_tryread(rtree_elm_t *elm, bool dependent) { child = (rtree_elm_t *)atomic_read_p(&elm->pun); } assert(!dependent || child != NULL); - return (child); + return child; } JEMALLOC_ALWAYS_INLINE rtree_elm_t * @@ -105,7 +105,7 @@ rtree_child_read(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level, child = rtree_child_read_hard(tsdn, rtree, elm, level); } assert(!dependent || child != NULL); - return (child); + return child; } JEMALLOC_ALWAYS_INLINE extent_t * @@ -132,7 +132,7 @@ rtree_elm_read(rtree_elm_t *elm, bool dependent) { /* Mask the lock bit. */ extent = (extent_t *)((uintptr_t)extent & ~((uintptr_t)0x1)); - return (extent); + return extent; } JEMALLOC_INLINE void @@ -151,7 +151,7 @@ rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent) { &rtree->levels[level].subtree_pun); } assert(!dependent || subtree != NULL); - return (subtree); + return subtree; } JEMALLOC_ALWAYS_INLINE rtree_elm_t * @@ -164,7 +164,7 @@ rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, unsigned level, subtree = rtree_subtree_read_hard(tsdn, rtree, level); } assert(!dependent || subtree != NULL); - return (subtree); + return subtree; } JEMALLOC_ALWAYS_INLINE rtree_elm_t * @@ -179,7 +179,7 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, if (dependent || init_missing) { if (likely(rtree_ctx->valid)) { if (key == rtree_ctx->key) { - return (rtree_ctx->elms[rtree->height]); + return rtree_ctx->elms[rtree->height]; } else { unsigned no_ctx_start_level = rtree_start_level(rtree, key); @@ -234,7 +234,7 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, if (init_missing) { \ rtree_ctx->valid = false; \ } \ - return (NULL); \ + return NULL; \ } \ subkey = rtree_subkey(rtree, key, level - \ RTREE_GET_BIAS); \ @@ -253,7 +253,7 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, if (init_missing) { \ rtree_ctx->valid = false; \ } \ - return (NULL); \ + return NULL; \ } \ subkey = rtree_subkey(rtree, key, level - \ RTREE_GET_BIAS); \ @@ -266,7 +266,7 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, rtree_ctx->elms[level - RTREE_GET_BIAS + 1] = \ node; \ } \ - return (node); + return node; #if RTREE_HEIGHT_MAX > 1 RTREE_GET_SUBTREE(0) #endif @@ -334,12 +334,12 @@ rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, false, true); if (elm == NULL) { - return (true); + return true; } assert(rtree_elm_read(elm, false) == NULL); rtree_elm_write(elm, extent); - return (false); + return false; } JEMALLOC_ALWAYS_INLINE extent_t * @@ -349,10 +349,10 @@ rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, dependent, false); if (elm == NULL) { - return (NULL); + return NULL; } - return (rtree_elm_read(elm, dependent)); + return rtree_elm_read(elm, dependent); } JEMALLOC_INLINE rtree_elm_t * @@ -363,7 +363,7 @@ rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, dependent, init_missing); if (!dependent && elm == NULL) { - return (NULL); + return NULL; } { extent_t *extent; @@ -380,7 +380,7 @@ rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, rtree_elm_witness_acquire(tsdn, rtree, key, elm); } - return (elm); + return elm; } JEMALLOC_INLINE extent_t * @@ -395,7 +395,7 @@ rtree_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm) { rtree_elm_witness_access(tsdn, rtree, elm); } - return (extent); + return extent; } JEMALLOC_INLINE void diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index 4721ba30..a90107f9 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -44,7 +44,7 @@ tcache_enabled_get(void) { tsd_tcache_enabled_set(tsd, tcache_enabled); } - return ((bool)tcache_enabled); + return (bool)tcache_enabled; } JEMALLOC_INLINE void @@ -69,19 +69,19 @@ tcache_get(tsd_t *tsd, bool create) { tcache_t *tcache; if (!config_tcache) { - return (NULL); + return NULL; } tcache = tsd_tcache_get(tsd); if (!create) { - return (tcache); + return tcache; } if (unlikely(tcache == NULL) && tsd_nominal(tsd)) { tcache = tcache_get_hard(tsd); tsd_tcache_set(tsd, tcache); } - return (tcache); + return tcache; } JEMALLOC_ALWAYS_INLINE void @@ -102,7 +102,7 @@ tcache_alloc_easy(tcache_bin_t *tbin, bool *tcache_success) { if (unlikely(tbin->ncached == 0)) { tbin->low_water = -1; *tcache_success = false; - return (NULL); + return NULL; } /* * tcache_success (instead of ret) should be checked upon the return of @@ -119,7 +119,7 @@ tcache_alloc_easy(tcache_bin_t *tbin, bool *tcache_success) { tbin->low_water = tbin->ncached; } - return (ret); + return ret; } JEMALLOC_ALWAYS_INLINE void * @@ -138,13 +138,13 @@ tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, bool tcache_hard_success; arena = arena_choose(tsd, arena); if (unlikely(arena == NULL)) { - return (NULL); + return NULL; } ret = tcache_alloc_small_hard(tsd_tsdn(tsd), arena, tcache, tbin, binind, &tcache_hard_success); if (tcache_hard_success == false) { - return (NULL); + return NULL; } } @@ -182,7 +182,7 @@ tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, tcache->prof_accumbytes += usize; } tcache_event(tsd, tcache); - return (ret); + return ret; } JEMALLOC_ALWAYS_INLINE void * @@ -203,12 +203,12 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, */ arena = arena_choose(tsd, arena); if (unlikely(arena == NULL)) { - return (NULL); + return NULL; } ret = large_malloc(tsd_tsdn(tsd), arena, s2u(size), zero); if (ret == NULL) { - return (NULL); + return NULL; } } else { size_t usize JEMALLOC_CC_SILENCE_INIT(0); @@ -242,7 +242,7 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, } tcache_event(tsd, tcache); - return (ret); + return ret; } JEMALLOC_ALWAYS_INLINE void @@ -306,7 +306,7 @@ tcaches_get(tsd_t *tsd, unsigned ind) { elm->tcache = tcache_create(tsd_tsdn(tsd), arena_choose(tsd, NULL)); } - return (elm->tcache); + return elm->tcache; } #endif diff --git a/include/jemalloc/internal/ticker_inlines.h b/include/jemalloc/internal/ticker_inlines.h index 6cc61343..9102ba6d 100644 --- a/include/jemalloc/internal/ticker_inlines.h +++ b/include/jemalloc/internal/ticker_inlines.h @@ -23,14 +23,14 @@ ticker_copy(ticker_t *ticker, const ticker_t *other) { JEMALLOC_INLINE int32_t ticker_read(const ticker_t *ticker) { - return (ticker->tick); + return ticker->tick; } JEMALLOC_INLINE bool ticker_ticks(ticker_t *ticker, int32_t nticks) { if (unlikely(ticker->tick < nticks)) { ticker->tick = ticker->nticks; - return (true); + return true; } ticker->tick -= nticks; return(false); @@ -38,7 +38,7 @@ ticker_ticks(ticker_t *ticker, int32_t nticks) { JEMALLOC_INLINE bool ticker_tick(ticker_t *ticker) { - return (ticker_ticks(ticker, 1)); + return ticker_ticks(ticker, 1); } #endif diff --git a/include/jemalloc/internal/tsd_inlines.h b/include/jemalloc/internal/tsd_inlines.h index 2093d610..4aafb8dc 100644 --- a/include/jemalloc/internal/tsd_inlines.h +++ b/include/jemalloc/internal/tsd_inlines.h @@ -29,7 +29,7 @@ tsd_fetch_impl(bool init) { tsd_t *tsd = tsd_get(init); if (!init && tsd_get_allocates() && tsd == NULL) { - return (NULL); + return NULL; } assert(tsd != NULL); @@ -46,17 +46,17 @@ tsd_fetch_impl(bool init) { } } - return (tsd); + return tsd; } JEMALLOC_ALWAYS_INLINE tsd_t * tsd_fetch(void) { - return (tsd_fetch_impl(true)); + return tsd_fetch_impl(true); } JEMALLOC_ALWAYS_INLINE tsdn_t * tsd_tsdn(tsd_t *tsd) { - return ((tsdn_t *)tsd); + return (tsdn_t *)tsd; } JEMALLOC_INLINE bool @@ -67,12 +67,12 @@ tsd_nominal(tsd_t *tsd) { #define O(n, t, c) \ JEMALLOC_ALWAYS_INLINE t * \ tsd_##n##p_get(tsd_t *tsd) { \ - return (&tsd->n); \ + return &tsd->n; \ } \ \ JEMALLOC_ALWAYS_INLINE t \ tsd_##n##_get(tsd_t *tsd) { \ - return (*tsd_##n##p_get(tsd)); \ + return *tsd_##n##p_get(tsd); \ } \ \ JEMALLOC_ALWAYS_INLINE void \ @@ -86,22 +86,22 @@ MALLOC_TSD JEMALLOC_ALWAYS_INLINE tsdn_t * tsdn_fetch(void) { if (!tsd_booted_get()) { - return (NULL); + return NULL; } - return (tsd_tsdn(tsd_fetch_impl(false))); + return tsd_tsdn(tsd_fetch_impl(false)); } JEMALLOC_ALWAYS_INLINE bool tsdn_null(const tsdn_t *tsdn) { - return (tsdn == NULL); + return tsdn == NULL; } JEMALLOC_ALWAYS_INLINE tsd_t * tsdn_tsd(tsdn_t *tsdn) { assert(!tsdn_null(tsdn)); - return (&tsdn->tsd); + return &tsdn->tsd; } JEMALLOC_ALWAYS_INLINE rtree_ctx_t * @@ -113,9 +113,9 @@ tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback) { if (unlikely(tsdn_null(tsdn))) { static const rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; memcpy(fallback, &rtree_ctx, sizeof(rtree_ctx_t)); - return (fallback); + return fallback; } - return (tsd_rtree_ctxp_get(tsdn_tsd(tsdn))); + return tsd_rtree_ctxp_get(tsdn_tsd(tsdn)); } #endif diff --git a/include/jemalloc/internal/tsd_types.h b/include/jemalloc/internal/tsd_types.h index ec40d9a7..a1dce928 100644 --- a/include/jemalloc/internal/tsd_types.h +++ b/include/jemalloc/internal/tsd_types.h @@ -180,7 +180,7 @@ a_name##tsd_cleanup_wrapper(void) { \ a_name##tsd_initialized = false; \ a_cleanup(&a_name##tsd_tls); \ } \ - return (a_name##tsd_initialized); \ + return a_name##tsd_initialized; \ } \ a_attr bool \ a_name##tsd_boot0(void) { \ @@ -189,7 +189,7 @@ a_name##tsd_boot0(void) { \ &a_name##tsd_cleanup_wrapper); \ } \ a_name##tsd_booted = true; \ - return (false); \ + return false; \ } \ a_attr void \ a_name##tsd_boot1(void) { \ @@ -197,21 +197,21 @@ a_name##tsd_boot1(void) { \ } \ a_attr bool \ a_name##tsd_boot(void) { \ - return (a_name##tsd_boot0()); \ + return a_name##tsd_boot0(); \ } \ a_attr bool \ a_name##tsd_booted_get(void) { \ - return (a_name##tsd_booted); \ + return a_name##tsd_booted; \ } \ a_attr bool \ a_name##tsd_get_allocates(void) { \ - return (false); \ + return false; \ } \ /* Get/set. */ \ a_attr a_type * \ a_name##tsd_get(bool init) { \ assert(a_name##tsd_booted); \ - return (&a_name##tsd_tls); \ + return &a_name##tsd_tls; \ } \ a_attr void \ a_name##tsd_set(a_type *val) { \ @@ -232,11 +232,11 @@ a_name##tsd_boot0(void) { \ if (a_cleanup != malloc_tsd_no_cleanup) { \ if (pthread_key_create(&a_name##tsd_tsd, a_cleanup) != \ 0) { \ - return (true); \ + return true; \ } \ } \ a_name##tsd_booted = true; \ - return (false); \ + return false; \ } \ a_attr void \ a_name##tsd_boot1(void) { \ @@ -244,21 +244,21 @@ a_name##tsd_boot1(void) { \ } \ a_attr bool \ a_name##tsd_boot(void) { \ - return (a_name##tsd_boot0()); \ + return a_name##tsd_boot0(); \ } \ a_attr bool \ a_name##tsd_booted_get(void) { \ - return (a_name##tsd_booted); \ + return a_name##tsd_booted; \ } \ a_attr bool \ a_name##tsd_get_allocates(void) { \ - return (false); \ + return false; \ } \ /* Get/set. */ \ a_attr a_type * \ a_name##tsd_get(bool init) { \ assert(a_name##tsd_booted); \ - return (&a_name##tsd_tls); \ + return &a_name##tsd_tls; \ } \ a_attr void \ a_name##tsd_set(a_type *val) { \ @@ -289,7 +289,7 @@ a_name##tsd_cleanup_wrapper(void) { \ SetLastError(error); \ \ if (wrapper == NULL) { \ - return (false); \ + return false; \ } \ if (a_cleanup != malloc_tsd_no_cleanup && \ wrapper->initialized) { \ @@ -297,11 +297,11 @@ a_name##tsd_cleanup_wrapper(void) { \ a_cleanup(&wrapper->val); \ if (wrapper->initialized) { \ /* Trigger another cleanup round. */ \ - return (true); \ + return true; \ } \ } \ malloc_tsd_dalloc(wrapper); \ - return (false); \ + return false; \ } \ a_attr void \ a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) { \ @@ -331,13 +331,13 @@ a_name##tsd_wrapper_get(bool init) { \ } \ a_name##tsd_wrapper_set(wrapper); \ } \ - return (wrapper); \ + return wrapper; \ } \ a_attr bool \ a_name##tsd_boot0(void) { \ a_name##tsd_tsd = TlsAlloc(); \ if (a_name##tsd_tsd == TLS_OUT_OF_INDEXES) { \ - return (true); \ + return true; \ } \ if (a_cleanup != malloc_tsd_no_cleanup) { \ malloc_tsd_cleanup_register( \ @@ -345,7 +345,7 @@ a_name##tsd_boot0(void) { \ } \ a_name##tsd_wrapper_set(&a_name##tsd_boot_wrapper); \ a_name##tsd_booted = true; \ - return (false); \ + return false; \ } \ a_attr void \ a_name##tsd_boot1(void) { \ @@ -364,18 +364,18 @@ a_name##tsd_boot1(void) { \ a_attr bool \ a_name##tsd_boot(void) { \ if (a_name##tsd_boot0()) { \ - return (true); \ + return true; \ } \ a_name##tsd_boot1(); \ - return (false); \ + return false; \ } \ a_attr bool \ a_name##tsd_booted_get(void) { \ - return (a_name##tsd_booted); \ + return a_name##tsd_booted; \ } \ a_attr bool \ a_name##tsd_get_allocates(void) { \ - return (true); \ + return true; \ } \ /* Get/set. */ \ a_attr a_type * \ @@ -385,9 +385,9 @@ a_name##tsd_get(bool init) { \ assert(a_name##tsd_booted); \ wrapper = a_name##tsd_wrapper_get(init); \ if (a_name##tsd_get_allocates() && !init && wrapper == NULL) { \ - return (NULL); \ + return NULL; \ } \ - return (&wrapper->val); \ + return &wrapper->val; \ } \ a_attr void \ a_name##tsd_set(a_type *val) { \ @@ -449,7 +449,7 @@ a_name##tsd_wrapper_get(bool init) { \ tsd_init_check_recursion(&a_name##tsd_init_head, \ &block); \ if (wrapper) { \ - return (wrapper); \ + return wrapper; \ } \ wrapper = (a_name##tsd_wrapper_t *) \ malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ @@ -465,17 +465,17 @@ a_name##tsd_wrapper_get(bool init) { \ a_name##tsd_wrapper_set(wrapper); \ tsd_init_finish(&a_name##tsd_init_head, &block); \ } \ - return (wrapper); \ + return wrapper; \ } \ a_attr bool \ a_name##tsd_boot0(void) { \ if (pthread_key_create(&a_name##tsd_tsd, \ a_name##tsd_cleanup_wrapper) != 0) { \ - return (true); \ + return true; \ } \ a_name##tsd_wrapper_set(&a_name##tsd_boot_wrapper); \ a_name##tsd_booted = true; \ - return (false); \ + return false; \ } \ a_attr void \ a_name##tsd_boot1(void) { \ @@ -494,18 +494,18 @@ a_name##tsd_boot1(void) { \ a_attr bool \ a_name##tsd_boot(void) { \ if (a_name##tsd_boot0()) { \ - return (true); \ + return true; \ } \ a_name##tsd_boot1(); \ - return (false); \ + return false; \ } \ a_attr bool \ a_name##tsd_booted_get(void) { \ - return (a_name##tsd_booted); \ + return a_name##tsd_booted; \ } \ a_attr bool \ a_name##tsd_get_allocates(void) { \ - return (true); \ + return true; \ } \ /* Get/set. */ \ a_attr a_type * \ @@ -515,9 +515,9 @@ a_name##tsd_get(bool init) { \ assert(a_name##tsd_booted); \ wrapper = a_name##tsd_wrapper_get(init); \ if (a_name##tsd_get_allocates() && !init && wrapper == NULL) { \ - return (NULL); \ + return NULL; \ } \ - return (&wrapper->val); \ + return &wrapper->val; \ } \ a_attr void \ a_name##tsd_set(a_type *val) { \ diff --git a/include/jemalloc/internal/util_inlines.h b/include/jemalloc/internal/util_inlines.h index 271673ae..c09bd6da 100644 --- a/include/jemalloc/internal/util_inlines.h +++ b/include/jemalloc/internal/util_inlines.h @@ -26,27 +26,27 @@ int get_errno(void); JEMALLOC_ALWAYS_INLINE unsigned ffs_llu(unsigned long long bitmap) { - return (JEMALLOC_INTERNAL_FFSLL(bitmap)); + return JEMALLOC_INTERNAL_FFSLL(bitmap); } JEMALLOC_ALWAYS_INLINE unsigned ffs_lu(unsigned long bitmap) { - return (JEMALLOC_INTERNAL_FFSL(bitmap)); + return JEMALLOC_INTERNAL_FFSL(bitmap); } JEMALLOC_ALWAYS_INLINE unsigned ffs_u(unsigned bitmap) { - return (JEMALLOC_INTERNAL_FFS(bitmap)); + return JEMALLOC_INTERNAL_FFS(bitmap); } JEMALLOC_ALWAYS_INLINE unsigned ffs_zu(size_t bitmap) { #if LG_SIZEOF_PTR == LG_SIZEOF_INT - return (ffs_u(bitmap)); + return ffs_u(bitmap); #elif LG_SIZEOF_PTR == LG_SIZEOF_LONG - return (ffs_lu(bitmap)); + return ffs_lu(bitmap); #elif LG_SIZEOF_PTR == LG_SIZEOF_LONG_LONG - return (ffs_llu(bitmap)); + return ffs_llu(bitmap); #else #error No implementation for size_t ffs() #endif @@ -55,9 +55,9 @@ ffs_zu(size_t bitmap) { JEMALLOC_ALWAYS_INLINE unsigned ffs_u64(uint64_t bitmap) { #if LG_SIZEOF_LONG == 3 - return (ffs_lu(bitmap)); + return ffs_lu(bitmap); #elif LG_SIZEOF_LONG_LONG == 3 - return (ffs_llu(bitmap)); + return ffs_llu(bitmap); #else #error No implementation for 64-bit ffs() #endif @@ -66,11 +66,11 @@ ffs_u64(uint64_t bitmap) { JEMALLOC_ALWAYS_INLINE unsigned ffs_u32(uint32_t bitmap) { #if LG_SIZEOF_INT == 2 - return (ffs_u(bitmap)); + return ffs_u(bitmap); #else #error No implementation for 32-bit ffs() #endif - return (ffs_u(bitmap)); + return ffs_u(bitmap); } JEMALLOC_INLINE uint64_t @@ -83,7 +83,7 @@ pow2_ceil_u64(uint64_t x) { x |= x >> 16; x |= x >> 32; x++; - return (x); + return x; } JEMALLOC_INLINE uint32_t @@ -95,16 +95,16 @@ pow2_ceil_u32(uint32_t x) { x |= x >> 8; x |= x >> 16; x++; - return (x); + return x; } /* Compute the smallest power of 2 that is >= x. */ JEMALLOC_INLINE size_t pow2_ceil_zu(size_t x) { #if (LG_SIZEOF_PTR == 3) - return (pow2_ceil_u64(x)); + return pow2_ceil_u64(x); #else - return (pow2_ceil_u32(x)); + return pow2_ceil_u32(x); #endif } @@ -120,7 +120,7 @@ lg_floor(size_t x) { : "r"(x) // Inputs. ); assert(ret < UINT_MAX); - return ((unsigned)ret); + return (unsigned)ret; } #elif (defined(_MSC_VER)) JEMALLOC_INLINE unsigned @@ -137,7 +137,7 @@ lg_floor(size_t x) { # error "Unsupported type size for lg_floor()" #endif assert(ret < UINT_MAX); - return ((unsigned)ret); + return (unsigned)ret; } #elif (defined(JEMALLOC_HAVE_BUILTIN_CLZ)) JEMALLOC_INLINE unsigned @@ -145,9 +145,9 @@ lg_floor(size_t x) { assert(x != 0); #if (LG_SIZEOF_PTR == LG_SIZEOF_INT) - return (((8 << LG_SIZEOF_PTR) - 1) - __builtin_clz(x)); + return ((8 << LG_SIZEOF_PTR) - 1) - __builtin_clz(x); #elif (LG_SIZEOF_PTR == LG_SIZEOF_LONG) - return (((8 << LG_SIZEOF_PTR) - 1) - __builtin_clzl(x)); + return ((8 << LG_SIZEOF_PTR) - 1) - __builtin_clzl(x); #else # error "Unsupported type size for lg_floor()" #endif @@ -166,10 +166,10 @@ lg_floor(size_t x) { x |= (x >> 32); #endif if (x == SIZE_T_MAX) { - return ((8 << LG_SIZEOF_PTR) - 1); + return (8 << LG_SIZEOF_PTR) - 1; } x++; - return (ffs_zu(x) - 2); + return ffs_zu(x) - 2; } #endif @@ -187,9 +187,9 @@ set_errno(int errnum) { JEMALLOC_INLINE int get_errno(void) { #ifdef _WIN32 - return (GetLastError()); + return GetLastError(); #else - return (errno); + return errno; #endif } #endif diff --git a/include/jemalloc/internal/witness_inlines.h b/include/jemalloc/internal/witness_inlines.h index 2e5ebccc..c2a27812 100644 --- a/include/jemalloc/internal/witness_inlines.h +++ b/include/jemalloc/internal/witness_inlines.h @@ -22,11 +22,11 @@ witness_owner(tsd_t *tsd, const witness_t *witness) { witnesses = tsd_witnessesp_get(tsd); ql_foreach(w, witnesses, link) { if (w == witness) { - return (true); + return true; } } - return (false); + return false; } JEMALLOC_INLINE void diff --git a/include/msvc_compat/strings.h b/include/msvc_compat/strings.h index 971b36d4..996f256c 100644 --- a/include/msvc_compat/strings.h +++ b/include/msvc_compat/strings.h @@ -10,13 +10,13 @@ static __forceinline int ffsl(long x) { unsigned long i; if (_BitScanForward(&i, x)) { - return (i + 1); + return i + 1; } - return (0); + return 0; } static __forceinline int ffs(int x) { - return (ffsl(x)); + return ffsl(x); } # ifdef _M_X64 @@ -27,9 +27,9 @@ static __forceinline int ffsll(unsigned __int64 x) { unsigned long i; #ifdef _M_X64 if (_BitScanForward64(&i, x)) { - return (i + 1); + return i + 1; } - return (0); + return 0; #else // Fallback for 32-bit build where 64-bit version not available // assuming little endian @@ -41,11 +41,11 @@ static __forceinline int ffsll(unsigned __int64 x) { s.ll = x; if (_BitScanForward(&i, s.l[0])) { - return (i + 1); + return i + 1; } else if(_BitScanForward(&i, s.l[1])) { - return (i + 33); + return i + 33; } - return (0); + return 0; #endif } diff --git a/src/arena.c b/src/arena.c index 5cf9bd07..fe4b5de2 100644 --- a/src/arena.c +++ b/src/arena.c @@ -50,8 +50,8 @@ arena_extent_cache_alloc_locked(tsdn_t *tsdn, arena_t *arena, malloc_mutex_assert_owner(tsdn, &arena->lock); - return (extent_alloc_cache(tsdn, arena, r_extent_hooks, new_addr, usize, - pad, alignment, zero, &commit, slab)); + return extent_alloc_cache(tsdn, arena, r_extent_hooks, new_addr, usize, + pad, alignment, zero, &commit, slab); } extent_t * @@ -65,7 +65,7 @@ arena_extent_cache_alloc(tsdn_t *tsdn, arena_t *arena, new_addr, size, 0, alignment, zero, false); malloc_mutex_unlock(tsdn, &arena->lock); - return (extent); + return extent; } static void @@ -122,7 +122,7 @@ arena_slab_reg_alloc(tsdn_t *tsdn, extent_t *slab, ret = (void *)((uintptr_t)extent_addr_get(slab) + (uintptr_t)(bin_info->reg_size * regind)); slab_data->nfree--; - return (ret); + return ret; } #ifndef JEMALLOC_JET @@ -160,7 +160,7 @@ arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr) { assert(regind < arena_bin_info[binind].nregs); - return (regind); + return regind; } JEMALLOC_INLINE_C void @@ -282,7 +282,7 @@ arena_extent_alloc_large_hard(tsdn_t *tsdn, arena_t *arena, malloc_mutex_unlock(tsdn, &arena->lock); } - return (extent); + return extent; } extent_t * @@ -308,7 +308,7 @@ arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, &extent_hooks, usize, alignment, zero); } - return (extent); + return extent; } void @@ -409,7 +409,7 @@ arena_decay_backlog_npages_limit(const arena_t *arena) { } npages_limit_backlog = (size_t)(sum >> SMOOTHSTEP_BFP); - return (npages_limit_backlog); + return npages_limit_backlog; } static void @@ -499,12 +499,12 @@ arena_decay_init(arena_t *arena, ssize_t decay_time) { static bool arena_decay_time_valid(ssize_t decay_time) { if (decay_time < -1) { - return (false); + return false; } if (decay_time == -1 || (uint64_t)decay_time <= NSTIME_SEC_MAX) { - return (true); + return true; } - return (false); + return false; } ssize_t @@ -515,13 +515,13 @@ arena_decay_time_get(tsdn_t *tsdn, arena_t *arena) { decay_time = arena->decay.time; malloc_mutex_unlock(tsdn, &arena->lock); - return (decay_time); + return decay_time; } bool arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { if (!arena_decay_time_valid(decay_time)) { - return (true); + return true; } malloc_mutex_lock(tsdn, &arena->lock); @@ -537,7 +537,7 @@ arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { arena_maybe_purge(tsdn, arena); malloc_mutex_unlock(tsdn, &arena->lock); - return (false); + return false; } static void @@ -609,7 +609,7 @@ arena_dirty_count(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_unlock(tsdn, &arena->extents_mtx); - return (ndirty); + return ndirty; } static size_t @@ -648,7 +648,7 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, } malloc_mutex_unlock(tsdn, &arena->extents_mtx); - return (nstashed); + return nstashed; } static size_t @@ -680,7 +680,7 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, arena->stats.purged += npurged; } - return (npurged); + return npurged; } /* @@ -757,12 +757,12 @@ static extent_t * arena_bin_slabs_nonfull_tryget(arena_bin_t *bin) { extent_t *slab = extent_heap_remove_first(&bin->slabs_nonfull); if (slab == NULL) { - return (NULL); + return NULL; } if (config_stats) { bin->stats.reslabs++; } - return (slab); + return slab; } static void @@ -936,7 +936,7 @@ arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, bin_info->slab_size, 0, PAGE, &zero, &commit, true); malloc_mutex_lock(tsdn, &arena->lock); - return (slab); + return slab; } static extent_t * @@ -953,7 +953,7 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, slab = arena_slab_alloc_hard(tsdn, arena, &extent_hooks, bin_info); if (slab == NULL) { - return (NULL); + return NULL; } } assert(extent_slab_get(slab)); @@ -970,7 +970,7 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, arena->stats.mapped += extent_size_get(slab); } - return (slab); + return slab; } static extent_t * @@ -982,7 +982,7 @@ arena_bin_nonfull_slab_get(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, /* Look for a usable slab. */ slab = arena_bin_slabs_nonfull_tryget(bin); if (slab != NULL) { - return (slab); + return slab; } /* No existing slabs have any space available. */ @@ -1001,7 +1001,7 @@ arena_bin_nonfull_slab_get(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, bin->stats.nslabs++; bin->stats.curslabs++; } - return (slab); + return slab; } /* @@ -1011,10 +1011,10 @@ arena_bin_nonfull_slab_get(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, */ slab = arena_bin_slabs_nonfull_tryget(bin); if (slab != NULL) { - return (slab); + return slab; } - return (NULL); + return NULL; } /* Re-fill bin->slabcur, then call arena_slab_reg_alloc(). */ @@ -1057,7 +1057,7 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, bin); } } - return (ret); + return ret; } arena_bin_slabs_full_insert(bin, bin->slabcur); @@ -1065,13 +1065,13 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, } if (slab == NULL) { - return (NULL); + return NULL; } bin->slabcur = slab; assert(extent_slab_data_get(bin->slabcur)->nfree > 0); - return (arena_slab_reg_alloc(tsdn, slab, bin_info)); + return arena_slab_reg_alloc(tsdn, slab, bin_info); } void @@ -1172,7 +1172,7 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) { if (ret == NULL) { malloc_mutex_unlock(tsdn, &bin->lock); - return (NULL); + return NULL; } if (config_stats) { @@ -1203,7 +1203,7 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) { } arena_decay_tick(tsdn, arena); - return (ret); + return ret; } void * @@ -1215,13 +1215,13 @@ arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, arena = arena_choose(tsdn_tsd(tsdn), arena); } if (unlikely(arena == NULL)) { - return (NULL); + return NULL; } if (likely(size <= SMALL_MAXCLASS)) { - return (arena_malloc_small(tsdn, arena, ind, zero)); + return arena_malloc_small(tsdn, arena, ind, zero); } - return (large_malloc(tsdn, arena, index2size(ind), zero)); + return large_malloc(tsdn, arena, index2size(ind), zero); } void * @@ -1241,7 +1241,7 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, ret = large_palloc(tsdn, arena, usize, alignment, zero); } } - return (ret); + return ret; } void @@ -1282,7 +1282,7 @@ arena_prof_demote(tsdn_t *tsdn, extent_t *extent, const void *ptr) { assert(isalloc(tsdn, extent, ptr) == LARGE_MINCLASS); - return (LARGE_MINCLASS); + return LARGE_MINCLASS; } void @@ -1425,7 +1425,7 @@ arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, assert(extra == 0 || size + extra <= LARGE_MAXCLASS); if (unlikely(size > LARGE_MAXCLASS)) { - return (true); + return true; } usize_min = s2u(size); @@ -1440,31 +1440,31 @@ arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, if ((usize_max > SMALL_MAXCLASS || size2index(usize_max) != size2index(oldsize)) && (size > oldsize || usize_max < oldsize)) { - return (true); + return true; } arena_decay_tick(tsdn, extent_arena_get(extent)); - return (false); + return false; } else if (oldsize >= LARGE_MINCLASS && usize_max >= LARGE_MINCLASS) { - return (large_ralloc_no_move(tsdn, extent, usize_min, usize_max, - zero)); + return large_ralloc_no_move(tsdn, extent, usize_min, usize_max, + zero); } - return (true); + return true; } static void * arena_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero, tcache_t *tcache) { if (alignment == 0) { - return (arena_malloc(tsdn, arena, usize, size2index(usize), - zero, tcache, true)); + return arena_malloc(tsdn, arena, usize, size2index(usize), + zero, tcache, true); } usize = sa2u(usize, alignment); if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { - return (NULL); + return NULL; } - return (ipalloct(tsdn, usize, alignment, zero, tcache, arena)); + return ipalloct(tsdn, usize, alignment, zero, tcache, arena); } void * @@ -1476,20 +1476,20 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, usize = s2u(size); if (unlikely(usize == 0 || size > LARGE_MAXCLASS)) { - return (NULL); + return NULL; } if (likely(usize <= SMALL_MAXCLASS)) { /* Try to avoid moving the allocation. */ if (!arena_ralloc_no_move(tsdn, extent, ptr, oldsize, usize, 0, zero)) { - return (ptr); + return ptr; } } if (oldsize >= LARGE_MINCLASS && usize >= LARGE_MINCLASS) { - return (large_ralloc(tsdn, arena, extent, usize, alignment, - zero, tcache)); + return large_ralloc(tsdn, arena, extent, usize, alignment, + zero, tcache); } /* @@ -1499,7 +1499,7 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, ret = arena_ralloc_move_helper(tsdn, arena, usize, alignment, zero, tcache); if (ret == NULL) { - return (NULL); + return NULL; } /* @@ -1510,7 +1510,7 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, copysize = (usize < oldsize) ? usize : oldsize; memcpy(ret, ptr, copysize); isdalloct(tsdn, extent, ptr, oldsize, tcache, true); - return (ret); + return ret; } dss_prec_t @@ -1520,7 +1520,7 @@ arena_dss_prec_get(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_lock(tsdn, &arena->lock); ret = arena->dss_prec; malloc_mutex_unlock(tsdn, &arena->lock); - return (ret); + return ret; } bool @@ -1531,21 +1531,21 @@ arena_dss_prec_set(tsdn_t *tsdn, arena_t *arena, dss_prec_t dss_prec) { malloc_mutex_lock(tsdn, &arena->lock); arena->dss_prec = dss_prec; malloc_mutex_unlock(tsdn, &arena->lock); - return (false); + return false; } ssize_t arena_decay_time_default_get(void) { - return ((ssize_t)atomic_read_zu((size_t *)&decay_time_default)); + return (ssize_t)atomic_read_zu((size_t *)&decay_time_default); } bool arena_decay_time_default_set(ssize_t decay_time) { if (!arena_decay_time_valid(decay_time)) { - return (true); + return true; } atomic_write_zu((size_t *)&decay_time_default, (size_t)decay_time); - return (false); + return false; } static void @@ -1642,7 +1642,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, unsigned arena_nthreads_get(arena_t *arena, bool internal) { - return (atomic_read_u(&arena->nthreads[internal])); + return atomic_read_u(&arena->nthreads[internal]); } void @@ -1657,7 +1657,7 @@ arena_nthreads_dec(arena_t *arena, bool internal) { size_t arena_extent_sn_next(arena_t *arena) { - return (atomic_add_zu(&arena->extent_sn_next, 1) - 1); + return atomic_add_zu(&arena->extent_sn_next, 1) - 1; } arena_t * @@ -1671,7 +1671,7 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { } else { base = base_new(tsdn, ind, extent_hooks); if (base == NULL) { - return (NULL); + return NULL; } } @@ -1762,12 +1762,12 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena->base = base; - return (arena); + return arena; label_error: if (ind != 0) { base_delete(base); } - return (NULL); + return NULL; } void diff --git a/src/base.c b/src/base.c index ee964faa..886a6bde 100644 --- a/src/base.c +++ b/src/base.c @@ -23,7 +23,7 @@ base_map(extent_hooks_t *extent_hooks, unsigned ind, size_t size) { &zero, &commit, ind); } - return (addr); + return addr; } static void @@ -105,7 +105,7 @@ base_extent_bump_alloc_helper(extent_t *extent, size_t *gap_size, size_t size, extent_init(extent, NULL, (void *)((uintptr_t)extent_addr_get(extent) + *gap_size + size), extent_size_get(extent) - *gap_size - size, 0, extent_sn_get(extent), true, true, true, false); - return (ret); + return ret; } static void @@ -142,7 +142,7 @@ base_extent_bump_alloc(tsdn_t *tsdn, base_t *base, extent_t *extent, ret = base_extent_bump_alloc_helper(extent, &gap_size, size, alignment); base_extent_bump_alloc_post(tsdn, base, extent, gap_size, ret, size); - return (ret); + return ret; } /* @@ -163,14 +163,14 @@ base_block_alloc(extent_hooks_t *extent_hooks, unsigned ind, block_size = HUGEPAGE_CEILING(header_size + gap_size + usize); block = (base_block_t *)base_map(extent_hooks, ind, block_size); if (block == NULL) { - return (NULL); + return NULL; } block->size = block_size; block->next = NULL; assert(block_size >= header_size); base_extent_init(extent_sn_next, &block->extent, (void *)((uintptr_t)block + header_size), block_size - header_size); - return (block); + return block; } /* @@ -187,7 +187,7 @@ base_extent_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) { block = base_block_alloc(extent_hooks, base_ind_get(base), &base->extent_sn_next, size, alignment); if (block == NULL) { - return (NULL); + return NULL; } block->next = base->blocks; base->blocks = block; @@ -198,12 +198,12 @@ base_extent_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) { assert(base->allocated <= base->resident); assert(base->resident <= base->mapped); } - return (&block->extent); + return &block->extent; } base_t * b0get(void) { - return (b0); + return b0; } base_t * @@ -217,7 +217,7 @@ base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { block = base_block_alloc(extent_hooks, ind, &extent_sn_next, sizeof(base_t), QUANTUM); if (block == NULL) { - return (NULL); + return NULL; } base_alignment = CACHELINE; @@ -228,7 +228,7 @@ base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { base->extent_hooks = extent_hooks; if (malloc_mutex_init(&base->mtx, "base", WITNESS_RANK_BASE)) { base_unmap(extent_hooks, ind, block, block->size); - return (NULL); + return NULL; } base->extent_sn_next = extent_sn_next; base->blocks = block; @@ -245,7 +245,7 @@ base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { base_extent_bump_alloc_post(tsdn, base, &block->extent, gap_size, base, base_size); - return (base); + return base; } void @@ -262,7 +262,7 @@ base_delete(base_t *base) { extent_hooks_t * base_extent_hooks_get(base_t *base) { - return ((extent_hooks_t *)atomic_read_p(&base->extent_hooks_pun)); + return (extent_hooks_t *)atomic_read_p(&base->extent_hooks_pun); } extent_hooks_t * @@ -276,7 +276,7 @@ base_extent_hooks_set(base_t *base, extent_hooks_t *extent_hooks) { u.h = &base->extent_hooks; atomic_write_p(u.v, extent_hooks); - return (old_extent_hooks); + return old_extent_hooks; } /* @@ -319,7 +319,7 @@ base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) { ret = base_extent_bump_alloc(tsdn, base, extent, usize, alignment); label_return: malloc_mutex_unlock(tsdn, &base->mtx); - return (ret); + return ret; } void diff --git a/src/bitmap.c b/src/bitmap.c index 7cbc7d45..a9d48685 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -35,7 +35,7 @@ bitmap_info_init(bitmap_info_t *binfo, size_t nbits) { static size_t bitmap_info_ngroups(const bitmap_info_t *binfo) { - return (binfo->levels[binfo->nlevels].group_offset); + return binfo->levels[binfo->nlevels].group_offset; } void @@ -80,7 +80,7 @@ bitmap_info_init(bitmap_info_t *binfo, size_t nbits) { static size_t bitmap_info_ngroups(const bitmap_info_t *binfo) { - return (binfo->ngroups); + return binfo->ngroups; } void diff --git a/src/ckh.c b/src/ckh.c index 0deaf809..7a652185 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -57,11 +57,11 @@ ckh_bucket_search(ckh_t *ckh, size_t bucket, const void *key) { for (i = 0; i < (ZU(1) << LG_CKH_BUCKET_CELLS); i++) { cell = &ckh->tab[(bucket << LG_CKH_BUCKET_CELLS) + i]; if (cell->key != NULL && ckh->keycomp(key, cell->key)) { - return ((bucket << LG_CKH_BUCKET_CELLS) + i); + return (bucket << LG_CKH_BUCKET_CELLS) + i; } } - return (SIZE_T_MAX); + return SIZE_T_MAX; } /* @@ -79,13 +79,13 @@ ckh_isearch(ckh_t *ckh, const void *key) { bucket = hashes[0] & ((ZU(1) << ckh->lg_curbuckets) - 1); cell = ckh_bucket_search(ckh, bucket, key); if (cell != SIZE_T_MAX) { - return (cell); + return cell; } /* Search secondary bucket. */ bucket = hashes[1] & ((ZU(1) << ckh->lg_curbuckets) - 1); cell = ckh_bucket_search(ckh, bucket, key); - return (cell); + return cell; } JEMALLOC_INLINE_C bool @@ -107,11 +107,11 @@ ckh_try_bucket_insert(ckh_t *ckh, size_t bucket, const void *key, cell->key = key; cell->data = data; ckh->count++; - return (false); + return false; } } - return (true); + return true; } /* @@ -181,12 +181,12 @@ ckh_evict_reloc_insert(ckh_t *ckh, size_t argbucket, void const **argkey, if (tbucket == argbucket) { *argkey = key; *argdata = data; - return (true); + return true; } bucket = tbucket; if (!ckh_try_bucket_insert(ckh, bucket, key, data)) { - return (false); + return false; } } } @@ -202,19 +202,19 @@ ckh_try_insert(ckh_t *ckh, void const**argkey, void const**argdata) { /* Try to insert in primary bucket. */ bucket = hashes[0] & ((ZU(1) << ckh->lg_curbuckets) - 1); if (!ckh_try_bucket_insert(ckh, bucket, key, data)) { - return (false); + return false; } /* Try to insert in secondary bucket. */ bucket = hashes[1] & ((ZU(1) << ckh->lg_curbuckets) - 1); if (!ckh_try_bucket_insert(ckh, bucket, key, data)) { - return (false); + return false; } /* * Try to find a place for this item via iterative eviction/relocation. */ - return (ckh_evict_reloc_insert(ckh, bucket, argkey, argdata)); + return ckh_evict_reloc_insert(ckh, bucket, argkey, argdata); } /* @@ -234,13 +234,13 @@ ckh_rebuild(ckh_t *ckh, ckhc_t *aTab) { data = aTab[i].data; if (ckh_try_insert(ckh, &key, &data)) { ckh->count = count; - return (true); + return true; } nins++; } } - return (false); + return false; } static bool @@ -296,7 +296,7 @@ ckh_grow(tsd_t *tsd, ckh_t *ckh) { ret = false; label_return: - return (ret); + return ret; } static void @@ -403,7 +403,7 @@ ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ret = false; label_return: - return (ret); + return ret; } void @@ -433,7 +433,7 @@ size_t ckh_count(ckh_t *ckh) { assert(ckh != NULL); - return (ckh->count); + return ckh->count; } bool @@ -450,11 +450,11 @@ ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data) { *data = (void *)ckh->tab[i].data; } *tabind = i + 1; - return (false); + return false; } } - return (true); + return true; } bool @@ -477,7 +477,7 @@ ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data) { ret = false; label_return: - return (ret); + return ret; } bool @@ -507,10 +507,10 @@ ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key, ckh_shrink(tsd, ckh); } - return (false); + return false; } - return (true); + return true; } bool @@ -527,10 +527,10 @@ ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data) { if (data != NULL) { *data = (void *)ckh->tab[cell].data; } - return (false); + return false; } - return (true); + return true; } void @@ -543,7 +543,7 @@ ckh_string_keycomp(const void *k1, const void *k2) { assert(k1 != NULL); assert(k2 != NULL); - return (strcmp((char *)k1, (char *)k2) ? false : true); + return !strcmp((char *)k1, (char *)k2); } void @@ -560,5 +560,5 @@ ckh_pointer_hash(const void *key, size_t r_hash[2]) { bool ckh_pointer_keycomp(const void *k1, const void *k2) { - return ((k1 == k2) ? true : false); + return (k1 == k2); } diff --git a/src/ctl.c b/src/ctl.c index 929176f2..232fbd71 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -464,12 +464,12 @@ arenas_i2a_impl(size_t i, bool compat, bool validate) { break; } - return (a); + return a; } static unsigned arenas_i2a(size_t i) { - return (arenas_i2a_impl(i, true, false)); + return arenas_i2a_impl(i, true, false); } static ctl_arena_t * @@ -505,14 +505,14 @@ arenas_i_impl(tsdn_t *tsdn, size_t i, bool compat, bool init) { } assert(ret == NULL || arenas_i2a(ret->arena_ind) == arenas_i2a(i)); - return (ret); + return ret; } static ctl_arena_t * arenas_i(size_t i) { ctl_arena_t *ret = arenas_i_impl(TSDN_NULL, i, true, false); assert(ret != NULL); - return (ret); + return ret; } static void @@ -692,19 +692,19 @@ ctl_arena_init(tsdn_t *tsdn, extent_hooks_t *extent_hooks) { /* Trigger stats allocation. */ if (arenas_i_impl(tsdn, arena_ind, false, true) == NULL) { - return (UINT_MAX); + return UINT_MAX; } /* Initialize new arena. */ if (arena_init(tsdn, arena_ind, extent_hooks) == NULL) { - return (UINT_MAX); + return UINT_MAX; } if (arena_ind == ctl_arenas->narenas) { ctl_arenas->narenas++; } - return (arena_ind); + return arena_ind; } static void @@ -819,7 +819,7 @@ ctl_init(tsdn_t *tsdn) { ret = false; label_return: malloc_mutex_unlock(tsdn, &ctl_mtx); - return (ret); + return ret; } static int @@ -917,7 +917,7 @@ ctl_lookup(tsdn_t *tsdn, const char *name, ctl_node_t const **nodesp, ret = 0; label_return: - return (ret); + return ret; } int @@ -1019,12 +1019,12 @@ label_return: bool ctl_boot(void) { if (malloc_mutex_init(&ctl_mtx, "ctl", WITNESS_RANK_CTL)) { - return (true); + return true; } ctl_initialized = false; - return (false); + return false; } void @@ -1110,7 +1110,7 @@ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ t oldval; \ \ if (!(c)) { \ - return (ENOENT); \ + return ENOENT; \ } \ if (l) { \ malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); \ @@ -1124,7 +1124,7 @@ label_return: \ if (l) { \ malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); \ } \ - return (ret); \ + return ret; \ } #define CTL_RO_CGEN(c, n, v, t) \ @@ -1135,7 +1135,7 @@ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ t oldval; \ \ if (!(c)) { \ - return (ENOENT); \ + return ENOENT; \ } \ malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); \ READONLY(); \ @@ -1145,7 +1145,7 @@ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ ret = 0; \ label_return: \ malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); \ - return (ret); \ + return ret; \ } #define CTL_RO_GEN(n, v, t) \ @@ -1163,7 +1163,7 @@ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ ret = 0; \ label_return: \ malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); \ - return (ret); \ + return ret; \ } /* @@ -1178,7 +1178,7 @@ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ t oldval; \ \ if (!(c)) { \ - return (ENOENT); \ + return ENOENT; \ } \ READONLY(); \ oldval = (v); \ @@ -1186,7 +1186,7 @@ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ \ ret = 0; \ label_return: \ - return (ret); \ + return ret; \ } #define CTL_RO_NL_GEN(n, v, t) \ @@ -1202,7 +1202,7 @@ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ \ ret = 0; \ label_return: \ - return (ret); \ + return ret; \ } #define CTL_TSD_RO_NL_CGEN(c, n, m, t) \ @@ -1213,7 +1213,7 @@ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ t oldval; \ \ if (!(c)) { \ - return (ENOENT); \ + return ENOENT; \ } \ READONLY(); \ oldval = (m(tsd)); \ @@ -1221,7 +1221,7 @@ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ \ ret = 0; \ label_return: \ - return (ret); \ + return ret; \ } #define CTL_RO_CONFIG_GEN(n, t) \ @@ -1237,7 +1237,7 @@ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ \ ret = 0; \ label_return: \ - return (ret); \ + return ret; \ } /******************************************************************************/ @@ -1260,7 +1260,7 @@ epoch_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); - return (ret); + return ret; } /******************************************************************************/ @@ -1316,7 +1316,7 @@ thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, oldarena = arena_choose(tsd, NULL); if (oldarena == NULL) { - return (EAGAIN); + return EAGAIN; } newind = oldind = arena_ind_get(oldarena); @@ -1350,7 +1350,7 @@ thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - return (ret); + return ret; } CTL_TSD_RO_NL_CGEN(config_stats, thread_allocated, tsd_thread_allocated_get, @@ -1369,7 +1369,7 @@ thread_tcache_enabled_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, bool oldval; if (!config_tcache) { - return (ENOENT); + return ENOENT; } oldval = tcache_enabled_get(); @@ -1384,7 +1384,7 @@ thread_tcache_enabled_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, ret = 0; label_return: - return (ret); + return ret; } static int @@ -1393,7 +1393,7 @@ thread_tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, int ret; if (!config_tcache) { - return (ENOENT); + return ENOENT; } READONLY(); @@ -1403,7 +1403,7 @@ thread_tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, ret = 0; label_return: - return (ret); + return ret; } static int @@ -1412,7 +1412,7 @@ thread_prof_name_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, int ret; if (!config_prof) { - return (ENOENT); + return ENOENT; } READ_XOR_WRITE(); @@ -1434,7 +1434,7 @@ thread_prof_name_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - return (ret); + return ret; } static int @@ -1444,7 +1444,7 @@ thread_prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, bool oldval; if (!config_prof) { - return (ENOENT); + return ENOENT; } oldval = prof_thread_active_get(tsd); @@ -1462,7 +1462,7 @@ thread_prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - return (ret); + return ret; } /******************************************************************************/ @@ -1474,7 +1474,7 @@ tcache_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, unsigned tcache_ind; if (!config_tcache) { - return (ENOENT); + return ENOENT; } malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); @@ -1488,7 +1488,7 @@ tcache_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); - return (ret); + return ret; } static int @@ -1498,7 +1498,7 @@ tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, unsigned tcache_ind; if (!config_tcache) { - return (ENOENT); + return ENOENT; } WRITEONLY(); @@ -1512,7 +1512,7 @@ tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - return (ret); + return ret; } static int @@ -1522,7 +1522,7 @@ tcache_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, unsigned tcache_ind; if (!config_tcache) { - return (ENOENT); + return ENOENT; } WRITEONLY(); @@ -1536,7 +1536,7 @@ tcache_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - return (ret); + return ret; } /******************************************************************************/ @@ -1560,7 +1560,7 @@ arena_i_initialized_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, ret = 0; label_return: - return (ret); + return ret; } static void @@ -1622,7 +1622,7 @@ arena_i_purge_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - return (ret); + return ret; } static int @@ -1638,7 +1638,7 @@ arena_i_decay_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - return (ret); + return ret; } static int @@ -1664,7 +1664,7 @@ arena_i_reset_destroy_helper(tsd_t *tsd, const size_t *mib, size_t miblen, ret = 0; label_return: - return (ret); + return ret; } static int @@ -1677,12 +1677,12 @@ arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = arena_i_reset_destroy_helper(tsd, mib, miblen, oldp, oldlenp, newp, newlen, &arena_ind, &arena); if (ret != 0) { - return (ret); + return ret; } arena_reset(tsd, arena); - return (ret); + return ret; } static int @@ -1721,7 +1721,7 @@ arena_i_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, assert(ret == 0); label_return: - return (ret); + return ret; } static int @@ -1782,7 +1782,7 @@ arena_i_dss_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); - return (ret); + return ret; } static int @@ -1817,7 +1817,7 @@ arena_i_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - return (ret); + return ret; } static int @@ -1851,7 +1851,7 @@ arena_i_extent_hooks_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, ret = 0; label_return: malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); - return (ret); + return ret; } static const ctl_named_node_t * @@ -1874,7 +1874,7 @@ arena_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { ret = super_arena_i_node; label_return: malloc_mutex_unlock(tsdn, &ctl_mtx); - return (ret); + return ret; } /******************************************************************************/ @@ -1897,7 +1897,7 @@ arenas_narenas_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); - return (ret); + return ret; } static int @@ -1922,7 +1922,7 @@ arenas_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - return (ret); + return ret; } CTL_RO_NL_GEN(arenas_quantum, QUANTUM, size_t) @@ -1936,9 +1936,9 @@ CTL_RO_NL_GEN(arenas_bin_i_slab_size, arena_bin_info[mib[2]].slab_size, size_t) static const ctl_named_node_t * arenas_bin_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { if (i > NBINS) { - return (NULL); + return NULL; } - return (super_arenas_bin_i_node); + return super_arenas_bin_i_node; } CTL_RO_NL_GEN(arenas_nlextents, NSIZES - NBINS, unsigned) @@ -1947,9 +1947,9 @@ static const ctl_named_node_t * arenas_lextent_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { if (i > NSIZES - NBINS) { - return (NULL); + return NULL; } - return (super_arenas_lextent_i_node); + return super_arenas_lextent_i_node; } static int @@ -1973,7 +1973,7 @@ arenas_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); - return (ret); + return ret; } /******************************************************************************/ @@ -1985,7 +1985,7 @@ prof_thread_active_init_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, bool oldval; if (!config_prof) { - return (ENOENT); + return ENOENT; } if (newp != NULL) { @@ -2002,7 +2002,7 @@ prof_thread_active_init_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, ret = 0; label_return: - return (ret); + return ret; } static int @@ -2012,7 +2012,7 @@ prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, bool oldval; if (!config_prof) { - return (ENOENT); + return ENOENT; } if (newp != NULL) { @@ -2028,7 +2028,7 @@ prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - return (ret); + return ret; } static int @@ -2038,7 +2038,7 @@ prof_dump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, const char *filename = NULL; if (!config_prof) { - return (ENOENT); + return ENOENT; } WRITEONLY(); @@ -2051,7 +2051,7 @@ prof_dump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - return (ret); + return ret; } static int @@ -2061,7 +2061,7 @@ prof_gdump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, bool oldval; if (!config_prof) { - return (ENOENT); + return ENOENT; } if (newp != NULL) { @@ -2077,7 +2077,7 @@ prof_gdump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - return (ret); + return ret; } static int @@ -2087,7 +2087,7 @@ prof_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t lg_sample = lg_prof_sample; if (!config_prof) { - return (ENOENT); + return ENOENT; } WRITEONLY(); @@ -2100,7 +2100,7 @@ prof_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - return (ret); + return ret; } CTL_RO_NL_CGEN(config_prof, prof_interval, prof_interval, uint64_t) @@ -2180,9 +2180,9 @@ static const ctl_named_node_t * stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t j) { if (j > NBINS) { - return (NULL); + return NULL; } - return (super_stats_arenas_i_bins_j_node); + return super_stats_arenas_i_bins_j_node; } CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nmalloc, @@ -2198,9 +2198,9 @@ static const ctl_named_node_t * stats_arenas_i_lextents_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t j) { if (j > NSIZES - NBINS) { - return (NULL); + return NULL; } - return (super_stats_arenas_i_lextents_j_node); + return super_stats_arenas_i_lextents_j_node; } static const ctl_named_node_t * @@ -2218,5 +2218,5 @@ stats_arenas_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { ret = super_stats_arenas_i_node; label_return: malloc_mutex_unlock(tsdn, &ctl_mtx); - return (ret); + return ret; } diff --git a/src/extent.c b/src/extent.c index 5cf2e25c..bcdaccf5 100644 --- a/src/extent.c +++ b/src/extent.c @@ -82,12 +82,12 @@ extent_alloc(tsdn_t *tsdn, arena_t *arena) { extent = ql_last(&arena->extent_cache, ql_link); if (extent == NULL) { malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); - return (base_alloc(tsdn, arena->base, sizeof(extent_t), - QUANTUM)); + return base_alloc(tsdn, arena->base, sizeof(extent_t), + QUANTUM); } ql_tail_remove(&arena->extent_cache, extent_t, ql_link); malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); - return (extent); + return extent; } void @@ -100,12 +100,12 @@ extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { extent_hooks_t * extent_hooks_get(arena_t *arena) { - return (base_extent_hooks_get(arena->base)); + return base_extent_hooks_get(arena->base); } extent_hooks_t * extent_hooks_set(arena_t *arena, extent_hooks_t *extent_hooks) { - return (base_extent_hooks_set(arena->base, extent_hooks)); + return base_extent_hooks_set(arena->base, extent_hooks); } static void @@ -139,11 +139,11 @@ extent_size_quantize_floor(size_t size) { * PAGE-spaced size classes, but it's simplest to just handle * the one case that would cause erroneous results. */ - return (size); + return size; } ret = pind2sz(pind - 1) + large_pad; assert(ret <= size); - return (ret); + return ret; } #ifdef JEMALLOC_JET #undef extent_size_quantize_floor @@ -176,7 +176,7 @@ extent_size_quantize_ceil(size_t size) { */ ret = pind2sz(psz2ind(ret - large_pad + 1)) + large_pad; } - return (ret); + return ret; } #ifdef JEMALLOC_JET #undef extent_size_quantize_ceil @@ -217,7 +217,7 @@ extent_rtree_acquire(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, *r_elm_a = rtree_elm_acquire(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_base_get(extent), dependent, init_missing); if (!dependent && *r_elm_a == NULL) { - return (true); + return true; } assert(*r_elm_a != NULL); @@ -227,14 +227,14 @@ extent_rtree_acquire(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, init_missing); if (!dependent && *r_elm_b == NULL) { rtree_elm_release(tsdn, &extents_rtree, *r_elm_a); - return (true); + return true; } assert(*r_elm_b != NULL); } else { *r_elm_b = NULL; } - return (false); + return false; } static void @@ -308,7 +308,7 @@ extent_register(tsdn_t *tsdn, const extent_t *extent) { if (extent_rtree_acquire(tsdn, rtree_ctx, extent, false, true, &elm_a, &elm_b)) { - return (true); + return true; } extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent); if (extent_slab_get(extent)) { @@ -320,7 +320,7 @@ extent_register(tsdn_t *tsdn, const extent_t *extent) { extent_gprof_add(tsdn, extent); } - return (false); + return false; } static void @@ -378,11 +378,11 @@ extent_first_best_fit(tsdn_t *tsdn, arena_t *arena, for (i = pind; i < NPSIZES+1; i++) { extent_t *extent = extent_heap_first(&extent_heaps[i]); if (extent != NULL) { - return (extent); + return extent; } } - return (NULL); + return NULL; } static void @@ -444,7 +444,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, alloc_size = size + PAGE_CEILING(alignment) - PAGE; /* Beware size_t wrap-around. */ if (alloc_size < usize) { - return (NULL); + return NULL; } if (!locked) { malloc_mutex_lock(tsdn, &arena->extents_mtx); @@ -479,7 +479,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, if (!locked) { malloc_mutex_unlock(tsdn, &arena->extents_mtx); } - return (NULL); + return NULL; } extent_heaps_remove(tsdn, extent_heaps, extent); arena_extent_cache_maybe_remove(tsdn, arena, extent, cache); @@ -508,7 +508,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, if (!locked) { malloc_mutex_unlock(tsdn, &arena->extents_mtx); } - return (NULL); + return NULL; } extent_heaps_insert(tsdn, extent_heaps, lead); arena_extent_cache_maybe_insert(tsdn, arena, lead, cache); @@ -525,7 +525,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, if (!locked) { malloc_mutex_unlock(tsdn, &arena->extents_mtx); } - return (NULL); + return NULL; } extent_heaps_insert(tsdn, extent_heaps, trail); arena_extent_cache_maybe_insert(tsdn, arena, trail, cache); @@ -545,7 +545,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, } extent_record(tsdn, arena, r_extent_hooks, extent_heaps, cache, extent); - return (NULL); + return NULL; } extent_zeroed_set(extent, true); } @@ -577,7 +577,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, } } } - return (extent); + return extent; } /* @@ -598,22 +598,22 @@ extent_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, if (have_dss && dss_prec == dss_prec_primary && (ret = extent_alloc_dss(tsdn, arena, new_addr, size, alignment, zero, commit)) != NULL) { - return (ret); + return ret; } /* mmap. */ if ((ret = extent_alloc_mmap(new_addr, size, alignment, zero, commit)) != NULL) { - return (ret); + return ret; } /* "secondary" dss. */ if (have_dss && dss_prec == dss_prec_secondary && (ret = extent_alloc_dss(tsdn, arena, new_addr, size, alignment, zero, commit)) != NULL) { - return (ret); + return ret; } /* All strategies for allocation failed. */ - return (NULL); + return NULL; } static extent_t * @@ -628,7 +628,7 @@ extent_alloc_cache_impl(tsdn_t *tsdn, arena_t *arena, extent = extent_recycle(tsdn, arena, r_extent_hooks, arena->extents_cached, locked, true, new_addr, usize, pad, alignment, zero, commit, slab); - return (extent); + return extent; } extent_t * @@ -637,16 +637,16 @@ extent_alloc_cache_locked(tsdn_t *tsdn, arena_t *arena, size_t alignment, bool *zero, bool *commit, bool slab) { malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); - return (extent_alloc_cache_impl(tsdn, arena, r_extent_hooks, true, - new_addr, usize, pad, alignment, zero, commit, slab)); + return extent_alloc_cache_impl(tsdn, arena, r_extent_hooks, true, + new_addr, usize, pad, alignment, zero, commit, slab); } extent_t * extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) { - return (extent_alloc_cache_impl(tsdn, arena, r_extent_hooks, false, - new_addr, usize, pad, alignment, zero, commit, slab)); + return extent_alloc_cache_impl(tsdn, arena, r_extent_hooks, false, + new_addr, usize, pad, alignment, zero, commit, slab); } static void * @@ -656,7 +656,7 @@ extent_alloc_default_impl(tsdn_t *tsdn, arena_t *arena, void *new_addr, ret = extent_alloc_core(tsdn, arena, new_addr, size, alignment, zero, commit, arena->dss_prec); - return (ret); + return ret; } static void * @@ -675,8 +675,8 @@ extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, size_t size, */ assert(arena != NULL); - return (extent_alloc_default_impl(tsdn, arena, new_addr, size, - alignment, zero, commit)); + return extent_alloc_default_impl(tsdn, arena, new_addr, size, + alignment, zero, commit); } static void @@ -714,14 +714,14 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, alloc_size_min = size + PAGE_CEILING(alignment) - PAGE; /* Beware size_t wrap-around. */ if (alloc_size_min < usize) { - return (NULL); + return NULL; } if (alloc_size < alloc_size_min) { - return (NULL); + return NULL; } extent = extent_alloc(tsdn, arena); if (extent == NULL) { - return (NULL); + return NULL; } zeroed = false; committed = false; @@ -731,7 +731,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, arena_extent_sn_next(arena), false, zeroed, committed, false); if (ptr == NULL || extent_register(tsdn, extent)) { extent_dalloc(tsdn, arena, extent); - return (NULL); + return NULL; } /* * Set the extent as active *after registration so that no gprof-related @@ -759,7 +759,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, if (extent == NULL) { extent_deregister(tsdn, lead); extent_leak(tsdn, arena, r_extent_hooks, false, lead); - return (NULL); + return NULL; } extent_retain(tsdn, arena, r_extent_hooks, lead); } @@ -771,7 +771,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, if (trail == NULL) { extent_deregister(tsdn, extent); extent_leak(tsdn, arena, r_extent_hooks, false, extent); - return (NULL); + return NULL; } extent_retain(tsdn, arena, r_extent_hooks, trail); } else if (leadsize == 0) { @@ -786,7 +786,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, if (extent_commit_wrapper(tsdn, arena, r_extent_hooks, extent, 0, extent_size_get(extent))) { extent_retain(tsdn, arena, r_extent_hooks, extent); - return (NULL); + return NULL; } extent_zeroed_set(extent, true); } @@ -812,7 +812,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, if (arena->extent_grow_next + 1 < NPSIZES) { arena->extent_grow_next++; } - return (extent); + return extent; } static extent_t * @@ -841,7 +841,7 @@ extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, new_addr, usize, pad, alignment, zero, commit, slab); } - return (extent); + return extent; } static extent_t * @@ -855,7 +855,7 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, size = usize + pad; extent = extent_alloc(tsdn, arena); if (extent == NULL) { - return (NULL); + return NULL; } if (*r_extent_hooks == &extent_hooks_default) { /* Call directly to propagate tsdn. */ @@ -867,7 +867,7 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, } if (addr == NULL) { extent_dalloc(tsdn, arena, extent); - return (NULL); + return NULL; } extent_init(extent, arena, addr, size, usize, arena_extent_sn_next(arena), true, zero, commit, slab); @@ -876,10 +876,10 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, } if (extent_register(tsdn, extent)) { extent_leak(tsdn, arena, r_extent_hooks, false, extent); - return (NULL); + return NULL; } - return (extent); + return extent; } extent_t * @@ -897,25 +897,25 @@ extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, new_addr, usize, pad, alignment, zero, commit, slab); } - return (extent); + return extent; } static bool extent_can_coalesce(const extent_t *a, const extent_t *b) { if (extent_arena_get(a) != extent_arena_get(b)) { - return (false); + return false; } if (extent_active_get(a) != extent_active_get(b)) { - return (false); + return false; } if (extent_committed_get(a) != extent_committed_get(b)) { - return (false); + return false; } if (extent_retained_get(a) != extent_retained_get(b)) { - return (false); + return false; } - return (true); + return true; } static void @@ -1016,9 +1016,9 @@ extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, static bool extent_dalloc_default_impl(void *addr, size_t size) { if (!have_dss || !extent_in_dss(addr)) { - return (extent_dalloc_mmap(addr, size)); + return extent_dalloc_mmap(addr, size); } - return (true); + return true; } static bool @@ -1026,7 +1026,7 @@ extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, size_t size, bool committed, unsigned arena_ind) { assert(extent_hooks == &extent_hooks_default); - return (extent_dalloc_default_impl(addr, size)); + return extent_dalloc_default_impl(addr, size); } bool @@ -1060,7 +1060,7 @@ extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, extent_dalloc(tsdn, arena, extent); } - return (err); + return err; } void @@ -1110,8 +1110,8 @@ extent_commit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { assert(extent_hooks == &extent_hooks_default); - return (pages_commit((void *)((uintptr_t)addr + (uintptr_t)offset), - length)); + return pages_commit((void *)((uintptr_t)addr + (uintptr_t)offset), + length); } bool @@ -1125,7 +1125,7 @@ extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, (*r_extent_hooks)->commit(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), offset, length, arena_ind_get(arena))); extent_committed_set(extent, extent_committed_get(extent) || !err); - return (err); + return err; } static bool @@ -1133,8 +1133,8 @@ extent_decommit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { assert(extent_hooks == &extent_hooks_default); - return (pages_decommit((void *)((uintptr_t)addr + (uintptr_t)offset), - length)); + return pages_decommit((void *)((uintptr_t)addr + (uintptr_t)offset), + length); } bool @@ -1150,7 +1150,7 @@ extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_base_get(extent), extent_size_get(extent), offset, length, arena_ind_get(arena))); extent_committed_set(extent, extent_committed_get(extent) && err); - return (err); + return err; } #ifdef PAGES_CAN_PURGE_LAZY @@ -1163,8 +1163,8 @@ extent_purge_lazy_default(extent_hooks_t *extent_hooks, void *addr, size_t size, assert(length != 0); assert((length & PAGE_MASK) == 0); - return (pages_purge_lazy((void *)((uintptr_t)addr + (uintptr_t)offset), - length)); + return pages_purge_lazy((void *)((uintptr_t)addr + (uintptr_t)offset), + length); } #endif @@ -1189,8 +1189,8 @@ extent_purge_forced_default(extent_hooks_t *extent_hooks, void *addr, assert(length != 0); assert((length & PAGE_MASK) == 0); - return (pages_purge_forced((void *)((uintptr_t)addr + - (uintptr_t)offset), length)); + return pages_purge_forced((void *)((uintptr_t)addr + + (uintptr_t)offset), length); } #endif @@ -1211,10 +1211,7 @@ extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t size_a, size_t size_b, bool committed, unsigned arena_ind) { assert(extent_hooks == &extent_hooks_default); - if (!maps_coalesce) { - return (true); - } - return (false); + return !maps_coalesce; } #endif @@ -1232,7 +1229,7 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_assure_initialized(arena, r_extent_hooks); if ((*r_extent_hooks)->split == NULL) { - return (NULL); + return NULL; } trail = extent_alloc(tsdn, arena); @@ -1278,7 +1275,7 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); extent_rtree_release(tsdn, trail_elm_a, trail_elm_b); - return (trail); + return trail; label_error_d: extent_rtree_release(tsdn, trail_elm_a, trail_elm_b); label_error_c: @@ -1286,19 +1283,19 @@ label_error_c: label_error_b: extent_dalloc(tsdn, arena, trail); label_error_a: - return (NULL); + return NULL; } static bool extent_merge_default_impl(void *addr_a, void *addr_b) { if (!maps_coalesce) { - return (true); + return true; } if (have_dss && !extent_dss_mergeable(addr_a, addr_b)) { - return (true); + return true; } - return (false); + return false; } #ifdef JEMALLOC_MAPS_COALESCE @@ -1307,7 +1304,7 @@ extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, void *addr_b, size_t size_b, bool committed, unsigned arena_ind) { assert(extent_hooks == &extent_hooks_default); - return (extent_merge_default_impl(addr_a, addr_b)); + return extent_merge_default_impl(addr_a, addr_b); } #endif @@ -1322,7 +1319,7 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_assure_initialized(arena, r_extent_hooks); if ((*r_extent_hooks)->merge == NULL) { - return (true); + return true; } if (*r_extent_hooks == &extent_hooks_default) { @@ -1337,7 +1334,7 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, } if (err) { - return (true); + return true; } /* @@ -1372,19 +1369,19 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_dalloc(tsdn, extent_arena_get(b), b); - return (false); + return false; } bool extent_boot(void) { if (rtree_new(&extents_rtree, (unsigned)((ZU(1) << (LG_SIZEOF_PTR+3)) - LG_PAGE))) { - return (true); + return true; } if (have_dss) { extent_dss_boot(); } - return (false); + return false; } diff --git a/src/extent_dss.c b/src/extent_dss.c index d61d5464..93bd6fba 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -32,10 +32,10 @@ static void *dss_max; static void * extent_dss_sbrk(intptr_t increment) { #ifdef JEMALLOC_DSS - return (sbrk(increment)); + return sbrk(increment); #else not_implemented(); - return (NULL); + return NULL; #endif } @@ -44,10 +44,10 @@ extent_dss_prec_get(void) { dss_prec_t ret; if (!have_dss) { - return (dss_prec_disabled); + return dss_prec_disabled; } ret = (dss_prec_t)atomic_read_u(&dss_prec_default); - return (ret); + return ret; } bool @@ -56,7 +56,7 @@ extent_dss_prec_set(dss_prec_t dss_prec) { return (dss_prec != dss_prec_disabled); } atomic_write_u(&dss_prec_default, (unsigned)dss_prec); - return (false); + return false; } static void * @@ -87,10 +87,10 @@ extent_dss_max_update(void *new_addr) { } /* Fixed new_addr can only be supported if it is at the edge of DSS. */ if (new_addr != NULL && max_cur != new_addr) { - return (NULL); + return NULL; } - return (max_cur); + return max_cur; } void * @@ -107,12 +107,12 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, * interpret a large allocation request as a negative increment. */ if ((intptr_t)size < 0) { - return (NULL); + return NULL; } gap = extent_alloc(tsdn, arena); if (gap == NULL) { - return (NULL); + return NULL; } if (!atomic_read_u(&dss_exhausted)) { @@ -187,7 +187,7 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, memset(ret, 0, size); } } - return (ret); + return ret; } /* * Failure, whether due to OOM or a race with a raw @@ -207,7 +207,7 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, } label_oom: extent_dalloc(tsdn, arena, gap); - return (NULL); + return NULL; } static bool @@ -220,7 +220,7 @@ bool extent_in_dss(void *addr) { cassert(have_dss); - return (extent_in_dss_helper(addr, atomic_read_p(&dss_max))); + return extent_in_dss_helper(addr, atomic_read_p(&dss_max)); } bool @@ -231,7 +231,7 @@ extent_dss_mergeable(void *addr_a, void *addr_b) { if ((uintptr_t)addr_a < (uintptr_t)dss_base && (uintptr_t)addr_b < (uintptr_t)dss_base) { - return (true); + return true; } max = atomic_read_p(&dss_max); diff --git a/src/extent_mmap.c b/src/extent_mmap.c index 2c00b588..495d9beb 100644 --- a/src/extent_mmap.c +++ b/src/extent_mmap.c @@ -12,14 +12,14 @@ extent_alloc_mmap_slow(size_t size, size_t alignment, bool *zero, alloc_size = size + alignment - PAGE; /* Beware size_t wrap-around. */ if (alloc_size < size) { - return (NULL); + return NULL; } do { void *pages; size_t leadsize; pages = pages_map(NULL, alloc_size, commit); if (pages == NULL) { - return (NULL); + return NULL; } leadsize = ALIGNMENT_CEILING((uintptr_t)pages, alignment) - (uintptr_t)pages; @@ -28,7 +28,7 @@ extent_alloc_mmap_slow(size_t size, size_t alignment, bool *zero, assert(ret != NULL); *zero = true; - return (ret); + return ret; } void * @@ -54,18 +54,18 @@ extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, ret = pages_map(new_addr, size, commit); if (ret == NULL || ret == new_addr) { - return (ret); + return ret; } assert(new_addr == NULL); offset = ALIGNMENT_ADDR2OFFSET(ret, alignment); if (offset != 0) { pages_unmap(ret, size); - return (extent_alloc_mmap_slow(size, alignment, zero, commit)); + return extent_alloc_mmap_slow(size, alignment, zero, commit); } assert(ret != NULL); *zero = true; - return (ret); + return ret; } bool @@ -73,5 +73,5 @@ extent_dalloc_mmap(void *addr, size_t size) { if (config_munmap) { pages_unmap(addr, size); } - return (!config_munmap); + return !config_munmap; } diff --git a/src/jemalloc.c b/src/jemalloc.c index 2de42c3e..67b430f4 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -280,17 +280,17 @@ malloc_initialized(void) { JEMALLOC_ALWAYS_INLINE_C bool malloc_init_a0(void) { if (unlikely(malloc_init_state == malloc_init_uninitialized)) { - return (malloc_init_hard_a0()); + return malloc_init_hard_a0(); } - return (false); + return false; } JEMALLOC_ALWAYS_INLINE_C bool malloc_init(void) { if (unlikely(!malloc_initialized()) && malloc_init_hard()) { - return (true); + return true; } - return (false); + return false; } /* @@ -301,11 +301,11 @@ malloc_init(void) { static void * a0ialloc(size_t size, bool zero, bool is_internal) { if (unlikely(malloc_init_a0())) { - return (NULL); + return NULL; } - return (iallocztm(TSDN_NULL, size, size2index(size), zero, NULL, - is_internal, arena_get(TSDN_NULL, 0, true), true)); + return iallocztm(TSDN_NULL, size, size2index(size), zero, NULL, + is_internal, arena_get(TSDN_NULL, 0, true), true); } static void @@ -315,7 +315,7 @@ a0idalloc(extent_t *extent, void *ptr, bool is_internal) { void * a0malloc(size_t size) { - return (a0ialloc(size, false, true)); + return a0ialloc(size, false, true); } void @@ -335,7 +335,7 @@ bootstrap_malloc(size_t size) { size = 1; } - return (a0ialloc(size, false, false)); + return a0ialloc(size, false, false); } void * @@ -348,7 +348,7 @@ bootstrap_calloc(size_t num, size_t size) { num_size = 1; } - return (a0ialloc(num_size, true, false)); + return a0ialloc(num_size, true, false); } void @@ -377,7 +377,7 @@ narenas_total_inc(void) { unsigned narenas_total_get(void) { - return (atomic_read_u(&narenas_total)); + return atomic_read_u(&narenas_total); } /* Create a new arena and insert it into the arenas array at index ind. */ @@ -387,7 +387,7 @@ arena_init_locked(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { assert(ind <= narenas_total_get()); if (ind > MALLOCX_ARENA_MAX) { - return (NULL); + return NULL; } if (ind == narenas_total_get()) { narenas_total_inc(); @@ -400,13 +400,13 @@ arena_init_locked(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena = arena_get(tsdn, ind, false); if (arena != NULL) { assert(ind < narenas_auto); - return (arena); + return arena; } /* Actually initialize the arena. */ arena = arena_new(tsdn, ind, extent_hooks); arena_set(ind, arena); - return (arena); + return arena; } arena_t * @@ -416,7 +416,7 @@ arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { malloc_mutex_lock(tsdn, &arenas_lock); arena = arena_init_locked(tsdn, ind, extent_hooks); malloc_mutex_unlock(tsdn, &arenas_lock); - return (arena); + return arena; } static void @@ -534,7 +534,7 @@ label_return: if (arenas_tdata_old != NULL) { a0dalloc(arenas_tdata_old); } - return (tdata); + return tdata; } /* Slow path, called only by arena_choose(). */ @@ -612,7 +612,7 @@ arena_choose_hard(tsd_t *tsd, bool internal) { if (arena == NULL) { malloc_mutex_unlock(tsd_tsdn(tsd), &arenas_lock); - return (NULL); + return NULL; } if (!!j == internal) { ret = arena; @@ -627,7 +627,7 @@ arena_choose_hard(tsd_t *tsd, bool internal) { arena_bind(tsd, 0, true); } - return (ret); + return ret; } void @@ -714,10 +714,10 @@ static char * secure_getenv(const char *name) { # ifdef JEMALLOC_HAVE_ISSETUGID if (issetugid() != 0) { - return (NULL); + return NULL; } # endif - return (getenv(name)); + return getenv(name); } #endif @@ -785,10 +785,10 @@ malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p, malloc_write(": Conf string ends " "with key\n"); } - return (true); + return true; default: malloc_write(": Malformed conf string\n"); - return (true); + return true; } } @@ -821,7 +821,7 @@ malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p, } *opts_p = opts; - return (false); + return false; } static void @@ -1147,7 +1147,7 @@ malloc_init_hard_needed(void) { * acquired init_lock, or this thread is the initializing * thread, and it is recursively allocating. */ - return (false); + return false; } #ifdef JEMALLOC_THREADED_INIT if (malloc_initializer != NO_INITIALIZER && !IS_INITIALIZER) { @@ -1160,10 +1160,10 @@ malloc_init_hard_needed(void) { spin_adaptive(&spinner); malloc_mutex_lock(TSDN_NULL, &init_lock); } while (!malloc_initialized()); - return (false); + return false; } #endif - return (true); + return true; } static bool @@ -1185,23 +1185,23 @@ malloc_init_hard_a0_locked() { } pages_boot(); if (base_boot(TSDN_NULL)) { - return (true); + return true; } if (extent_boot()) { - return (true); + return true; } if (ctl_boot()) { - return (true); + return true; } if (config_prof) { prof_boot1(); } arena_boot(); if (config_tcache && tcache_boot(TSDN_NULL)) { - return (true); + return true; } if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS)) { - return (true); + return true; } /* * Create enough scaffolding to allow recursive allocation in @@ -1217,12 +1217,12 @@ malloc_init_hard_a0_locked() { */ if (arena_init(TSDN_NULL, 0, (extent_hooks_t *)&extent_hooks_default) == NULL) { - return (true); + return true; } malloc_init_state = malloc_init_a0_initialized; - return (false); + return false; } static bool @@ -1232,7 +1232,7 @@ malloc_init_hard_a0(void) { malloc_mutex_lock(TSDN_NULL, &init_lock); ret = malloc_init_hard_a0_locked(); malloc_mutex_unlock(TSDN_NULL, &init_lock); - return (ret); + return ret; } /* Initialize data structures which may trigger recursive allocation. */ @@ -1252,17 +1252,17 @@ malloc_init_hard_recursible(void) { if (opt_abort) { abort(); } - return (true); + return true; } #endif - return (false); + return false; } static bool malloc_init_hard_finish(tsdn_t *tsdn) { if (malloc_mutex_boot()) { - return (true); + return true; } if (opt_narenas == 0) { @@ -1291,7 +1291,7 @@ malloc_init_hard_finish(tsdn_t *tsdn) { arenas = (arena_t **)base_alloc(tsdn, a0->base, sizeof(arena_t *) * (MALLOCX_ARENA_MAX+1), CACHELINE); if (arenas == NULL) { - return (true); + return true; } /* Copy the pointer to the one arena that was already initialized. */ arena_set(0, a0); @@ -1299,7 +1299,7 @@ malloc_init_hard_finish(tsdn_t *tsdn) { malloc_init_state = malloc_init_initialized; malloc_slow_flag_init(); - return (false); + return false; } static bool @@ -1312,39 +1312,39 @@ malloc_init_hard(void) { malloc_mutex_lock(TSDN_NULL, &init_lock); if (!malloc_init_hard_needed()) { malloc_mutex_unlock(TSDN_NULL, &init_lock); - return (false); + return false; } if (malloc_init_state != malloc_init_a0_initialized && malloc_init_hard_a0_locked()) { malloc_mutex_unlock(TSDN_NULL, &init_lock); - return (true); + return true; } malloc_mutex_unlock(TSDN_NULL, &init_lock); /* Recursive allocation relies on functional tsd. */ tsd = malloc_tsd_boot0(); if (tsd == NULL) { - return (true); + return true; } if (malloc_init_hard_recursible()) { - return (true); + return true; } malloc_mutex_lock(tsd_tsdn(tsd), &init_lock); if (config_prof && prof_boot2(tsd)) { malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); - return (true); + return true; } if (malloc_init_hard_finish(tsd_tsdn(tsd))) { malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); - return (true); + return true; } malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); malloc_tsd_boot1(); - return (false); + return false; } /* @@ -1679,8 +1679,6 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { witness_assert_lockless(tsd_tsdn(tsd)); - - /* Success! */ *dopts->result = allocation; return 0; @@ -1829,7 +1827,7 @@ je_aligned_alloc(size_t alignment, size_t size) { dopts.alignment = alignment; imalloc(&sopts, &dopts); - return (ret); + return ret; } JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN @@ -1864,13 +1862,13 @@ irealloc_prof_sample(tsd_t *tsd, extent_t *extent, void *old_ptr, void *p; if (tctx == NULL) { - return (NULL); + return NULL; } if (usize <= SMALL_MAXCLASS) { p = iralloc(tsd, extent, old_ptr, old_usize, LARGE_MINCLASS, 0, false); if (p == NULL) { - return (NULL); + return NULL; } arena_prof_promote(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, usize); @@ -1878,7 +1876,7 @@ irealloc_prof_sample(tsd_t *tsd, extent_t *extent, void *old_ptr, p = iralloc(tsd, extent, old_ptr, old_usize, usize, 0, false); } - return (p); + return p; } JEMALLOC_ALWAYS_INLINE_C void * @@ -1901,13 +1899,13 @@ irealloc_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, } if (unlikely(p == NULL)) { prof_alloc_rollback(tsd, tctx, true); - return (NULL); + return NULL; } extent = (p == old_ptr) ? old_extent : iealloc(tsd_tsdn(tsd), p); prof_realloc(tsd, extent, p, usize, tctx, prof_active, true, old_extent, old_ptr, old_usize, old_tctx); - return (p); + return p; } JEMALLOC_INLINE_C void @@ -1977,7 +1975,7 @@ je_realloc(void *ptr, size_t size) { UTRACE(ptr, 0, 0); tsd = tsd_fetch(); ifree(tsd, ptr, tcache_get(tsd, false), true); - return (NULL); + return NULL; } size = 1; } @@ -2029,7 +2027,7 @@ je_realloc(void *ptr, size_t size) { } UTRACE(ptr, size, ret); witness_assert_lockless(tsdn); - return (ret); + return ret; } JEMALLOC_EXPORT void JEMALLOC_NOTHROW @@ -2113,7 +2111,7 @@ je_valloc(size_t size) { imalloc(&sopts, &dopts); - return (ret); + return ret; } #endif @@ -2226,13 +2224,13 @@ irallocx_prof_sample(tsdn_t *tsdn, extent_t *extent, void *old_ptr, void *p; if (tctx == NULL) { - return (NULL); + return NULL; } if (usize <= SMALL_MAXCLASS) { p = iralloct(tsdn, extent, old_ptr, old_usize, LARGE_MINCLASS, alignment, zero, tcache, arena); if (p == NULL) { - return (NULL); + return NULL; } arena_prof_promote(tsdn, iealloc(tsdn, p), p, usize); } else { @@ -2240,7 +2238,7 @@ irallocx_prof_sample(tsdn_t *tsdn, extent_t *extent, void *old_ptr, zero, tcache, arena); } - return (p); + return p; } JEMALLOC_ALWAYS_INLINE_C void * @@ -2264,7 +2262,7 @@ irallocx_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, } if (unlikely(p == NULL)) { prof_alloc_rollback(tsd, tctx, false); - return (NULL); + return NULL; } if (p == old_ptr && alignment != 0) { @@ -2284,7 +2282,7 @@ irallocx_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, prof_realloc(tsd, extent, p, *usize, tctx, prof_active, false, old_extent, old_ptr, old_usize, old_tctx); - return (p); + return p; } JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN @@ -2359,7 +2357,7 @@ je_rallocx(void *ptr, size_t size, int flags) { } UTRACE(ptr, size, p); witness_assert_lockless(tsd_tsdn(tsd)); - return (p); + return p; label_oom: if (config_xmalloc && unlikely(opt_xmalloc)) { malloc_write(": Error in rallocx(): out of memory\n"); @@ -2367,7 +2365,7 @@ label_oom: } UTRACE(ptr, size, 0); witness_assert_lockless(tsd_tsdn(tsd)); - return (NULL); + return NULL; } JEMALLOC_ALWAYS_INLINE_C size_t @@ -2377,11 +2375,11 @@ ixallocx_helper(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t old_usize, if (ixalloc(tsdn, extent, ptr, old_usize, size, extra, alignment, zero)) { - return (old_usize); + return old_usize; } usize = isalloc(tsdn, extent, ptr); - return (usize); + return usize; } static size_t @@ -2391,12 +2389,12 @@ ixallocx_prof_sample(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t usize; if (tctx == NULL) { - return (old_usize); + return old_usize; } usize = ixallocx_helper(tsdn, extent, ptr, old_usize, size, extra, alignment, zero); - return (usize); + return usize; } JEMALLOC_ALWAYS_INLINE_C size_t @@ -2440,12 +2438,12 @@ ixallocx_prof(tsd_t *tsd, extent_t *extent, void *ptr, size_t old_usize, } if (usize == old_usize) { prof_alloc_rollback(tsd, tctx, false); - return (usize); + return usize; } prof_realloc(tsd, extent, ptr, usize, tctx, prof_active, false, extent, ptr, old_usize, old_tctx); - return (usize); + return usize; } JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW @@ -2501,7 +2499,7 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) { label_not_resized: UTRACE(ptr, size, ptr); witness_assert_lockless(tsd_tsdn(tsd)); - return (usize); + return usize; } JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW @@ -2522,7 +2520,7 @@ je_sallocx(const void *ptr, int flags) { } witness_assert_lockless(tsdn); - return (usize); + return usize; } JEMALLOC_EXPORT void JEMALLOC_NOTHROW @@ -2566,7 +2564,7 @@ inallocx(tsdn_t *tsdn, size_t size, int flags) { usize = sa2u(size, MALLOCX_ALIGN_GET_SPECIFIED(flags)); } witness_assert_lockless(tsdn); - return (usize); + return usize; } JEMALLOC_EXPORT void JEMALLOC_NOTHROW @@ -2612,7 +2610,7 @@ je_nallocx(size_t size, int flags) { assert(size != 0); if (unlikely(malloc_init())) { - return (0); + return 0; } tsdn = tsdn_fetch(); @@ -2620,11 +2618,11 @@ je_nallocx(size_t size, int flags) { usize = inallocx(tsdn, size, flags); if (unlikely(usize > LARGE_MAXCLASS)) { - return (0); + return 0; } witness_assert_lockless(tsdn); - return (usize); + return usize; } JEMALLOC_EXPORT int JEMALLOC_NOTHROW @@ -2634,14 +2632,14 @@ je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, tsd_t *tsd; if (unlikely(malloc_init())) { - return (EAGAIN); + return EAGAIN; } tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); ret = ctl_byname(tsd, name, oldp, oldlenp, newp, newlen); witness_assert_lockless(tsd_tsdn(tsd)); - return (ret); + return ret; } JEMALLOC_EXPORT int JEMALLOC_NOTHROW @@ -2650,14 +2648,14 @@ je_mallctlnametomib(const char *name, size_t *mibp, size_t *miblenp) { tsdn_t *tsdn; if (unlikely(malloc_init())) { - return (EAGAIN); + return EAGAIN; } tsdn = tsdn_fetch(); witness_assert_lockless(tsdn); ret = ctl_nametomib(tsdn, name, mibp, miblenp); witness_assert_lockless(tsdn); - return (ret); + return ret; } JEMALLOC_EXPORT int JEMALLOC_NOTHROW @@ -2667,14 +2665,14 @@ je_mallctlbymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, tsd_t *tsd; if (unlikely(malloc_init())) { - return (EAGAIN); + return EAGAIN; } tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); ret = ctl_bymib(tsd, mib, miblen, oldp, oldlenp, newp, newlen); witness_assert_lockless(tsd_tsdn(tsd)); - return (ret); + return ret; } JEMALLOC_EXPORT void JEMALLOC_NOTHROW @@ -2706,7 +2704,7 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) { } witness_assert_lockless(tsdn); - return (ret); + return ret; } /* diff --git a/src/jemalloc_cpp.cpp b/src/jemalloc_cpp.cpp index 030ff995..394fbffe 100644 --- a/src/jemalloc_cpp.cpp +++ b/src/jemalloc_cpp.cpp @@ -36,7 +36,7 @@ void * newImpl(std::size_t size) noexcept(IsNoExcept) { void *ptr = je_malloc(size); if (likely(ptr != nullptr)) - return (ptr); + return ptr; while (ptr == nullptr) { std::new_handler handler; @@ -62,27 +62,27 @@ newImpl(std::size_t size) noexcept(IsNoExcept) { if (ptr == nullptr && !IsNoExcept) std::__throw_bad_alloc(); - return (ptr); + return ptr; } void * operator new(std::size_t size) { - return (newImpl(size)); + return newImpl(size); } void * operator new[](std::size_t size) { - return (newImpl(size)); + return newImpl(size); } void * operator new(std::size_t size, const std::nothrow_t &) noexcept { - return (newImpl(size)); + return newImpl(size); } void * operator new[](std::size_t size, const std::nothrow_t &) noexcept { - return (newImpl(size)); + return newImpl(size); } void diff --git a/src/large.c b/src/large.c index 0f2f1763..62d4441f 100644 --- a/src/large.c +++ b/src/large.c @@ -7,7 +7,7 @@ void * large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero) { assert(usize == s2u(usize)); - return (large_palloc(tsdn, arena, usize, CACHELINE, zero)); + return large_palloc(tsdn, arena, usize, CACHELINE, zero); } void * @@ -22,7 +22,7 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, ausize = sa2u(usize, alignment); if (unlikely(ausize == 0 || ausize > LARGE_MAXCLASS)) { - return (NULL); + return NULL; } /* @@ -35,7 +35,7 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, } if (unlikely(arena == NULL) || (extent = arena_extent_alloc_large(tsdn, arena, usize, alignment, &is_zeroed)) == NULL) { - return (NULL); + return NULL; } /* Insert extent into large. */ @@ -58,7 +58,7 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, } arena_decay_tick(tsdn, arena); - return (extent_addr_get(extent)); + return extent_addr_get(extent); } #ifdef JEMALLOC_JET @@ -108,7 +108,7 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { assert(oldusize > usize); if (extent_hooks->split == NULL) { - return (true); + return true; } /* Split excess pages. */ @@ -117,7 +117,7 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { &extent_hooks, extent, usize + large_pad, usize, diff, diff); if (trail == NULL) { - return (true); + return true; } if (config_fill && unlikely(opt_junk_free)) { @@ -130,7 +130,7 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { arena_extent_ralloc_large_shrink(tsdn, arena, extent, oldusize); - return (false); + return false; } static bool @@ -144,7 +144,7 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, extent_t *trail; if (extent_hooks->merge == NULL) { - return (true); + return true; } if ((trail = arena_extent_cache_alloc(tsdn, arena, &extent_hooks, @@ -154,13 +154,13 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, if ((trail = extent_alloc_wrapper(tsdn, arena, &extent_hooks, extent_past_get(extent), trailsize, 0, CACHELINE, &is_zeroed_trail, &commit, false)) == NULL) { - return (true); + return true; } } if (extent_merge_wrapper(tsdn, arena, &extent_hooks, extent, trail)) { extent_dalloc_wrapper(tsdn, arena, &extent_hooks, trail); - return (true); + return true; } if (zero || (config_fill && unlikely(opt_zero))) { @@ -191,7 +191,7 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, arena_extent_ralloc_large_expand(tsdn, arena, extent, oldusize); - return (false); + return false; } bool @@ -209,7 +209,7 @@ large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, if (!large_ralloc_no_move_expand(tsdn, extent, usize_max, zero)) { arena_decay_tick(tsdn, extent_arena_get(extent)); - return (false); + return false; } /* Try again, this time with usize_min. */ if (usize_min < usize_max && usize_min > @@ -217,7 +217,7 @@ large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, large_ralloc_no_move_expand(tsdn, extent, usize_min, zero)) { arena_decay_tick(tsdn, extent_arena_get(extent)); - return (false); + return false; } } @@ -228,26 +228,26 @@ large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, if (extent_usize_get(extent) >= usize_min && extent_usize_get(extent) <= usize_max) { arena_decay_tick(tsdn, extent_arena_get(extent)); - return (false); + return false; } /* Attempt to shrink the allocation in-place. */ if (extent_usize_get(extent) > usize_max) { if (!large_ralloc_no_move_shrink(tsdn, extent, usize_max)) { arena_decay_tick(tsdn, extent_arena_get(extent)); - return (false); + return false; } } - return (true); + return true; } static void * large_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero) { if (alignment <= CACHELINE) { - return (large_malloc(tsdn, arena, usize, zero)); + return large_malloc(tsdn, arena, usize, zero); } - return (large_palloc(tsdn, arena, usize, alignment, zero)); + return large_palloc(tsdn, arena, usize, alignment, zero); } void * @@ -264,7 +264,7 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, /* Try to avoid moving the allocation. */ if (!large_ralloc_no_move(tsdn, extent, usize, usize, zero)) { - return (extent_addr_get(extent)); + return extent_addr_get(extent); } /* @@ -274,7 +274,7 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, */ ret = large_ralloc_move_helper(tsdn, arena, usize, alignment, zero); if (ret == NULL) { - return (NULL); + return NULL; } copysize = (usize < extent_usize_get(extent)) ? usize : @@ -282,7 +282,7 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, memcpy(ret, extent_addr_get(extent), copysize); isdalloct(tsdn, extent, extent_addr_get(extent), extent_usize_get(extent), tcache, true); - return (ret); + return ret; } /* @@ -321,12 +321,12 @@ large_dalloc(tsdn_t *tsdn, extent_t *extent) { size_t large_salloc(tsdn_t *tsdn, const extent_t *extent) { - return (extent_usize_get(extent)); + return extent_usize_get(extent); } prof_tctx_t * large_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent) { - return (extent_prof_tctx_get(extent)); + return extent_prof_tctx_get(extent); } void diff --git a/src/mutex.c b/src/mutex.c index bc0869f8..f883b9d7 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -54,7 +54,7 @@ pthread_create(pthread_t *__restrict thread, pthread_once(&once_control, pthread_create_once); - return (pthread_create_fptr(thread, attr, start_routine, arg)); + return pthread_create_fptr(thread, attr, start_routine, arg); } #endif @@ -74,7 +74,7 @@ malloc_mutex_init(malloc_mutex_t *mutex, const char *name, # else if (!InitializeCriticalSectionAndSpinCount(&mutex->lock, _CRT_SPINCOUNT)) { - return (true); + return true; } # endif #elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) @@ -88,26 +88,26 @@ malloc_mutex_init(malloc_mutex_t *mutex, const char *name, } else { if (_pthread_mutex_init_calloc_cb(&mutex->lock, bootstrap_calloc) != 0) { - return (true); + return true; } } #else pthread_mutexattr_t attr; if (pthread_mutexattr_init(&attr) != 0) { - return (true); + return true; } pthread_mutexattr_settype(&attr, MALLOC_MUTEX_TYPE); if (pthread_mutex_init(&mutex->lock, &attr) != 0) { pthread_mutexattr_destroy(&attr); - return (true); + return true; } pthread_mutexattr_destroy(&attr); #endif if (config_debug) { witness_init(&mutex->witness, name, rank, NULL, NULL); } - return (false); + return false; } void @@ -143,10 +143,10 @@ malloc_mutex_boot(void) { while (postponed_mutexes != NULL) { if (_pthread_mutex_init_calloc_cb(&postponed_mutexes->lock, bootstrap_calloc) != 0) { - return (true); + return true; } postponed_mutexes = postponed_mutexes->postponed_next; } #endif - return (false); + return false; } diff --git a/src/nstime.c b/src/nstime.c index 66989a07..09cd7786 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -14,17 +14,17 @@ nstime_init2(nstime_t *time, uint64_t sec, uint64_t nsec) { uint64_t nstime_ns(const nstime_t *time) { - return (time->ns); + return time->ns; } uint64_t nstime_sec(const nstime_t *time) { - return (time->ns / BILLION); + return time->ns / BILLION; } uint64_t nstime_nsec(const nstime_t *time) { - return (time->ns % BILLION); + return time->ns % BILLION; } void @@ -34,7 +34,7 @@ nstime_copy(nstime_t *time, const nstime_t *source) { int nstime_compare(const nstime_t *a, const nstime_t *b) { - return ((a->ns > b->ns) - (a->ns < b->ns)); + return (a->ns > b->ns) - (a->ns < b->ns); } void @@ -70,7 +70,7 @@ uint64_t nstime_divide(const nstime_t *time, const nstime_t *divisor) { assert(divisor->ns != 0); - return (time->ns / divisor->ns); + return time->ns / divisor->ns; } #ifdef _WIN32 @@ -126,7 +126,7 @@ nstime_get(nstime_t *time) { #endif bool nstime_monotonic(void) { - return (NSTIME_MONOTONIC); + return NSTIME_MONOTONIC; #undef NSTIME_MONOTONIC } #ifdef JEMALLOC_JET @@ -149,10 +149,10 @@ nstime_update(nstime_t *time) { /* Handle non-monotonic clocks. */ if (unlikely(nstime_compare(&old_time, time) > 0)) { nstime_copy(time, &old_time); - return (true); + return true; } - return (false); + return false; } #ifdef JEMALLOC_JET #undef nstime_update diff --git a/src/pages.c b/src/pages.c index c23dccd7..0b678e7d 100644 --- a/src/pages.c +++ b/src/pages.c @@ -58,7 +58,7 @@ pages_map(void *addr, size_t size, bool *commit) { #endif assert(ret == NULL || (addr == NULL && ret != addr) || (addr != NULL && ret == addr)); - return (ret); + return ret; } void @@ -98,12 +98,12 @@ pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size, pages_unmap(addr, alloc_size); new_addr = pages_map(ret, size, commit); if (new_addr == ret) { - return (ret); + return ret; } if (new_addr) { pages_unmap(new_addr, size); } - return (NULL); + return NULL; } #else { @@ -115,7 +115,7 @@ pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size, if (trailsize != 0) { pages_unmap((void *)((uintptr_t)ret + size), trailsize); } - return (ret); + return ret; } #endif } @@ -123,7 +123,7 @@ pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size, static bool pages_commit_impl(void *addr, size_t size, bool commit) { if (os_overcommits) { - return (true); + return true; } #ifdef _WIN32 @@ -135,7 +135,7 @@ pages_commit_impl(void *addr, size_t size, bool commit) { void *result = mmap(addr, size, prot, mmap_flags | MAP_FIXED, -1, 0); if (result == MAP_FAILED) { - return (true); + return true; } if (result != addr) { /* @@ -143,27 +143,27 @@ pages_commit_impl(void *addr, size_t size, bool commit) { * place. */ pages_unmap(result, size); - return (true); + return true; } - return (false); + return false; } #endif } bool pages_commit(void *addr, size_t size) { - return (pages_commit_impl(addr, size, true)); + return pages_commit_impl(addr, size, true); } bool pages_decommit(void *addr, size_t size) { - return (pages_commit_impl(addr, size, false)); + return pages_commit_impl(addr, size, false); } bool pages_purge_lazy(void *addr, size_t size) { if (!pages_can_purge_lazy) { - return (true); + return true; } #ifdef _WIN32 @@ -173,13 +173,13 @@ pages_purge_lazy(void *addr, size_t size) { #else not_reached(); #endif - return (false); + return false; } bool pages_purge_forced(void *addr, size_t size) { if (!pages_can_purge_forced) { - return (true); + return true; } #if defined(JEMALLOC_PURGE_MADVISE_DONTNEED) @@ -197,7 +197,7 @@ pages_huge(void *addr, size_t size) { #ifdef JEMALLOC_THP return (madvise(addr, size, MADV_HUGEPAGE) != 0); #else - return (true); + return true; #endif } @@ -209,7 +209,7 @@ pages_nohuge(void *addr, size_t size) { #ifdef JEMALLOC_THP return (madvise(addr, size, MADV_NOHUGEPAGE) != 0); #else - return (false); + return false; #endif } @@ -221,7 +221,7 @@ os_overcommits_sysctl(void) { sz = sizeof(vm_overcommit); if (sysctlbyname("vm.overcommit", &vm_overcommit, &sz, NULL, 0) != 0) { - return (false); /* Error. */ + return false; /* Error. */ } return ((vm_overcommit & 0x3) == 0); @@ -246,7 +246,7 @@ os_overcommits_proc(void) { fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY); #endif if (fd == -1) { - return (false); /* Error. */ + return false; /* Error. */ } #if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_read) @@ -262,7 +262,7 @@ os_overcommits_proc(void) { #endif if (nread < 1) { - return (false); /* Error. */ + return false; /* Error. */ } /* * /proc/sys/vm/overcommit_memory meanings: diff --git a/src/prof.c b/src/prof.c index ca01d8b1..1b34a750 100644 --- a/src/prof.c +++ b/src/prof.c @@ -149,7 +149,7 @@ prof_tctx_comp(const prof_tctx_t *a, const prof_tctx_t *b) { b_tctx_uid); } } - return (ret); + return ret; } rb_gen(static UNUSED, tctx_tree_, prof_tctx_tree_t, prof_tctx_t, @@ -164,7 +164,7 @@ prof_gctx_comp(const prof_gctx_t *a, const prof_gctx_t *b) { if (ret == 0) { ret = (a_len > b_len) - (a_len < b_len); } - return (ret); + return ret; } rb_gen(static UNUSED, gctx_tree_, prof_gctx_tree_t, prof_gctx_t, dump_link, @@ -183,7 +183,7 @@ prof_tdata_comp(const prof_tdata_t *a, const prof_tdata_t *b) { ret = ((a_discrim > b_discrim) - (a_discrim < b_discrim)); } - return (ret); + return ret; } rb_gen(static UNUSED, tdata_tree_, prof_tdata_tree_t, prof_tdata_t, tdata_link, @@ -319,7 +319,7 @@ static _Unwind_Reason_Code prof_unwind_init_callback(struct _Unwind_Context *context, void *arg) { cassert(config_prof); - return (_URC_NO_REASON); + return _URC_NO_REASON; } static _Unwind_Reason_Code @@ -331,15 +331,15 @@ prof_unwind_callback(struct _Unwind_Context *context, void *arg) { ip = (void *)_Unwind_GetIP(context); if (ip == NULL) { - return (_URC_END_OF_STACK); + return _URC_END_OF_STACK; } data->bt->vec[data->bt->len] = ip; data->bt->len++; if (data->bt->len == data->max) { - return (_URC_END_OF_STACK); + return _URC_END_OF_STACK; } - return (_URC_NO_REASON); + return _URC_NO_REASON; } void @@ -525,12 +525,12 @@ static malloc_mutex_t * prof_gctx_mutex_choose(void) { unsigned ngctxs = atomic_add_u(&cum_gctxs, 1); - return (&gctx_locks[(ngctxs - 1) % PROF_NCTX_LOCKS]); + return &gctx_locks[(ngctxs - 1) % PROF_NCTX_LOCKS]; } static malloc_mutex_t * prof_tdata_mutex_choose(uint64_t thr_uid) { - return (&tdata_locks[thr_uid % PROF_NTDATA_LOCKS]); + return &tdata_locks[thr_uid % PROF_NTDATA_LOCKS]; } static prof_gctx_t * @@ -543,7 +543,7 @@ prof_gctx_create(tsdn_t *tsdn, prof_bt_t *bt) { size2index(size), false, NULL, true, arena_get(TSDN_NULL, 0, true), true); if (gctx == NULL) { - return (NULL); + return NULL; } gctx->lock = prof_gctx_mutex_choose(); /* @@ -556,7 +556,7 @@ prof_gctx_create(tsdn_t *tsdn, prof_bt_t *bt) { memcpy(gctx->vec, bt->vec, bt->len * sizeof(void *)); gctx->bt.vec = gctx->vec; gctx->bt.len = bt->len; - return (gctx); + return gctx; } static void @@ -600,29 +600,29 @@ prof_tctx_should_destroy(tsdn_t *tsdn, prof_tctx_t *tctx) { malloc_mutex_assert_owner(tsdn, tctx->tdata->lock); if (opt_prof_accum) { - return (false); + return false; } if (tctx->cnts.curobjs != 0) { - return (false); + return false; } if (tctx->prepared) { - return (false); + return false; } - return (true); + return true; } static bool prof_gctx_should_destroy(prof_gctx_t *gctx) { if (opt_prof_accum) { - return (false); + return false; } if (!tctx_tree_empty(&gctx->tctxs)) { - return (false); + return false; } if (gctx->nlimbo != 0) { - return (false); + return false; } - return (true); + return true; } static void @@ -721,7 +721,7 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, gctx.p = prof_gctx_create(tsd_tsdn(tsd), bt); if (gctx.v == NULL) { prof_leave(tsd, tdata); - return (true); + return true; } btkey.p = &gctx.p->bt; if (ckh_insert(tsd, &bt2gctx, btkey.v, gctx.v)) { @@ -729,7 +729,7 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, prof_leave(tsd, tdata); idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), gctx.v), gctx.v, NULL, true, true); - return (true); + return true; } new_gctx = true; } else { @@ -747,7 +747,7 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, *p_btkey = btkey.v; *p_gctx = gctx.p; *p_new_gctx = new_gctx; - return (false); + return false; } prof_tctx_t * @@ -763,7 +763,7 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) { tdata = prof_tdata_get(tsd, false); if (tdata == NULL) { - return (NULL); + return NULL; } malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock); @@ -783,7 +783,7 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) { */ if (prof_lookup_global(tsd, bt, tdata, &btkey, &gctx, &new_gctx)) { - return (NULL); + return NULL; } /* Link a prof_tctx_t into gctx for this thread. */ @@ -794,7 +794,7 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) { if (new_gctx) { prof_gctx_try_destroy(tsd, tdata, gctx, tdata); } - return (NULL); + return NULL; } ret.p->tdata = tdata; ret.p->thr_uid = tdata->thr_uid; @@ -813,7 +813,7 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) { } idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), ret.v), ret.v, NULL, true, true); - return (NULL); + return NULL; } malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock); ret.p->state = prof_tctx_state_nominal; @@ -822,7 +822,7 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) { malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock); } - return (ret.p); + return ret.p; } /* @@ -887,7 +887,7 @@ prof_tdata_count_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, (*tdata_count)++; - return (NULL); + return NULL; } size_t @@ -901,7 +901,7 @@ prof_tdata_count(void) { (void *)&tdata_count); malloc_mutex_unlock(tsdn, &tdatas_mtx); - return (tdata_count); + return tdata_count; } #endif @@ -915,14 +915,14 @@ prof_bt_count(void) { tsd = tsd_fetch(); tdata = prof_tdata_get(tsd, false); if (tdata == NULL) { - return (0); + return 0; } malloc_mutex_lock(tsd_tsdn(tsd), &bt2gctx_mtx); bt_count = ckh_count(&bt2gctx); malloc_mutex_unlock(tsd_tsdn(tsd), &bt2gctx_mtx); - return (bt_count); + return bt_count; } #endif @@ -943,7 +943,7 @@ prof_dump_open(bool propagate_err, const char *filename) { } } - return (fd); + return fd; } #ifdef JEMALLOC_JET #undef prof_dump_open @@ -971,7 +971,7 @@ prof_dump_flush(bool propagate_err) { } prof_dump_buf_end = 0; - return (ret); + return ret; } static bool @@ -983,7 +983,7 @@ prof_dump_close(bool propagate_err) { close(prof_dump_fd); prof_dump_fd = -1; - return (ret); + return ret; } static bool @@ -998,7 +998,7 @@ prof_dump_write(bool propagate_err, const char *s) { /* Flush the buffer if it is full. */ if (prof_dump_buf_end == PROF_DUMP_BUFSIZE) { if (prof_dump_flush(propagate_err) && propagate_err) { - return (true); + return true; } } @@ -1014,7 +1014,7 @@ prof_dump_write(bool propagate_err, const char *s) { i += n; } - return (false); + return false; } JEMALLOC_FORMAT_PRINTF(2, 3) @@ -1029,7 +1029,7 @@ prof_dump_printf(bool propagate_err, const char *format, ...) { va_end(ap); ret = prof_dump_write(propagate_err, buf); - return (ret); + return ret; } static void @@ -1093,7 +1093,7 @@ prof_tctx_merge_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) { not_reached(); } - return (NULL); + return NULL; } struct prof_tctx_dump_iter_arg_s { @@ -1120,13 +1120,13 @@ prof_tctx_dump_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *opaque) { "%"FMTu64"]\n", tctx->thr_uid, tctx->dump_cnts.curobjs, tctx->dump_cnts.curbytes, tctx->dump_cnts.accumobjs, tctx->dump_cnts.accumbytes)) { - return (tctx); + return tctx; } break; default: not_reached(); } - return (NULL); + return NULL; } static prof_tctx_t * @@ -1152,7 +1152,7 @@ prof_tctx_finish_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) { ret = NULL; label_return: - return (ret); + return ret; } static void @@ -1192,7 +1192,7 @@ prof_gctx_merge_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *opaque) { } malloc_mutex_unlock(arg->tsdn, gctx->lock); - return (NULL); + return NULL; } static void @@ -1279,7 +1279,7 @@ prof_tdata_merge_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, } malloc_mutex_unlock(arg->tsdn, tdata->lock); - return (NULL); + return NULL; } static prof_tdata_t * @@ -1288,7 +1288,7 @@ prof_tdata_dump_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, bool propagate_err = *(bool *)arg; if (!tdata->dumping) { - return (NULL); + return NULL; } if (prof_dump_printf(propagate_err, @@ -1298,9 +1298,9 @@ prof_tdata_dump_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, tdata->cnt_summed.accumbytes, (tdata->thread_name != NULL) ? " " : "", (tdata->thread_name != NULL) ? tdata->thread_name : "")) { - return (tdata); + return tdata; } - return (NULL); + return NULL; } #ifdef JEMALLOC_JET @@ -1316,14 +1316,14 @@ prof_dump_header(tsdn_t *tsdn, bool propagate_err, const prof_cnt_t *cnt_all) { " t*: %"FMTu64": %"FMTu64" [%"FMTu64": %"FMTu64"]\n", ((uint64_t)1U << lg_prof_sample), cnt_all->curobjs, cnt_all->curbytes, cnt_all->accumobjs, cnt_all->accumbytes)) { - return (true); + return true; } malloc_mutex_lock(tsdn, &tdatas_mtx); ret = (tdata_tree_iter(&tdatas, NULL, prof_tdata_dump_iter, (void *)&propagate_err) != NULL); malloc_mutex_unlock(tsdn, &tdatas_mtx); - return (ret); + return ret; } #ifdef JEMALLOC_JET #undef prof_dump_header @@ -1383,7 +1383,7 @@ prof_dump_gctx(tsdn_t *tsdn, bool propagate_err, prof_gctx_t *gctx, ret = false; label_return: - return (ret); + return ret; } #ifndef _WIN32 @@ -1399,16 +1399,16 @@ prof_open_maps(const char *format, ...) { va_end(ap); mfd = open(filename, O_RDONLY); - return (mfd); + return mfd; } #endif static int prof_getpid(void) { #ifdef _WIN32 - return (GetCurrentProcessId()); + return GetCurrentProcessId(); #else - return (getpid()); + return getpid(); #endif } @@ -1464,7 +1464,7 @@ label_return: if (mfd != -1) { close(mfd); } - return (ret); + return ret; } /* @@ -1524,7 +1524,7 @@ prof_gctx_dump_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *opaque) { ret = NULL; label_return: malloc_mutex_unlock(arg->tsdn, gctx->lock); - return (ret); + return ret; } static void @@ -1773,13 +1773,13 @@ prof_mdump(tsd_t *tsd, const char *filename) { cassert(config_prof); if (!opt_prof || !prof_booted) { - return (true); + return true; } if (filename == NULL) { /* No filename specified, so automatically generate one. */ if (opt_prof_prefix[0] == '\0') { - return (true); + return true; } malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_seq_mtx); prof_dump_filename(filename_buf, 'm', prof_dump_mseq); @@ -1787,7 +1787,7 @@ prof_mdump(tsd_t *tsd, const char *filename) { malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_seq_mtx); filename = filename_buf; } - return (prof_dump(tsd, true, filename, false)); + return prof_dump(tsd, true, filename, false); } void @@ -1837,7 +1837,7 @@ prof_bt_keycomp(const void *k1, const void *k2) { cassert(config_prof); if (bt1->len != bt2->len) { - return (false); + return false; } return (memcmp(bt1->vec, bt2->vec, bt1->len * sizeof(void *)) == 0); } @@ -1851,7 +1851,7 @@ prof_thr_uid_alloc(tsdn_t *tsdn) { next_thr_uid++; malloc_mutex_unlock(tsdn, &next_thr_uid_mtx); - return (thr_uid); + return thr_uid; } static prof_tdata_t * @@ -1866,7 +1866,7 @@ prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim, size2index(sizeof(prof_tdata_t)), false, NULL, true, arena_get(TSDN_NULL, 0, true), true); if (tdata == NULL) { - return (NULL); + return NULL; } tdata->lock = prof_tdata_mutex_choose(thr_uid); @@ -1881,7 +1881,7 @@ prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim, prof_bt_keycomp)) { idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tdata), tdata, NULL, true, true); - return (NULL); + return NULL; } tdata->prng_state = (uint64_t)(uintptr_t)tdata; @@ -1898,24 +1898,24 @@ prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim, tdata_tree_insert(&tdatas, tdata); malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx); - return (tdata); + return tdata; } prof_tdata_t * prof_tdata_init(tsd_t *tsd) { - return (prof_tdata_init_impl(tsd, prof_thr_uid_alloc(tsd_tsdn(tsd)), 0, - NULL, prof_thread_active_init_get(tsd_tsdn(tsd)))); + return prof_tdata_init_impl(tsd, prof_thr_uid_alloc(tsd_tsdn(tsd)), 0, + NULL, prof_thread_active_init_get(tsd_tsdn(tsd))); } static bool prof_tdata_should_destroy_unlocked(prof_tdata_t *tdata, bool even_if_attached) { if (tdata->attached && !even_if_attached) { - return (false); + return false; } if (ckh_count(&tdata->bt2tctx) != 0) { - return (false); + return false; } - return (true); + return true; } static bool @@ -1923,7 +1923,7 @@ prof_tdata_should_destroy(tsdn_t *tsdn, prof_tdata_t *tdata, bool even_if_attached) { malloc_mutex_assert_owner(tsdn, tdata->lock); - return (prof_tdata_should_destroy_unlocked(tdata, even_if_attached)); + return prof_tdata_should_destroy_unlocked(tdata, even_if_attached); } static void @@ -1985,8 +1985,8 @@ prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata) { bool active = tdata->active; prof_tdata_detach(tsd, tdata); - return (prof_tdata_init_impl(tsd, thr_uid, thr_discrim, thread_name, - active)); + return prof_tdata_init_impl(tsd, thr_uid, thr_discrim, thread_name, + active); } static bool @@ -2003,7 +2003,7 @@ prof_tdata_expire(tsdn_t *tsdn, prof_tdata_t *tdata) { } malloc_mutex_unlock(tsdn, tdata->lock); - return (destroy_tdata); + return destroy_tdata; } static prof_tdata_t * @@ -2062,7 +2062,7 @@ prof_active_get(tsdn_t *tsdn) { malloc_mutex_lock(tsdn, &prof_active_mtx); prof_active_current = prof_active; malloc_mutex_unlock(tsdn, &prof_active_mtx); - return (prof_active_current); + return prof_active_current; } bool @@ -2073,7 +2073,7 @@ prof_active_set(tsdn_t *tsdn, bool active) { prof_active_old = prof_active; prof_active = active; malloc_mutex_unlock(tsdn, &prof_active_mtx); - return (prof_active_old); + return prof_active_old; } const char * @@ -2082,7 +2082,7 @@ prof_thread_name_get(tsd_t *tsd) { tdata = prof_tdata_get(tsd, true); if (tdata == NULL) { - return (""); + return ""; } return (tdata->thread_name != NULL ? tdata->thread_name : ""); } @@ -2093,21 +2093,21 @@ prof_thread_name_alloc(tsdn_t *tsdn, const char *thread_name) { size_t size; if (thread_name == NULL) { - return (NULL); + return NULL; } size = strlen(thread_name) + 1; if (size == 1) { - return (""); + return ""; } ret = iallocztm(tsdn, size, size2index(size), false, NULL, true, arena_get(TSDN_NULL, 0, true), true); if (ret == NULL) { - return (NULL); + return NULL; } memcpy(ret, thread_name, size); - return (ret); + return ret; } int @@ -2118,23 +2118,23 @@ prof_thread_name_set(tsd_t *tsd, const char *thread_name) { tdata = prof_tdata_get(tsd, true); if (tdata == NULL) { - return (EAGAIN); + return EAGAIN; } /* Validate input. */ if (thread_name == NULL) { - return (EFAULT); + return EFAULT; } for (i = 0; thread_name[i] != '\0'; i++) { char c = thread_name[i]; if (!isgraph(c) && !isblank(c)) { - return (EFAULT); + return EFAULT; } } s = prof_thread_name_alloc(tsd_tsdn(tsd), thread_name); if (s == NULL) { - return (EAGAIN); + return EAGAIN; } if (tdata->thread_name != NULL) { @@ -2145,7 +2145,7 @@ prof_thread_name_set(tsd_t *tsd, const char *thread_name) { if (strlen(s) > 0) { tdata->thread_name = s; } - return (0); + return 0; } bool @@ -2154,9 +2154,9 @@ prof_thread_active_get(tsd_t *tsd) { tdata = prof_tdata_get(tsd, true); if (tdata == NULL) { - return (false); + return false; } - return (tdata->active); + return tdata->active; } bool @@ -2165,10 +2165,10 @@ prof_thread_active_set(tsd_t *tsd, bool active) { tdata = prof_tdata_get(tsd, true); if (tdata == NULL) { - return (true); + return true; } tdata->active = active; - return (false); + return false; } bool @@ -2178,7 +2178,7 @@ prof_thread_active_init_get(tsdn_t *tsdn) { malloc_mutex_lock(tsdn, &prof_thread_active_init_mtx); active_init = prof_thread_active_init; malloc_mutex_unlock(tsdn, &prof_thread_active_init_mtx); - return (active_init); + return active_init; } bool @@ -2189,7 +2189,7 @@ prof_thread_active_init_set(tsdn_t *tsdn, bool active_init) { active_init_old = prof_thread_active_init; prof_thread_active_init = active_init; malloc_mutex_unlock(tsdn, &prof_thread_active_init_mtx); - return (active_init_old); + return active_init_old; } bool @@ -2199,7 +2199,7 @@ prof_gdump_get(tsdn_t *tsdn) { malloc_mutex_lock(tsdn, &prof_gdump_mtx); prof_gdump_current = prof_gdump_val; malloc_mutex_unlock(tsdn, &prof_gdump_mtx); - return (prof_gdump_current); + return prof_gdump_current; } bool @@ -2210,7 +2210,7 @@ prof_gdump_set(tsdn_t *tsdn, bool gdump) { prof_gdump_old = prof_gdump_val; prof_gdump_val = gdump; malloc_mutex_unlock(tsdn, &prof_gdump_mtx); - return (prof_gdump_old); + return prof_gdump_old; } void @@ -2257,50 +2257,50 @@ prof_boot2(tsd_t *tsd) { prof_active = opt_prof_active; if (malloc_mutex_init(&prof_active_mtx, "prof_active", WITNESS_RANK_PROF_ACTIVE)) { - return (true); + return true; } prof_gdump_val = opt_prof_gdump; if (malloc_mutex_init(&prof_gdump_mtx, "prof_gdump", WITNESS_RANK_PROF_GDUMP)) { - return (true); + return true; } prof_thread_active_init = opt_prof_thread_active_init; if (malloc_mutex_init(&prof_thread_active_init_mtx, "prof_thread_active_init", WITNESS_RANK_PROF_THREAD_ACTIVE_INIT)) { - return (true); + return true; } if (ckh_new(tsd, &bt2gctx, PROF_CKH_MINITEMS, prof_bt_hash, prof_bt_keycomp)) { - return (true); + return true; } if (malloc_mutex_init(&bt2gctx_mtx, "prof_bt2gctx", WITNESS_RANK_PROF_BT2GCTX)) { - return (true); + return true; } tdata_tree_new(&tdatas); if (malloc_mutex_init(&tdatas_mtx, "prof_tdatas", WITNESS_RANK_PROF_TDATAS)) { - return (true); + return true; } next_thr_uid = 0; if (malloc_mutex_init(&next_thr_uid_mtx, "prof_next_thr_uid", WITNESS_RANK_PROF_NEXT_THR_UID)) { - return (true); + return true; } if (malloc_mutex_init(&prof_dump_seq_mtx, "prof_dump_seq", WITNESS_RANK_PROF_DUMP_SEQ)) { - return (true); + return true; } if (malloc_mutex_init(&prof_dump_mtx, "prof_dump", WITNESS_RANK_PROF_DUMP)) { - return (true); + return true; } if (opt_prof_final && opt_prof_prefix[0] != '\0' && @@ -2315,12 +2315,12 @@ prof_boot2(tsd_t *tsd) { b0get(), PROF_NCTX_LOCKS * sizeof(malloc_mutex_t), CACHELINE); if (gctx_locks == NULL) { - return (true); + return true; } for (i = 0; i < PROF_NCTX_LOCKS; i++) { if (malloc_mutex_init(&gctx_locks[i], "prof_gctx", WITNESS_RANK_PROF_GCTX)) { - return (true); + return true; } } @@ -2328,12 +2328,12 @@ prof_boot2(tsd_t *tsd) { b0get(), PROF_NTDATA_LOCKS * sizeof(malloc_mutex_t), CACHELINE); if (tdata_locks == NULL) { - return (true); + return true; } for (i = 0; i < PROF_NTDATA_LOCKS; i++) { if (malloc_mutex_init(&tdata_locks[i], "prof_tdata", WITNESS_RANK_PROF_TDATA)) { - return (true); + return true; } } } @@ -2348,7 +2348,7 @@ prof_boot2(tsd_t *tsd) { prof_booted = true; - return (false); + return false; } void diff --git a/src/rtree.c b/src/rtree.c index de3e5962..d0c5fe65 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -60,7 +60,7 @@ rtree_new(rtree_t *rtree, unsigned bits) { malloc_mutex_init(&rtree->init_lock, "rtree", WITNESS_RANK_RTREE); - return (false); + return false; } #ifdef JEMALLOC_JET @@ -69,8 +69,8 @@ rtree_new(rtree_t *rtree, unsigned bits) { #endif static rtree_elm_t * rtree_node_alloc(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { - return ((rtree_elm_t *)base_alloc(tsdn, b0get(), nelms * - sizeof(rtree_elm_t), CACHELINE)); + return (rtree_elm_t *)base_alloc(tsdn, b0get(), nelms * + sizeof(rtree_elm_t), CACHELINE); } #ifdef JEMALLOC_JET #undef rtree_node_alloc @@ -137,25 +137,25 @@ rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level, rtree->levels[level].bits); if (node == NULL) { malloc_mutex_unlock(tsdn, &rtree->init_lock); - return (NULL); + return NULL; } atomic_write_p((void **)elmp, node); } malloc_mutex_unlock(tsdn, &rtree->init_lock); - return (node); + return node; } rtree_elm_t * rtree_subtree_read_hard(tsdn_t *tsdn, rtree_t *rtree, unsigned level) { - return (rtree_node_init(tsdn, rtree, level, - &rtree->levels[level].subtree)); + return rtree_node_init(tsdn, rtree, level, + &rtree->levels[level].subtree); } rtree_elm_t * rtree_child_read_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level) { - return (rtree_node_init(tsdn, rtree, level+1, &elm->child)); + return rtree_node_init(tsdn, rtree, level+1, &elm->child); } static int @@ -167,7 +167,7 @@ rtree_elm_witness_comp(const witness_t *a, void *oa, const witness_t *b, assert(ka != 0); assert(kb != 0); - return ((ka > kb) - (ka < kb)); + return (ka > kb) - (ka < kb); } static witness_t * @@ -192,7 +192,7 @@ rtree_elm_witness_alloc(tsd_t *tsd, uintptr_t key, const rtree_elm_t *elm) { } } assert(witness != NULL); - return (witness); + return witness; } static witness_t * @@ -205,7 +205,7 @@ rtree_elm_witness_find(tsd_t *tsd, const rtree_elm_t *elm) { rtree_elm_witness_t *rew = &witnesses->witnesses[i]; if (rew->elm == elm) { - return (&rew->witness); + return &rew->witness; } } not_reached(); diff --git a/src/tcache.c b/src/tcache.c index bb6a5a75..0501c3fc 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -25,7 +25,7 @@ static tcaches_t *tcaches_avail; size_t tcache_salloc(tsdn_t *tsdn, const void *ptr) { - return (arena_salloc(tsdn, iealloc(tsdn, ptr), ptr)); + return arena_salloc(tsdn, iealloc(tsdn, ptr), ptr); } void @@ -82,7 +82,7 @@ tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, } ret = tcache_alloc_easy(tbin, tcache_success); - return (ret); + return ret; } void @@ -297,13 +297,13 @@ tcache_get_hard(tsd_t *tsd) { if (tsd_nominal(tsd)) { tcache_enabled_set(false); /* Memoize. */ } - return (NULL); + return NULL; } arena = arena_choose(tsd, NULL); if (unlikely(arena == NULL)) { - return (NULL); + return NULL; } - return (tcache_create(tsd_tsdn(tsd), arena)); + return tcache_create(tsd_tsdn(tsd), arena); } tcache_t * @@ -323,7 +323,7 @@ tcache_create(tsdn_t *tsdn, arena_t *arena) { tcache = ipallocztm(tsdn, size, CACHELINE, true, NULL, true, arena_get(TSDN_NULL, 0, true)); if (tcache == NULL) { - return (NULL); + return NULL; } tcache_arena_associate(tsdn, tcache, arena); @@ -343,7 +343,7 @@ tcache_create(tsdn_t *tsdn, arena_t *arena) { (uintptr_t)stack_offset); } - return (tcache); + return tcache; } static void @@ -432,20 +432,20 @@ tcaches_create(tsd_t *tsd, unsigned *r_ind) { tcaches = base_alloc(tsd_tsdn(tsd), b0get(), sizeof(tcache_t *) * (MALLOCX_TCACHE_MAX+1), CACHELINE); if (tcaches == NULL) { - return (true); + return true; } } if (tcaches_avail == NULL && tcaches_past > MALLOCX_TCACHE_MAX) { - return (true); + return true; } arena = arena_ichoose(tsd, NULL); if (unlikely(arena == NULL)) { - return (true); + return true; } tcache = tcache_create(tsd_tsdn(tsd), arena); if (tcache == NULL) { - return (true); + return true; } if (tcaches_avail != NULL) { @@ -460,7 +460,7 @@ tcaches_create(tsd_t *tsd, unsigned *r_ind) { tcaches_past++; } - return (false); + return false; } static void @@ -503,7 +503,7 @@ tcache_boot(tsdn_t *tsdn) { tcache_bin_info = (tcache_bin_info_t *)base_alloc(tsdn, b0get(), nhbins * sizeof(tcache_bin_info_t), CACHELINE); if (tcache_bin_info == NULL) { - return (true); + return true; } stack_nelms = 0; for (i = 0; i < NBINS; i++) { @@ -525,5 +525,5 @@ tcache_boot(tsdn_t *tsdn) { stack_nelms += tcache_bin_info[i].ncached_max; } - return (false); + return false; } diff --git a/src/tsd.c b/src/tsd.c index f02fc28e..ae77fcb1 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -13,7 +13,7 @@ malloc_tsd_data(, , tsd_t, TSD_INITIALIZER) void * malloc_tsd_malloc(size_t size) { - return (a0malloc(CACHELINE_CEILING(size))); + return a0malloc(CACHELINE_CEILING(size)); } void @@ -109,11 +109,11 @@ malloc_tsd_boot0(void) { ncleanups = 0; if (tsd_boot0()) { - return (NULL); + return NULL; } tsd = tsd_fetch(); *tsd_arenas_tdata_bypassp_get(tsd) = true; - return (tsd); + return tsd; } void @@ -137,7 +137,7 @@ _tls_callback(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { default: break; } - return (true); + return true; } #ifdef _MSC_VER @@ -167,7 +167,7 @@ tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block) { ql_foreach(iter, &head->blocks, link) { if (iter->thread == self) { malloc_mutex_unlock(TSDN_NULL, &head->lock); - return (iter->data); + return iter->data; } } /* Insert block into list. */ @@ -175,7 +175,7 @@ tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block) { block->thread = self; ql_tail_insert(&head->blocks, block, link); malloc_mutex_unlock(TSDN_NULL, &head->lock); - return (NULL); + return NULL; } void diff --git a/src/util.c b/src/util.c index a9595397..faa97c8d 100644 --- a/src/util.c +++ b/src/util.c @@ -87,16 +87,16 @@ buferror(int err, char *buf, size_t buflen) { #ifdef _WIN32 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, (LPSTR)buf, (DWORD)buflen, NULL); - return (0); + return 0; #elif defined(__GLIBC__) && defined(_GNU_SOURCE) char *b = strerror_r(err, buf, buflen); if (b != buf) { strncpy(buf, b, buflen); buf[buflen-1] = '\0'; } - return (0); + return 0; #else - return (strerror_r(err, buf, buflen)); + return strerror_r(err, buf, buflen); #endif } @@ -218,7 +218,7 @@ label_return: *endptr = (char *)p; } } - return (ret); + return ret; } static char * @@ -260,7 +260,7 @@ u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p) { }} *slen_p = U2S_BUFSIZE - 1 - i; - return (&s[i]); + return &s[i]; } static char * @@ -288,7 +288,7 @@ d2s(intmax_t x, char sign, char *s, size_t *slen_p) { break; default: not_reached(); } - return (s); + return s; } static char * @@ -299,7 +299,7 @@ o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p) { (*slen_p)++; *s = '0'; } - return (s); + return s; } static char * @@ -310,7 +310,7 @@ x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p) { (*slen_p) += 2; memcpy(s, uppercase ? "0X" : "0x", 2); } - return (s); + return s; } size_t @@ -593,7 +593,7 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) { #undef APPEND_S #undef APPEND_PADDED_S #undef GET_ARG_NUMERIC - return (i); + return i; } JEMALLOC_FORMAT_PRINTF(3, 4) @@ -606,7 +606,7 @@ malloc_snprintf(char *str, size_t size, const char *format, ...) { ret = malloc_vsnprintf(str, size, format, ap); va_end(ap); - return (ret); + return ret; } void diff --git a/src/zone.c b/src/zone.c index 8e106632..e69f0b4a 100644 --- a/src/zone.c +++ b/src/zone.c @@ -135,17 +135,17 @@ zone_size(malloc_zone_t *zone, const void *ptr) { * not work in practice, we must check all pointers to assure that they * reside within a mapped extent before determining size. */ - return (ivsalloc(tsdn_fetch(), ptr)); + return ivsalloc(tsdn_fetch(), ptr); } static void * zone_malloc(malloc_zone_t *zone, size_t size) { - return (je_malloc(size)); + return je_malloc(size); } static void * zone_calloc(malloc_zone_t *zone, size_t num, size_t size) { - return (je_calloc(num, size)); + return je_calloc(num, size); } static void * @@ -154,7 +154,7 @@ zone_valloc(malloc_zone_t *zone, size_t size) { je_posix_memalign(&ret, PAGE, size); - return (ret); + return ret; } static void @@ -170,10 +170,10 @@ zone_free(malloc_zone_t *zone, void *ptr) { static void * zone_realloc(malloc_zone_t *zone, void *ptr, size_t size) { if (ivsalloc(tsdn_fetch(), ptr) != 0) { - return (je_realloc(ptr, size)); + return je_realloc(ptr, size); } - return (realloc(ptr, size)); + return realloc(ptr, size); } static void * @@ -182,7 +182,7 @@ zone_memalign(malloc_zone_t *zone, size_t alignment, size_t size) { je_posix_memalign(&ret, alignment, size); - return (ret); + return ret; } static void @@ -240,7 +240,7 @@ zone_good_size(malloc_zone_t *zone, size_t size) { if (size == 0) { size = 1; } - return (s2u(size)); + return s2u(size); } static kern_return_t @@ -368,10 +368,10 @@ zone_default_get(void) { } if (num_zones) { - return (zones[0]); + return zones[0]; } - return (malloc_default_zone()); + return malloc_default_zone(); } /* As written, this function can only promote jemalloc_zone. */ diff --git a/test/include/test/btalloc.h b/test/include/test/btalloc.h index 98366afe..8b733f50 100644 --- a/test/include/test/btalloc.h +++ b/test/include/test/btalloc.h @@ -26,5 +26,5 @@ btalloc_##n(size_t size, unsigned bits) { \ } \ /* Intentionally sabotage tail call optimization. */ \ assert_ptr_not_null(p, "Unexpected mallocx() failure"); \ - return (p); \ + return p; \ } diff --git a/test/include/test/extent_hooks.h b/test/include/test/extent_hooks.h index a664c433..96fee103 100644 --- a/test/include/test/extent_hooks.h +++ b/test/include/test/extent_hooks.h @@ -86,12 +86,12 @@ extent_alloc_hook(extent_hooks_t *extent_hooks, void *new_addr, size_t size, "Wrong hook function"); called_alloc = true; if (!try_alloc) { - return (NULL); + return NULL; } ret = default_hooks->alloc(default_hooks, new_addr, size, alignment, zero, commit, 0); did_alloc = (ret != NULL); - return (ret); + return ret; } static bool @@ -108,11 +108,11 @@ extent_dalloc_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, "Wrong hook function"); called_dalloc = true; if (!try_dalloc) { - return (true); + return true; } err = default_hooks->dalloc(default_hooks, addr, size, committed, 0); did_dalloc = !err; - return (err); + return err; } static bool @@ -129,12 +129,12 @@ extent_commit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, "Wrong hook function"); called_commit = true; if (!try_commit) { - return (true); + return true; } err = default_hooks->commit(default_hooks, addr, size, offset, length, 0); did_commit = !err; - return (err); + return err; } static bool @@ -151,12 +151,12 @@ extent_decommit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, "Wrong hook function"); called_decommit = true; if (!try_decommit) { - return (true); + return true; } err = default_hooks->decommit(default_hooks, addr, size, offset, length, 0); did_decommit = !err; - return (err); + return err; } static bool @@ -173,13 +173,13 @@ extent_purge_lazy_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, "Wrong hook function"); called_purge_lazy = true; if (!try_purge_lazy) { - return (true); + return true; } err = default_hooks->purge_lazy == NULL || default_hooks->purge_lazy(default_hooks, addr, size, offset, length, 0); did_purge_lazy = !err; - return (err); + return err; } static bool @@ -196,13 +196,13 @@ extent_purge_forced_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, "Wrong hook function"); called_purge_forced = true; if (!try_purge_forced) { - return (true); + return true; } err = default_hooks->purge_forced == NULL || default_hooks->purge_forced(default_hooks, addr, size, offset, length, 0); did_purge_forced = !err; - return (err); + return err; } static bool @@ -220,13 +220,13 @@ extent_split_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, "Wrong hook function"); called_split = true; if (!try_split) { - return (true); + return true; } err = (default_hooks->split == NULL || default_hooks->split(default_hooks, addr, size, size_a, size_b, committed, 0)); did_split = !err; - return (err); + return err; } static bool @@ -244,13 +244,13 @@ extent_merge_hook(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, "Wrong hook function"); called_merge = true; if (!try_merge) { - return (true); + return true; } err = (default_hooks->merge == NULL || default_hooks->merge(default_hooks, addr_a, size_a, addr_b, size_b, committed, 0)); did_merge = !err; - return (err); + return err; } static void diff --git a/test/include/test/math.h b/test/include/test/math.h index 08be69f8..94173bad 100644 --- a/test/include/test/math.h +++ b/test/include/test/math.h @@ -36,9 +36,9 @@ ln_gamma(double x) { z = 1.0 / (x * x); - return (f + (x-0.5) * log(x) - x + 0.918938533204673 + + return f + (x-0.5) * log(x) - x + 0.918938533204673 + (((-0.000595238095238 * z + 0.000793650793651) * z - - 0.002777777777778) * z + 0.083333333333333) / x); + 0.002777777777778) * z + 0.083333333333333) / x; } /* @@ -60,7 +60,7 @@ i_gamma(double x, double p, double ln_gamma_p) { assert(x >= 0.0); if (x == 0.0) { - return (0.0); + return 0.0; } acu = 1.0e-10; @@ -80,7 +80,7 @@ i_gamma(double x, double p, double ln_gamma_p) { gin += term; if (term <= acu) { gin *= factor / p; - return (gin); + return gin; } } } else { @@ -107,7 +107,7 @@ i_gamma(double x, double p, double ln_gamma_p) { dif = fabs(gin - rn); if (dif <= acu && dif <= acu * rn) { gin = 1.0 - factor * gin; - return (gin); + return gin; } gin = rn; } @@ -144,7 +144,7 @@ pt_norm(double p) { if (fabs(q) <= 0.425) { /* p close to 1/2. */ r = 0.180625 - q * q; - return (q * (((((((2.5090809287301226727e3 * r + + return q * (((((((2.5090809287301226727e3 * r + 3.3430575583588128105e4) * r + 6.7265770927008700853e4) * r + 4.5921953931549871457e4) * r + 1.3731693765509461125e4) * r + 1.9715909503065514427e3) * r + 1.3314166789178437745e2) @@ -153,7 +153,7 @@ pt_norm(double p) { 2.8729085735721942674e4) * r + 3.9307895800092710610e4) * r + 2.1213794301586595867e4) * r + 5.3941960214247511077e3) * r + 6.8718700749205790830e2) * r + 4.2313330701600911252e1) - * r + 1.0)); + * r + 1.0); } else { if (q < 0.0) { r = p; @@ -204,7 +204,7 @@ pt_norm(double p) { if (q < 0.0) { ret = -ret; } - return (ret); + return ret; } } @@ -240,7 +240,7 @@ pt_chi2(double p, double df, double ln_gamma_df_2) { /* Starting approximation for small Chi^2. */ ch = pow(p * xx * exp(ln_gamma_df_2 + xx * aa), 1.0 / xx); if (ch - e < 0.0) { - return (ch); + return ch; } } else { if (df > 0.32) { @@ -279,7 +279,7 @@ pt_chi2(double p, double df, double ln_gamma_df_2) { q = ch; p1 = 0.5 * ch; if (p1 < 0.0) { - return (-1.0); + return -1.0; } p2 = p - i_gamma(p1, xx, ln_gamma_df_2); t = p2 * exp(xx * aa + ln_gamma_df_2 + p1 - c * log(ch)); @@ -301,7 +301,7 @@ pt_chi2(double p, double df, double ln_gamma_df_2) { } } - return (ch); + return ch; } /* @@ -311,6 +311,6 @@ pt_chi2(double p, double df, double ln_gamma_df_2) { */ JEMALLOC_INLINE double pt_gamma(double p, double shape, double scale, double ln_gamma_shape) { - return (pt_chi2(p, shape * 2.0, ln_gamma_shape) * 0.5 * scale); + return pt_chi2(p, shape * 2.0, ln_gamma_shape) * 0.5 * scale; } #endif diff --git a/test/include/test/mq.h b/test/include/test/mq.h index fd66de95..8d9907ba 100644 --- a/test/include/test/mq.h +++ b/test/include/test/mq.h @@ -38,11 +38,11 @@ a_attr bool \ a_prefix##init(a_mq_type *mq) { \ \ if (mtx_init(&mq->lock)) { \ - return (true); \ + return true; \ } \ ql_new(&mq->msgs); \ mq->count = 0; \ - return (false); \ + return false; \ } \ a_attr void \ a_prefix##fini(a_mq_type *mq) { \ @@ -55,7 +55,7 @@ a_prefix##count(a_mq_type *mq) { \ mtx_lock(&mq->lock); \ count = mq->count; \ mtx_unlock(&mq->lock); \ - return (count); \ + return count; \ } \ a_attr a_mq_msg_type * \ a_prefix##tryget(a_mq_type *mq) { \ @@ -68,7 +68,7 @@ a_prefix##tryget(a_mq_type *mq) { \ mq->count--; \ } \ mtx_unlock(&mq->lock); \ - return (msg); \ + return msg; \ } \ a_attr a_mq_msg_type * \ a_prefix##get(a_mq_type *mq) { \ @@ -77,7 +77,7 @@ a_prefix##get(a_mq_type *mq) { \ \ msg = a_prefix##tryget(mq); \ if (msg != NULL) { \ - return (msg); \ + return msg; \ } \ \ ns = 1; \ @@ -85,7 +85,7 @@ a_prefix##get(a_mq_type *mq) { \ mq_nanosleep(ns); \ msg = a_prefix##tryget(mq); \ if (msg != NULL) { \ - return (msg); \ + return msg; \ } \ if (ns < 1000*1000*1000) { \ /* Double sleep time, up to max 1 second. */ \ diff --git a/test/integration/MALLOCX_ARENA.c b/test/integration/MALLOCX_ARENA.c index f706e5a5..b2ec6584 100644 --- a/test/integration/MALLOCX_ARENA.c +++ b/test/integration/MALLOCX_ARENA.c @@ -41,7 +41,7 @@ thd_start(void *arg) { assert_ptr_not_null(p, "Unexpected mallocx() error"); dallocx(p, 0); - return (NULL); + return NULL; } TEST_BEGIN(test_MALLOCX_ARENA) { @@ -61,6 +61,6 @@ TEST_END int main(void) { - return (test( - test_MALLOCX_ARENA)); + return test( + test_MALLOCX_ARENA); } diff --git a/test/integration/aligned_alloc.c b/test/integration/aligned_alloc.c index 8a3ad6b9..54b3bf24 100644 --- a/test/integration/aligned_alloc.c +++ b/test/integration/aligned_alloc.c @@ -126,8 +126,8 @@ TEST_END int main(void) { - return (test( + return test( test_alignment_errors, test_oom_errors, - test_alignment_and_size)); + test_alignment_and_size); } diff --git a/test/integration/allocated.c b/test/integration/allocated.c index 555d40a9..1425fd0a 100644 --- a/test/integration/allocated.c +++ b/test/integration/allocated.c @@ -91,12 +91,12 @@ thd_start(void *arg) { "Deallocated memory counter should increase by at least the amount " "explicitly deallocated"); - return (NULL); + return NULL; label_ENOENT: assert_false(config_stats, "ENOENT should only be returned if stats are disabled"); test_skip("\"thread.allocated\" mallctl not available"); - return (NULL); + return NULL; } TEST_BEGIN(test_main_thread) { @@ -115,10 +115,10 @@ TEST_END int main(void) { /* Run tests multiple times to check for bad interactions. */ - return (test( + return test( test_main_thread, test_subthread, test_main_thread, test_subthread, - test_main_thread)); + test_main_thread); } diff --git a/test/integration/cpp/basic.cpp b/test/integration/cpp/basic.cpp index fe8874fa..65890ecd 100644 --- a/test/integration/cpp/basic.cpp +++ b/test/integration/cpp/basic.cpp @@ -20,6 +20,6 @@ TEST_END int main() { - return (test( - test_basic)); + return test( + test_basic); } diff --git a/test/integration/extent.c b/test/integration/extent.c index d12c123c..08792df3 100644 --- a/test/integration/extent.c +++ b/test/integration/extent.c @@ -174,7 +174,7 @@ TEST_END int main(void) { - return (test( + return test( test_extent_manual_hook, - test_extent_auto_hook)); + test_extent_auto_hook); } diff --git a/test/integration/mallocx.c b/test/integration/mallocx.c index ec04c399..26076be4 100644 --- a/test/integration/mallocx.c +++ b/test/integration/mallocx.c @@ -13,12 +13,12 @@ get_nsizes_impl(const char *cmd) { assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctl(\"%s\", ...) failure", cmd); - return (ret); + return ret; } static unsigned get_nlarge(void) { - return (get_nsizes_impl("arenas.nlextents")); + return get_nsizes_impl("arenas.nlextents"); } static size_t @@ -36,12 +36,12 @@ get_size_impl(const char *cmd, size_t ind) { assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); - return (ret); + return ret; } static size_t get_large_size(size_t ind) { - return (get_size_impl("arenas.lextent.0.size", ind)); + return get_size_impl("arenas.lextent.0.size", ind); } /* @@ -216,9 +216,9 @@ TEST_END int main(void) { - return (test( + return test( test_overflow, test_oom, test_basic, - test_alignment_and_size)); + test_alignment_and_size); } diff --git a/test/integration/overflow.c b/test/integration/overflow.c index a7f4b515..6a9785b2 100644 --- a/test/integration/overflow.c +++ b/test/integration/overflow.c @@ -41,6 +41,6 @@ TEST_END int main(void) { - return (test( - test_overflow)); + return test( + test_overflow); } diff --git a/test/integration/posix_memalign.c b/test/integration/posix_memalign.c index 6bbf1839..97b9216a 100644 --- a/test/integration/posix_memalign.c +++ b/test/integration/posix_memalign.c @@ -120,8 +120,8 @@ TEST_END int main(void) { - return (test( + return test( test_alignment_errors, test_oom_errors, - test_alignment_and_size)); + test_alignment_and_size); } diff --git a/test/integration/rallocx.c b/test/integration/rallocx.c index 176b9957..7c0f9c5f 100644 --- a/test/integration/rallocx.c +++ b/test/integration/rallocx.c @@ -9,12 +9,12 @@ get_nsizes_impl(const char *cmd) { assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctl(\"%s\", ...) failure", cmd); - return (ret); + return ret; } static unsigned get_nlarge(void) { - return (get_nsizes_impl("arenas.nlextents")); + return get_nsizes_impl("arenas.nlextents"); } static size_t @@ -32,12 +32,12 @@ get_size_impl(const char *cmd, size_t ind) { assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); - return (ret); + return ret; } static size_t get_large_size(size_t ind) { - return (get_size_impl("arenas.lextent.0.size", ind)); + return get_size_impl("arenas.lextent.0.size", ind); } TEST_BEGIN(test_grow_and_shrink) { @@ -100,7 +100,7 @@ validate_fill(const void *p, uint8_t c, size_t offset, size_t len) { } } - return (ret); + return ret; } TEST_BEGIN(test_zero) { @@ -236,10 +236,10 @@ TEST_END int main(void) { - return (test( + return test( test_grow_and_shrink, test_zero, test_align, test_lg_align_and_zero, - test_overflow)); + test_overflow); } diff --git a/test/integration/sdallocx.c b/test/integration/sdallocx.c index bf2fd2c0..f7b42949 100644 --- a/test/integration/sdallocx.c +++ b/test/integration/sdallocx.c @@ -49,7 +49,7 @@ TEST_END int main(void) { - return (test( + return test( test_basic, - test_alignment_and_size)); + test_alignment_and_size); } diff --git a/test/integration/thread_arena.c b/test/integration/thread_arena.c index 5adb5ce0..d9dc170d 100644 --- a/test/integration/thread_arena.c +++ b/test/integration/thread_arena.c @@ -34,7 +34,7 @@ thd_start(void *arg) { assert_u_eq(arena_ind, main_arena_ind, "Arena index should be same as for main thread"); - return (NULL); + return NULL; } TEST_BEGIN(test_thread_arena) { @@ -72,6 +72,6 @@ TEST_END int main(void) { - return (test( - test_thread_arena)); + return test( + test_thread_arena); } diff --git a/test/integration/thread_tcache_enabled.c b/test/integration/thread_tcache_enabled.c index 117d06bf..a0ba56b4 100644 --- a/test/integration/thread_tcache_enabled.c +++ b/test/integration/thread_tcache_enabled.c @@ -77,10 +77,10 @@ thd_start(void *arg) { assert_false(e0, "tcache should be disabled"); free(malloc(1)); - return (NULL); + return NULL; label_ENOENT: test_skip("\"thread.tcache.enabled\" mallctl not available"); - return (NULL); + return NULL; } TEST_BEGIN(test_main_thread) { @@ -99,10 +99,10 @@ TEST_END int main(void) { /* Run tests multiple times to check for bad interactions. */ - return (test( + return test( test_main_thread, test_subthread, test_main_thread, test_subthread, - test_main_thread)); + test_main_thread); } diff --git a/test/integration/xallocx.c b/test/integration/xallocx.c index 9b4b68e0..158f7ee9 100644 --- a/test/integration/xallocx.c +++ b/test/integration/xallocx.c @@ -19,7 +19,7 @@ arena_ind(void) { 0), 0, "Unexpected mallctl failure creating arena"); } - return (ind); + return ind; } TEST_BEGIN(test_same_size) { @@ -76,17 +76,17 @@ get_nsizes_impl(const char *cmd) { assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctl(\"%s\", ...) failure", cmd); - return (ret); + return ret; } static unsigned get_nsmall(void) { - return (get_nsizes_impl("arenas.nbins")); + return get_nsizes_impl("arenas.nbins"); } static unsigned get_nlarge(void) { - return (get_nsizes_impl("arenas.nlextents")); + return get_nsizes_impl("arenas.nlextents"); } static size_t @@ -104,17 +104,17 @@ get_size_impl(const char *cmd, size_t ind) { assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); - return (ret); + return ret; } static size_t get_small_size(size_t ind) { - return (get_size_impl("arenas.bin.0.size", ind)); + return get_size_impl("arenas.bin.0.size", ind); } static size_t get_large_size(size_t ind) { - return (get_size_impl("arenas.lextent.0.size", ind)); + return get_size_impl("arenas.lextent.0.size", ind); } TEST_BEGIN(test_size) { @@ -312,7 +312,7 @@ validate_fill(const void *p, uint8_t c, size_t offset, size_t len) { print_filled_extents(p, c, offset + len); } - return (err); + return err; } static void @@ -376,7 +376,7 @@ TEST_END int main(void) { - return (test( + return test( test_same_size, test_extra_no_move, test_no_move_fail, @@ -384,5 +384,5 @@ main(void) { test_size_extra_overflow, test_extra_small, test_extra_large, - test_zero_large)); + test_zero_large); } diff --git a/test/src/btalloc.c b/test/src/btalloc.c index bc31f9b8..d570952c 100644 --- a/test/src/btalloc.c +++ b/test/src/btalloc.c @@ -2,5 +2,5 @@ void * btalloc(size_t size, unsigned bits) { - return (btalloc_0(size, bits)); + return btalloc_0(size, bits); } diff --git a/test/src/mtx.c b/test/src/mtx.c index 924ba287..b691b482 100644 --- a/test/src/mtx.c +++ b/test/src/mtx.c @@ -9,7 +9,7 @@ mtx_init(mtx_t *mtx) { #ifdef _WIN32 if (!InitializeCriticalSectionAndSpinCount(&mtx->lock, _CRT_SPINCOUNT)) { - return (true); + return true; } #elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) mtx->lock = OS_UNFAIR_LOCK_INIT; @@ -19,16 +19,16 @@ mtx_init(mtx_t *mtx) { pthread_mutexattr_t attr; if (pthread_mutexattr_init(&attr) != 0) { - return (true); + return true; } pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT); if (pthread_mutex_init(&mtx->lock, &attr) != 0) { pthread_mutexattr_destroy(&attr); - return (true); + return true; } pthread_mutexattr_destroy(&attr); #endif - return (false); + return false; } void diff --git a/test/src/test.c b/test/src/test.c index 1155326b..c5101d4e 100644 --- a/test/src/test.c +++ b/test/src/test.c @@ -65,7 +65,7 @@ p_test_impl(bool do_malloc_init, test_t *t, va_list ap) { */ if (nallocx(1, 0) == 0) { malloc_printf("Initialization error"); - return (test_status_fail); + return test_status_fail; } } @@ -85,7 +85,7 @@ p_test_impl(bool do_malloc_init, test_t *t, va_list ap) { test_status_string(test_status_fail), test_counts[test_status_fail], test_count); - return (ret); + return ret; } test_status_t @@ -98,7 +98,7 @@ p_test(test_t *t, ...) { ret = p_test_impl(true, t, ap); va_end(ap); - return (ret); + return ret; } test_status_t @@ -111,7 +111,7 @@ p_test_no_malloc_init(test_t *t, ...) { ret = p_test_impl(false, t, ap); va_end(ap); - return (ret); + return ret; } void diff --git a/test/src/timer.c b/test/src/timer.c index 1b186332..c451c639 100644 --- a/test/src/timer.c +++ b/test/src/timer.c @@ -18,7 +18,7 @@ timer_usec(const timedelta_t *timer) { nstime_copy(&delta, &timer->t1); nstime_subtract(&delta, &timer->t0); - return (nstime_ns(&delta) / 1000); + return nstime_ns(&delta) / 1000; } void diff --git a/test/stress/microbench.c b/test/stress/microbench.c index 3b7e9660..6ed15001 100644 --- a/test/stress/microbench.c +++ b/test/stress/microbench.c @@ -156,10 +156,10 @@ TEST_END int main(void) { - return (test( + return test( test_malloc_vs_mallocx, test_free_vs_dallocx, test_dallocx_vs_sdallocx, test_mus_vs_sallocx, - test_sallocx_vs_nallocx)); + test_sallocx_vs_nallocx); } diff --git a/test/unit/SFMT.c b/test/unit/SFMT.c index b1bcf3d3..b5730d63 100644 --- a/test/unit/SFMT.c +++ b/test/unit/SFMT.c @@ -1591,9 +1591,9 @@ TEST_END int main(void) { - return (test( + return test( test_gen_rand_32, test_by_array_32, test_gen_rand_64, - test_by_array_64)); + test_by_array_64); } diff --git a/test/unit/a0.c b/test/unit/a0.c index c7ce8cfb..a27ab3f4 100644 --- a/test/unit/a0.c +++ b/test/unit/a0.c @@ -11,6 +11,6 @@ TEST_END int main(void) { - return (test_no_malloc_init( - test_a0)); + return test_no_malloc_init( + test_a0); } diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 710aaf53..3d74e37a 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -13,17 +13,17 @@ get_nsizes_impl(const char *cmd) { assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctl(\"%s\", ...) failure", cmd); - return (ret); + return ret; } static unsigned get_nsmall(void) { - return (get_nsizes_impl("arenas.nbins")); + return get_nsizes_impl("arenas.nbins"); } static unsigned get_nlarge(void) { - return (get_nsizes_impl("arenas.nlextents")); + return get_nsizes_impl("arenas.nlextents"); } static size_t @@ -41,17 +41,17 @@ get_size_impl(const char *cmd, size_t ind) { assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0), 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); - return (ret); + return ret; } static size_t get_small_size(size_t ind) { - return (get_size_impl("arenas.bin.0.size", ind)); + return get_size_impl("arenas.bin.0.size", ind); } static size_t get_large_size(size_t ind) { - return (get_size_impl("arenas.lextent.0.size", ind)); + return get_size_impl("arenas.lextent.0.size", ind); } /* Like ivsalloc(), but safe to call on discarded allocations. */ @@ -61,13 +61,13 @@ vsalloc(tsdn_t *tsdn, const void *ptr) { extent = extent_lookup(tsdn, ptr, false); if (extent == NULL) { - return (0); + return 0; } if (!extent_active_get(extent)) { - return (0); + return 0; } - return (isalloc(tsdn, extent, ptr)); + return isalloc(tsdn, extent, ptr); } static unsigned @@ -77,7 +77,7 @@ do_arena_create(extent_hooks_t *h) { assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, (void *)(h != NULL ? &h : NULL), (h != NULL ? sizeof(h) : 0)), 0, "Unexpected mallctl() failure"); - return (arena_ind); + return arena_ind; } static void @@ -190,7 +190,7 @@ arena_i_initialized(unsigned arena_ind, bool refresh) { assert_d_eq(mallctlbymib(mib, miblen, (void *)&initialized, &sz, NULL, 0), 0, "Unexpected mallctlbymib() failure"); - return (initialized); + return initialized; } TEST_BEGIN(test_arena_destroy_initial) { @@ -255,11 +255,11 @@ extent_dalloc_unmap(extent_hooks_t *extent_hooks, void *addr, size_t size, "Wrong hook function"); called_dalloc = true; if (!try_dalloc) { - return (true); + return true; } pages_unmap(addr, size); did_dalloc = true; - return (false); + return false; } static extent_hooks_t hooks_orig; @@ -313,9 +313,9 @@ TEST_END int main(void) { - return (test( + return test( test_arena_reset, test_arena_destroy_initial, test_arena_destroy_hooks_default, - test_arena_destroy_hooks_unmap)); + test_arena_destroy_hooks_unmap); } diff --git a/test/unit/atomic.c b/test/unit/atomic.c index 3e36acd1..97ec7eb9 100644 --- a/test/unit/atomic.c +++ b/test/unit/atomic.c @@ -101,10 +101,10 @@ TEST_END int main(void) { - return (test( + return test( test_atomic_u64, test_atomic_u32, test_atomic_p, test_atomic_zu, - test_atomic_u)); + test_atomic_u); } diff --git a/test/unit/base.c b/test/unit/base.c index 65cf980b..87116a3c 100644 --- a/test/unit/base.c +++ b/test/unit/base.c @@ -212,8 +212,8 @@ TEST_END int main(void) { - return (test( + return test( test_base_hooks_default, test_base_hooks_null, - test_base_hooks_not_null)); + test_base_hooks_not_null); } diff --git a/test/unit/bitmap.c b/test/unit/bitmap.c index 6dfa72f2..e91f0928 100644 --- a/test/unit/bitmap.c +++ b/test/unit/bitmap.c @@ -143,7 +143,7 @@ test_bitmap_size_body(const bitmap_info_t *binfo, size_t nbits, assert_zu_ge(size, (nbits >> 3), "Bitmap size is smaller than expected"); assert_zu_ge(size, prev_size, "Bitmap size is smaller than expected"); - return (size); + return size; } TEST_BEGIN(test_bitmap_size) { @@ -329,11 +329,11 @@ TEST_END int main(void) { - return (test( + return test( test_bitmap_initializer, test_bitmap_size, test_bitmap_init, test_bitmap_set, test_bitmap_unset, - test_bitmap_sfu)); + test_bitmap_sfu); } diff --git a/test/unit/ckh.c b/test/unit/ckh.c index 0638cb33..842ae29b 100644 --- a/test/unit/ckh.c +++ b/test/unit/ckh.c @@ -204,8 +204,8 @@ TEST_END int main(void) { - return (test( + return test( test_new_delete, test_count_insert_search_remove, - test_insert_iter_remove)); + test_insert_iter_remove); } diff --git a/test/unit/decay.c b/test/unit/decay.c index d6334cd2..83c9f49e 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -11,7 +11,7 @@ static bool monotonic_mock; static bool nstime_monotonic_mock(void) { - return (monotonic_mock); + return monotonic_mock; } static bool @@ -20,7 +20,7 @@ nstime_update_mock(nstime_t *time) { if (monotonic_mock) { nstime_copy(time, &time_mock); } - return (!monotonic_mock); + return !monotonic_mock; } TEST_BEGIN(test_decay_ticks) { @@ -352,8 +352,8 @@ TEST_END int main(void) { - return (test( + return test( test_decay_ticks, test_decay_ticker, - test_decay_nonmonotonic)); + test_decay_nonmonotonic); } diff --git a/test/unit/extent_quantize.c b/test/unit/extent_quantize.c index 343d1d8f..52af7a3d 100644 --- a/test/unit/extent_quantize.c +++ b/test/unit/extent_quantize.c @@ -134,8 +134,8 @@ TEST_END int main(void) { - return (test( + return test( test_small_extent_size, test_large_extent_size, - test_monotonic)); + test_monotonic); } diff --git a/test/unit/fork.c b/test/unit/fork.c index 4880328e..96b1c5a0 100644 --- a/test/unit/fork.c +++ b/test/unit/fork.c @@ -57,6 +57,6 @@ TEST_END int main(void) { - return (test( - test_fork)); + return test( + test_fork); } diff --git a/test/unit/hash.c b/test/unit/hash.c index 977d058f..0204cdad 100644 --- a/test/unit/hash.c +++ b/test/unit/hash.c @@ -38,9 +38,9 @@ typedef enum { static int hash_variant_bits(hash_variant_t variant) { switch (variant) { - case hash_variant_x86_32: return (32); - case hash_variant_x86_128: return (128); - case hash_variant_x64_128: return (128); + case hash_variant_x86_32: return 32; + case hash_variant_x86_128: return 128; + case hash_variant_x64_128: return 128; default: not_reached(); } } @@ -48,9 +48,9 @@ hash_variant_bits(hash_variant_t variant) { static const char * hash_variant_string(hash_variant_t variant) { switch (variant) { - case hash_variant_x86_32: return ("hash_x86_32"); - case hash_variant_x86_128: return ("hash_x86_128"); - case hash_variant_x64_128: return ("hash_x64_128"); + case hash_variant_x86_32: return "hash_x86_32"; + case hash_variant_x86_128: return "hash_x86_128"; + case hash_variant_x64_128: return "hash_x64_128"; default: not_reached(); } } @@ -165,8 +165,8 @@ TEST_END int main(void) { - return (test( + return test( test_hash_x86_32, test_hash_x86_128, - test_hash_x64_128)); + test_hash_x64_128); } diff --git a/test/unit/junk.c b/test/unit/junk.c index 02f0726d..86c51089 100644 --- a/test/unit/junk.c +++ b/test/unit/junk.c @@ -138,7 +138,7 @@ TEST_END int main(void) { - return (test( + return test( test_junk_small, - test_junk_large)); + test_junk_large); } diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index a116894b..c531a06a 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -621,7 +621,7 @@ TEST_END int main(void) { - return (test( + return test( test_mallctl_errors, test_mallctlnametomib_errors, test_mallctlbymib_errors, @@ -643,5 +643,5 @@ main(void) { test_arenas_bin_constants, test_arenas_lextent_constants, test_arenas_create, - test_stats_arenas)); + test_stats_arenas); } diff --git a/test/unit/math.c b/test/unit/math.c index 15fc7d54..d2cf16dd 100644 --- a/test/unit/math.c +++ b/test/unit/math.c @@ -18,7 +18,7 @@ double_eq_rel(double a, double b, double max_rel_err, double max_abs_err) { double rel_err; if (fabs(a - b) < max_abs_err) { - return (true); + return true; } rel_err = (fabs(b) > fabs(a)) ? fabs((a-b)/b) : fabs((a-b)/a); return (rel_err < max_rel_err); @@ -33,7 +33,7 @@ factorial(unsigned x) { ret *= (uint64_t)i; } - return (ret); + return ret; } TEST_BEGIN(test_ln_gamma_factorial) { @@ -380,11 +380,11 @@ TEST_END int main(void) { - return (test( + return test( test_ln_gamma_factorial, test_ln_gamma_misc, test_pt_norm, test_pt_chi2, test_pt_gamma_shape, - test_pt_gamma_scale)); + test_pt_gamma_scale); } diff --git a/test/unit/mq.c b/test/unit/mq.c index 95c9c500..fe17943e 100644 --- a/test/unit/mq.c +++ b/test/unit/mq.c @@ -39,7 +39,7 @@ thd_receiver_start(void *arg) { assert_ptr_not_null(msg, "mq_get() should never return NULL"); dallocx(msg, 0); } - return (NULL); + return NULL; } static void * @@ -55,7 +55,7 @@ thd_sender_start(void *arg) { msg = (mq_msg_t *)p; mq_put(mq, msg); } - return (NULL); + return NULL; } TEST_BEGIN(test_mq_threaded) { @@ -82,8 +82,8 @@ TEST_END int main(void) { - return (test( + return test( test_mq_basic, - test_mq_threaded)); + test_mq_threaded); } diff --git a/test/unit/mtx.c b/test/unit/mtx.c index 0813a699..23740ce1 100644 --- a/test/unit/mtx.c +++ b/test/unit/mtx.c @@ -28,7 +28,7 @@ thd_start(void *varg) { arg->x++; mtx_unlock(&arg->mtx); } - return (NULL); + return NULL; } TEST_BEGIN(test_mtx_race) { @@ -51,7 +51,7 @@ TEST_END int main(void) { - return (test( + return test( test_mtx_basic, - test_mtx_race)); + test_mtx_race); } diff --git a/test/unit/nstime.c b/test/unit/nstime.c index f628a8f3..f7f1bdfd 100644 --- a/test/unit/nstime.c +++ b/test/unit/nstime.c @@ -198,7 +198,7 @@ TEST_END int main(void) { - return (test( + return test( test_nstime_init, test_nstime_init2, test_nstime_copy, @@ -209,5 +209,5 @@ main(void) { test_nstime_idivide, test_nstime_divide, test_nstime_monotonic, - test_nstime_update)); + test_nstime_update); } diff --git a/test/unit/pack.c b/test/unit/pack.c index 9237ba2e..3edd405d 100644 --- a/test/unit/pack.c +++ b/test/unit/pack.c @@ -41,12 +41,12 @@ binind_compute(void) { assert_d_eq(mallctlbymib(mib, miblen, (void *)&size, &sz, NULL, 0), 0, "Unexpected mallctlbymib failure"); if (size == SZ) { - return (i); + return i; } } test_fail("Unable to compute nregs_per_run"); - return (0); + return 0; } static size_t @@ -63,7 +63,7 @@ nregs_per_run_compute(void) { sz = sizeof(nregs); assert_d_eq(mallctlbymib(mib, miblen, (void *)&nregs, &sz, NULL, 0), 0, "Unexpected mallctlbymib failure"); - return (nregs); + return nregs; } static unsigned @@ -75,7 +75,7 @@ arenas_create_mallctl(void) { assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), 0, "Error in arenas.create"); - return (arena_ind); + return arena_ind; } static void @@ -158,6 +158,6 @@ TEST_END int main(void) { - return (test( - test_pack)); + return test( + test_pack); } diff --git a/test/unit/pages.c b/test/unit/pages.c index b6092de0..30d69592 100644 --- a/test/unit/pages.c +++ b/test/unit/pages.c @@ -22,6 +22,6 @@ TEST_END int main(void) { - return (test( - test_pages_huge)); + return test( + test_pages_huge); } diff --git a/test/unit/ph.c b/test/unit/ph.c index e49a0e78..5f3c5a45 100644 --- a/test/unit/ph.c +++ b/test/unit/ph.c @@ -22,7 +22,7 @@ node_cmp(const node_t *a, const node_t *b) { ret = (((uintptr_t)a) > ((uintptr_t)b)) - (((uintptr_t)a) < ((uintptr_t)b)); } - return (ret); + return ret; } static int @@ -31,7 +31,7 @@ node_cmp_magic(const node_t *a, const node_t *b) { assert_u32_eq(a->magic, NODE_MAGIC, "Bad magic"); assert_u32_eq(b->magic, NODE_MAGIC, "Bad magic"); - return (node_cmp(a, b)); + return node_cmp(a, b); } typedef ph(node_t) heap_t; @@ -94,7 +94,7 @@ node_validate(const node_t *node, const node_t *parent) { leftmost_child = phn_lchild_get(node_t, link, node); if (leftmost_child == NULL) { - return (nnodes); + return nnodes; } assert_ptr_eq((void *)phn_prev_get(node_t, link, leftmost_child), (void *)node, "Leftmost child does not link to node"); @@ -107,7 +107,7 @@ node_validate(const node_t *node, const node_t *parent) { "sibling's prev doesn't link to sibling"); nnodes += node_validate(sibling, node); } - return (nnodes); + return nnodes; } static unsigned @@ -133,7 +133,7 @@ label_return: if (false) { heap_print(heap); } - return (nnodes); + return nnodes; } TEST_BEGIN(test_ph_empty) { @@ -156,7 +156,7 @@ static node_t * node_remove_first(heap_t *heap) { node_t *node = heap_remove_first(heap); node->magic = 0; - return (node); + return node; } TEST_BEGIN(test_ph_random) { @@ -281,7 +281,7 @@ TEST_END int main(void) { - return (test( + return test( test_ph_empty, - test_ph_random)); + test_ph_random); } diff --git a/test/unit/prng.c b/test/unit/prng.c index b26da36e..cbccb8a0 100644 --- a/test/unit/prng.c +++ b/test/unit/prng.c @@ -221,7 +221,7 @@ TEST_END int main(void) { - return (test( + return test( test_prng_lg_range_u32_nonatomic, test_prng_lg_range_u32_atomic, test_prng_lg_range_u64_nonatomic, @@ -231,5 +231,5 @@ main(void) { test_prng_range_u32_atomic, test_prng_range_u64_nonatomic, test_prng_range_zu_nonatomic, - test_prng_range_zu_atomic)); + test_prng_range_zu_atomic); } diff --git a/test/unit/prof_accum.c b/test/unit/prof_accum.c index bed0c9a6..ad7a3eaa 100644 --- a/test/unit/prof_accum.c +++ b/test/unit/prof_accum.c @@ -17,12 +17,12 @@ prof_dump_open_intercept(bool propagate_err, const char *filename) { fd = open("/dev/null", O_WRONLY); assert_d_ne(fd, -1, "Unexpected open() failure"); - return (fd); + return fd; } static void * alloc_from_permuted_backtrace(unsigned thd_ind, unsigned iteration) { - return (btalloc(1, thd_ind*NALLOCS_PER_THREAD + iteration)); + return btalloc(1, thd_ind*NALLOCS_PER_THREAD + iteration); } static void * @@ -51,7 +51,7 @@ thd_start(void *varg) { } } - return (NULL); + return NULL; } TEST_BEGIN(test_idump) { @@ -81,6 +81,6 @@ TEST_END int main(void) { - return (test( - test_idump)); + return test( + test_idump); } diff --git a/test/unit/prof_active.c b/test/unit/prof_active.c index 422024f1..9bcb3e3b 100644 --- a/test/unit/prof_active.c +++ b/test/unit/prof_active.c @@ -117,6 +117,6 @@ TEST_END int main(void) { - return (test( - test_prof_active)); + return test( + test_prof_active); } diff --git a/test/unit/prof_gdump.c b/test/unit/prof_gdump.c index 0d8ec71c..30320b7a 100644 --- a/test/unit/prof_gdump.c +++ b/test/unit/prof_gdump.c @@ -15,7 +15,7 @@ prof_dump_open_intercept(bool propagate_err, const char *filename) { fd = open("/dev/null", O_WRONLY); assert_d_ne(fd, -1, "Unexpected open() failure"); - return (fd); + return fd; } TEST_BEGIN(test_gdump) { @@ -73,6 +73,6 @@ TEST_END int main(void) { - return (test( - test_gdump)); + return test( + test_gdump); } diff --git a/test/unit/prof_idump.c b/test/unit/prof_idump.c index 393211ea..1fed7b37 100644 --- a/test/unit/prof_idump.c +++ b/test/unit/prof_idump.c @@ -24,7 +24,7 @@ prof_dump_open_intercept(bool propagate_err, const char *filename) { fd = open("/dev/null", O_WRONLY); assert_d_ne(fd, -1, "Unexpected open() failure"); - return (fd); + return fd; } TEST_BEGIN(test_idump) { @@ -50,6 +50,6 @@ TEST_END int main(void) { - return (test( - test_idump)); + return test( + test_idump); } diff --git a/test/unit/prof_reset.c b/test/unit/prof_reset.c index 463f6893..c2bb50d6 100644 --- a/test/unit/prof_reset.c +++ b/test/unit/prof_reset.c @@ -12,7 +12,7 @@ prof_dump_open_intercept(bool propagate_err, const char *filename) { fd = open("/dev/null", O_WRONLY); assert_d_ne(fd, -1, "Unexpected open() failure"); - return (fd); + return fd; } static void @@ -29,7 +29,7 @@ get_lg_prof_sample(void) { assert_d_eq(mallctl("prof.lg_sample", (void *)&lg_prof_sample, &sz, NULL, 0), 0, "Unexpected mallctl failure while reading profiling sample rate"); - return (lg_prof_sample); + return lg_prof_sample; } static void @@ -94,7 +94,7 @@ prof_dump_header_intercept(tsdn_t *tsdn, bool propagate_err, prof_dump_header_intercepted = true; memcpy(&cnt_all_copy, cnt_all, sizeof(prof_cnt_t)); - return (false); + return false; } TEST_BEGIN(test_prof_reset_cleanup) { @@ -181,7 +181,7 @@ thd_start(void *varg) { } } - return (NULL); + return NULL; } TEST_BEGIN(test_prof_reset) { @@ -283,9 +283,9 @@ main(void) { /* Intercept dumping prior to running any tests. */ prof_dump_open = prof_dump_open_intercept; - return (test( + return test( test_prof_reset_basic, test_prof_reset_cleanup, test_prof_reset, - test_xallocx)); + test_xallocx); } diff --git a/test/unit/prof_thread_name.c b/test/unit/prof_thread_name.c index ba86e10e..bcf85f89 100644 --- a/test/unit/prof_thread_name.c +++ b/test/unit/prof_thread_name.c @@ -94,7 +94,7 @@ thd_start(void *varg) { mallctl_thread_name_set(thread_name); mallctl_thread_name_set(""); - return (NULL); + return NULL; } TEST_BEGIN(test_prof_thread_name_threaded) { @@ -118,7 +118,7 @@ TEST_END int main(void) { - return (test( + return test( test_prof_thread_name_validation, - test_prof_thread_name_threaded)); + test_prof_thread_name_threaded); } diff --git a/test/unit/ql.c b/test/unit/ql.c index 0bb896cb..231a7243 100644 --- a/test/unit/ql.c +++ b/test/unit/ql.c @@ -192,11 +192,11 @@ TEST_END int main(void) { - return (test( + return test( test_ql_empty, test_ql_tail_insert, test_ql_tail_remove, test_ql_head_insert, test_ql_head_remove, - test_ql_insert)); + test_ql_insert); } diff --git a/test/unit/qr.c b/test/unit/qr.c index 8061a345..9a72d308 100644 --- a/test/unit/qr.c +++ b/test/unit/qr.c @@ -232,10 +232,10 @@ TEST_END int main(void) { - return (test( + return test( test_qr_one, test_qr_after_insert, test_qr_remove, test_qr_before_insert, - test_qr_meld_split)); + test_qr_meld_split); } diff --git a/test/unit/rb.c b/test/unit/rb.c index dea86c6e..dab2c3a2 100644 --- a/test/unit/rb.c +++ b/test/unit/rb.c @@ -36,7 +36,7 @@ node_cmp(const node_t *a, const node_t *b) { ret = (((uintptr_t)a) > ((uintptr_t)b)) - (((uintptr_t)a) < ((uintptr_t)b)); } - return (ret); + return ret; } typedef rb_tree(node_t) tree_t; @@ -73,7 +73,7 @@ tree_recurse(node_t *node, unsigned black_height, unsigned black_depth) { node_t *right_node; if (node == NULL) { - return (ret); + return ret; } left_node = rbtn_left_get(node_t, link, node); @@ -112,7 +112,7 @@ tree_recurse(node_t *node, unsigned black_height, unsigned black_depth) { ret += (black_depth != black_height); } - return (ret); + return ret; } static node_t * @@ -139,7 +139,7 @@ tree_iterate_cb(tree_t *tree, node_t *node, void *data) { (*i)++; - return (NULL); + return NULL; } static unsigned @@ -149,7 +149,7 @@ tree_iterate(tree_t *tree) { i = 0; tree_iter(tree, NULL, tree_iterate_cb, (void *)&i); - return (i); + return i; } static unsigned @@ -159,7 +159,7 @@ tree_iterate_reverse(tree_t *tree) { i = 0; tree_reverse_iter(tree, NULL, tree_iterate_cb, (void *)&i); - return (i); + return i; } static void @@ -201,7 +201,7 @@ remove_iterate_cb(tree_t *tree, node_t *node, void *data) { node_remove(tree, node, *nnodes); - return (ret); + return ret; } static node_t * @@ -211,7 +211,7 @@ remove_reverse_iterate_cb(tree_t *tree, node_t *node, void *data) { node_remove(tree, node, *nnodes); - return (ret); + return ret; } static void @@ -347,7 +347,7 @@ TEST_END int main(void) { - return (test( + return test( test_rb_empty, - test_rb_random)); + test_rb_random); } diff --git a/test/unit/rtree.c b/test/unit/rtree.c index ca99f8a8..344ac16a 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -18,7 +18,7 @@ rtree_node_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { assert_ptr_not_null(node, "Unexpected calloc() failure"); malloc_mutex_lock(tsdn, &rtree->init_lock); - return (node); + return node; } static void @@ -102,7 +102,7 @@ thd_start(void *varg) { free(extent); fini_gen_rand(sfmt); - return (NULL); + return NULL; } TEST_BEGIN(test_rtree_concurrent) { @@ -283,10 +283,10 @@ main(void) { rtree_node_dalloc = rtree_node_dalloc_intercept; test_rtree = NULL; - return (test( + return test( test_rtree_read_empty, test_rtree_concurrent, test_rtree_extrema, test_rtree_bits, - test_rtree_random)); + test_rtree_random); } diff --git a/test/unit/size_classes.c b/test/unit/size_classes.c index 38ea9bee..70a86ad9 100644 --- a/test/unit/size_classes.c +++ b/test/unit/size_classes.c @@ -19,7 +19,7 @@ get_max_size_class(void) { assert_d_eq(mallctlbymib(mib, miblen, (void *)&max_size_class, &sz, NULL, 0), 0, "Unexpected mallctlbymib() error"); - return (max_size_class); + return max_size_class; } TEST_BEGIN(test_size_classes) { @@ -173,8 +173,8 @@ TEST_END int main(void) { - return (test( + return test( test_size_classes, test_psize_classes, - test_overflow)); + test_overflow); } diff --git a/test/unit/slab.c b/test/unit/slab.c index a5036f59..d3b45e80 100644 --- a/test/unit/slab.c +++ b/test/unit/slab.c @@ -27,6 +27,6 @@ TEST_END int main(void) { - return (test( - test_arena_slab_regind)); + return test( + test_arena_slab_regind); } diff --git a/test/unit/smoothstep.c b/test/unit/smoothstep.c index ac279159..bf5dfb1d 100644 --- a/test/unit/smoothstep.c +++ b/test/unit/smoothstep.c @@ -95,8 +95,8 @@ TEST_END int main(void) { - return (test( + return test( test_smoothstep_integral, test_smoothstep_monotonic, - test_smoothstep_slope)); + test_smoothstep_slope); } diff --git a/test/unit/stats.c b/test/unit/stats.c index 98673a8e..948132cb 100644 --- a/test/unit/stats.c +++ b/test/unit/stats.c @@ -116,7 +116,7 @@ TEST_END void * thd_start(void *arg) { - return (NULL); + return NULL; } static void @@ -339,12 +339,12 @@ TEST_END int main(void) { - return (test( + return test( test_stats_summary, test_stats_large, test_stats_arenas_summary, test_stats_arenas_small, test_stats_arenas_large, test_stats_arenas_bins, - test_stats_arenas_lextents)); + test_stats_arenas_lextents); } diff --git a/test/unit/stats_print.c b/test/unit/stats_print.c index 1fb8fe6f..5a11b503 100644 --- a/test/unit/stats_print.c +++ b/test/unit/stats_print.c @@ -983,7 +983,7 @@ TEST_END int main(void) { - return (test( + return test( test_json_parser, - test_stats_print_json)); + test_stats_print_json); } diff --git a/test/unit/ticker.c b/test/unit/ticker.c index be54356f..32236f2c 100644 --- a/test/unit/ticker.c +++ b/test/unit/ticker.c @@ -64,8 +64,8 @@ TEST_END int main(void) { - return (test( + return test( test_ticker_tick, test_ticker_ticks, - test_ticker_copy)); + test_ticker_copy); } diff --git a/test/unit/tsd.c b/test/unit/tsd.c index 484dc30b..f34f0e78 100644 --- a/test/unit/tsd.c +++ b/test/unit/tsd.c @@ -71,7 +71,7 @@ thd_start(void *arg) { "Resetting local data should have no effect on tsd"); free(p); - return (NULL); + return NULL; } TEST_BEGIN(test_tsd_main_thread) { @@ -95,11 +95,11 @@ main(void) { /* Core tsd bootstrapping must happen prior to data_tsd_boot(). */ if (nallocx(1, 0) == 0) { malloc_printf("Initialization error"); - return (test_status_fail); + return test_status_fail; } data_tsd_boot(); - return (test( + return test( test_tsd_main_thread, - test_tsd_sub_thread)); + test_tsd_sub_thread); } diff --git a/test/unit/util.c b/test/unit/util.c index 3d1ecf4e..81421e80 100644 --- a/test/unit/util.c +++ b/test/unit/util.c @@ -296,12 +296,12 @@ TEST_END int main(void) { - return (test( + return test( test_pow2_ceil_u64, test_pow2_ceil_u32, test_pow2_ceil_zu, test_malloc_strtoumax_no_endptr, test_malloc_strtoumax, test_malloc_snprintf_truncated, - test_malloc_snprintf)); + test_malloc_snprintf); } diff --git a/test/unit/witness.c b/test/unit/witness.c index d75ca482..c914e4b3 100644 --- a/test/unit/witness.c +++ b/test/unit/witness.c @@ -38,7 +38,7 @@ witness_comp(const witness_t *a, void *oa, const witness_t *b, void *ob) { assert(oa == (void *)a); assert(ob == (void *)b); - return (strcmp(a->name, b->name)); + return strcmp(a->name, b->name); } static int @@ -49,7 +49,7 @@ witness_comp_reverse(const witness_t *a, void *oa, const witness_t *b, assert(oa == (void *)a); assert(ob == (void *)b); - return (-strcmp(a->name, b->name)); + return -strcmp(a->name, b->name); } TEST_BEGIN(test_witness) { @@ -255,11 +255,11 @@ TEST_END int main(void) { - return (test( + return test( test_witness, test_witness_comp, test_witness_reversal, test_witness_recursive, test_witness_unlock_not_owned, - test_witness_lockful)); + test_witness_lockful); } diff --git a/test/unit/zero.c b/test/unit/zero.c index a802f053..88af9452 100644 --- a/test/unit/zero.c +++ b/test/unit/zero.c @@ -58,7 +58,7 @@ TEST_END int main(void) { - return (test( + return test( test_zero_small, - test_zero_large)); + test_zero_large); } -- GitLab From c0cc5db8717dd1d890bd52b687d9eef64a49554f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 19 Jan 2017 21:41:41 -0800 Subject: [PATCH 241/544] Replace tabs following #define with spaces. This resolves #564. --- include/jemalloc/internal/arena_types.h | 10 +- include/jemalloc/internal/assert.h | 8 +- include/jemalloc/internal/atomic_externs.h | 10 +- include/jemalloc/internal/bitmap_types.h | 42 ++-- include/jemalloc/internal/ckh_types.h | 6 +- include/jemalloc/internal/ctl_externs.h | 6 +- include/jemalloc/internal/extent_dss_types.h | 4 +- include/jemalloc/internal/extent_types.h | 2 +- .../jemalloc/internal/jemalloc_internal.h.in | 70 +++--- .../internal/jemalloc_internal_decls.h | 2 +- .../internal/jemalloc_internal_defs.h.in | 2 +- .../internal/jemalloc_internal_macros.h | 16 +- include/jemalloc/internal/nstime_types.h | 2 +- include/jemalloc/internal/pages_types.h | 16 +- include/jemalloc/internal/ph.h | 32 +-- .../jemalloc/internal/private_namespace.sh | 2 +- include/jemalloc/internal/prng_types.h | 8 +- include/jemalloc/internal/prof_types.h | 22 +- include/jemalloc/internal/public_namespace.sh | 2 +- include/jemalloc/internal/ql.h | 36 +-- include/jemalloc/internal/qr.h | 22 +- include/jemalloc/internal/rb.h | 54 ++--- include/jemalloc/internal/rtree_inlines.h | 6 +- include/jemalloc/internal/rtree_types.h | 14 +- include/jemalloc/internal/size_classes.sh | 26 +- include/jemalloc/internal/smoothstep.h | 8 +- include/jemalloc/internal/smoothstep.sh | 8 +- include/jemalloc/internal/tcache_types.h | 20 +- include/jemalloc/internal/tsd_inlines.h | 4 +- include/jemalloc/internal/tsd_structs.h | 6 +- include/jemalloc/internal/tsd_types.h | 38 +-- include/jemalloc/internal/util_types.h | 12 +- include/jemalloc/internal/witness_types.h | 62 ++--- include/jemalloc/jemalloc.sh | 3 +- include/jemalloc/jemalloc_macros.h.in | 26 +- include/msvc_compat/windows_extra.h | 2 +- src/arena.c | 20 +- src/atomic.c | 2 +- src/base.c | 2 +- src/bitmap.c | 2 +- src/ckh.c | 2 +- src/ctl.c | 42 ++-- src/extent.c | 10 +- src/extent_dss.c | 2 +- src/extent_mmap.c | 2 +- src/hash.c | 2 +- src/jemalloc.c | 94 ++++---- src/jemalloc_cpp.cpp | 2 +- src/large.c | 10 +- src/mb.c | 2 +- src/mutex.c | 4 +- src/nstime.c | 10 +- src/pages.c | 2 +- src/prng.c | 2 +- src/prof.c | 18 +- src/rtree.c | 10 +- src/spin.c | 2 +- src/stats.c | 22 +- src/tcache.c | 2 +- src/ticker.c | 2 +- src/tsd.c | 8 +- src/util.c | 24 +- src/witness.c | 18 +- test/include/test/btalloc.h | 4 +- test/include/test/jemalloc_test.h.in | 10 +- test/include/test/mq.h | 4 +- test/include/test/test.h | 228 +++++++++--------- test/integration/MALLOCX_ARENA.c | 2 +- test/integration/aligned_alloc.c | 4 +- test/integration/mallocx.c | 6 +- test/integration/posix_memalign.c | 4 +- test/integration/rallocx.c | 16 +- test/integration/sdallocx.c | 4 +- test/integration/thread_arena.c | 2 +- test/integration/xallocx.c | 2 +- test/src/SFMT.c | 2 +- test/src/math.c | 2 +- test/src/mtx.c | 2 +- test/unit/SFMT.c | 8 +- test/unit/arena_reset.c | 2 +- test/unit/arena_reset_prof.c | 2 +- test/unit/atomic.c | 4 +- test/unit/bitmap.c | 14 +- test/unit/ckh.c | 2 +- test/unit/decay.c | 4 +- test/unit/extent_quantize.c | 2 +- test/unit/hash.c | 4 +- test/unit/junk_alloc.c | 2 +- test/unit/junk_free.c | 2 +- test/unit/mallctl.c | 14 +- test/unit/math.c | 6 +- test/unit/mq.c | 4 +- test/unit/mtx.c | 4 +- test/unit/nstime.c | 2 +- test/unit/pack.c | 6 +- test/unit/ph.c | 8 +- test/unit/prng.c | 18 +- test/unit/prof_accum.c | 8 +- test/unit/prof_active.c | 10 +- test/unit/prof_reset.c | 12 +- test/unit/prof_thread_name.c | 8 +- test/unit/ql.c | 2 +- test/unit/qr.c | 4 +- test/unit/rb.c | 10 +- test/unit/rtree.c | 12 +- test/unit/smoothstep.c | 2 +- test/unit/ticker.c | 8 +- test/unit/tsd.c | 4 +- test/unit/util.c | 16 +- test/unit/zero.c | 2 +- 110 files changed, 712 insertions(+), 713 deletions(-) diff --git a/include/jemalloc/internal/arena_types.h b/include/jemalloc/internal/arena_types.h index a13a1b61..d821be45 100644 --- a/include/jemalloc/internal/arena_types.h +++ b/include/jemalloc/internal/arena_types.h @@ -1,16 +1,16 @@ #ifndef JEMALLOC_INTERNAL_ARENA_TYPES_H #define JEMALLOC_INTERNAL_ARENA_TYPES_H -#define LARGE_MINCLASS (ZU(1) << LG_LARGE_MINCLASS) +#define LARGE_MINCLASS (ZU(1) << LG_LARGE_MINCLASS) /* Maximum number of regions in one slab. */ -#define LG_SLAB_MAXREGS (LG_PAGE - LG_TINY_MIN) -#define SLAB_MAXREGS (1U << LG_SLAB_MAXREGS) +#define LG_SLAB_MAXREGS (LG_PAGE - LG_TINY_MIN) +#define SLAB_MAXREGS (1U << LG_SLAB_MAXREGS) /* Default decay time in seconds. */ -#define DECAY_TIME_DEFAULT 10 +#define DECAY_TIME_DEFAULT 10 /* Number of event ticks between time checks. */ -#define DECAY_NTICKS_PER_UPDATE 1000 +#define DECAY_NTICKS_PER_UPDATE 1000 typedef struct arena_slab_data_s arena_slab_data_t; typedef struct arena_bin_info_s arena_bin_info_t; diff --git a/include/jemalloc/internal/assert.h b/include/jemalloc/internal/assert.h index 5da0ef42..b9ab813e 100644 --- a/include/jemalloc/internal/assert.h +++ b/include/jemalloc/internal/assert.h @@ -3,7 +3,7 @@ * assertion failure. */ #ifndef assert -#define assert(e) do { \ +#define assert(e) do { \ if (unlikely(config_debug && !(e))) { \ malloc_printf( \ ": %s:%d: Failed assertion: \"%s\"\n", \ @@ -14,7 +14,7 @@ #endif #ifndef not_reached -#define not_reached() do { \ +#define not_reached() do { \ if (config_debug) { \ malloc_printf( \ ": %s:%d: Unreachable code reached\n", \ @@ -26,7 +26,7 @@ #endif #ifndef not_implemented -#define not_implemented() do { \ +#define not_implemented() do { \ if (config_debug) { \ malloc_printf(": %s:%d: Not implemented\n", \ __FILE__, __LINE__); \ @@ -36,7 +36,7 @@ #endif #ifndef assert_not_implemented -#define assert_not_implemented(e) do { \ +#define assert_not_implemented(e) do { \ if (unlikely(config_debug && !(e))) { \ not_implemented(); \ } \ diff --git a/include/jemalloc/internal/atomic_externs.h b/include/jemalloc/internal/atomic_externs.h index 002aebca..09f06408 100644 --- a/include/jemalloc/internal/atomic_externs.h +++ b/include/jemalloc/internal/atomic_externs.h @@ -2,11 +2,11 @@ #define JEMALLOC_INTERNAL_ATOMIC_EXTERNS_H #if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) -#define atomic_read_u64(p) atomic_add_u64(p, 0) +#define atomic_read_u64(p) atomic_add_u64(p, 0) #endif -#define atomic_read_u32(p) atomic_add_u32(p, 0) -#define atomic_read_p(p) atomic_add_p(p, NULL) -#define atomic_read_zu(p) atomic_add_zu(p, 0) -#define atomic_read_u(p) atomic_add_u(p, 0) +#define atomic_read_u32(p) atomic_add_u32(p, 0) +#define atomic_read_p(p) atomic_add_p(p, NULL) +#define atomic_read_zu(p) atomic_add_zu(p, 0) +#define atomic_read_u(p) atomic_add_u(p, 0) #endif /* JEMALLOC_INTERNAL_ATOMIC_EXTERNS_H */ diff --git a/include/jemalloc/internal/bitmap_types.h b/include/jemalloc/internal/bitmap_types.h index d823186f..ec8a6dc9 100644 --- a/include/jemalloc/internal/bitmap_types.h +++ b/include/jemalloc/internal/bitmap_types.h @@ -2,18 +2,18 @@ #define JEMALLOC_INTERNAL_BITMAP_TYPES_H /* Maximum bitmap bit count is 2^LG_BITMAP_MAXBITS. */ -#define LG_BITMAP_MAXBITS LG_SLAB_MAXREGS -#define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS) +#define LG_BITMAP_MAXBITS LG_SLAB_MAXREGS +#define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS) typedef struct bitmap_level_s bitmap_level_t; typedef struct bitmap_info_s bitmap_info_t; typedef unsigned long bitmap_t; -#define LG_SIZEOF_BITMAP LG_SIZEOF_LONG +#define LG_SIZEOF_BITMAP LG_SIZEOF_LONG /* Number of bits per group. */ -#define LG_BITMAP_GROUP_NBITS (LG_SIZEOF_BITMAP + 3) -#define BITMAP_GROUP_NBITS (1U << LG_BITMAP_GROUP_NBITS) -#define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1) +#define LG_BITMAP_GROUP_NBITS (LG_SIZEOF_BITMAP + 3) +#define BITMAP_GROUP_NBITS (1U << LG_BITMAP_GROUP_NBITS) +#define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1) /* * Do some analysis on how big the bitmap is before we use a tree. For a brute @@ -25,22 +25,22 @@ typedef unsigned long bitmap_t; #endif /* Number of groups required to store a given number of bits. */ -#define BITMAP_BITS2GROUPS(nbits) \ +#define BITMAP_BITS2GROUPS(nbits) \ (((nbits) + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS) /* * Number of groups required at a particular level for a given number of bits. */ -#define BITMAP_GROUPS_L0(nbits) \ +#define BITMAP_GROUPS_L0(nbits) \ BITMAP_BITS2GROUPS(nbits) -#define BITMAP_GROUPS_L1(nbits) \ +#define BITMAP_GROUPS_L1(nbits) \ BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits)) -#define BITMAP_GROUPS_L2(nbits) \ +#define BITMAP_GROUPS_L2(nbits) \ BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))) -#define BITMAP_GROUPS_L3(nbits) \ +#define BITMAP_GROUPS_L3(nbits) \ BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ BITMAP_BITS2GROUPS((nbits))))) -#define BITMAP_GROUPS_L4(nbits) \ +#define BITMAP_GROUPS_L4(nbits) \ BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))))) @@ -48,15 +48,15 @@ typedef unsigned long bitmap_t; * Assuming the number of levels, number of groups required for a given number * of bits. */ -#define BITMAP_GROUPS_1_LEVEL(nbits) \ +#define BITMAP_GROUPS_1_LEVEL(nbits) \ BITMAP_GROUPS_L0(nbits) -#define BITMAP_GROUPS_2_LEVEL(nbits) \ +#define BITMAP_GROUPS_2_LEVEL(nbits) \ (BITMAP_GROUPS_1_LEVEL(nbits) + BITMAP_GROUPS_L1(nbits)) -#define BITMAP_GROUPS_3_LEVEL(nbits) \ +#define BITMAP_GROUPS_3_LEVEL(nbits) \ (BITMAP_GROUPS_2_LEVEL(nbits) + BITMAP_GROUPS_L2(nbits)) -#define BITMAP_GROUPS_4_LEVEL(nbits) \ +#define BITMAP_GROUPS_4_LEVEL(nbits) \ (BITMAP_GROUPS_3_LEVEL(nbits) + BITMAP_GROUPS_L3(nbits)) -#define BITMAP_GROUPS_5_LEVEL(nbits) \ +#define BITMAP_GROUPS_5_LEVEL(nbits) \ (BITMAP_GROUPS_4_LEVEL(nbits) + BITMAP_GROUPS_L4(nbits)) /* @@ -92,9 +92,9 @@ typedef unsigned long bitmap_t; * unused trailing entries in bitmap_info_t structures; the bitmaps themselves * are not impacted. */ -#define BITMAP_MAX_LEVELS 5 +#define BITMAP_MAX_LEVELS 5 -#define BITMAP_INFO_INITIALIZER(nbits) { \ +#define BITMAP_INFO_INITIALIZER(nbits) { \ /* nbits. */ \ nbits, \ /* nlevels. */ \ @@ -119,9 +119,9 @@ typedef unsigned long bitmap_t; #else /* BITMAP_USE_TREE */ -#define BITMAP_GROUPS_MAX BITMAP_BITS2GROUPS(BITMAP_MAXBITS) +#define BITMAP_GROUPS_MAX BITMAP_BITS2GROUPS(BITMAP_MAXBITS) -#define BITMAP_INFO_INITIALIZER(nbits) { \ +#define BITMAP_INFO_INITIALIZER(nbits) { \ /* nbits. */ \ nbits, \ /* ngroups. */ \ diff --git a/include/jemalloc/internal/ckh_types.h b/include/jemalloc/internal/ckh_types.h index 9a1d8d49..b5911db4 100644 --- a/include/jemalloc/internal/ckh_types.h +++ b/include/jemalloc/internal/ckh_types.h @@ -9,14 +9,14 @@ typedef void ckh_hash_t (const void *, size_t[2]); typedef bool ckh_keycomp_t (const void *, const void *); /* Maintain counters used to get an idea of performance. */ -/* #define CKH_COUNT */ +/* #define CKH_COUNT */ /* Print counter values in ckh_delete() (requires CKH_COUNT). */ -/* #define CKH_VERBOSE */ +/* #define CKH_VERBOSE */ /* * There are 2^LG_CKH_BUCKET_CELLS cells in each hash table bucket. Try to fit * one bucket per L1 cache line. */ -#define LG_CKH_BUCKET_CELLS (LG_CACHELINE - LG_SIZEOF_PTR - 1) +#define LG_CKH_BUCKET_CELLS (LG_CACHELINE - LG_SIZEOF_PTR - 1) #endif /* JEMALLOC_INTERNAL_CKH_TYPES_H */ diff --git a/include/jemalloc/internal/ctl_externs.h b/include/jemalloc/internal/ctl_externs.h index 11f77cfb..2ef48c66 100644 --- a/include/jemalloc/internal/ctl_externs.h +++ b/include/jemalloc/internal/ctl_externs.h @@ -13,7 +13,7 @@ void ctl_prefork(tsdn_t *tsdn); void ctl_postfork_parent(tsdn_t *tsdn); void ctl_postfork_child(tsdn_t *tsdn); -#define xmallctl(name, oldp, oldlenp, newp, newlen) do { \ +#define xmallctl(name, oldp, oldlenp, newp, newlen) do { \ if (je_mallctl(name, oldp, oldlenp, newp, newlen) \ != 0) { \ malloc_printf( \ @@ -23,7 +23,7 @@ void ctl_postfork_child(tsdn_t *tsdn); } \ } while (0) -#define xmallctlnametomib(name, mibp, miblenp) do { \ +#define xmallctlnametomib(name, mibp, miblenp) do { \ if (je_mallctlnametomib(name, mibp, miblenp) != 0) { \ malloc_printf(": Failure in " \ "xmallctlnametomib(\"%s\", ...)\n", name); \ @@ -31,7 +31,7 @@ void ctl_postfork_child(tsdn_t *tsdn); } \ } while (0) -#define xmallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) do { \ +#define xmallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) do { \ if (je_mallctlbymib(mib, miblen, oldp, oldlenp, newp, \ newlen) != 0) { \ malloc_write( \ diff --git a/include/jemalloc/internal/extent_dss_types.h b/include/jemalloc/internal/extent_dss_types.h index 2839757c..a851c7cb 100644 --- a/include/jemalloc/internal/extent_dss_types.h +++ b/include/jemalloc/internal/extent_dss_types.h @@ -8,7 +8,7 @@ typedef enum { dss_prec_limit = 3 } dss_prec_t; -#define DSS_PREC_DEFAULT dss_prec_secondary -#define DSS_DEFAULT "secondary" +#define DSS_PREC_DEFAULT dss_prec_secondary +#define DSS_DEFAULT "secondary" #endif /* JEMALLOC_INTERNAL_EXTENT_DSS_TYPES_H */ diff --git a/include/jemalloc/internal/extent_types.h b/include/jemalloc/internal/extent_types.h index 4873dc54..53db1c36 100644 --- a/include/jemalloc/internal/extent_types.h +++ b/include/jemalloc/internal/extent_types.h @@ -3,6 +3,6 @@ typedef struct extent_s extent_t; -#define EXTENT_HOOKS_INITIALIZER NULL +#define EXTENT_HOOKS_INITIALIZER NULL #endif /* JEMALLOC_INTERNAL_EXTENT_TYPES_H */ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 03a50a4d..33fd2fac 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -1,5 +1,5 @@ #ifndef JEMALLOC_INTERNAL_H -#define JEMALLOC_INTERNAL_H +#define JEMALLOC_INTERNAL_H #ifdef __cplusplus extern "C" { @@ -12,7 +12,7 @@ extern "C" { #include #endif -#define JEMALLOC_NO_DEMANGLE +#define JEMALLOC_NO_DEMANGLE #ifdef JEMALLOC_JET # define JEMALLOC_N(n) jet_##n # include "jemalloc/internal/public_namespace.h" @@ -166,7 +166,7 @@ static const bool have_thp = #include "jemalloc/internal/ph.h" #ifndef __PGI -#define RB_COMPACT +#define RB_COMPACT #endif #include "jemalloc/internal/rb.h" #include "jemalloc/internal/qr.h" @@ -224,34 +224,34 @@ typedef unsigned szind_t; * * aaaaaaaa aaaatttt tttttttt 0znnnnnn */ -#define MALLOCX_ARENA_BITS 12 -#define MALLOCX_TCACHE_BITS 12 -#define MALLOCX_LG_ALIGN_BITS 6 -#define MALLOCX_ARENA_SHIFT 20 -#define MALLOCX_TCACHE_SHIFT 8 -#define MALLOCX_ARENA_MASK \ +#define MALLOCX_ARENA_BITS 12 +#define MALLOCX_TCACHE_BITS 12 +#define MALLOCX_LG_ALIGN_BITS 6 +#define MALLOCX_ARENA_SHIFT 20 +#define MALLOCX_TCACHE_SHIFT 8 +#define MALLOCX_ARENA_MASK \ (((1 << MALLOCX_ARENA_BITS) - 1) << MALLOCX_ARENA_SHIFT) /* NB: Arena index bias decreases the maximum number of arenas by 1. */ -#define MALLOCX_ARENA_MAX ((1 << MALLOCX_ARENA_BITS) - 2) -#define MALLOCX_TCACHE_MASK \ +#define MALLOCX_ARENA_MAX ((1 << MALLOCX_ARENA_BITS) - 2) +#define MALLOCX_TCACHE_MASK \ (((1 << MALLOCX_TCACHE_BITS) - 1) << MALLOCX_TCACHE_SHIFT) -#define MALLOCX_TCACHE_MAX ((1 << MALLOCX_TCACHE_BITS) - 3) -#define MALLOCX_LG_ALIGN_MASK ((1 << MALLOCX_LG_ALIGN_BITS) - 1) +#define MALLOCX_TCACHE_MAX ((1 << MALLOCX_TCACHE_BITS) - 3) +#define MALLOCX_LG_ALIGN_MASK ((1 << MALLOCX_LG_ALIGN_BITS) - 1) /* Use MALLOCX_ALIGN_GET() if alignment may not be specified in flags. */ -#define MALLOCX_ALIGN_GET_SPECIFIED(flags) \ +#define MALLOCX_ALIGN_GET_SPECIFIED(flags) \ (ZU(1) << (flags & MALLOCX_LG_ALIGN_MASK)) -#define MALLOCX_ALIGN_GET(flags) \ +#define MALLOCX_ALIGN_GET(flags) \ (MALLOCX_ALIGN_GET_SPECIFIED(flags) & (SIZE_T_MAX-1)) -#define MALLOCX_ZERO_GET(flags) \ +#define MALLOCX_ZERO_GET(flags) \ ((bool)(flags & MALLOCX_ZERO)) -#define MALLOCX_TCACHE_GET(flags) \ +#define MALLOCX_TCACHE_GET(flags) \ (((unsigned)((flags & MALLOCX_TCACHE_MASK) >> MALLOCX_TCACHE_SHIFT)) - 2) -#define MALLOCX_ARENA_GET(flags) \ +#define MALLOCX_ARENA_GET(flags) \ (((unsigned)(((unsigned)flags) >> MALLOCX_ARENA_SHIFT)) - 1) /* Smallest size class to support. */ -#define TINY_MIN (1U << LG_TINY_MIN) +#define TINY_MIN (1U << LG_TINY_MIN) /* * Minimum allocation alignment is 2^LG_QUANTUM bytes (ignoring tiny size @@ -312,25 +312,25 @@ typedef unsigned szind_t; # endif #endif -#define QUANTUM ((size_t)(1U << LG_QUANTUM)) -#define QUANTUM_MASK (QUANTUM - 1) +#define QUANTUM ((size_t)(1U << LG_QUANTUM)) +#define QUANTUM_MASK (QUANTUM - 1) /* Return the smallest quantum multiple that is >= a. */ -#define QUANTUM_CEILING(a) \ +#define QUANTUM_CEILING(a) \ (((a) + QUANTUM_MASK) & ~QUANTUM_MASK) -#define LONG ((size_t)(1U << LG_SIZEOF_LONG)) -#define LONG_MASK (LONG - 1) +#define LONG ((size_t)(1U << LG_SIZEOF_LONG)) +#define LONG_MASK (LONG - 1) /* Return the smallest long multiple that is >= a. */ -#define LONG_CEILING(a) \ +#define LONG_CEILING(a) \ (((a) + LONG_MASK) & ~LONG_MASK) -#define SIZEOF_PTR (1U << LG_SIZEOF_PTR) -#define PTR_MASK (SIZEOF_PTR - 1) +#define SIZEOF_PTR (1U << LG_SIZEOF_PTR) +#define PTR_MASK (SIZEOF_PTR - 1) /* Return the smallest (void *) multiple that is >= a. */ -#define PTR_CEILING(a) \ +#define PTR_CEILING(a) \ (((a) + PTR_MASK) & ~PTR_MASK) /* @@ -340,24 +340,24 @@ typedef unsigned szind_t; * CACHELINE cannot be based on LG_CACHELINE because __declspec(align()) can * only handle raw constants. */ -#define LG_CACHELINE 6 -#define CACHELINE 64 -#define CACHELINE_MASK (CACHELINE - 1) +#define LG_CACHELINE 6 +#define CACHELINE 64 +#define CACHELINE_MASK (CACHELINE - 1) /* Return the smallest cacheline multiple that is >= s. */ -#define CACHELINE_CEILING(s) \ +#define CACHELINE_CEILING(s) \ (((s) + CACHELINE_MASK) & ~CACHELINE_MASK) /* Return the nearest aligned address at or below a. */ -#define ALIGNMENT_ADDR2BASE(a, alignment) \ +#define ALIGNMENT_ADDR2BASE(a, alignment) \ ((void *)((uintptr_t)(a) & ((~(alignment)) + 1))) /* Return the offset between a and the nearest aligned address at or below a. */ -#define ALIGNMENT_ADDR2OFFSET(a, alignment) \ +#define ALIGNMENT_ADDR2OFFSET(a, alignment) \ ((size_t)((uintptr_t)(a) & (alignment - 1))) /* Return the smallest alignment multiple that is >= s. */ -#define ALIGNMENT_CEILING(s, alignment) \ +#define ALIGNMENT_CEILING(s, alignment) \ (((s) + (alignment - 1)) & ((~(alignment)) + 1)) /* Declare a variable-length array. */ diff --git a/include/jemalloc/internal/jemalloc_internal_decls.h b/include/jemalloc/internal/jemalloc_internal_decls.h index fd80fdf0..21a4183d 100644 --- a/include/jemalloc/internal/jemalloc_internal_decls.h +++ b/include/jemalloc/internal/jemalloc_internal_decls.h @@ -1,5 +1,5 @@ #ifndef JEMALLOC_INTERNAL_DECLS_H -#define JEMALLOC_INTERNAL_DECLS_H +#define JEMALLOC_INTERNAL_DECLS_H #include #ifdef _WIN32 diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index c777ab02..396a1a27 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -1,5 +1,5 @@ #ifndef JEMALLOC_INTERNAL_DEFS_H_ -#define JEMALLOC_INTERNAL_DEFS_H_ +#define JEMALLOC_INTERNAL_DEFS_H_ /* * If JEMALLOC_PREFIX is defined via --with-jemalloc-prefix, it will cause all * public APIs to be prefixed. This makes it possible, with some care, to use diff --git a/include/jemalloc/internal/jemalloc_internal_macros.h b/include/jemalloc/internal/jemalloc_internal_macros.h index 80820f87..b70d08a2 100644 --- a/include/jemalloc/internal/jemalloc_internal_macros.h +++ b/include/jemalloc/internal/jemalloc_internal_macros.h @@ -41,15 +41,15 @@ # define UNUSED #endif -#define ZU(z) ((size_t)z) -#define ZI(z) ((ssize_t)z) -#define QU(q) ((uint64_t)q) -#define QI(q) ((int64_t)q) +#define ZU(z) ((size_t)z) +#define ZI(z) ((ssize_t)z) +#define QU(q) ((uint64_t)q) +#define QI(q) ((int64_t)q) -#define KZU(z) ZU(z##ULL) -#define KZI(z) ZI(z##LL) -#define KQU(q) QU(q##ULL) -#define KQI(q) QI(q##LL) +#define KZU(z) ZU(z##ULL) +#define KZI(z) ZI(z##LL) +#define KQU(q) QU(q##ULL) +#define KQI(q) QI(q##LL) #ifndef __DECONST # define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) diff --git a/include/jemalloc/internal/nstime_types.h b/include/jemalloc/internal/nstime_types.h index 861c5a8a..d6039e03 100644 --- a/include/jemalloc/internal/nstime_types.h +++ b/include/jemalloc/internal/nstime_types.h @@ -4,6 +4,6 @@ typedef struct nstime_s nstime_t; /* Maximum supported number of seconds (~584 years). */ -#define NSTIME_SEC_MAX KQU(18446744072) +#define NSTIME_SEC_MAX KQU(18446744072) #endif /* JEMALLOC_INTERNAL_NSTIME_TYPES_H */ diff --git a/include/jemalloc/internal/pages_types.h b/include/jemalloc/internal/pages_types.h index be1e245f..9e6e7c5c 100644 --- a/include/jemalloc/internal/pages_types.h +++ b/include/jemalloc/internal/pages_types.h @@ -5,23 +5,23 @@ #ifdef PAGE_MASK # undef PAGE_MASK #endif -#define PAGE ((size_t)(1U << LG_PAGE)) -#define PAGE_MASK ((size_t)(PAGE - 1)) +#define PAGE ((size_t)(1U << LG_PAGE)) +#define PAGE_MASK ((size_t)(PAGE - 1)) /* Return the page base address for the page containing address a. */ -#define PAGE_ADDR2BASE(a) \ +#define PAGE_ADDR2BASE(a) \ ((void *)((uintptr_t)(a) & ~PAGE_MASK)) /* Return the smallest pagesize multiple that is >= s. */ -#define PAGE_CEILING(s) \ +#define PAGE_CEILING(s) \ (((s) + PAGE_MASK) & ~PAGE_MASK) /* Huge page size. LG_HUGEPAGE is determined by the configure script. */ -#define HUGEPAGE ((size_t)(1U << LG_HUGEPAGE)) -#define HUGEPAGE_MASK ((size_t)(HUGEPAGE - 1)) +#define HUGEPAGE ((size_t)(1U << LG_HUGEPAGE)) +#define HUGEPAGE_MASK ((size_t)(HUGEPAGE - 1)) /* Return the huge page base address for the huge page containing address a. */ -#define HUGEPAGE_ADDR2BASE(a) \ +#define HUGEPAGE_ADDR2BASE(a) \ ((void *)((uintptr_t)(a) & ~HUGEPAGE_MASK)) /* Return the smallest pagesize multiple that is >= s. */ -#define HUGEPAGE_CEILING(s) \ +#define HUGEPAGE_CEILING(s) \ (((s) + HUGEPAGE_MASK) & ~HUGEPAGE_MASK) /* PAGES_CAN_PURGE_LAZY is defined if lazy purging is supported. */ diff --git a/include/jemalloc/internal/ph.h b/include/jemalloc/internal/ph.h index b8141eff..7e1920cb 100644 --- a/include/jemalloc/internal/ph.h +++ b/include/jemalloc/internal/ph.h @@ -13,10 +13,10 @@ */ #ifndef PH_H_ -#define PH_H_ +#define PH_H_ /* Node structure. */ -#define phn(a_type) \ +#define phn(a_type) \ struct { \ a_type *phn_prev; \ a_type *phn_next; \ @@ -24,31 +24,31 @@ struct { \ } /* Root structure. */ -#define ph(a_type) \ +#define ph(a_type) \ struct { \ a_type *ph_root; \ } /* Internal utility macros. */ -#define phn_lchild_get(a_type, a_field, a_phn) \ +#define phn_lchild_get(a_type, a_field, a_phn) \ (a_phn->a_field.phn_lchild) -#define phn_lchild_set(a_type, a_field, a_phn, a_lchild) do { \ +#define phn_lchild_set(a_type, a_field, a_phn, a_lchild) do { \ a_phn->a_field.phn_lchild = a_lchild; \ } while (0) -#define phn_next_get(a_type, a_field, a_phn) \ +#define phn_next_get(a_type, a_field, a_phn) \ (a_phn->a_field.phn_next) -#define phn_prev_set(a_type, a_field, a_phn, a_prev) do { \ +#define phn_prev_set(a_type, a_field, a_phn, a_prev) do { \ a_phn->a_field.phn_prev = a_prev; \ } while (0) -#define phn_prev_get(a_type, a_field, a_phn) \ +#define phn_prev_get(a_type, a_field, a_phn) \ (a_phn->a_field.phn_prev) -#define phn_next_set(a_type, a_field, a_phn, a_next) do { \ +#define phn_next_set(a_type, a_field, a_phn, a_next) do { \ a_phn->a_field.phn_next = a_next; \ } while (0) -#define phn_merge_ordered(a_type, a_field, a_phn0, a_phn1, a_cmp) do { \ +#define phn_merge_ordered(a_type, a_field, a_phn0, a_phn1, a_cmp) do { \ a_type *phn0child; \ \ assert(a_phn0 != NULL); \ @@ -64,7 +64,7 @@ struct { \ phn_lchild_set(a_type, a_field, a_phn0, a_phn1); \ } while (0) -#define phn_merge(a_type, a_field, a_phn0, a_phn1, a_cmp, r_phn) do { \ +#define phn_merge(a_type, a_field, a_phn0, a_phn1, a_cmp, r_phn) do { \ if (a_phn0 == NULL) { \ r_phn = a_phn1; \ } else if (a_phn1 == NULL) { \ @@ -80,7 +80,7 @@ struct { \ } \ } while (0) -#define ph_merge_siblings(a_type, a_field, a_phn, a_cmp, r_phn) do { \ +#define ph_merge_siblings(a_type, a_field, a_phn, a_cmp, r_phn) do { \ a_type *head = NULL; \ a_type *tail = NULL; \ a_type *phn0 = a_phn; \ @@ -167,7 +167,7 @@ struct { \ r_phn = phn0; \ } while (0) -#define ph_merge_aux(a_type, a_field, a_ph, a_cmp) do { \ +#define ph_merge_aux(a_type, a_field, a_ph, a_cmp) do { \ a_type *phn = phn_next_get(a_type, a_field, a_ph->ph_root); \ if (phn != NULL) { \ phn_prev_set(a_type, a_field, a_ph->ph_root, NULL); \ @@ -180,7 +180,7 @@ struct { \ } \ } while (0) -#define ph_merge_children(a_type, a_field, a_phn, a_cmp, r_phn) do { \ +#define ph_merge_children(a_type, a_field, a_phn, a_cmp, r_phn) do { \ a_type *lchild = phn_lchild_get(a_type, a_field, a_phn); \ if (lchild == NULL) { \ r_phn = NULL; \ @@ -194,7 +194,7 @@ struct { \ * The ph_proto() macro generates function prototypes that correspond to the * functions generated by an equivalently parameterized call to ph_gen(). */ -#define ph_proto(a_attr, a_prefix, a_ph_type, a_type) \ +#define ph_proto(a_attr, a_prefix, a_ph_type, a_type) \ a_attr void a_prefix##new(a_ph_type *ph); \ a_attr bool a_prefix##empty(a_ph_type *ph); \ a_attr a_type *a_prefix##first(a_ph_type *ph); \ @@ -206,7 +206,7 @@ a_attr void a_prefix##remove(a_ph_type *ph, a_type *phn); * The ph_gen() macro generates a type-specific pairing heap implementation, * based on the above cpp macros. */ -#define ph_gen(a_attr, a_prefix, a_ph_type, a_type, a_field, a_cmp) \ +#define ph_gen(a_attr, a_prefix, a_ph_type, a_type, a_field, a_cmp) \ a_attr void \ a_prefix##new(a_ph_type *ph) { \ memset(ph, 0, sizeof(ph(a_type))); \ diff --git a/include/jemalloc/internal/private_namespace.sh b/include/jemalloc/internal/private_namespace.sh index cd25eb30..820862fe 100755 --- a/include/jemalloc/internal/private_namespace.sh +++ b/include/jemalloc/internal/private_namespace.sh @@ -1,5 +1,5 @@ #!/bin/sh for symbol in `cat $1` ; do - echo "#define ${symbol} JEMALLOC_N(${symbol})" + echo "#define ${symbol} JEMALLOC_N(${symbol})" done diff --git a/include/jemalloc/internal/prng_types.h b/include/jemalloc/internal/prng_types.h index dec44c09..3e8e1834 100644 --- a/include/jemalloc/internal/prng_types.h +++ b/include/jemalloc/internal/prng_types.h @@ -20,10 +20,10 @@ * bits. */ -#define PRNG_A_32 UINT32_C(1103515241) -#define PRNG_C_32 UINT32_C(12347) +#define PRNG_A_32 UINT32_C(1103515241) +#define PRNG_C_32 UINT32_C(12347) -#define PRNG_A_64 UINT64_C(6364136223846793005) -#define PRNG_C_64 UINT64_C(1442695040888963407) +#define PRNG_A_64 UINT64_C(6364136223846793005) +#define PRNG_C_64 UINT64_C(1442695040888963407) #endif /* JEMALLOC_INTERNAL_PRNG_TYPES_H */ diff --git a/include/jemalloc/internal/prof_types.h b/include/jemalloc/internal/prof_types.h index e1eb7fb1..ff0db65e 100644 --- a/include/jemalloc/internal/prof_types.h +++ b/include/jemalloc/internal/prof_types.h @@ -13,43 +13,43 @@ typedef struct prof_tdata_s prof_tdata_t; #else # define PROF_PREFIX_DEFAULT "" #endif -#define LG_PROF_SAMPLE_DEFAULT 19 -#define LG_PROF_INTERVAL_DEFAULT -1 +#define LG_PROF_SAMPLE_DEFAULT 19 +#define LG_PROF_INTERVAL_DEFAULT -1 /* * Hard limit on stack backtrace depth. The version of prof_backtrace() that * is based on __builtin_return_address() necessarily has a hard-coded number * of backtrace frame handlers, and should be kept in sync with this setting. */ -#define PROF_BT_MAX 128 +#define PROF_BT_MAX 128 /* Initial hash table size. */ -#define PROF_CKH_MINITEMS 64 +#define PROF_CKH_MINITEMS 64 /* Size of memory buffer to use when writing dump files. */ -#define PROF_DUMP_BUFSIZE 65536 +#define PROF_DUMP_BUFSIZE 65536 /* Size of stack-allocated buffer used by prof_printf(). */ -#define PROF_PRINTF_BUFSIZE 128 +#define PROF_PRINTF_BUFSIZE 128 /* * Number of mutexes shared among all gctx's. No space is allocated for these * unless profiling is enabled, so it's okay to over-provision. */ -#define PROF_NCTX_LOCKS 1024 +#define PROF_NCTX_LOCKS 1024 /* * Number of mutexes shared among all tdata's. No space is allocated for these * unless profiling is enabled, so it's okay to over-provision. */ -#define PROF_NTDATA_LOCKS 256 +#define PROF_NTDATA_LOCKS 256 /* * prof_tdata pointers close to NULL are used to encode state information that * is used for cleaning up during thread shutdown. */ -#define PROF_TDATA_STATE_REINCARNATED ((prof_tdata_t *)(uintptr_t)1) -#define PROF_TDATA_STATE_PURGATORY ((prof_tdata_t *)(uintptr_t)2) -#define PROF_TDATA_STATE_MAX PROF_TDATA_STATE_PURGATORY +#define PROF_TDATA_STATE_REINCARNATED ((prof_tdata_t *)(uintptr_t)1) +#define PROF_TDATA_STATE_PURGATORY ((prof_tdata_t *)(uintptr_t)2) +#define PROF_TDATA_STATE_MAX PROF_TDATA_STATE_PURGATORY #endif /* JEMALLOC_INTERNAL_PROF_TYPES_H */ diff --git a/include/jemalloc/internal/public_namespace.sh b/include/jemalloc/internal/public_namespace.sh index 362109f7..4d415ba0 100755 --- a/include/jemalloc/internal/public_namespace.sh +++ b/include/jemalloc/internal/public_namespace.sh @@ -2,5 +2,5 @@ for nm in `cat $1` ; do n=`echo ${nm} |tr ':' ' ' |awk '{print $1}'` - echo "#define je_${n} JEMALLOC_N(${n})" + echo "#define je_${n} JEMALLOC_N(${n})" done diff --git a/include/jemalloc/internal/ql.h b/include/jemalloc/internal/ql.h index 424485c4..b3a428c7 100644 --- a/include/jemalloc/internal/ql.h +++ b/include/jemalloc/internal/ql.h @@ -2,61 +2,61 @@ #define JEMALLOC_INTERNAL_QL_H /* List definitions. */ -#define ql_head(a_type) \ +#define ql_head(a_type) \ struct { \ a_type *qlh_first; \ } -#define ql_head_initializer(a_head) {NULL} +#define ql_head_initializer(a_head) {NULL} -#define ql_elm(a_type) qr(a_type) +#define ql_elm(a_type) qr(a_type) /* List functions. */ -#define ql_new(a_head) do { \ +#define ql_new(a_head) do { \ (a_head)->qlh_first = NULL; \ } while (0) -#define ql_elm_new(a_elm, a_field) qr_new((a_elm), a_field) +#define ql_elm_new(a_elm, a_field) qr_new((a_elm), a_field) -#define ql_first(a_head) ((a_head)->qlh_first) +#define ql_first(a_head) ((a_head)->qlh_first) -#define ql_last(a_head, a_field) \ +#define ql_last(a_head, a_field) \ ((ql_first(a_head) != NULL) \ ? qr_prev(ql_first(a_head), a_field) : NULL) -#define ql_next(a_head, a_elm, a_field) \ +#define ql_next(a_head, a_elm, a_field) \ ((ql_last(a_head, a_field) != (a_elm)) \ ? qr_next((a_elm), a_field) : NULL) -#define ql_prev(a_head, a_elm, a_field) \ +#define ql_prev(a_head, a_elm, a_field) \ ((ql_first(a_head) != (a_elm)) ? qr_prev((a_elm), a_field) \ : NULL) -#define ql_before_insert(a_head, a_qlelm, a_elm, a_field) do { \ +#define ql_before_insert(a_head, a_qlelm, a_elm, a_field) do { \ qr_before_insert((a_qlelm), (a_elm), a_field); \ if (ql_first(a_head) == (a_qlelm)) { \ ql_first(a_head) = (a_elm); \ } \ } while (0) -#define ql_after_insert(a_qlelm, a_elm, a_field) \ +#define ql_after_insert(a_qlelm, a_elm, a_field) \ qr_after_insert((a_qlelm), (a_elm), a_field) -#define ql_head_insert(a_head, a_elm, a_field) do { \ +#define ql_head_insert(a_head, a_elm, a_field) do { \ if (ql_first(a_head) != NULL) { \ qr_before_insert(ql_first(a_head), (a_elm), a_field); \ } \ ql_first(a_head) = (a_elm); \ } while (0) -#define ql_tail_insert(a_head, a_elm, a_field) do { \ +#define ql_tail_insert(a_head, a_elm, a_field) do { \ if (ql_first(a_head) != NULL) { \ qr_before_insert(ql_first(a_head), (a_elm), a_field); \ } \ ql_first(a_head) = qr_next((a_elm), a_field); \ } while (0) -#define ql_remove(a_head, a_elm, a_field) do { \ +#define ql_remove(a_head, a_elm, a_field) do { \ if (ql_first(a_head) == (a_elm)) { \ ql_first(a_head) = qr_next(ql_first(a_head), a_field); \ } \ @@ -67,20 +67,20 @@ struct { \ } \ } while (0) -#define ql_head_remove(a_head, a_type, a_field) do { \ +#define ql_head_remove(a_head, a_type, a_field) do { \ a_type *t = ql_first(a_head); \ ql_remove((a_head), t, a_field); \ } while (0) -#define ql_tail_remove(a_head, a_type, a_field) do { \ +#define ql_tail_remove(a_head, a_type, a_field) do { \ a_type *t = ql_last(a_head, a_field); \ ql_remove((a_head), t, a_field); \ } while (0) -#define ql_foreach(a_var, a_head, a_field) \ +#define ql_foreach(a_var, a_head, a_field) \ qr_foreach((a_var), ql_first(a_head), a_field) -#define ql_reverse_foreach(a_var, a_head, a_field) \ +#define ql_reverse_foreach(a_var, a_head, a_field) \ qr_reverse_foreach((a_var), ql_first(a_head), a_field) #endif /* JEMALLOC_INTERNAL_QL_H */ diff --git a/include/jemalloc/internal/qr.h b/include/jemalloc/internal/qr.h index a04f7504..1e1056b3 100644 --- a/include/jemalloc/internal/qr.h +++ b/include/jemalloc/internal/qr.h @@ -2,37 +2,37 @@ #define JEMALLOC_INTERNAL_QR_H /* Ring definitions. */ -#define qr(a_type) \ +#define qr(a_type) \ struct { \ a_type *qre_next; \ a_type *qre_prev; \ } /* Ring functions. */ -#define qr_new(a_qr, a_field) do { \ +#define qr_new(a_qr, a_field) do { \ (a_qr)->a_field.qre_next = (a_qr); \ (a_qr)->a_field.qre_prev = (a_qr); \ } while (0) -#define qr_next(a_qr, a_field) ((a_qr)->a_field.qre_next) +#define qr_next(a_qr, a_field) ((a_qr)->a_field.qre_next) -#define qr_prev(a_qr, a_field) ((a_qr)->a_field.qre_prev) +#define qr_prev(a_qr, a_field) ((a_qr)->a_field.qre_prev) -#define qr_before_insert(a_qrelm, a_qr, a_field) do { \ +#define qr_before_insert(a_qrelm, a_qr, a_field) do { \ (a_qr)->a_field.qre_prev = (a_qrelm)->a_field.qre_prev; \ (a_qr)->a_field.qre_next = (a_qrelm); \ (a_qr)->a_field.qre_prev->a_field.qre_next = (a_qr); \ (a_qrelm)->a_field.qre_prev = (a_qr); \ } while (0) -#define qr_after_insert(a_qrelm, a_qr, a_field) do { \ +#define qr_after_insert(a_qrelm, a_qr, a_field) do { \ (a_qr)->a_field.qre_next = (a_qrelm)->a_field.qre_next; \ (a_qr)->a_field.qre_prev = (a_qrelm); \ (a_qr)->a_field.qre_next->a_field.qre_prev = (a_qr); \ (a_qrelm)->a_field.qre_next = (a_qr); \ } while (0) -#define qr_meld(a_qr_a, a_qr_b, a_type, a_field) do { \ +#define qr_meld(a_qr_a, a_qr_b, a_type, a_field) do { \ a_type *t; \ (a_qr_a)->a_field.qre_prev->a_field.qre_next = (a_qr_b); \ (a_qr_b)->a_field.qre_prev->a_field.qre_next = (a_qr_a); \ @@ -45,10 +45,10 @@ struct { \ * qr_meld() and qr_split() are functionally equivalent, so there's no need to * have two copies of the code. */ -#define qr_split(a_qr_a, a_qr_b, a_type, a_field) \ +#define qr_split(a_qr_a, a_qr_b, a_type, a_field) \ qr_meld((a_qr_a), (a_qr_b), a_type, a_field) -#define qr_remove(a_qr, a_field) do { \ +#define qr_remove(a_qr, a_field) do { \ (a_qr)->a_field.qre_prev->a_field.qre_next \ = (a_qr)->a_field.qre_next; \ (a_qr)->a_field.qre_next->a_field.qre_prev \ @@ -57,13 +57,13 @@ struct { \ (a_qr)->a_field.qre_prev = (a_qr); \ } while (0) -#define qr_foreach(var, a_qr, a_field) \ +#define qr_foreach(var, a_qr, a_field) \ for ((var) = (a_qr); \ (var) != NULL; \ (var) = (((var)->a_field.qre_next != (a_qr)) \ ? (var)->a_field.qre_next : NULL)) -#define qr_reverse_foreach(var, a_qr, a_field) \ +#define qr_reverse_foreach(var, a_qr, a_field) \ for ((var) = ((a_qr) != NULL) ? qr_prev(a_qr, a_field) : NULL; \ (var) != NULL; \ (var) = (((var) != (a_qr)) \ diff --git a/include/jemalloc/internal/rb.h b/include/jemalloc/internal/rb.h index 7018325f..aa76061e 100644 --- a/include/jemalloc/internal/rb.h +++ b/include/jemalloc/internal/rb.h @@ -20,17 +20,17 @@ */ #ifndef RB_H_ -#define RB_H_ +#define RB_H_ #ifdef RB_COMPACT /* Node structure. */ -#define rb_node(a_type) \ +#define rb_node(a_type) \ struct { \ a_type *rbn_left; \ a_type *rbn_right_red; \ } #else -#define rb_node(a_type) \ +#define rb_node(a_type) \ struct { \ a_type *rbn_left; \ a_type *rbn_right; \ @@ -39,48 +39,48 @@ struct { \ #endif /* Root structure. */ -#define rb_tree(a_type) \ +#define rb_tree(a_type) \ struct { \ a_type *rbt_root; \ } /* Left accessors. */ -#define rbtn_left_get(a_type, a_field, a_node) \ +#define rbtn_left_get(a_type, a_field, a_node) \ ((a_node)->a_field.rbn_left) -#define rbtn_left_set(a_type, a_field, a_node, a_left) do { \ +#define rbtn_left_set(a_type, a_field, a_node, a_left) do { \ (a_node)->a_field.rbn_left = a_left; \ } while (0) #ifdef RB_COMPACT /* Right accessors. */ -#define rbtn_right_get(a_type, a_field, a_node) \ +#define rbtn_right_get(a_type, a_field, a_node) \ ((a_type *) (((intptr_t) (a_node)->a_field.rbn_right_red) \ & ((ssize_t)-2))) -#define rbtn_right_set(a_type, a_field, a_node, a_right) do { \ +#define rbtn_right_set(a_type, a_field, a_node, a_right) do { \ (a_node)->a_field.rbn_right_red = (a_type *) (((uintptr_t) a_right) \ | (((uintptr_t) (a_node)->a_field.rbn_right_red) & ((size_t)1))); \ } while (0) /* Color accessors. */ -#define rbtn_red_get(a_type, a_field, a_node) \ +#define rbtn_red_get(a_type, a_field, a_node) \ ((bool) (((uintptr_t) (a_node)->a_field.rbn_right_red) \ & ((size_t)1))) -#define rbtn_color_set(a_type, a_field, a_node, a_red) do { \ +#define rbtn_color_set(a_type, a_field, a_node, a_red) do { \ (a_node)->a_field.rbn_right_red = (a_type *) ((((intptr_t) \ (a_node)->a_field.rbn_right_red) & ((ssize_t)-2)) \ | ((ssize_t)a_red)); \ } while (0) -#define rbtn_red_set(a_type, a_field, a_node) do { \ +#define rbtn_red_set(a_type, a_field, a_node) do { \ (a_node)->a_field.rbn_right_red = (a_type *) (((uintptr_t) \ (a_node)->a_field.rbn_right_red) | ((size_t)1)); \ } while (0) -#define rbtn_black_set(a_type, a_field, a_node) do { \ +#define rbtn_black_set(a_type, a_field, a_node) do { \ (a_node)->a_field.rbn_right_red = (a_type *) (((intptr_t) \ (a_node)->a_field.rbn_right_red) & ((ssize_t)-2)); \ } while (0) /* Node initializer. */ -#define rbt_node_new(a_type, a_field, a_rbt, a_node) do { \ +#define rbt_node_new(a_type, a_field, a_rbt, a_node) do { \ /* Bookkeeping bit cannot be used by node pointer. */ \ assert(((uintptr_t)(a_node) & 0x1) == 0); \ rbtn_left_set(a_type, a_field, (a_node), NULL); \ @@ -89,27 +89,27 @@ struct { \ } while (0) #else /* Right accessors. */ -#define rbtn_right_get(a_type, a_field, a_node) \ +#define rbtn_right_get(a_type, a_field, a_node) \ ((a_node)->a_field.rbn_right) -#define rbtn_right_set(a_type, a_field, a_node, a_right) do { \ +#define rbtn_right_set(a_type, a_field, a_node, a_right) do { \ (a_node)->a_field.rbn_right = a_right; \ } while (0) /* Color accessors. */ -#define rbtn_red_get(a_type, a_field, a_node) \ +#define rbtn_red_get(a_type, a_field, a_node) \ ((a_node)->a_field.rbn_red) -#define rbtn_color_set(a_type, a_field, a_node, a_red) do { \ +#define rbtn_color_set(a_type, a_field, a_node, a_red) do { \ (a_node)->a_field.rbn_red = (a_red); \ } while (0) -#define rbtn_red_set(a_type, a_field, a_node) do { \ +#define rbtn_red_set(a_type, a_field, a_node) do { \ (a_node)->a_field.rbn_red = true; \ } while (0) -#define rbtn_black_set(a_type, a_field, a_node) do { \ +#define rbtn_black_set(a_type, a_field, a_node) do { \ (a_node)->a_field.rbn_red = false; \ } while (0) /* Node initializer. */ -#define rbt_node_new(a_type, a_field, a_rbt, a_node) do { \ +#define rbt_node_new(a_type, a_field, a_rbt, a_node) do { \ rbtn_left_set(a_type, a_field, (a_node), NULL); \ rbtn_right_set(a_type, a_field, (a_node), NULL); \ rbtn_red_set(a_type, a_field, (a_node)); \ @@ -117,12 +117,12 @@ struct { \ #endif /* Tree initializer. */ -#define rb_new(a_type, a_field, a_rbt) do { \ +#define rb_new(a_type, a_field, a_rbt) do { \ (a_rbt)->rbt_root = NULL; \ } while (0) /* Internal utility macros. */ -#define rbtn_first(a_type, a_field, a_rbt, a_root, r_node) do { \ +#define rbtn_first(a_type, a_field, a_rbt, a_root, r_node) do { \ (r_node) = (a_root); \ if ((r_node) != NULL) { \ for (; \ @@ -132,7 +132,7 @@ struct { \ } \ } while (0) -#define rbtn_last(a_type, a_field, a_rbt, a_root, r_node) do { \ +#define rbtn_last(a_type, a_field, a_rbt, a_root, r_node) do { \ (r_node) = (a_root); \ if ((r_node) != NULL) { \ for (; rbtn_right_get(a_type, a_field, (r_node)) != NULL; \ @@ -141,14 +141,14 @@ struct { \ } \ } while (0) -#define rbtn_rotate_left(a_type, a_field, a_node, r_node) do { \ +#define rbtn_rotate_left(a_type, a_field, a_node, r_node) do { \ (r_node) = rbtn_right_get(a_type, a_field, (a_node)); \ rbtn_right_set(a_type, a_field, (a_node), \ rbtn_left_get(a_type, a_field, (r_node))); \ rbtn_left_set(a_type, a_field, (r_node), (a_node)); \ } while (0) -#define rbtn_rotate_right(a_type, a_field, a_node, r_node) do { \ +#define rbtn_rotate_right(a_type, a_field, a_node, r_node) do { \ (r_node) = rbtn_left_get(a_type, a_field, (a_node)); \ rbtn_left_set(a_type, a_field, (a_node), \ rbtn_right_get(a_type, a_field, (r_node))); \ @@ -160,7 +160,7 @@ struct { \ * functions generated by an equivalently parameterized call to rb_gen(). */ -#define rb_proto(a_attr, a_prefix, a_rbt_type, a_type) \ +#define rb_proto(a_attr, a_prefix, a_rbt_type, a_type) \ a_attr void \ a_prefix##new(a_rbt_type *rbtree); \ a_attr bool \ @@ -335,7 +335,7 @@ a_prefix##destroy(a_rbt_type *rbtree, void (*cb)(a_type *, void *), \ * has begun. * arg : Opaque pointer passed to cb(). */ -#define rb_gen(a_attr, a_prefix, a_rbt_type, a_type, a_field, a_cmp) \ +#define rb_gen(a_attr, a_prefix, a_rbt_type, a_type, a_field, a_cmp) \ a_attr void \ a_prefix##new(a_rbt_type *rbtree) { \ rb_new(a_type, a_field, rbtree); \ diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index c9a06f64..795a88f7 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -225,9 +225,9 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, start_level, dependent); } -#define RTREE_GET_BIAS (RTREE_HEIGHT_MAX - rtree->height) +#define RTREE_GET_BIAS (RTREE_HEIGHT_MAX - rtree->height) switch (start_level + RTREE_GET_BIAS) { -#define RTREE_GET_SUBTREE(level) \ +#define RTREE_GET_SUBTREE(level) \ case level: \ assert(level < (RTREE_HEIGHT_MAX-1)); \ if (!dependent && unlikely(!rtree_node_valid(node))) { \ @@ -246,7 +246,7 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, node; \ } \ /* Fall through. */ -#define RTREE_GET_LEAF(level) \ +#define RTREE_GET_LEAF(level) \ case level: \ assert(level == (RTREE_HEIGHT_MAX-1)); \ if (!dependent && unlikely(!rtree_node_valid(node))) { \ diff --git a/include/jemalloc/internal/rtree_types.h b/include/jemalloc/internal/rtree_types.h index c02ab7a1..122d5cef 100644 --- a/include/jemalloc/internal/rtree_types.h +++ b/include/jemalloc/internal/rtree_types.h @@ -19,13 +19,13 @@ typedef struct rtree_s rtree_t; * RTREE_BITS_PER_LEVEL must be a power of two that is no larger than the * machine address width. */ -#define LG_RTREE_BITS_PER_LEVEL 4 -#define RTREE_BITS_PER_LEVEL (1U << LG_RTREE_BITS_PER_LEVEL) +#define LG_RTREE_BITS_PER_LEVEL 4 +#define RTREE_BITS_PER_LEVEL (1U << LG_RTREE_BITS_PER_LEVEL) /* Maximum rtree height. */ -#define RTREE_HEIGHT_MAX \ +#define RTREE_HEIGHT_MAX \ ((1U << (LG_SIZEOF_PTR+3)) / RTREE_BITS_PER_LEVEL) -#define RTREE_CTX_INITIALIZER { \ +#define RTREE_CTX_INITIALIZER { \ false, \ 0, \ 0, \ @@ -38,15 +38,15 @@ typedef struct rtree_s rtree_t; * have a witness_t directly embedded, but that would dramatically bloat the * tree. This must contain enough entries to e.g. coalesce two extents. */ -#define RTREE_ELM_ACQUIRE_MAX 4 +#define RTREE_ELM_ACQUIRE_MAX 4 /* Initializers for rtree_elm_witness_tsd_t. */ -#define RTREE_ELM_WITNESS_INITIALIZER { \ +#define RTREE_ELM_WITNESS_INITIALIZER { \ NULL, \ WITNESS_INITIALIZER("rtree_elm", WITNESS_RANK_RTREE_ELM) \ } -#define RTREE_ELM_WITNESS_TSD_INITIALIZER { \ +#define RTREE_ELM_WITNESS_TSD_INITIALIZER { \ { \ RTREE_ELM_WITNESS_INITIALIZER, \ RTREE_ELM_WITNESS_INITIALIZER, \ diff --git a/include/jemalloc/internal/size_classes.sh b/include/jemalloc/internal/size_classes.sh index 3680b653..06892d8d 100755 --- a/include/jemalloc/internal/size_classes.sh +++ b/include/jemalloc/internal/size_classes.sh @@ -150,7 +150,7 @@ size_classes() { pow2 $((${lg_z} + 3)); ptr_bits=${pow2_result} pow2 ${lg_g}; g=${pow2_result} - echo "#define SIZE_CLASSES \\" + echo "#define SIZE_CLASSES \\" echo " /* index, lg_grp, lg_delta, ndelta, psz, bin, pgs, lg_delta_lookup */ \\" ntbins=0 @@ -294,7 +294,7 @@ cat <state == tsd_state_nominal); } -#define O(n, t, c) \ +#define O(n, t, c) \ JEMALLOC_ALWAYS_INLINE t * \ tsd_##n##p_get(tsd_t *tsd) { \ return &tsd->n; \ diff --git a/include/jemalloc/internal/tsd_structs.h b/include/jemalloc/internal/tsd_structs.h index 8d94c5be..ca013208 100644 --- a/include/jemalloc/internal/tsd_structs.h +++ b/include/jemalloc/internal/tsd_structs.h @@ -14,7 +14,7 @@ struct tsd_init_head_s { }; #endif -#define MALLOC_TSD \ +#define MALLOC_TSD \ /* O(name, type, cleanup) */ \ O(tcache, tcache_t *, yes) \ O(thread_allocated, uint64_t, no) \ @@ -31,7 +31,7 @@ struct tsd_init_head_s { O(rtree_elm_witnesses, rtree_elm_witness_tsd_t,no) \ O(witness_fork, bool, no) \ -#define TSD_INITIALIZER { \ +#define TSD_INITIALIZER { \ tsd_state_uninitialized, \ NULL, \ 0, \ @@ -51,7 +51,7 @@ struct tsd_init_head_s { struct tsd_s { tsd_state_t state; -#define O(n, t, c) \ +#define O(n, t, c) \ t n; MALLOC_TSD #undef O diff --git a/include/jemalloc/internal/tsd_types.h b/include/jemalloc/internal/tsd_types.h index a1dce928..195b6493 100644 --- a/include/jemalloc/internal/tsd_types.h +++ b/include/jemalloc/internal/tsd_types.h @@ -2,7 +2,7 @@ #define JEMALLOC_INTERNAL_TSD_TYPES_H /* Maximum number of malloc_tsd users with cleanup functions. */ -#define MALLOC_TSD_CLEANUPS_MAX 2 +#define MALLOC_TSD_CLEANUPS_MAX 2 typedef bool (*malloc_tsd_cleanup_t)(void); @@ -15,7 +15,7 @@ typedef struct tsd_init_head_s tsd_init_head_t; typedef struct tsd_s tsd_t; typedef struct tsdn_s tsdn_t; -#define TSDN_NULL ((tsdn_t *)0) +#define TSDN_NULL ((tsdn_t *)0) typedef enum { tsd_state_uninitialized, @@ -77,17 +77,17 @@ typedef enum { /* malloc_tsd_types(). */ #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP -#define malloc_tsd_types(a_name, a_type) +#define malloc_tsd_types(a_name, a_type) #elif (defined(JEMALLOC_TLS)) -#define malloc_tsd_types(a_name, a_type) +#define malloc_tsd_types(a_name, a_type) #elif (defined(_WIN32)) -#define malloc_tsd_types(a_name, a_type) \ +#define malloc_tsd_types(a_name, a_type) \ typedef struct { \ bool initialized; \ a_type val; \ } a_name##tsd_wrapper_t; #else -#define malloc_tsd_types(a_name, a_type) \ +#define malloc_tsd_types(a_name, a_type) \ typedef struct { \ bool initialized; \ a_type val; \ @@ -95,7 +95,7 @@ typedef struct { \ #endif /* malloc_tsd_protos(). */ -#define malloc_tsd_protos(a_attr, a_name, a_type) \ +#define malloc_tsd_protos(a_attr, a_name, a_type) \ a_attr bool \ a_name##tsd_boot0(void); \ a_attr void \ @@ -111,22 +111,22 @@ a_name##tsd_set(a_type *val); /* malloc_tsd_externs(). */ #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP -#define malloc_tsd_externs(a_name, a_type) \ +#define malloc_tsd_externs(a_name, a_type) \ extern __thread a_type a_name##tsd_tls; \ extern __thread bool a_name##tsd_initialized; \ extern bool a_name##tsd_booted; #elif (defined(JEMALLOC_TLS)) -#define malloc_tsd_externs(a_name, a_type) \ +#define malloc_tsd_externs(a_name, a_type) \ extern __thread a_type a_name##tsd_tls; \ extern pthread_key_t a_name##tsd_tsd; \ extern bool a_name##tsd_booted; #elif (defined(_WIN32)) -#define malloc_tsd_externs(a_name, a_type) \ +#define malloc_tsd_externs(a_name, a_type) \ extern DWORD a_name##tsd_tsd; \ extern a_name##tsd_wrapper_t a_name##tsd_boot_wrapper; \ extern bool a_name##tsd_booted; #else -#define malloc_tsd_externs(a_name, a_type) \ +#define malloc_tsd_externs(a_name, a_type) \ extern pthread_key_t a_name##tsd_tsd; \ extern tsd_init_head_t a_name##tsd_init_head; \ extern a_name##tsd_wrapper_t a_name##tsd_boot_wrapper; \ @@ -135,20 +135,20 @@ extern bool a_name##tsd_booted; /* malloc_tsd_data(). */ #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP -#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ +#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ a_attr __thread a_type JEMALLOC_TLS_MODEL \ a_name##tsd_tls = a_initializer; \ a_attr __thread bool JEMALLOC_TLS_MODEL \ a_name##tsd_initialized = false; \ a_attr bool a_name##tsd_booted = false; #elif (defined(JEMALLOC_TLS)) -#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ +#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ a_attr __thread a_type JEMALLOC_TLS_MODEL \ a_name##tsd_tls = a_initializer; \ a_attr pthread_key_t a_name##tsd_tsd; \ a_attr bool a_name##tsd_booted = false; #elif (defined(_WIN32)) -#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ +#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ a_attr DWORD a_name##tsd_tsd; \ a_attr a_name##tsd_wrapper_t a_name##tsd_boot_wrapper = { \ false, \ @@ -156,7 +156,7 @@ a_attr a_name##tsd_wrapper_t a_name##tsd_boot_wrapper = { \ }; \ a_attr bool a_name##tsd_booted = false; #else -#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ +#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ a_attr pthread_key_t a_name##tsd_tsd; \ a_attr tsd_init_head_t a_name##tsd_init_head = { \ ql_head_initializer(blocks), \ @@ -171,7 +171,7 @@ a_attr bool a_name##tsd_booted = false; /* malloc_tsd_funcs(). */ #ifdef JEMALLOC_MALLOC_THREAD_CLEANUP -#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ +#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ a_cleanup) \ /* Initialization/cleanup. */ \ a_attr bool \ @@ -224,7 +224,7 @@ a_name##tsd_set(a_type *val) { \ } \ } #elif (defined(JEMALLOC_TLS)) -#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ +#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ a_cleanup) \ /* Initialization/cleanup. */ \ a_attr bool \ @@ -278,7 +278,7 @@ a_name##tsd_set(a_type *val) { \ } \ } #elif (defined(_WIN32)) -#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ +#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ a_cleanup) \ /* Initialization/cleanup. */ \ a_attr bool \ @@ -403,7 +403,7 @@ a_name##tsd_set(a_type *val) { \ } \ } #else -#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ +#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ a_cleanup) \ /* Initialization/cleanup. */ \ a_attr void \ diff --git a/include/jemalloc/internal/util_types.h b/include/jemalloc/internal/util_types.h index 4fe206bc..e0f79aad 100644 --- a/include/jemalloc/internal/util_types.h +++ b/include/jemalloc/internal/util_types.h @@ -32,13 +32,13 @@ #endif /* Size of stack-allocated buffer passed to buferror(). */ -#define BUFERROR_BUF 64 +#define BUFERROR_BUF 64 /* * Size of stack-allocated buffer used by malloc_{,v,vc}printf(). This must be * large enough for all possible uses within jemalloc. */ -#define MALLOC_PRINTF_BUFSIZE 4096 +#define MALLOC_PRINTF_BUFSIZE 4096 /* Junk fill patterns. */ #ifndef JEMALLOC_ALLOC_JUNK @@ -52,11 +52,11 @@ * Wrap a cpp argument that contains commas such that it isn't broken up into * multiple arguments. */ -#define JEMALLOC_ARG_CONCAT(...) __VA_ARGS__ +#define JEMALLOC_ARG_CONCAT(...) __VA_ARGS__ /* cpp macro definition stringification. */ -#define STRINGIFY_HELPER(x) #x -#define STRINGIFY(x) STRINGIFY_HELPER(x) +#define STRINGIFY_HELPER(x) #x +#define STRINGIFY(x) STRINGIFY_HELPER(x) /* * Silence compiler warnings due to uninitialized values. This is used @@ -86,7 +86,7 @@ #include "jemalloc/internal/assert.h" /* Use to assert a particular configuration, e.g., cassert(config_debug). */ -#define cassert(c) do { \ +#define cassert(c) do { \ if (unlikely(!(c))) { \ not_reached(); \ } \ diff --git a/include/jemalloc/internal/witness_types.h b/include/jemalloc/internal/witness_types.h index ef962824..c2a73f2e 100644 --- a/include/jemalloc/internal/witness_types.h +++ b/include/jemalloc/internal/witness_types.h @@ -11,36 +11,36 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *, * Lock ranks. Witnesses with rank WITNESS_RANK_OMIT are completely ignored by * the witness machinery. */ -#define WITNESS_RANK_OMIT 0U - -#define WITNESS_RANK_INIT 1U -#define WITNESS_RANK_CTL 1U -#define WITNESS_RANK_ARENAS 2U - -#define WITNESS_RANK_PROF_DUMP 3U -#define WITNESS_RANK_PROF_BT2GCTX 4U -#define WITNESS_RANK_PROF_TDATAS 5U -#define WITNESS_RANK_PROF_TDATA 6U -#define WITNESS_RANK_PROF_GCTX 7U - -#define WITNESS_RANK_ARENA 8U -#define WITNESS_RANK_ARENA_EXTENTS 9U -#define WITNESS_RANK_ARENA_EXTENT_CACHE 10 - -#define WITNESS_RANK_RTREE_ELM 11U -#define WITNESS_RANK_RTREE 12U -#define WITNESS_RANK_BASE 13U - -#define WITNESS_RANK_LEAF 0xffffffffU -#define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF -#define WITNESS_RANK_ARENA_LARGE WITNESS_RANK_LEAF -#define WITNESS_RANK_DSS WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_ACTIVE WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_DUMP_SEQ WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_GDUMP WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_NEXT_THR_UID WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_THREAD_ACTIVE_INIT WITNESS_RANK_LEAF - -#define WITNESS_INITIALIZER(name, rank) {name, rank, NULL, NULL, {NULL, NULL}} +#define WITNESS_RANK_OMIT 0U + +#define WITNESS_RANK_INIT 1U +#define WITNESS_RANK_CTL 1U +#define WITNESS_RANK_ARENAS 2U + +#define WITNESS_RANK_PROF_DUMP 3U +#define WITNESS_RANK_PROF_BT2GCTX 4U +#define WITNESS_RANK_PROF_TDATAS 5U +#define WITNESS_RANK_PROF_TDATA 6U +#define WITNESS_RANK_PROF_GCTX 7U + +#define WITNESS_RANK_ARENA 8U +#define WITNESS_RANK_ARENA_EXTENTS 9U +#define WITNESS_RANK_ARENA_EXTENT_CACHE 10 + +#define WITNESS_RANK_RTREE_ELM 11U +#define WITNESS_RANK_RTREE 12U +#define WITNESS_RANK_BASE 13U + +#define WITNESS_RANK_LEAF 0xffffffffU +#define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF +#define WITNESS_RANK_ARENA_LARGE WITNESS_RANK_LEAF +#define WITNESS_RANK_DSS WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_ACTIVE WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_DUMP_SEQ WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_GDUMP WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_NEXT_THR_UID WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_THREAD_ACTIVE_INIT WITNESS_RANK_LEAF + +#define WITNESS_INITIALIZER(name, rank) {name, rank, NULL, NULL, {NULL, NULL}} #endif /* JEMALLOC_INTERNAL_WITNESS_TYPES_H */ diff --git a/include/jemalloc/jemalloc.sh b/include/jemalloc/jemalloc.sh index c085814f..b19b1548 100755 --- a/include/jemalloc/jemalloc.sh +++ b/include/jemalloc/jemalloc.sh @@ -4,7 +4,7 @@ objroot=$1 cat < #include -#define JEMALLOC_VERSION "@jemalloc_version@" -#define JEMALLOC_VERSION_MAJOR @jemalloc_version_major@ -#define JEMALLOC_VERSION_MINOR @jemalloc_version_minor@ -#define JEMALLOC_VERSION_BUGFIX @jemalloc_version_bugfix@ -#define JEMALLOC_VERSION_NREV @jemalloc_version_nrev@ -#define JEMALLOC_VERSION_GID "@jemalloc_version_gid@" +#define JEMALLOC_VERSION "@jemalloc_version@" +#define JEMALLOC_VERSION_MAJOR @jemalloc_version_major@ +#define JEMALLOC_VERSION_MINOR @jemalloc_version_minor@ +#define JEMALLOC_VERSION_BUGFIX @jemalloc_version_bugfix@ +#define JEMALLOC_VERSION_NREV @jemalloc_version_nrev@ +#define JEMALLOC_VERSION_GID "@jemalloc_version_gid@" -#define MALLOCX_LG_ALIGN(la) ((int)(la)) +#define MALLOCX_LG_ALIGN(la) ((int)(la)) #if LG_SIZEOF_PTR == 2 # define MALLOCX_ALIGN(a) ((int)(ffs((int)(a))-1)) #else @@ -19,17 +19,17 @@ ((int)(((size_t)(a) < (size_t)INT_MAX) ? ffs((int)(a))-1 : \ ffs((int)(((size_t)(a))>>32))+31)) #endif -#define MALLOCX_ZERO ((int)0x40) +#define MALLOCX_ZERO ((int)0x40) /* * Bias tcache index bits so that 0 encodes "automatic tcache management", and 1 * encodes MALLOCX_TCACHE_NONE. */ -#define MALLOCX_TCACHE(tc) ((int)(((tc)+2) << 8)) -#define MALLOCX_TCACHE_NONE MALLOCX_TCACHE(-1) +#define MALLOCX_TCACHE(tc) ((int)(((tc)+2) << 8)) +#define MALLOCX_TCACHE_NONE MALLOCX_TCACHE(-1) /* * Bias arena index bits so that 0 encodes "use an automatically chosen arena". */ -#define MALLOCX_ARENA(a) ((((int)(a))+1) << 20) +#define MALLOCX_ARENA(a) ((((int)(a))+1) << 20) /* * Use as arena index in "arena..{purge,decay,dss}" and @@ -43,12 +43,12 @@ * mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".purge", NULL, NULL, NULL, * 0); */ -#define MALLCTL_ARENAS_ALL 4096 +#define MALLCTL_ARENAS_ALL 4096 /* * Use as arena index in "stats.arenas..*" mallctl interfaces to select * destroyed arenas. */ -#define MALLCTL_ARENAS_DESTROYED 4097 +#define MALLCTL_ARENAS_DESTROYED 4097 #if defined(__cplusplus) && defined(JEMALLOC_USE_CXX_THROW) # define JEMALLOC_CXX_THROW throw() diff --git a/include/msvc_compat/windows_extra.h b/include/msvc_compat/windows_extra.h index 3008faa3..a6ebb930 100644 --- a/include/msvc_compat/windows_extra.h +++ b/include/msvc_compat/windows_extra.h @@ -1,5 +1,5 @@ #ifndef MSVC_COMPAT_WINDOWS_EXTRA_H -#define MSVC_COMPAT_WINDOWS_EXTRA_H +#define MSVC_COMPAT_WINDOWS_EXTRA_H #include diff --git a/src/arena.c b/src/arena.c index fe4b5de2..b0da9a03 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1,4 +1,4 @@ -#define JEMALLOC_ARENA_C_ +#define JEMALLOC_ARENA_C_ #include "jemalloc/internal/jemalloc_internal.h" /******************************************************************************/ @@ -8,10 +8,10 @@ ssize_t opt_decay_time = DECAY_TIME_DEFAULT; static ssize_t decay_time_default; const arena_bin_info_t arena_bin_info[NBINS] = { -#define BIN_INFO_bin_yes(reg_size, slab_size, nregs) \ +#define BIN_INFO_bin_yes(reg_size, slab_size, nregs) \ {reg_size, slab_size, nregs, BITMAP_INFO_INITIALIZER(nregs)}, -#define BIN_INFO_bin_no(reg_size, slab_size, nregs) -#define SC(index, lg_grp, lg_delta, ndelta, psz, bin, pgs, \ +#define BIN_INFO_bin_no(reg_size, slab_size, nregs) +#define SC(index, lg_grp, lg_delta, ndelta, psz, bin, pgs, \ lg_delta_lookup) \ BIN_INFO_bin_##bin((1U< UINT_MAX) { \ ret = EFAULT; \ goto label_return; \ @@ -1102,7 +1102,7 @@ ctl_postfork_child(tsdn_t *tsdn) { * There's a lot of code duplication in the following macros due to limitations * in how nested cpp macros are expanded. */ -#define CTL_RO_CLGEN(c, l, n, v, t) \ +#define CTL_RO_CLGEN(c, l, n, v, t) \ static int \ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ size_t *oldlenp, void *newp, size_t newlen) { \ @@ -1127,7 +1127,7 @@ label_return: \ return ret; \ } -#define CTL_RO_CGEN(c, n, v, t) \ +#define CTL_RO_CGEN(c, n, v, t) \ static int \ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ size_t *oldlenp, void *newp, size_t newlen) { \ @@ -1148,7 +1148,7 @@ label_return: \ return ret; \ } -#define CTL_RO_GEN(n, v, t) \ +#define CTL_RO_GEN(n, v, t) \ static int \ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ size_t *oldlenp, void *newp, size_t newlen) { \ @@ -1170,7 +1170,7 @@ label_return: \ * ctl_mtx is not acquired, under the assumption that no pertinent data will * mutate during the call. */ -#define CTL_RO_NL_CGEN(c, n, v, t) \ +#define CTL_RO_NL_CGEN(c, n, v, t) \ static int \ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ size_t *oldlenp, void *newp, size_t newlen) { \ @@ -1189,7 +1189,7 @@ label_return: \ return ret; \ } -#define CTL_RO_NL_GEN(n, v, t) \ +#define CTL_RO_NL_GEN(n, v, t) \ static int \ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ size_t *oldlenp, void *newp, size_t newlen) { \ @@ -1205,7 +1205,7 @@ label_return: \ return ret; \ } -#define CTL_TSD_RO_NL_CGEN(c, n, m, t) \ +#define CTL_TSD_RO_NL_CGEN(c, n, m, t) \ static int \ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ size_t *oldlenp, void *newp, size_t newlen) { \ @@ -1224,7 +1224,7 @@ label_return: \ return ret; \ } -#define CTL_RO_CONFIG_GEN(n, t) \ +#define CTL_RO_CONFIG_GEN(n, t) \ static int \ n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \ size_t *oldlenp, void *newp, size_t newlen) { \ diff --git a/src/extent.c b/src/extent.c index bcdaccf5..0dbde72a 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1,4 +1,4 @@ -#define JEMALLOC_EXTENT_C_ +#define JEMALLOC_EXTENT_C_ #include "jemalloc/internal/jemalloc_internal.h" /******************************************************************************/ @@ -118,7 +118,7 @@ extent_hooks_assure_initialized(arena_t *arena, #ifdef JEMALLOC_JET #undef extent_size_quantize_floor -#define extent_size_quantize_floor JEMALLOC_N(n_extent_size_quantize_floor) +#define extent_size_quantize_floor JEMALLOC_N(n_extent_size_quantize_floor) #endif size_t extent_size_quantize_floor(size_t size) { @@ -147,14 +147,14 @@ extent_size_quantize_floor(size_t size) { } #ifdef JEMALLOC_JET #undef extent_size_quantize_floor -#define extent_size_quantize_floor JEMALLOC_N(extent_size_quantize_floor) +#define extent_size_quantize_floor JEMALLOC_N(extent_size_quantize_floor) extent_size_quantize_t *extent_size_quantize_floor = JEMALLOC_N(n_extent_size_quantize_floor); #endif #ifdef JEMALLOC_JET #undef extent_size_quantize_ceil -#define extent_size_quantize_ceil JEMALLOC_N(n_extent_size_quantize_ceil) +#define extent_size_quantize_ceil JEMALLOC_N(n_extent_size_quantize_ceil) #endif size_t extent_size_quantize_ceil(size_t size) { @@ -180,7 +180,7 @@ extent_size_quantize_ceil(size_t size) { } #ifdef JEMALLOC_JET #undef extent_size_quantize_ceil -#define extent_size_quantize_ceil JEMALLOC_N(extent_size_quantize_ceil) +#define extent_size_quantize_ceil JEMALLOC_N(extent_size_quantize_ceil) extent_size_quantize_t *extent_size_quantize_ceil = JEMALLOC_N(n_extent_size_quantize_ceil); #endif diff --git a/src/extent_dss.c b/src/extent_dss.c index 93bd6fba..ed4140e7 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -1,4 +1,4 @@ -#define JEMALLOC_EXTENT_DSS_C_ +#define JEMALLOC_EXTENT_DSS_C_ #include "jemalloc/internal/jemalloc_internal.h" /******************************************************************************/ /* Data. */ diff --git a/src/extent_mmap.c b/src/extent_mmap.c index 495d9beb..7265159a 100644 --- a/src/extent_mmap.c +++ b/src/extent_mmap.c @@ -1,4 +1,4 @@ -#define JEMALLOC_EXTENT_MMAP_C_ +#define JEMALLOC_EXTENT_MMAP_C_ #include "jemalloc/internal/jemalloc_internal.h" /******************************************************************************/ diff --git a/src/hash.c b/src/hash.c index cfa4da02..ffd4f2be 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1,2 +1,2 @@ -#define JEMALLOC_HASH_C_ +#define JEMALLOC_HASH_C_ #include "jemalloc/internal/jemalloc_internal.h" diff --git a/src/jemalloc.c b/src/jemalloc.c index 67b430f4..a9a74973 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1,4 +1,4 @@ -#define JEMALLOC_C_ +#define JEMALLOC_C_ #include "jemalloc/internal/jemalloc_internal.h" /******************************************************************************/ @@ -84,10 +84,10 @@ static uint8_t malloc_slow_flags; JEMALLOC_ALIGNED(CACHELINE) const size_t pind2sz_tab[NPSIZES+1] = { -#define PSZ_yes(lg_grp, ndelta, lg_delta) \ +#define PSZ_yes(lg_grp, ndelta, lg_delta) \ (((ZU(1)< (max)) -#define CONF_HANDLE_T_U(t, o, n, min, max, check_min, check_max, clip) \ +#define CONF_MIN_no(um, min) false +#define CONF_MIN_yes(um, min) ((um) < (min)) +#define CONF_MAX_no(um, max) false +#define CONF_MAX_yes(um, max) ((um) > (max)) +#define CONF_HANDLE_T_U(t, o, n, min, max, check_min, check_max, clip) \ if (CONF_MATCH(n)) { \ uintmax_t um; \ char *end; \ @@ -989,14 +989,14 @@ malloc_conf_init(void) { } \ continue; \ } -#define CONF_HANDLE_UNSIGNED(o, n, min, max, check_min, check_max, \ +#define CONF_HANDLE_UNSIGNED(o, n, min, max, check_min, check_max, \ clip) \ CONF_HANDLE_T_U(unsigned, o, n, min, max, \ check_min, check_max, clip) -#define CONF_HANDLE_SIZE_T(o, n, min, max, check_min, check_max, clip) \ +#define CONF_HANDLE_SIZE_T(o, n, min, max, check_min, check_max, clip) \ CONF_HANDLE_T_U(size_t, o, n, min, max, \ check_min, check_max, clip) -#define CONF_HANDLE_SSIZE_T(o, n, min, max) \ +#define CONF_HANDLE_SSIZE_T(o, n, min, max) \ if (CONF_MATCH(n)) { \ long l; \ char *end; \ @@ -1018,7 +1018,7 @@ malloc_conf_init(void) { } \ continue; \ } -#define CONF_HANDLE_CHAR_P(o, n, d) \ +#define CONF_HANDLE_CHAR_P(o, n, d) \ if (CONF_MATCH(n)) { \ size_t cpylen = (vlen <= \ sizeof(o)-1) ? vlen : \ @@ -2119,9 +2119,9 @@ je_valloc(size_t size) { * is_malloc(je_malloc) is some macro magic to detect if jemalloc_defs.h has * #define je_malloc malloc */ -#define malloc_is_malloc 1 -#define is_malloc_(a) malloc_is_ ## a -#define is_malloc(a) is_malloc_(a) +#define malloc_is_malloc 1 +#define is_malloc_(a) malloc_is_ ## a +#define is_malloc(a) is_malloc_(a) #if ((is_malloc(je_malloc) == 1) && defined(JEMALLOC_GLIBC_MALLOC_HOOK)) /* @@ -2147,9 +2147,9 @@ JEMALLOC_EXPORT void *(*__memalign_hook)(size_t alignment, size_t size) = * be implemented also, so none of glibc's malloc.o functions are added to the * link. */ -#define ALIAS(je_fn) __attribute__((alias (#je_fn), used)) +#define ALIAS(je_fn) __attribute__((alias (#je_fn), used)) /* To force macro expansion of je_ prefix before stringification. */ -#define PREALIAS(je_fn) ALIAS(je_fn) +#define PREALIAS(je_fn) ALIAS(je_fn) void *__libc_malloc(size_t size) PREALIAS(je_malloc); void __libc_free(void* ptr) PREALIAS(je_free); void *__libc_realloc(void* ptr, size_t size) PREALIAS(je_realloc); diff --git a/src/jemalloc_cpp.cpp b/src/jemalloc_cpp.cpp index 394fbffe..9692b5ba 100644 --- a/src/jemalloc_cpp.cpp +++ b/src/jemalloc_cpp.cpp @@ -1,7 +1,7 @@ #include #include -#define JEMALLOC_CPP_CPP_ +#define JEMALLOC_CPP_CPP_ #include "jemalloc/internal/jemalloc_internal.h" // All operators in this file are exported. diff --git a/src/large.c b/src/large.c index 62d4441f..6458d81a 100644 --- a/src/large.c +++ b/src/large.c @@ -1,4 +1,4 @@ -#define JEMALLOC_LARGE_C_ +#define JEMALLOC_LARGE_C_ #include "jemalloc/internal/jemalloc_internal.h" /******************************************************************************/ @@ -63,7 +63,7 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, #ifdef JEMALLOC_JET #undef large_dalloc_junk -#define large_dalloc_junk JEMALLOC_N(n_large_dalloc_junk) +#define large_dalloc_junk JEMALLOC_N(n_large_dalloc_junk) #endif void large_dalloc_junk(void *ptr, size_t usize) { @@ -71,13 +71,13 @@ large_dalloc_junk(void *ptr, size_t usize) { } #ifdef JEMALLOC_JET #undef large_dalloc_junk -#define large_dalloc_junk JEMALLOC_N(large_dalloc_junk) +#define large_dalloc_junk JEMALLOC_N(large_dalloc_junk) large_dalloc_junk_t *large_dalloc_junk = JEMALLOC_N(n_large_dalloc_junk); #endif #ifdef JEMALLOC_JET #undef large_dalloc_maybe_junk -#define large_dalloc_maybe_junk JEMALLOC_N(n_large_dalloc_maybe_junk) +#define large_dalloc_maybe_junk JEMALLOC_N(n_large_dalloc_maybe_junk) #endif void large_dalloc_maybe_junk(void *ptr, size_t usize) { @@ -93,7 +93,7 @@ large_dalloc_maybe_junk(void *ptr, size_t usize) { } #ifdef JEMALLOC_JET #undef large_dalloc_maybe_junk -#define large_dalloc_maybe_junk JEMALLOC_N(large_dalloc_maybe_junk) +#define large_dalloc_maybe_junk JEMALLOC_N(large_dalloc_maybe_junk) large_dalloc_maybe_junk_t *large_dalloc_maybe_junk = JEMALLOC_N(n_large_dalloc_maybe_junk); #endif diff --git a/src/mb.c b/src/mb.c index dc2c0a25..94f3c724 100644 --- a/src/mb.c +++ b/src/mb.c @@ -1,2 +1,2 @@ -#define JEMALLOC_MB_C_ +#define JEMALLOC_MB_C_ #include "jemalloc/internal/jemalloc_internal.h" diff --git a/src/mutex.c b/src/mutex.c index f883b9d7..f1aa155e 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -1,4 +1,4 @@ -#define JEMALLOC_MUTEX_C_ +#define JEMALLOC_MUTEX_C_ #include "jemalloc/internal/jemalloc_internal.h" #if defined(JEMALLOC_LAZY_LOCK) && !defined(_WIN32) @@ -6,7 +6,7 @@ #endif #ifndef _CRT_SPINCOUNT -#define _CRT_SPINCOUNT 4000 +#define _CRT_SPINCOUNT 4000 #endif /******************************************************************************/ diff --git a/src/nstime.c b/src/nstime.c index 09cd7786..a3f6c1de 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -1,6 +1,6 @@ #include "jemalloc/internal/jemalloc_internal.h" -#define BILLION UINT64_C(1000000000) +#define BILLION UINT64_C(1000000000) void nstime_init(nstime_t *time, uint64_t ns) { @@ -122,7 +122,7 @@ nstime_get(nstime_t *time) { #ifdef JEMALLOC_JET #undef nstime_monotonic -#define nstime_monotonic JEMALLOC_N(n_nstime_monotonic) +#define nstime_monotonic JEMALLOC_N(n_nstime_monotonic) #endif bool nstime_monotonic(void) { @@ -131,13 +131,13 @@ nstime_monotonic(void) { } #ifdef JEMALLOC_JET #undef nstime_monotonic -#define nstime_monotonic JEMALLOC_N(nstime_monotonic) +#define nstime_monotonic JEMALLOC_N(nstime_monotonic) nstime_monotonic_t *nstime_monotonic = JEMALLOC_N(n_nstime_monotonic); #endif #ifdef JEMALLOC_JET #undef nstime_update -#define nstime_update JEMALLOC_N(n_nstime_update) +#define nstime_update JEMALLOC_N(n_nstime_update) #endif bool nstime_update(nstime_t *time) { @@ -156,6 +156,6 @@ nstime_update(nstime_t *time) { } #ifdef JEMALLOC_JET #undef nstime_update -#define nstime_update JEMALLOC_N(nstime_update) +#define nstime_update JEMALLOC_N(nstime_update) nstime_update_t *nstime_update = JEMALLOC_N(n_nstime_update); #endif diff --git a/src/pages.c b/src/pages.c index 0b678e7d..444a97c2 100644 --- a/src/pages.c +++ b/src/pages.c @@ -1,4 +1,4 @@ -#define JEMALLOC_PAGES_C_ +#define JEMALLOC_PAGES_C_ #include "jemalloc/internal/jemalloc_internal.h" #ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT diff --git a/src/prng.c b/src/prng.c index 76646a2a..bf908790 100644 --- a/src/prng.c +++ b/src/prng.c @@ -1,2 +1,2 @@ -#define JEMALLOC_PRNG_C_ +#define JEMALLOC_PRNG_C_ #include "jemalloc/internal/jemalloc_internal.h" diff --git a/src/prof.c b/src/prof.c index 1b34a750..1dd0f54d 100644 --- a/src/prof.c +++ b/src/prof.c @@ -1,9 +1,9 @@ -#define JEMALLOC_PROF_C_ +#define JEMALLOC_PROF_C_ #include "jemalloc/internal/jemalloc_internal.h" /******************************************************************************/ #ifdef JEMALLOC_PROF_LIBUNWIND -#define UNW_LOCAL_ONLY +#define UNW_LOCAL_ONLY #include #endif @@ -353,7 +353,7 @@ prof_backtrace(prof_bt_t *bt) { #elif (defined(JEMALLOC_PROF_GCC)) void prof_backtrace(prof_bt_t *bt) { -#define BT_FRAME(i) \ +#define BT_FRAME(i) \ if ((i) < PROF_BT_MAX) { \ void *p; \ if (__builtin_frame_address(i) == 0) { \ @@ -928,7 +928,7 @@ prof_bt_count(void) { #ifdef JEMALLOC_JET #undef prof_dump_open -#define prof_dump_open JEMALLOC_N(prof_dump_open_impl) +#define prof_dump_open JEMALLOC_N(prof_dump_open_impl) #endif static int prof_dump_open(bool propagate_err, const char *filename) { @@ -947,7 +947,7 @@ prof_dump_open(bool propagate_err, const char *filename) { } #ifdef JEMALLOC_JET #undef prof_dump_open -#define prof_dump_open JEMALLOC_N(prof_dump_open) +#define prof_dump_open JEMALLOC_N(prof_dump_open) prof_dump_open_t *prof_dump_open = JEMALLOC_N(prof_dump_open_impl); #endif @@ -1305,7 +1305,7 @@ prof_tdata_dump_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, #ifdef JEMALLOC_JET #undef prof_dump_header -#define prof_dump_header JEMALLOC_N(prof_dump_header_impl) +#define prof_dump_header JEMALLOC_N(prof_dump_header_impl) #endif static bool prof_dump_header(tsdn_t *tsdn, bool propagate_err, const prof_cnt_t *cnt_all) { @@ -1327,7 +1327,7 @@ prof_dump_header(tsdn_t *tsdn, bool propagate_err, const prof_cnt_t *cnt_all) { } #ifdef JEMALLOC_JET #undef prof_dump_header -#define prof_dump_header JEMALLOC_N(prof_dump_header) +#define prof_dump_header JEMALLOC_N(prof_dump_header) prof_dump_header_t *prof_dump_header = JEMALLOC_N(prof_dump_header_impl); #endif @@ -1696,8 +1696,8 @@ prof_cnt_all(uint64_t *curobjs, uint64_t *curbytes, uint64_t *accumobjs, } #endif -#define DUMP_FILENAME_BUFSIZE (PATH_MAX + 1) -#define VSEQ_INVALID UINT64_C(0xffffffffffffffff) +#define DUMP_FILENAME_BUFSIZE (PATH_MAX + 1) +#define VSEQ_INVALID UINT64_C(0xffffffffffffffff) static void prof_dump_filename(char *filename, char v, uint64_t vseq) { cassert(config_prof); diff --git a/src/rtree.c b/src/rtree.c index d0c5fe65..d760816e 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -1,4 +1,4 @@ -#define JEMALLOC_RTREE_C_ +#define JEMALLOC_RTREE_C_ #include "jemalloc/internal/jemalloc_internal.h" static unsigned @@ -65,7 +65,7 @@ rtree_new(rtree_t *rtree, unsigned bits) { #ifdef JEMALLOC_JET #undef rtree_node_alloc -#define rtree_node_alloc JEMALLOC_N(rtree_node_alloc_impl) +#define rtree_node_alloc JEMALLOC_N(rtree_node_alloc_impl) #endif static rtree_elm_t * rtree_node_alloc(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { @@ -74,13 +74,13 @@ rtree_node_alloc(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { } #ifdef JEMALLOC_JET #undef rtree_node_alloc -#define rtree_node_alloc JEMALLOC_N(rtree_node_alloc) +#define rtree_node_alloc JEMALLOC_N(rtree_node_alloc) rtree_node_alloc_t *rtree_node_alloc = JEMALLOC_N(rtree_node_alloc_impl); #endif #ifdef JEMALLOC_JET #undef rtree_node_dalloc -#define rtree_node_dalloc JEMALLOC_N(rtree_node_dalloc_impl) +#define rtree_node_dalloc JEMALLOC_N(rtree_node_dalloc_impl) #endif UNUSED static void rtree_node_dalloc(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) { @@ -89,7 +89,7 @@ rtree_node_dalloc(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) { } #ifdef JEMALLOC_JET #undef rtree_node_dalloc -#define rtree_node_dalloc JEMALLOC_N(rtree_node_dalloc) +#define rtree_node_dalloc JEMALLOC_N(rtree_node_dalloc) rtree_node_dalloc_t *rtree_node_dalloc = JEMALLOC_N(rtree_node_dalloc_impl); #endif diff --git a/src/spin.c b/src/spin.c index 5242d95a..d7eb5fa8 100644 --- a/src/spin.c +++ b/src/spin.c @@ -1,2 +1,2 @@ -#define JEMALLOC_SPIN_C_ +#define JEMALLOC_SPIN_C_ #include "jemalloc/internal/jemalloc_internal.h" diff --git a/src/stats.c b/src/stats.c index b0a7fca2..2a424a73 100644 --- a/src/stats.c +++ b/src/stats.c @@ -1,12 +1,12 @@ -#define JEMALLOC_STATS_C_ +#define JEMALLOC_STATS_C_ #include "jemalloc/internal/jemalloc_internal.h" -#define CTL_GET(n, v, t) do { \ +#define CTL_GET(n, v, t) do { \ size_t sz = sizeof(t); \ xmallctl(n, (void *)v, &sz, NULL, 0); \ } while (0) -#define CTL_M2_GET(n, i, v, t) do { \ +#define CTL_M2_GET(n, i, v, t) do { \ size_t mib[6]; \ size_t miblen = sizeof(mib) / sizeof(size_t); \ size_t sz = sizeof(t); \ @@ -15,7 +15,7 @@ xmallctlbymib(mib, miblen, (void *)v, &sz, NULL, 0); \ } while (0) -#define CTL_M2_M4_GET(n, i, j, v, t) do { \ +#define CTL_M2_M4_GET(n, i, j, v, t) do { \ size_t mib[6]; \ size_t miblen = sizeof(mib) / sizeof(size_t); \ size_t sz = sizeof(t); \ @@ -478,7 +478,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, } /* config. */ -#define CONFIG_WRITE_BOOL_JSON(n, c) \ +#define CONFIG_WRITE_BOOL_JSON(n, c) \ if (json) { \ CTL_GET("config."#n, &bv, bool); \ malloc_cprintf(write_cb, cbopaque, \ @@ -531,7 +531,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, #undef CONFIG_WRITE_BOOL_JSON /* opt. */ -#define OPT_WRITE_BOOL(n, c) \ +#define OPT_WRITE_BOOL(n, c) \ if (je_mallctl("opt."#n, (void *)&bv, &bsz, NULL, 0) == 0) { \ if (json) { \ malloc_cprintf(write_cb, cbopaque, \ @@ -542,7 +542,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, " opt."#n": %s\n", bv ? "true" : "false"); \ } \ } -#define OPT_WRITE_BOOL_MUTABLE(n, m, c) { \ +#define OPT_WRITE_BOOL_MUTABLE(n, m, c) { \ bool bv2; \ if (je_mallctl("opt."#n, (void *)&bv, &bsz, NULL, 0) == 0 && \ je_mallctl(#m, (void *)&bv2, &bsz, NULL, 0) == 0) { \ @@ -557,7 +557,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, } \ } \ } -#define OPT_WRITE_UNSIGNED(n, c) \ +#define OPT_WRITE_UNSIGNED(n, c) \ if (je_mallctl("opt."#n, (void *)&uv, &usz, NULL, 0) == 0) { \ if (json) { \ malloc_cprintf(write_cb, cbopaque, \ @@ -567,7 +567,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, " opt."#n": %u\n", uv); \ } \ } -#define OPT_WRITE_SSIZE_T(n, c) \ +#define OPT_WRITE_SSIZE_T(n, c) \ if (je_mallctl("opt."#n, (void *)&ssv, &sssz, NULL, 0) == 0) { \ if (json) { \ malloc_cprintf(write_cb, cbopaque, \ @@ -577,7 +577,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, " opt."#n": %zd\n", ssv); \ } \ } -#define OPT_WRITE_SSIZE_T_MUTABLE(n, m, c) { \ +#define OPT_WRITE_SSIZE_T_MUTABLE(n, m, c) { \ ssize_t ssv2; \ if (je_mallctl("opt."#n, (void *)&ssv, &sssz, NULL, 0) == 0 && \ je_mallctl(#m, (void *)&ssv2, &sssz, NULL, 0) == 0) { \ @@ -591,7 +591,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, } \ } \ } -#define OPT_WRITE_CHAR_P(n, c) \ +#define OPT_WRITE_CHAR_P(n, c) \ if (je_mallctl("opt."#n, (void *)&cpv, &cpsz, NULL, 0) == 0) { \ if (json) { \ malloc_cprintf(write_cb, cbopaque, \ diff --git a/src/tcache.c b/src/tcache.c index 0501c3fc..96a42add 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -1,4 +1,4 @@ -#define JEMALLOC_TCACHE_C_ +#define JEMALLOC_TCACHE_C_ #include "jemalloc/internal/jemalloc_internal.h" /******************************************************************************/ diff --git a/src/ticker.c b/src/ticker.c index db090240..b0149e1c 100644 --- a/src/ticker.c +++ b/src/ticker.c @@ -1,2 +1,2 @@ -#define JEMALLOC_TICKER_C_ +#define JEMALLOC_TICKER_C_ #include "jemalloc/internal/jemalloc_internal.h" diff --git a/src/tsd.c b/src/tsd.c index ae77fcb1..7d56e689 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -1,4 +1,4 @@ -#define JEMALLOC_TSD_C_ +#define JEMALLOC_TSD_C_ #include "jemalloc/internal/jemalloc_internal.h" /******************************************************************************/ @@ -69,10 +69,10 @@ tsd_cleanup(void *arg) { /* Do nothing. */ break; case tsd_state_nominal: -#define MALLOC_TSD_cleanup_yes(n, t) \ +#define MALLOC_TSD_cleanup_yes(n, t) \ n##_cleanup(tsd); -#define MALLOC_TSD_cleanup_no(n, t) -#define O(n, t, c) \ +#define MALLOC_TSD_cleanup_no(n, t) +#define O(n, t, c) \ MALLOC_TSD_cleanup_##c(n, t) MALLOC_TSD #undef MALLOC_TSD_cleanup_yes diff --git a/src/util.c b/src/util.c index faa97c8d..ee5fa47e 100644 --- a/src/util.c +++ b/src/util.c @@ -2,14 +2,14 @@ * Define simple versions of assertion macros that won't recurse in case * of assertion failures in malloc_*printf(). */ -#define assert(e) do { \ +#define assert(e) do { \ if (config_debug && !(e)) { \ malloc_write(": Failed assertion\n"); \ abort(); \ } \ } while (0) -#define not_reached() do { \ +#define not_reached() do { \ if (config_debug) { \ malloc_write(": Unreachable code reached\n"); \ abort(); \ @@ -17,28 +17,28 @@ unreachable(); \ } while (0) -#define not_implemented() do { \ +#define not_implemented() do { \ if (config_debug) { \ malloc_write(": Not implemented\n"); \ abort(); \ } \ } while (0) -#define JEMALLOC_UTIL_C_ +#define JEMALLOC_UTIL_C_ #include "jemalloc/internal/jemalloc_internal.h" /******************************************************************************/ /* Function prototypes for non-inline static functions. */ static void wrtmessage(void *cbopaque, const char *s); -#define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1) +#define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1) static char *u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p); -#define D2S_BUFSIZE (1 + U2S_BUFSIZE) +#define D2S_BUFSIZE (1 + U2S_BUFSIZE) static char *d2s(intmax_t x, char sign, char *s, size_t *slen_p); -#define O2S_BUFSIZE (1 + U2S_BUFSIZE) +#define O2S_BUFSIZE (1 + U2S_BUFSIZE) static char *o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p); -#define X2S_BUFSIZE (2 + U2S_BUFSIZE) +#define X2S_BUFSIZE (2 + U2S_BUFSIZE) static char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p); @@ -318,20 +318,20 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) { size_t i; const char *f; -#define APPEND_C(c) do { \ +#define APPEND_C(c) do { \ if (i < size) { \ str[i] = (c); \ } \ i++; \ } while (0) -#define APPEND_S(s, slen) do { \ +#define APPEND_S(s, slen) do { \ if (i < size) { \ size_t cpylen = (slen <= size - i) ? slen : size - i; \ memcpy(&str[i], s, cpylen); \ } \ i += slen; \ } while (0) -#define APPEND_PADDED_S(s, slen, width, left_justify) do { \ +#define APPEND_PADDED_S(s, slen, width, left_justify) do { \ /* Left padding. */ \ size_t pad_len = (width == -1) ? 0 : ((slen < (size_t)width) ? \ (size_t)width - slen : 0); \ @@ -351,7 +351,7 @@ malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap) { } \ } \ } while (0) -#define GET_ARG_NUMERIC(val, len) do { \ +#define GET_ARG_NUMERIC(val, len) do { \ switch (len) { \ case '?': \ val = va_arg(ap, int); \ diff --git a/src/witness.c b/src/witness.c index f8d66217..1c03457e 100644 --- a/src/witness.c +++ b/src/witness.c @@ -1,4 +1,4 @@ -#define JEMALLOC_WITNESS_C_ +#define JEMALLOC_WITNESS_C_ #include "jemalloc/internal/jemalloc_internal.h" void @@ -12,7 +12,7 @@ witness_init(witness_t *witness, const char *name, witness_rank_t rank, #ifdef JEMALLOC_JET #undef witness_lock_error -#define witness_lock_error JEMALLOC_N(n_witness_lock_error) +#define witness_lock_error JEMALLOC_N(n_witness_lock_error) #endif void witness_lock_error(const witness_list_t *witnesses, const witness_t *witness) { @@ -27,13 +27,13 @@ witness_lock_error(const witness_list_t *witnesses, const witness_t *witness) { } #ifdef JEMALLOC_JET #undef witness_lock_error -#define witness_lock_error JEMALLOC_N(witness_lock_error) +#define witness_lock_error JEMALLOC_N(witness_lock_error) witness_lock_error_t *witness_lock_error = JEMALLOC_N(n_witness_lock_error); #endif #ifdef JEMALLOC_JET #undef witness_owner_error -#define witness_owner_error JEMALLOC_N(n_witness_owner_error) +#define witness_owner_error JEMALLOC_N(n_witness_owner_error) #endif void witness_owner_error(const witness_t *witness) { @@ -43,13 +43,13 @@ witness_owner_error(const witness_t *witness) { } #ifdef JEMALLOC_JET #undef witness_owner_error -#define witness_owner_error JEMALLOC_N(witness_owner_error) +#define witness_owner_error JEMALLOC_N(witness_owner_error) witness_owner_error_t *witness_owner_error = JEMALLOC_N(n_witness_owner_error); #endif #ifdef JEMALLOC_JET #undef witness_not_owner_error -#define witness_not_owner_error JEMALLOC_N(n_witness_not_owner_error) +#define witness_not_owner_error JEMALLOC_N(n_witness_not_owner_error) #endif void witness_not_owner_error(const witness_t *witness) { @@ -59,14 +59,14 @@ witness_not_owner_error(const witness_t *witness) { } #ifdef JEMALLOC_JET #undef witness_not_owner_error -#define witness_not_owner_error JEMALLOC_N(witness_not_owner_error) +#define witness_not_owner_error JEMALLOC_N(witness_not_owner_error) witness_not_owner_error_t *witness_not_owner_error = JEMALLOC_N(n_witness_not_owner_error); #endif #ifdef JEMALLOC_JET #undef witness_lockless_error -#define witness_lockless_error JEMALLOC_N(n_witness_lockless_error) +#define witness_lockless_error JEMALLOC_N(n_witness_lockless_error) #endif void witness_lockless_error(const witness_list_t *witnesses) { @@ -81,7 +81,7 @@ witness_lockless_error(const witness_list_t *witnesses) { } #ifdef JEMALLOC_JET #undef witness_lockless_error -#define witness_lockless_error JEMALLOC_N(witness_lockless_error) +#define witness_lockless_error JEMALLOC_N(witness_lockless_error) witness_lockless_error_t *witness_lockless_error = JEMALLOC_N(n_witness_lockless_error); #endif diff --git a/test/include/test/btalloc.h b/test/include/test/btalloc.h index 8b733f50..5877ea77 100644 --- a/test/include/test/btalloc.h +++ b/test/include/test/btalloc.h @@ -1,12 +1,12 @@ /* btalloc() provides a mechanism for allocating via permuted backtraces. */ void *btalloc(size_t size, unsigned bits); -#define btalloc_n_proto(n) \ +#define btalloc_n_proto(n) \ void *btalloc_##n(size_t size, unsigned bits); btalloc_n_proto(0) btalloc_n_proto(1) -#define btalloc_n_gen(n) \ +#define btalloc_n_gen(n) \ void * \ btalloc_##n(size_t size, unsigned bits) { \ void *p; \ diff --git a/test/include/test/jemalloc_test.h.in b/test/include/test/jemalloc_test.h.in index a0b94747..36d59cff 100644 --- a/test/include/test/jemalloc_test.h.in +++ b/test/include/test/jemalloc_test.h.in @@ -123,7 +123,7 @@ static const bool config_debug = #include "test/test.h" #include "test/timer.h" #include "test/thd.h" -#define MEXP 19937 +#define MEXP 19937 #include "test/SFMT.h" /******************************************************************************/ @@ -136,7 +136,7 @@ static const bool config_debug = #undef not_implemented #undef assert_not_implemented -#define assert(e) do { \ +#define assert(e) do { \ if (!(e)) { \ malloc_printf( \ ": %s:%d: Failed assertion: \"%s\"\n", \ @@ -145,20 +145,20 @@ static const bool config_debug = } \ } while (0) -#define not_reached() do { \ +#define not_reached() do { \ malloc_printf( \ ": %s:%d: Unreachable code reached\n", \ __FILE__, __LINE__); \ abort(); \ } while (0) -#define not_implemented() do { \ +#define not_implemented() do { \ malloc_printf(": %s:%d: Not implemented\n", \ __FILE__, __LINE__); \ abort(); \ } while (0) -#define assert_not_implemented(e) do { \ +#define assert_not_implemented(e) do { \ if (!(e)) { \ not_implemented(); \ } \ diff --git a/test/include/test/mq.h b/test/include/test/mq.h index 8d9907ba..af2c078d 100644 --- a/test/include/test/mq.h +++ b/test/include/test/mq.h @@ -26,9 +26,9 @@ void mq_nanosleep(unsigned ns); * does not perform any cleanup of messages, since it knows nothing of their * payloads. */ -#define mq_msg(a_mq_msg_type) ql_elm(a_mq_msg_type) +#define mq_msg(a_mq_msg_type) ql_elm(a_mq_msg_type) -#define mq_gen(a_attr, a_prefix, a_mq_type, a_mq_msg_type, a_field) \ +#define mq_gen(a_attr, a_prefix, a_mq_type, a_mq_msg_type, a_field) \ typedef struct { \ mtx_t lock; \ ql_head(a_mq_msg_type) msgs; \ diff --git a/test/include/test/test.h b/test/include/test/test.h index a1b6f72a..d7f05fad 100644 --- a/test/include/test/test.h +++ b/test/include/test/test.h @@ -1,6 +1,6 @@ -#define ASSERT_BUFSIZE 256 +#define ASSERT_BUFSIZE 256 -#define assert_cmp(t, a, b, cmp, neg_cmp, pri, ...) do { \ +#define assert_cmp(t, a, b, cmp, neg_cmp, pri, ...) do { \ t a_ = (a); \ t b_ = (b); \ if (!(a_ cmp b_)) { \ @@ -17,200 +17,200 @@ } \ } while (0) -#define assert_ptr_eq(a, b, ...) assert_cmp(void *, a, b, ==, \ +#define assert_ptr_eq(a, b, ...) assert_cmp(void *, a, b, ==, \ !=, "p", __VA_ARGS__) -#define assert_ptr_ne(a, b, ...) assert_cmp(void *, a, b, !=, \ +#define assert_ptr_ne(a, b, ...) assert_cmp(void *, a, b, !=, \ ==, "p", __VA_ARGS__) -#define assert_ptr_null(a, ...) assert_cmp(void *, a, NULL, ==, \ +#define assert_ptr_null(a, ...) assert_cmp(void *, a, NULL, ==, \ !=, "p", __VA_ARGS__) -#define assert_ptr_not_null(a, ...) assert_cmp(void *, a, NULL, !=, \ +#define assert_ptr_not_null(a, ...) assert_cmp(void *, a, NULL, !=, \ ==, "p", __VA_ARGS__) -#define assert_c_eq(a, b, ...) assert_cmp(char, a, b, ==, !=, "c", __VA_ARGS__) -#define assert_c_ne(a, b, ...) assert_cmp(char, a, b, !=, ==, "c", __VA_ARGS__) -#define assert_c_lt(a, b, ...) assert_cmp(char, a, b, <, >=, "c", __VA_ARGS__) -#define assert_c_le(a, b, ...) assert_cmp(char, a, b, <=, >, "c", __VA_ARGS__) -#define assert_c_ge(a, b, ...) assert_cmp(char, a, b, >=, <, "c", __VA_ARGS__) -#define assert_c_gt(a, b, ...) assert_cmp(char, a, b, >, <=, "c", __VA_ARGS__) +#define assert_c_eq(a, b, ...) assert_cmp(char, a, b, ==, !=, "c", __VA_ARGS__) +#define assert_c_ne(a, b, ...) assert_cmp(char, a, b, !=, ==, "c", __VA_ARGS__) +#define assert_c_lt(a, b, ...) assert_cmp(char, a, b, <, >=, "c", __VA_ARGS__) +#define assert_c_le(a, b, ...) assert_cmp(char, a, b, <=, >, "c", __VA_ARGS__) +#define assert_c_ge(a, b, ...) assert_cmp(char, a, b, >=, <, "c", __VA_ARGS__) +#define assert_c_gt(a, b, ...) assert_cmp(char, a, b, >, <=, "c", __VA_ARGS__) -#define assert_x_eq(a, b, ...) assert_cmp(int, a, b, ==, !=, "#x", __VA_ARGS__) -#define assert_x_ne(a, b, ...) assert_cmp(int, a, b, !=, ==, "#x", __VA_ARGS__) -#define assert_x_lt(a, b, ...) assert_cmp(int, a, b, <, >=, "#x", __VA_ARGS__) -#define assert_x_le(a, b, ...) assert_cmp(int, a, b, <=, >, "#x", __VA_ARGS__) -#define assert_x_ge(a, b, ...) assert_cmp(int, a, b, >=, <, "#x", __VA_ARGS__) -#define assert_x_gt(a, b, ...) assert_cmp(int, a, b, >, <=, "#x", __VA_ARGS__) +#define assert_x_eq(a, b, ...) assert_cmp(int, a, b, ==, !=, "#x", __VA_ARGS__) +#define assert_x_ne(a, b, ...) assert_cmp(int, a, b, !=, ==, "#x", __VA_ARGS__) +#define assert_x_lt(a, b, ...) assert_cmp(int, a, b, <, >=, "#x", __VA_ARGS__) +#define assert_x_le(a, b, ...) assert_cmp(int, a, b, <=, >, "#x", __VA_ARGS__) +#define assert_x_ge(a, b, ...) assert_cmp(int, a, b, >=, <, "#x", __VA_ARGS__) +#define assert_x_gt(a, b, ...) assert_cmp(int, a, b, >, <=, "#x", __VA_ARGS__) -#define assert_d_eq(a, b, ...) assert_cmp(int, a, b, ==, !=, "d", __VA_ARGS__) -#define assert_d_ne(a, b, ...) assert_cmp(int, a, b, !=, ==, "d", __VA_ARGS__) -#define assert_d_lt(a, b, ...) assert_cmp(int, a, b, <, >=, "d", __VA_ARGS__) -#define assert_d_le(a, b, ...) assert_cmp(int, a, b, <=, >, "d", __VA_ARGS__) -#define assert_d_ge(a, b, ...) assert_cmp(int, a, b, >=, <, "d", __VA_ARGS__) -#define assert_d_gt(a, b, ...) assert_cmp(int, a, b, >, <=, "d", __VA_ARGS__) +#define assert_d_eq(a, b, ...) assert_cmp(int, a, b, ==, !=, "d", __VA_ARGS__) +#define assert_d_ne(a, b, ...) assert_cmp(int, a, b, !=, ==, "d", __VA_ARGS__) +#define assert_d_lt(a, b, ...) assert_cmp(int, a, b, <, >=, "d", __VA_ARGS__) +#define assert_d_le(a, b, ...) assert_cmp(int, a, b, <=, >, "d", __VA_ARGS__) +#define assert_d_ge(a, b, ...) assert_cmp(int, a, b, >=, <, "d", __VA_ARGS__) +#define assert_d_gt(a, b, ...) assert_cmp(int, a, b, >, <=, "d", __VA_ARGS__) -#define assert_u_eq(a, b, ...) assert_cmp(int, a, b, ==, !=, "u", __VA_ARGS__) -#define assert_u_ne(a, b, ...) assert_cmp(int, a, b, !=, ==, "u", __VA_ARGS__) -#define assert_u_lt(a, b, ...) assert_cmp(int, a, b, <, >=, "u", __VA_ARGS__) -#define assert_u_le(a, b, ...) assert_cmp(int, a, b, <=, >, "u", __VA_ARGS__) -#define assert_u_ge(a, b, ...) assert_cmp(int, a, b, >=, <, "u", __VA_ARGS__) -#define assert_u_gt(a, b, ...) assert_cmp(int, a, b, >, <=, "u", __VA_ARGS__) +#define assert_u_eq(a, b, ...) assert_cmp(int, a, b, ==, !=, "u", __VA_ARGS__) +#define assert_u_ne(a, b, ...) assert_cmp(int, a, b, !=, ==, "u", __VA_ARGS__) +#define assert_u_lt(a, b, ...) assert_cmp(int, a, b, <, >=, "u", __VA_ARGS__) +#define assert_u_le(a, b, ...) assert_cmp(int, a, b, <=, >, "u", __VA_ARGS__) +#define assert_u_ge(a, b, ...) assert_cmp(int, a, b, >=, <, "u", __VA_ARGS__) +#define assert_u_gt(a, b, ...) assert_cmp(int, a, b, >, <=, "u", __VA_ARGS__) -#define assert_ld_eq(a, b, ...) assert_cmp(long, a, b, ==, \ +#define assert_ld_eq(a, b, ...) assert_cmp(long, a, b, ==, \ !=, "ld", __VA_ARGS__) -#define assert_ld_ne(a, b, ...) assert_cmp(long, a, b, !=, \ +#define assert_ld_ne(a, b, ...) assert_cmp(long, a, b, !=, \ ==, "ld", __VA_ARGS__) -#define assert_ld_lt(a, b, ...) assert_cmp(long, a, b, <, \ +#define assert_ld_lt(a, b, ...) assert_cmp(long, a, b, <, \ >=, "ld", __VA_ARGS__) -#define assert_ld_le(a, b, ...) assert_cmp(long, a, b, <=, \ +#define assert_ld_le(a, b, ...) assert_cmp(long, a, b, <=, \ >, "ld", __VA_ARGS__) -#define assert_ld_ge(a, b, ...) assert_cmp(long, a, b, >=, \ +#define assert_ld_ge(a, b, ...) assert_cmp(long, a, b, >=, \ <, "ld", __VA_ARGS__) -#define assert_ld_gt(a, b, ...) assert_cmp(long, a, b, >, \ +#define assert_ld_gt(a, b, ...) assert_cmp(long, a, b, >, \ <=, "ld", __VA_ARGS__) -#define assert_lu_eq(a, b, ...) assert_cmp(unsigned long, \ +#define assert_lu_eq(a, b, ...) assert_cmp(unsigned long, \ a, b, ==, !=, "lu", __VA_ARGS__) -#define assert_lu_ne(a, b, ...) assert_cmp(unsigned long, \ +#define assert_lu_ne(a, b, ...) assert_cmp(unsigned long, \ a, b, !=, ==, "lu", __VA_ARGS__) -#define assert_lu_lt(a, b, ...) assert_cmp(unsigned long, \ +#define assert_lu_lt(a, b, ...) assert_cmp(unsigned long, \ a, b, <, >=, "lu", __VA_ARGS__) -#define assert_lu_le(a, b, ...) assert_cmp(unsigned long, \ +#define assert_lu_le(a, b, ...) assert_cmp(unsigned long, \ a, b, <=, >, "lu", __VA_ARGS__) -#define assert_lu_ge(a, b, ...) assert_cmp(unsigned long, \ +#define assert_lu_ge(a, b, ...) assert_cmp(unsigned long, \ a, b, >=, <, "lu", __VA_ARGS__) -#define assert_lu_gt(a, b, ...) assert_cmp(unsigned long, \ +#define assert_lu_gt(a, b, ...) assert_cmp(unsigned long, \ a, b, >, <=, "lu", __VA_ARGS__) -#define assert_qd_eq(a, b, ...) assert_cmp(long long, a, b, ==, \ +#define assert_qd_eq(a, b, ...) assert_cmp(long long, a, b, ==, \ !=, "qd", __VA_ARGS__) -#define assert_qd_ne(a, b, ...) assert_cmp(long long, a, b, !=, \ +#define assert_qd_ne(a, b, ...) assert_cmp(long long, a, b, !=, \ ==, "qd", __VA_ARGS__) -#define assert_qd_lt(a, b, ...) assert_cmp(long long, a, b, <, \ +#define assert_qd_lt(a, b, ...) assert_cmp(long long, a, b, <, \ >=, "qd", __VA_ARGS__) -#define assert_qd_le(a, b, ...) assert_cmp(long long, a, b, <=, \ +#define assert_qd_le(a, b, ...) assert_cmp(long long, a, b, <=, \ >, "qd", __VA_ARGS__) -#define assert_qd_ge(a, b, ...) assert_cmp(long long, a, b, >=, \ +#define assert_qd_ge(a, b, ...) assert_cmp(long long, a, b, >=, \ <, "qd", __VA_ARGS__) -#define assert_qd_gt(a, b, ...) assert_cmp(long long, a, b, >, \ +#define assert_qd_gt(a, b, ...) assert_cmp(long long, a, b, >, \ <=, "qd", __VA_ARGS__) -#define assert_qu_eq(a, b, ...) assert_cmp(unsigned long long, \ +#define assert_qu_eq(a, b, ...) assert_cmp(unsigned long long, \ a, b, ==, !=, "qu", __VA_ARGS__) -#define assert_qu_ne(a, b, ...) assert_cmp(unsigned long long, \ +#define assert_qu_ne(a, b, ...) assert_cmp(unsigned long long, \ a, b, !=, ==, "qu", __VA_ARGS__) -#define assert_qu_lt(a, b, ...) assert_cmp(unsigned long long, \ +#define assert_qu_lt(a, b, ...) assert_cmp(unsigned long long, \ a, b, <, >=, "qu", __VA_ARGS__) -#define assert_qu_le(a, b, ...) assert_cmp(unsigned long long, \ +#define assert_qu_le(a, b, ...) assert_cmp(unsigned long long, \ a, b, <=, >, "qu", __VA_ARGS__) -#define assert_qu_ge(a, b, ...) assert_cmp(unsigned long long, \ +#define assert_qu_ge(a, b, ...) assert_cmp(unsigned long long, \ a, b, >=, <, "qu", __VA_ARGS__) -#define assert_qu_gt(a, b, ...) assert_cmp(unsigned long long, \ +#define assert_qu_gt(a, b, ...) assert_cmp(unsigned long long, \ a, b, >, <=, "qu", __VA_ARGS__) -#define assert_jd_eq(a, b, ...) assert_cmp(intmax_t, a, b, ==, \ +#define assert_jd_eq(a, b, ...) assert_cmp(intmax_t, a, b, ==, \ !=, "jd", __VA_ARGS__) -#define assert_jd_ne(a, b, ...) assert_cmp(intmax_t, a, b, !=, \ +#define assert_jd_ne(a, b, ...) assert_cmp(intmax_t, a, b, !=, \ ==, "jd", __VA_ARGS__) -#define assert_jd_lt(a, b, ...) assert_cmp(intmax_t, a, b, <, \ +#define assert_jd_lt(a, b, ...) assert_cmp(intmax_t, a, b, <, \ >=, "jd", __VA_ARGS__) -#define assert_jd_le(a, b, ...) assert_cmp(intmax_t, a, b, <=, \ +#define assert_jd_le(a, b, ...) assert_cmp(intmax_t, a, b, <=, \ >, "jd", __VA_ARGS__) -#define assert_jd_ge(a, b, ...) assert_cmp(intmax_t, a, b, >=, \ +#define assert_jd_ge(a, b, ...) assert_cmp(intmax_t, a, b, >=, \ <, "jd", __VA_ARGS__) -#define assert_jd_gt(a, b, ...) assert_cmp(intmax_t, a, b, >, \ +#define assert_jd_gt(a, b, ...) assert_cmp(intmax_t, a, b, >, \ <=, "jd", __VA_ARGS__) -#define assert_ju_eq(a, b, ...) assert_cmp(uintmax_t, a, b, ==, \ +#define assert_ju_eq(a, b, ...) assert_cmp(uintmax_t, a, b, ==, \ !=, "ju", __VA_ARGS__) -#define assert_ju_ne(a, b, ...) assert_cmp(uintmax_t, a, b, !=, \ +#define assert_ju_ne(a, b, ...) assert_cmp(uintmax_t, a, b, !=, \ ==, "ju", __VA_ARGS__) -#define assert_ju_lt(a, b, ...) assert_cmp(uintmax_t, a, b, <, \ +#define assert_ju_lt(a, b, ...) assert_cmp(uintmax_t, a, b, <, \ >=, "ju", __VA_ARGS__) -#define assert_ju_le(a, b, ...) assert_cmp(uintmax_t, a, b, <=, \ +#define assert_ju_le(a, b, ...) assert_cmp(uintmax_t, a, b, <=, \ >, "ju", __VA_ARGS__) -#define assert_ju_ge(a, b, ...) assert_cmp(uintmax_t, a, b, >=, \ +#define assert_ju_ge(a, b, ...) assert_cmp(uintmax_t, a, b, >=, \ <, "ju", __VA_ARGS__) -#define assert_ju_gt(a, b, ...) assert_cmp(uintmax_t, a, b, >, \ +#define assert_ju_gt(a, b, ...) assert_cmp(uintmax_t, a, b, >, \ <=, "ju", __VA_ARGS__) -#define assert_zd_eq(a, b, ...) assert_cmp(ssize_t, a, b, ==, \ +#define assert_zd_eq(a, b, ...) assert_cmp(ssize_t, a, b, ==, \ !=, "zd", __VA_ARGS__) -#define assert_zd_ne(a, b, ...) assert_cmp(ssize_t, a, b, !=, \ +#define assert_zd_ne(a, b, ...) assert_cmp(ssize_t, a, b, !=, \ ==, "zd", __VA_ARGS__) -#define assert_zd_lt(a, b, ...) assert_cmp(ssize_t, a, b, <, \ +#define assert_zd_lt(a, b, ...) assert_cmp(ssize_t, a, b, <, \ >=, "zd", __VA_ARGS__) -#define assert_zd_le(a, b, ...) assert_cmp(ssize_t, a, b, <=, \ +#define assert_zd_le(a, b, ...) assert_cmp(ssize_t, a, b, <=, \ >, "zd", __VA_ARGS__) -#define assert_zd_ge(a, b, ...) assert_cmp(ssize_t, a, b, >=, \ +#define assert_zd_ge(a, b, ...) assert_cmp(ssize_t, a, b, >=, \ <, "zd", __VA_ARGS__) -#define assert_zd_gt(a, b, ...) assert_cmp(ssize_t, a, b, >, \ +#define assert_zd_gt(a, b, ...) assert_cmp(ssize_t, a, b, >, \ <=, "zd", __VA_ARGS__) -#define assert_zu_eq(a, b, ...) assert_cmp(size_t, a, b, ==, \ +#define assert_zu_eq(a, b, ...) assert_cmp(size_t, a, b, ==, \ !=, "zu", __VA_ARGS__) -#define assert_zu_ne(a, b, ...) assert_cmp(size_t, a, b, !=, \ +#define assert_zu_ne(a, b, ...) assert_cmp(size_t, a, b, !=, \ ==, "zu", __VA_ARGS__) -#define assert_zu_lt(a, b, ...) assert_cmp(size_t, a, b, <, \ +#define assert_zu_lt(a, b, ...) assert_cmp(size_t, a, b, <, \ >=, "zu", __VA_ARGS__) -#define assert_zu_le(a, b, ...) assert_cmp(size_t, a, b, <=, \ +#define assert_zu_le(a, b, ...) assert_cmp(size_t, a, b, <=, \ >, "zu", __VA_ARGS__) -#define assert_zu_ge(a, b, ...) assert_cmp(size_t, a, b, >=, \ +#define assert_zu_ge(a, b, ...) assert_cmp(size_t, a, b, >=, \ <, "zu", __VA_ARGS__) -#define assert_zu_gt(a, b, ...) assert_cmp(size_t, a, b, >, \ +#define assert_zu_gt(a, b, ...) assert_cmp(size_t, a, b, >, \ <=, "zu", __VA_ARGS__) -#define assert_d32_eq(a, b, ...) assert_cmp(int32_t, a, b, ==, \ +#define assert_d32_eq(a, b, ...) assert_cmp(int32_t, a, b, ==, \ !=, FMTd32, __VA_ARGS__) -#define assert_d32_ne(a, b, ...) assert_cmp(int32_t, a, b, !=, \ +#define assert_d32_ne(a, b, ...) assert_cmp(int32_t, a, b, !=, \ ==, FMTd32, __VA_ARGS__) -#define assert_d32_lt(a, b, ...) assert_cmp(int32_t, a, b, <, \ +#define assert_d32_lt(a, b, ...) assert_cmp(int32_t, a, b, <, \ >=, FMTd32, __VA_ARGS__) -#define assert_d32_le(a, b, ...) assert_cmp(int32_t, a, b, <=, \ +#define assert_d32_le(a, b, ...) assert_cmp(int32_t, a, b, <=, \ >, FMTd32, __VA_ARGS__) -#define assert_d32_ge(a, b, ...) assert_cmp(int32_t, a, b, >=, \ +#define assert_d32_ge(a, b, ...) assert_cmp(int32_t, a, b, >=, \ <, FMTd32, __VA_ARGS__) -#define assert_d32_gt(a, b, ...) assert_cmp(int32_t, a, b, >, \ +#define assert_d32_gt(a, b, ...) assert_cmp(int32_t, a, b, >, \ <=, FMTd32, __VA_ARGS__) -#define assert_u32_eq(a, b, ...) assert_cmp(uint32_t, a, b, ==, \ +#define assert_u32_eq(a, b, ...) assert_cmp(uint32_t, a, b, ==, \ !=, FMTu32, __VA_ARGS__) -#define assert_u32_ne(a, b, ...) assert_cmp(uint32_t, a, b, !=, \ +#define assert_u32_ne(a, b, ...) assert_cmp(uint32_t, a, b, !=, \ ==, FMTu32, __VA_ARGS__) -#define assert_u32_lt(a, b, ...) assert_cmp(uint32_t, a, b, <, \ +#define assert_u32_lt(a, b, ...) assert_cmp(uint32_t, a, b, <, \ >=, FMTu32, __VA_ARGS__) -#define assert_u32_le(a, b, ...) assert_cmp(uint32_t, a, b, <=, \ +#define assert_u32_le(a, b, ...) assert_cmp(uint32_t, a, b, <=, \ >, FMTu32, __VA_ARGS__) -#define assert_u32_ge(a, b, ...) assert_cmp(uint32_t, a, b, >=, \ +#define assert_u32_ge(a, b, ...) assert_cmp(uint32_t, a, b, >=, \ <, FMTu32, __VA_ARGS__) -#define assert_u32_gt(a, b, ...) assert_cmp(uint32_t, a, b, >, \ +#define assert_u32_gt(a, b, ...) assert_cmp(uint32_t, a, b, >, \ <=, FMTu32, __VA_ARGS__) -#define assert_d64_eq(a, b, ...) assert_cmp(int64_t, a, b, ==, \ +#define assert_d64_eq(a, b, ...) assert_cmp(int64_t, a, b, ==, \ !=, FMTd64, __VA_ARGS__) -#define assert_d64_ne(a, b, ...) assert_cmp(int64_t, a, b, !=, \ +#define assert_d64_ne(a, b, ...) assert_cmp(int64_t, a, b, !=, \ ==, FMTd64, __VA_ARGS__) -#define assert_d64_lt(a, b, ...) assert_cmp(int64_t, a, b, <, \ +#define assert_d64_lt(a, b, ...) assert_cmp(int64_t, a, b, <, \ >=, FMTd64, __VA_ARGS__) -#define assert_d64_le(a, b, ...) assert_cmp(int64_t, a, b, <=, \ +#define assert_d64_le(a, b, ...) assert_cmp(int64_t, a, b, <=, \ >, FMTd64, __VA_ARGS__) -#define assert_d64_ge(a, b, ...) assert_cmp(int64_t, a, b, >=, \ +#define assert_d64_ge(a, b, ...) assert_cmp(int64_t, a, b, >=, \ <, FMTd64, __VA_ARGS__) -#define assert_d64_gt(a, b, ...) assert_cmp(int64_t, a, b, >, \ +#define assert_d64_gt(a, b, ...) assert_cmp(int64_t, a, b, >, \ <=, FMTd64, __VA_ARGS__) -#define assert_u64_eq(a, b, ...) assert_cmp(uint64_t, a, b, ==, \ +#define assert_u64_eq(a, b, ...) assert_cmp(uint64_t, a, b, ==, \ !=, FMTu64, __VA_ARGS__) -#define assert_u64_ne(a, b, ...) assert_cmp(uint64_t, a, b, !=, \ +#define assert_u64_ne(a, b, ...) assert_cmp(uint64_t, a, b, !=, \ ==, FMTu64, __VA_ARGS__) -#define assert_u64_lt(a, b, ...) assert_cmp(uint64_t, a, b, <, \ +#define assert_u64_lt(a, b, ...) assert_cmp(uint64_t, a, b, <, \ >=, FMTu64, __VA_ARGS__) -#define assert_u64_le(a, b, ...) assert_cmp(uint64_t, a, b, <=, \ +#define assert_u64_le(a, b, ...) assert_cmp(uint64_t, a, b, <=, \ >, FMTu64, __VA_ARGS__) -#define assert_u64_ge(a, b, ...) assert_cmp(uint64_t, a, b, >=, \ +#define assert_u64_ge(a, b, ...) assert_cmp(uint64_t, a, b, >=, \ <, FMTu64, __VA_ARGS__) -#define assert_u64_gt(a, b, ...) assert_cmp(uint64_t, a, b, >, \ +#define assert_u64_gt(a, b, ...) assert_cmp(uint64_t, a, b, >, \ <=, FMTu64, __VA_ARGS__) -#define assert_b_eq(a, b, ...) do { \ +#define assert_b_eq(a, b, ...) do { \ bool a_ = (a); \ bool b_ = (b); \ if (!(a_ == b_)) { \ @@ -226,7 +226,7 @@ p_test_fail(prefix, message); \ } \ } while (0) -#define assert_b_ne(a, b, ...) do { \ +#define assert_b_ne(a, b, ...) do { \ bool a_ = (a); \ bool b_ = (b); \ if (!(a_ != b_)) { \ @@ -242,10 +242,10 @@ p_test_fail(prefix, message); \ } \ } while (0) -#define assert_true(a, ...) assert_b_eq(a, true, __VA_ARGS__) -#define assert_false(a, ...) assert_b_eq(a, false, __VA_ARGS__) +#define assert_true(a, ...) assert_b_eq(a, true, __VA_ARGS__) +#define assert_false(a, ...) assert_b_eq(a, false, __VA_ARGS__) -#define assert_str_eq(a, b, ...) do { \ +#define assert_str_eq(a, b, ...) do { \ if (strcmp((a), (b))) { \ char prefix[ASSERT_BUFSIZE]; \ char message[ASSERT_BUFSIZE]; \ @@ -258,7 +258,7 @@ p_test_fail(prefix, message); \ } \ } while (0) -#define assert_str_ne(a, b, ...) do { \ +#define assert_str_ne(a, b, ...) do { \ if (!strcmp((a), (b))) { \ char prefix[ASSERT_BUFSIZE]; \ char message[ASSERT_BUFSIZE]; \ @@ -272,7 +272,7 @@ } \ } while (0) -#define assert_not_reached(...) do { \ +#define assert_not_reached(...) do { \ char prefix[ASSERT_BUFSIZE]; \ char message[ASSERT_BUFSIZE]; \ malloc_snprintf(prefix, sizeof(prefix), \ @@ -296,24 +296,24 @@ typedef enum { typedef void (test_t)(void); -#define TEST_BEGIN(f) \ +#define TEST_BEGIN(f) \ static void \ f(void) { \ p_test_init(#f); -#define TEST_END \ +#define TEST_END \ goto label_test_end; \ label_test_end: \ p_test_fini(); \ } -#define test(...) \ +#define test(...) \ p_test(__VA_ARGS__, NULL) -#define test_no_malloc_init(...) \ +#define test_no_malloc_init(...) \ p_test_no_malloc_init(__VA_ARGS__, NULL) -#define test_skip_if(e) do { \ +#define test_skip_if(e) do { \ if (e) { \ test_skip("%s:%s:%d: Test skipped: (%s)", \ __func__, __FILE__, __LINE__, #e); \ diff --git a/test/integration/MALLOCX_ARENA.c b/test/integration/MALLOCX_ARENA.c index b2ec6584..222164d6 100644 --- a/test/integration/MALLOCX_ARENA.c +++ b/test/integration/MALLOCX_ARENA.c @@ -1,6 +1,6 @@ #include "test/jemalloc_test.h" -#define NTHREADS 10 +#define NTHREADS 10 static bool have_dss = #ifdef JEMALLOC_DSS diff --git a/test/integration/aligned_alloc.c b/test/integration/aligned_alloc.c index 54b3bf24..536b67ea 100644 --- a/test/integration/aligned_alloc.c +++ b/test/integration/aligned_alloc.c @@ -1,6 +1,6 @@ #include "test/jemalloc_test.h" -#define MAXALIGN (((size_t)1) << 23) +#define MAXALIGN (((size_t)1) << 23) /* * On systems which can't merge extents, tests that call this function generate @@ -79,7 +79,7 @@ TEST_BEGIN(test_oom_errors) { TEST_END TEST_BEGIN(test_alignment_and_size) { -#define NITER 4 +#define NITER 4 size_t alignment, size, total; unsigned i; void *ps[NITER]; diff --git a/test/integration/mallocx.c b/test/integration/mallocx.c index 26076be4..b60e27b6 100644 --- a/test/integration/mallocx.c +++ b/test/integration/mallocx.c @@ -118,7 +118,7 @@ TEST_BEGIN(test_oom) { TEST_END TEST_BEGIN(test_basic) { -#define MAXSZ (((size_t)1) << 23) +#define MAXSZ (((size_t)1) << 23) size_t sz; for (sz = 1; sz < MAXSZ; sz = nallocx(sz, 0) + 1) { @@ -155,8 +155,8 @@ TEST_BEGIN(test_basic) { TEST_END TEST_BEGIN(test_alignment_and_size) { -#define MAXALIGN (((size_t)1) << 23) -#define NITER 4 +#define MAXALIGN (((size_t)1) << 23) +#define NITER 4 size_t nsz, rsz, sz, alignment, total; unsigned i; void *ps[NITER]; diff --git a/test/integration/posix_memalign.c b/test/integration/posix_memalign.c index 97b9216a..2c2726de 100644 --- a/test/integration/posix_memalign.c +++ b/test/integration/posix_memalign.c @@ -1,6 +1,6 @@ #include "test/jemalloc_test.h" -#define MAXALIGN (((size_t)1) << 23) +#define MAXALIGN (((size_t)1) << 23) /* * On systems which can't merge extents, tests that call this function generate @@ -71,7 +71,7 @@ TEST_BEGIN(test_oom_errors) { TEST_END TEST_BEGIN(test_alignment_and_size) { -#define NITER 4 +#define NITER 4 size_t alignment, size, total; unsigned i; int err; diff --git a/test/integration/rallocx.c b/test/integration/rallocx.c index 7c0f9c5f..7821ca5f 100644 --- a/test/integration/rallocx.c +++ b/test/integration/rallocx.c @@ -43,11 +43,11 @@ get_large_size(size_t ind) { TEST_BEGIN(test_grow_and_shrink) { void *p, *q; size_t tsz; -#define NCYCLES 3 +#define NCYCLES 3 unsigned i, j; -#define NSZS 1024 +#define NSZS 1024 size_t szs[NSZS]; -#define MAXSZ ZU(12 * 1024 * 1024) +#define MAXSZ ZU(12 * 1024 * 1024) p = mallocx(1, 0); assert_ptr_not_null(p, "Unexpected mallocx() error"); @@ -107,8 +107,8 @@ TEST_BEGIN(test_zero) { void *p, *q; size_t psz, qsz, i, j; size_t start_sizes[] = {1, 3*1024, 63*1024, 4095*1024}; -#define FILL_BYTE 0xaaU -#define RANGE 2048 +#define FILL_BYTE 0xaaU +#define RANGE 2048 for (i = 0; i < sizeof(start_sizes)/sizeof(size_t); i++) { size_t start_size = start_sizes[i]; @@ -150,7 +150,7 @@ TEST_END TEST_BEGIN(test_align) { void *p, *q; size_t align; -#define MAX_ALIGN (ZU(1) << 25) +#define MAX_ALIGN (ZU(1) << 25) align = ZU(1); p = mallocx(1, MALLOCX_ALIGN(align)); @@ -175,8 +175,8 @@ TEST_BEGIN(test_lg_align_and_zero) { void *p, *q; unsigned lg_align; size_t sz; -#define MAX_LG_ALIGN 25 -#define MAX_VALIDATE (ZU(1) << 22) +#define MAX_LG_ALIGN 25 +#define MAX_VALIDATE (ZU(1) << 22) lg_align = 0; p = mallocx(1, MALLOCX_LG_ALIGN(lg_align)|MALLOCX_ZERO); diff --git a/test/integration/sdallocx.c b/test/integration/sdallocx.c index f7b42949..e7ea1d82 100644 --- a/test/integration/sdallocx.c +++ b/test/integration/sdallocx.c @@ -1,7 +1,7 @@ #include "test/jemalloc_test.h" -#define MAXALIGN (((size_t)1) << 22) -#define NITER 3 +#define MAXALIGN (((size_t)1) << 22) +#define NITER 3 TEST_BEGIN(test_basic) { void *ptr = mallocx(64, 0); diff --git a/test/integration/thread_arena.c b/test/integration/thread_arena.c index d9dc170d..9991a42f 100644 --- a/test/integration/thread_arena.c +++ b/test/integration/thread_arena.c @@ -1,6 +1,6 @@ #include "test/jemalloc_test.h" -#define NTHREADS 10 +#define NTHREADS 10 void * thd_start(void *arg) { diff --git a/test/integration/xallocx.c b/test/integration/xallocx.c index 158f7ee9..c95fbf18 100644 --- a/test/integration/xallocx.c +++ b/test/integration/xallocx.c @@ -320,7 +320,7 @@ test_zero(size_t szmin, size_t szmax) { int flags = MALLOCX_ARENA(arena_ind()) | MALLOCX_ZERO; size_t sz, nsz; void *p; -#define FILL_BYTE 0x7aU +#define FILL_BYTE 0x7aU sz = szmax; p = mallocx(sz, flags); diff --git a/test/src/SFMT.c b/test/src/SFMT.c index 80cabe05..4dc32599 100644 --- a/test/src/SFMT.c +++ b/test/src/SFMT.c @@ -45,7 +45,7 @@ * * The new BSD License is applied to this software, see LICENSE.txt */ -#define SFMT_C_ +#define SFMT_C_ #include "test/jemalloc_test.h" #include "test/SFMT-params.h" diff --git a/test/src/math.c b/test/src/math.c index 887a3639..1758c677 100644 --- a/test/src/math.c +++ b/test/src/math.c @@ -1,2 +1,2 @@ -#define MATH_C_ +#define MATH_C_ #include "test/jemalloc_test.h" diff --git a/test/src/mtx.c b/test/src/mtx.c index b691b482..a393c01f 100644 --- a/test/src/mtx.c +++ b/test/src/mtx.c @@ -1,7 +1,7 @@ #include "test/jemalloc_test.h" #ifndef _CRT_SPINCOUNT -#define _CRT_SPINCOUNT 4000 +#define _CRT_SPINCOUNT 4000 #endif bool diff --git a/test/unit/SFMT.c b/test/unit/SFMT.c index b5730d63..1fc8cf1b 100644 --- a/test/unit/SFMT.c +++ b/test/unit/SFMT.c @@ -35,10 +35,10 @@ */ #include "test/jemalloc_test.h" -#define BLOCK_SIZE 10000 -#define BLOCK_SIZE64 (BLOCK_SIZE / 2) -#define COUNT_1 1000 -#define COUNT_2 700 +#define BLOCK_SIZE 10000 +#define BLOCK_SIZE64 (BLOCK_SIZE / 2) +#define COUNT_1 1000 +#define COUNT_2 700 static const uint32_t init_gen_rand_32_expected[] = { 3440181298U, 1564997079U, 1510669302U, 2930277156U, 1452439940U, diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 3d74e37a..d2a9bb4f 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -82,7 +82,7 @@ do_arena_create(extent_hooks_t *h) { static void do_arena_reset_pre(unsigned arena_ind, void ***ptrs, unsigned *nptrs) { -#define NLARGE 32 +#define NLARGE 32 unsigned nsmall, nlarge, i; size_t sz; int flags; diff --git a/test/unit/arena_reset_prof.c b/test/unit/arena_reset_prof.c index 0fd362e9..6d83c843 100644 --- a/test/unit/arena_reset_prof.c +++ b/test/unit/arena_reset_prof.c @@ -1,5 +1,5 @@ #include "test/jemalloc_test.h" -#define ARENA_RESET_PROF_C_ +#define ARENA_RESET_PROF_C_ const char *malloc_conf = "prof:true,lg_prof_sample:0"; #include "arena_reset.c" diff --git a/test/unit/atomic.c b/test/unit/atomic.c index 97ec7eb9..78661597 100644 --- a/test/unit/atomic.c +++ b/test/unit/atomic.c @@ -1,6 +1,6 @@ #include "test/jemalloc_test.h" -#define TEST_STRUCT(p, t) \ +#define TEST_STRUCT(p, t) \ struct p##_test_s { \ t accum0; \ t x; \ @@ -8,7 +8,7 @@ struct p##_test_s { \ }; \ typedef struct p##_test_s p##_test_t; -#define TEST_BODY(p, t, tc, ta, FMT) do { \ +#define TEST_BODY(p, t, tc, ta, FMT) do { \ const p##_test_t tests[] = { \ {(t)-1, (t)-1, (t)-2}, \ {(t)-1, (t) 0, (t)-2}, \ diff --git a/test/unit/bitmap.c b/test/unit/bitmap.c index e91f0928..ca657608 100644 --- a/test/unit/bitmap.c +++ b/test/unit/bitmap.c @@ -1,6 +1,6 @@ #include "test/jemalloc_test.h" -#define NBITS_TAB \ +#define NBITS_TAB \ NB( 1) \ NB( 2) \ NB( 3) \ @@ -124,7 +124,7 @@ test_bitmap_initializer_body(const bitmap_info_t *binfo, size_t nbits) { } TEST_BEGIN(test_bitmap_initializer) { -#define NB(nbits) { \ +#define NB(nbits) { \ if (nbits <= BITMAP_MAXBITS) { \ bitmap_info_t binfo = \ BITMAP_INFO_INITIALIZER(nbits); \ @@ -155,7 +155,7 @@ TEST_BEGIN(test_bitmap_size) { bitmap_info_init(&binfo, nbits); prev_size = test_bitmap_size_body(&binfo, nbits, prev_size); } -#define NB(nbits) { \ +#define NB(nbits) { \ bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \ prev_size = test_bitmap_size_body(&binfo, nbits, \ prev_size); \ @@ -188,7 +188,7 @@ TEST_BEGIN(test_bitmap_init) { bitmap_info_init(&binfo, nbits); test_bitmap_init_body(&binfo, nbits); } -#define NB(nbits) { \ +#define NB(nbits) { \ bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \ test_bitmap_init_body(&binfo, nbits); \ } @@ -219,7 +219,7 @@ TEST_BEGIN(test_bitmap_set) { bitmap_info_init(&binfo, nbits); test_bitmap_set_body(&binfo, nbits); } -#define NB(nbits) { \ +#define NB(nbits) { \ bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \ test_bitmap_set_body(&binfo, nbits); \ } @@ -257,7 +257,7 @@ TEST_BEGIN(test_bitmap_unset) { bitmap_info_init(&binfo, nbits); test_bitmap_unset_body(&binfo, nbits); } -#define NB(nbits) { \ +#define NB(nbits) { \ bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \ test_bitmap_unset_body(&binfo, nbits); \ } @@ -318,7 +318,7 @@ TEST_BEGIN(test_bitmap_sfu) { bitmap_info_init(&binfo, nbits); test_bitmap_sfu_body(&binfo, nbits); } -#define NB(nbits) { \ +#define NB(nbits) { \ bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \ test_bitmap_sfu_body(&binfo, nbits); \ } diff --git a/test/unit/ckh.c b/test/unit/ckh.c index 842ae29b..707ea5f8 100644 --- a/test/unit/ckh.c +++ b/test/unit/ckh.c @@ -104,7 +104,7 @@ TEST_BEGIN(test_count_insert_search_remove) { TEST_END TEST_BEGIN(test_insert_iter_remove) { -#define NITEMS ZU(1000) +#define NITEMS ZU(1000) tsd_t *tsd; ckh_t ckh; void **p[NITEMS]; diff --git a/test/unit/decay.c b/test/unit/decay.c index 83c9f49e..4d172a54 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -196,7 +196,7 @@ TEST_BEGIN(test_decay_ticks) { TEST_END TEST_BEGIN(test_decay_ticker) { -#define NPS 1024 +#define NPS 1024 int flags = (MALLOCX_ARENA(0) | MALLOCX_TCACHE_NONE); void *ps[NPS]; uint64_t epoch; @@ -289,7 +289,7 @@ TEST_BEGIN(test_decay_ticker) { TEST_END TEST_BEGIN(test_decay_nonmonotonic) { -#define NPS (SMOOTHSTEP_NSTEPS + 1) +#define NPS (SMOOTHSTEP_NSTEPS + 1) int flags = (MALLOCX_ARENA(0) | MALLOCX_TCACHE_NONE); void *ps[NPS]; uint64_t epoch; diff --git a/test/unit/extent_quantize.c b/test/unit/extent_quantize.c index 52af7a3d..0ca7a75d 100644 --- a/test/unit/extent_quantize.c +++ b/test/unit/extent_quantize.c @@ -99,7 +99,7 @@ TEST_BEGIN(test_large_extent_size) { TEST_END TEST_BEGIN(test_monotonic) { -#define SZ_MAX ZU(4 * 1024 * 1024) +#define SZ_MAX ZU(4 * 1024 * 1024) unsigned i; size_t floor_prev, ceil_prev; diff --git a/test/unit/hash.c b/test/unit/hash.c index 0204cdad..48507515 100644 --- a/test/unit/hash.c +++ b/test/unit/hash.c @@ -55,7 +55,7 @@ hash_variant_string(hash_variant_t variant) { } } -#define KEY_SIZE 256 +#define KEY_SIZE 256 static void hash_variant_verify_key(hash_variant_t variant, uint8_t *key) { const int hashbytes = hash_variant_bits(variant) / 8; @@ -137,7 +137,7 @@ hash_variant_verify_key(hash_variant_t variant, uint8_t *key) { static void hash_variant_verify(hash_variant_t variant) { -#define MAX_ALIGN 16 +#define MAX_ALIGN 16 uint8_t key[KEY_SIZE + (MAX_ALIGN - 1)]; unsigned i; diff --git a/test/unit/junk_alloc.c b/test/unit/junk_alloc.c index a5895b5c..8db3331d 100644 --- a/test/unit/junk_alloc.c +++ b/test/unit/junk_alloc.c @@ -1,3 +1,3 @@ -#define JEMALLOC_TEST_JUNK_OPT "junk:alloc" +#define JEMALLOC_TEST_JUNK_OPT "junk:alloc" #include "junk.c" #undef JEMALLOC_TEST_JUNK_OPT diff --git a/test/unit/junk_free.c b/test/unit/junk_free.c index bb5183c9..482a61d0 100644 --- a/test/unit/junk_free.c +++ b/test/unit/junk_free.c @@ -1,3 +1,3 @@ -#define JEMALLOC_TEST_JUNK_OPT "junk:free" +#define JEMALLOC_TEST_JUNK_OPT "junk:free" #include "junk.c" #undef JEMALLOC_TEST_JUNK_OPT diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index c531a06a..c931e378 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -115,7 +115,7 @@ TEST_BEGIN(test_mallctlnametomib_short_mib) { TEST_END TEST_BEGIN(test_mallctl_config) { -#define TEST_MALLCTL_CONFIG(config, t) do { \ +#define TEST_MALLCTL_CONFIG(config, t) do { \ t oldval; \ size_t sz = sizeof(oldval); \ assert_d_eq(mallctl("config."#config, (void *)&oldval, &sz, \ @@ -146,7 +146,7 @@ TEST_END TEST_BEGIN(test_mallctl_opt) { bool config_always = true; -#define TEST_MALLCTL_OPT(t, opt, config) do { \ +#define TEST_MALLCTL_OPT(t, opt, config) do { \ t oldval; \ size_t sz = sizeof(oldval); \ int expected = config_##config ? 0 : ENOENT; \ @@ -232,7 +232,7 @@ TEST_BEGIN(test_tcache_none) { TEST_END TEST_BEGIN(test_tcache) { -#define NTCACHES 10 +#define NTCACHES 10 unsigned tis[NTCACHES]; void *ps[NTCACHES]; void *qs[NTCACHES]; @@ -534,7 +534,7 @@ TEST_BEGIN(test_arenas_decay_time) { TEST_END TEST_BEGIN(test_arenas_constants) { -#define TEST_ARENAS_CONSTANT(t, name, expected) do { \ +#define TEST_ARENAS_CONSTANT(t, name, expected) do { \ t name; \ size_t sz = sizeof(t); \ assert_d_eq(mallctl("arenas."#name, (void *)&name, &sz, NULL, \ @@ -552,7 +552,7 @@ TEST_BEGIN(test_arenas_constants) { TEST_END TEST_BEGIN(test_arenas_bin_constants) { -#define TEST_ARENAS_BIN_CONSTANT(t, name, expected) do { \ +#define TEST_ARENAS_BIN_CONSTANT(t, name, expected) do { \ t name; \ size_t sz = sizeof(t); \ assert_d_eq(mallctl("arenas.bin.0."#name, (void *)&name, &sz, \ @@ -570,7 +570,7 @@ TEST_BEGIN(test_arenas_bin_constants) { TEST_END TEST_BEGIN(test_arenas_lextent_constants) { -#define TEST_ARENAS_LEXTENT_CONSTANT(t, name, expected) do { \ +#define TEST_ARENAS_LEXTENT_CONSTANT(t, name, expected) do { \ t name; \ size_t sz = sizeof(t); \ assert_d_eq(mallctl("arenas.lextent.0."#name, (void *)&name, \ @@ -602,7 +602,7 @@ TEST_BEGIN(test_arenas_create) { TEST_END TEST_BEGIN(test_stats_arenas) { -#define TEST_STATS_ARENAS(t, name) do { \ +#define TEST_STATS_ARENAS(t, name) do { \ t name; \ size_t sz = sizeof(t); \ assert_d_eq(mallctl("stats.arenas.0."#name, (void *)&name, &sz, \ diff --git a/test/unit/math.c b/test/unit/math.c index d2cf16dd..09ef20c7 100644 --- a/test/unit/math.c +++ b/test/unit/math.c @@ -1,7 +1,7 @@ #include "test/jemalloc_test.h" -#define MAX_REL_ERR 1.0e-9 -#define MAX_ABS_ERR 1.0e-9 +#define MAX_REL_ERR 1.0e-9 +#define MAX_ABS_ERR 1.0e-9 #include @@ -10,7 +10,7 @@ #endif #ifndef INFINITY -#define INFINITY (DBL_MAX + DBL_MAX) +#define INFINITY (DBL_MAX + DBL_MAX) #endif static bool diff --git a/test/unit/mq.c b/test/unit/mq.c index fe17943e..57a4d54e 100644 --- a/test/unit/mq.c +++ b/test/unit/mq.c @@ -1,7 +1,7 @@ #include "test/jemalloc_test.h" -#define NSENDERS 3 -#define NMSGS 100000 +#define NSENDERS 3 +#define NMSGS 100000 typedef struct mq_msg_s mq_msg_t; struct mq_msg_s { diff --git a/test/unit/mtx.c b/test/unit/mtx.c index 23740ce1..424587b0 100644 --- a/test/unit/mtx.c +++ b/test/unit/mtx.c @@ -1,7 +1,7 @@ #include "test/jemalloc_test.h" -#define NTHREADS 2 -#define NINCRS 2000000 +#define NTHREADS 2 +#define NINCRS 2000000 TEST_BEGIN(test_mtx_basic) { mtx_t mtx; diff --git a/test/unit/nstime.c b/test/unit/nstime.c index f7f1bdfd..f8384f5a 100644 --- a/test/unit/nstime.c +++ b/test/unit/nstime.c @@ -1,6 +1,6 @@ #include "test/jemalloc_test.h" -#define BILLION UINT64_C(1000000000) +#define BILLION UINT64_C(1000000000) TEST_BEGIN(test_nstime_init) { nstime_t nst; diff --git a/test/unit/pack.c b/test/unit/pack.c index 3edd405d..d35ac5ea 100644 --- a/test/unit/pack.c +++ b/test/unit/pack.c @@ -7,9 +7,9 @@ const char *malloc_conf = "decay_time:-1"; * Size class that is a divisor of the page size, ideally 4+ regions per run. */ #if LG_PAGE <= 14 -#define SZ (ZU(1) << (LG_PAGE - 2)) +#define SZ (ZU(1) << (LG_PAGE - 2)) #else -#define SZ 4096 +#define SZ 4096 #endif /* @@ -17,7 +17,7 @@ const char *malloc_conf = "decay_time:-1"; * if mmap()ed memory grows downward, downward growth of mmap()ed memory is * tested. */ -#define NSLABS 8 +#define NSLABS 8 static unsigned binind_compute(void) { diff --git a/test/unit/ph.c b/test/unit/ph.c index 5f3c5a45..91516fae 100644 --- a/test/unit/ph.c +++ b/test/unit/ph.c @@ -3,7 +3,7 @@ typedef struct node_s node_t; struct node_s { -#define NODE_MAGIC 0x9823af7e +#define NODE_MAGIC 0x9823af7e uint32_t magic; phn(node_t) link; uint64_t key; @@ -160,9 +160,9 @@ node_remove_first(heap_t *heap) { } TEST_BEGIN(test_ph_random) { -#define NNODES 25 -#define NBAGS 250 -#define SEED 42 +#define NNODES 25 +#define NBAGS 250 +#define SEED 42 sfmt_t *sfmt; uint64_t bag[NNODES]; heap_t heap; diff --git a/test/unit/prng.c b/test/unit/prng.c index cbccb8a0..74d9cf73 100644 --- a/test/unit/prng.c +++ b/test/unit/prng.c @@ -137,9 +137,9 @@ TEST_END static void test_prng_range_u32(bool atomic) { uint32_t range; -#define MAX_RANGE 10000000 -#define RANGE_STEP 97 -#define NREPS 10 +#define MAX_RANGE 10000000 +#define RANGE_STEP 97 +#define NREPS 10 for (range = 2; range < MAX_RANGE; range += RANGE_STEP) { uint32_t s; @@ -157,9 +157,9 @@ test_prng_range_u32(bool atomic) { static void test_prng_range_u64(void) { uint64_t range; -#define MAX_RANGE 10000000 -#define RANGE_STEP 97 -#define NREPS 10 +#define MAX_RANGE 10000000 +#define RANGE_STEP 97 +#define NREPS 10 for (range = 2; range < MAX_RANGE; range += RANGE_STEP) { uint64_t s; @@ -177,9 +177,9 @@ test_prng_range_u64(void) { static void test_prng_range_zu(bool atomic) { size_t range; -#define MAX_RANGE 10000000 -#define RANGE_STEP 97 -#define NREPS 10 +#define MAX_RANGE 10000000 +#define RANGE_STEP 97 +#define NREPS 10 for (range = 2; range < MAX_RANGE; range += RANGE_STEP) { size_t s; diff --git a/test/unit/prof_accum.c b/test/unit/prof_accum.c index ad7a3eaa..bcd1d881 100644 --- a/test/unit/prof_accum.c +++ b/test/unit/prof_accum.c @@ -1,9 +1,9 @@ #include "test/jemalloc_test.h" -#define NTHREADS 4 -#define NALLOCS_PER_THREAD 50 -#define DUMP_INTERVAL 1 -#define BT_COUNT_CHECK_INTERVAL 5 +#define NTHREADS 4 +#define NALLOCS_PER_THREAD 50 +#define DUMP_INTERVAL 1 +#define BT_COUNT_CHECK_INTERVAL 5 #ifdef JEMALLOC_PROF const char *malloc_conf = diff --git a/test/unit/prof_active.c b/test/unit/prof_active.c index 9bcb3e3b..c0e085a8 100644 --- a/test/unit/prof_active.c +++ b/test/unit/prof_active.c @@ -37,7 +37,7 @@ mallctl_prof_active_get_impl(bool prof_active_old_expected, const char *func, int line) { mallctl_bool_get("prof.active", prof_active_old_expected, func, line); } -#define mallctl_prof_active_get(a) \ +#define mallctl_prof_active_get(a) \ mallctl_prof_active_get_impl(a, __func__, __LINE__) static void @@ -46,7 +46,7 @@ mallctl_prof_active_set_impl(bool prof_active_old_expected, mallctl_bool_set("prof.active", prof_active_old_expected, prof_active_new, func, line); } -#define mallctl_prof_active_set(a, b) \ +#define mallctl_prof_active_set(a, b) \ mallctl_prof_active_set_impl(a, b, __func__, __LINE__) static void @@ -55,7 +55,7 @@ mallctl_thread_prof_active_get_impl(bool thread_prof_active_old_expected, mallctl_bool_get("thread.prof.active", thread_prof_active_old_expected, func, line); } -#define mallctl_thread_prof_active_get(a) \ +#define mallctl_thread_prof_active_get(a) \ mallctl_thread_prof_active_get_impl(a, __func__, __LINE__) static void @@ -64,7 +64,7 @@ mallctl_thread_prof_active_set_impl(bool thread_prof_active_old_expected, mallctl_bool_set("thread.prof.active", thread_prof_active_old_expected, thread_prof_active_new, func, line); } -#define mallctl_thread_prof_active_set(a, b) \ +#define mallctl_thread_prof_active_set(a, b) \ mallctl_thread_prof_active_set_impl(a, b, __func__, __LINE__) static void @@ -80,7 +80,7 @@ prof_sampling_probe_impl(bool expect_sample, const char *func, int line) { "%s():%d: Unexpected backtrace count", func, line); dallocx(p, 0); } -#define prof_sampling_probe(a) \ +#define prof_sampling_probe(a) \ prof_sampling_probe_impl(a, __func__, __LINE__) TEST_BEGIN(test_prof_active) { diff --git a/test/unit/prof_reset.c b/test/unit/prof_reset.c index c2bb50d6..fc954f9f 100644 --- a/test/unit/prof_reset.c +++ b/test/unit/prof_reset.c @@ -135,11 +135,11 @@ TEST_BEGIN(test_prof_reset_cleanup) { } TEST_END -#define NTHREADS 4 -#define NALLOCS_PER_THREAD (1U << 13) -#define OBJ_RING_BUF_COUNT 1531 -#define RESET_INTERVAL (1U << 10) -#define DUMP_INTERVAL 3677 +#define NTHREADS 4 +#define NALLOCS_PER_THREAD (1U << 13) +#define OBJ_RING_BUF_COUNT 1531 +#define RESET_INTERVAL (1U << 10) +#define DUMP_INTERVAL 3677 static void * thd_start(void *varg) { unsigned thd_ind = *(unsigned *)varg; @@ -228,7 +228,7 @@ TEST_END #undef DUMP_INTERVAL /* Test sampling at the same allocation site across resets. */ -#define NITER 10 +#define NITER 10 TEST_BEGIN(test_xallocx) { size_t lg_prof_sample_orig; unsigned i; diff --git a/test/unit/prof_thread_name.c b/test/unit/prof_thread_name.c index bcf85f89..a094a1c0 100644 --- a/test/unit/prof_thread_name.c +++ b/test/unit/prof_thread_name.c @@ -18,7 +18,7 @@ mallctl_thread_name_get_impl(const char *thread_name_expected, const char *func, assert_str_eq(thread_name_old, thread_name_expected, "%s():%d: Unexpected thread.prof.name value", func, line); } -#define mallctl_thread_name_get(a) \ +#define mallctl_thread_name_get(a) \ mallctl_thread_name_get_impl(a, __func__, __LINE__) static void @@ -30,7 +30,7 @@ mallctl_thread_name_set_impl(const char *thread_name, const char *func, func, line); mallctl_thread_name_get_impl(thread_name, func, line); } -#define mallctl_thread_name_set(a) \ +#define mallctl_thread_name_set(a) \ mallctl_thread_name_set_impl(a, __func__, __LINE__) TEST_BEGIN(test_prof_thread_name_validation) { @@ -72,8 +72,8 @@ TEST_BEGIN(test_prof_thread_name_validation) { } TEST_END -#define NTHREADS 4 -#define NRESET 25 +#define NTHREADS 4 +#define NRESET 25 static void * thd_start(void *varg) { unsigned thd_ind = *(unsigned *)varg; diff --git a/test/unit/ql.c b/test/unit/ql.c index 231a7243..ae6481fd 100644 --- a/test/unit/ql.c +++ b/test/unit/ql.c @@ -1,7 +1,7 @@ #include "test/jemalloc_test.h" /* Number of ring entries, in [2..26]. */ -#define NENTRIES 9 +#define NENTRIES 9 typedef struct list_s list_t; typedef ql_head(list_t) list_head_t; diff --git a/test/unit/qr.c b/test/unit/qr.c index 9a72d308..80c5c27d 100644 --- a/test/unit/qr.c +++ b/test/unit/qr.c @@ -1,9 +1,9 @@ #include "test/jemalloc_test.h" /* Number of ring entries, in [2..26]. */ -#define NENTRIES 9 +#define NENTRIES 9 /* Split index, in [1..NENTRIES). */ -#define SPLIT_INDEX 5 +#define SPLIT_INDEX 5 typedef struct ring_s ring_t; diff --git a/test/unit/rb.c b/test/unit/rb.c index dab2c3a2..0bcc3c31 100644 --- a/test/unit/rb.c +++ b/test/unit/rb.c @@ -1,6 +1,6 @@ #include "test/jemalloc_test.h" -#define rbtn_black_height(a_type, a_field, a_rbt, r_height) do { \ +#define rbtn_black_height(a_type, a_field, a_rbt, r_height) do { \ a_type *rbp_bh_t; \ for (rbp_bh_t = (a_rbt)->rbt_root, (r_height) = 0; rbp_bh_t != \ NULL; rbp_bh_t = rbtn_left_get(a_type, a_field, \ @@ -14,7 +14,7 @@ typedef struct node_s node_t; struct node_s { -#define NODE_MAGIC 0x9823af7e +#define NODE_MAGIC 0x9823af7e uint32_t magic; rb_node(node_t) link; uint64_t key; @@ -223,9 +223,9 @@ destroy_cb(node_t *node, void *data) { } TEST_BEGIN(test_rb_random) { -#define NNODES 25 -#define NBAGS 250 -#define SEED 42 +#define NNODES 25 +#define NBAGS 250 +#define SEED 42 sfmt_t *sfmt; uint64_t bag[NNODES]; tree_t tree; diff --git a/test/unit/rtree.c b/test/unit/rtree.c index 344ac16a..d40e6490 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -51,10 +51,10 @@ TEST_BEGIN(test_rtree_read_empty) { } TEST_END -#define NTHREADS 8 -#define MAX_NBITS 18 -#define NITERS 1000 -#define SEED 42 +#define NTHREADS 8 +#define MAX_NBITS 18 +#define NITERS 1000 +#define SEED 42 typedef struct { unsigned nbits; @@ -218,8 +218,8 @@ TEST_BEGIN(test_rtree_random) { unsigned i; sfmt_t *sfmt; tsdn_t *tsdn; -#define NSET 16 -#define SEED 42 +#define NSET 16 +#define SEED 42 sfmt = init_gen_rand(SEED); tsdn = tsdn_fetch(); diff --git a/test/unit/smoothstep.c b/test/unit/smoothstep.c index bf5dfb1d..6e3eb0f9 100644 --- a/test/unit/smoothstep.c +++ b/test/unit/smoothstep.c @@ -1,7 +1,7 @@ #include "test/jemalloc_test.h" static const uint64_t smoothstep_tab[] = { -#define STEP(step, h, x, y) \ +#define STEP(step, h, x, y) \ h, SMOOTHSTEP #undef STEP diff --git a/test/unit/ticker.c b/test/unit/ticker.c index 32236f2c..c2ad7295 100644 --- a/test/unit/ticker.c +++ b/test/unit/ticker.c @@ -1,8 +1,8 @@ #include "test/jemalloc_test.h" TEST_BEGIN(test_ticker_tick) { -#define NREPS 2 -#define NTICKS 3 +#define NREPS 2 +#define NTICKS 3 ticker_t ticker; int32_t i, j; @@ -26,7 +26,7 @@ TEST_BEGIN(test_ticker_tick) { TEST_END TEST_BEGIN(test_ticker_ticks) { -#define NTICKS 3 +#define NTICKS 3 ticker_t ticker; ticker_init(&ticker, NTICKS); @@ -44,7 +44,7 @@ TEST_BEGIN(test_ticker_ticks) { TEST_END TEST_BEGIN(test_ticker_copy) { -#define NTICKS 3 +#define NTICKS 3 ticker_t ta, tb; ticker_init(&ta, NTICKS); diff --git a/test/unit/tsd.c b/test/unit/tsd.c index f34f0e78..ae47d23e 100644 --- a/test/unit/tsd.c +++ b/test/unit/tsd.c @@ -1,6 +1,6 @@ #include "test/jemalloc_test.h" -#define THREAD_DATA 0x72b65c10 +#define THREAD_DATA 0x72b65c10 typedef unsigned int data_t; @@ -47,7 +47,7 @@ data_cleanup(void *arg) { } malloc_tsd_externs(data_, data_t) -#define DATA_INIT 0x12345678 +#define DATA_INIT 0x12345678 malloc_tsd_data(, data_, data_t, DATA_INIT) malloc_tsd_funcs(, data_, data_t, DATA_INIT, data_cleanup) diff --git a/test/unit/util.c b/test/unit/util.c index 81421e80..5760966f 100644 --- a/test/unit/util.c +++ b/test/unit/util.c @@ -1,6 +1,6 @@ #include "test/jemalloc_test.h" -#define TEST_POW2_CEIL(t, suf, pri) do { \ +#define TEST_POW2_CEIL(t, suf, pri) do { \ unsigned i, pow2; \ t x; \ \ @@ -65,9 +65,9 @@ TEST_BEGIN(test_malloc_strtoumax) { const char *expected_errno_name; uintmax_t expected_x; }; -#define ERR(e) e, #e -#define KUMAX(x) ((uintmax_t)x##ULL) -#define KSMAX(x) ((uintmax_t)(intmax_t)x##LL) +#define ERR(e) e, #e +#define KUMAX(x) ((uintmax_t)x##ULL) +#define KSMAX(x) ((uintmax_t)(intmax_t)x##LL) struct test_s tests[] = { {"0", "0", -1, ERR(EINVAL), UINTMAX_MAX}, {"0", "0", 1, ERR(EINVAL), UINTMAX_MAX}, @@ -151,11 +151,11 @@ TEST_BEGIN(test_malloc_strtoumax) { TEST_END TEST_BEGIN(test_malloc_snprintf_truncated) { -#define BUFLEN 15 +#define BUFLEN 15 char buf[BUFLEN]; size_t result; size_t len; -#define TEST(expected_str_untruncated, ...) do { \ +#define TEST(expected_str_untruncated, ...) do { \ result = malloc_snprintf(buf, len, __VA_ARGS__); \ assert_d_eq(strncmp(buf, expected_str_untruncated, len-1), 0, \ "Unexpected string inequality (\"%s\" vs \"%s\")", \ @@ -183,10 +183,10 @@ TEST_BEGIN(test_malloc_snprintf_truncated) { TEST_END TEST_BEGIN(test_malloc_snprintf) { -#define BUFLEN 128 +#define BUFLEN 128 char buf[BUFLEN]; size_t result; -#define TEST(expected_str, ...) do { \ +#define TEST(expected_str, ...) do { \ result = malloc_snprintf(buf, sizeof(buf), __VA_ARGS__); \ assert_str_eq(buf, expected_str, "Unexpected output"); \ assert_zu_eq(result, strlen(expected_str), "Unexpected result");\ diff --git a/test/unit/zero.c b/test/unit/zero.c index 88af9452..d5b03f8d 100644 --- a/test/unit/zero.c +++ b/test/unit/zero.c @@ -9,7 +9,7 @@ static void test_zero(size_t sz_min, size_t sz_max) { uint8_t *s; size_t sz_prev, sz, i; -#define MAGIC ((uint8_t)0x61) +#define MAGIC ((uint8_t)0x61) sz_prev = 0; s = (uint8_t *)mallocx(sz_min, 0); -- GitLab From 0874b648e050c3503a4944963aa83bbb4cd414d6 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 24 Jan 2017 14:54:18 -0500 Subject: [PATCH 242/544] Avoid redeclaring glibc's secure_getenv Avoid the name secure_getenv to avoid redeclaring secure_getenv when secure_getenv is present but its use is manually disabled via ac_cv_func_secure_getenv=no. --- src/jemalloc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index a9a74973..d0c8c037 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -709,17 +709,19 @@ stats_print_atexit(void) { * Begin initialization functions. */ -#ifndef JEMALLOC_HAVE_SECURE_GETENV static char * -secure_getenv(const char *name) { +jemalloc_secure_getenv(const char *name) { +#ifdef JEMALLOC_HAVE_SECURE_GETENV + return secure_getenv(name); +#else # ifdef JEMALLOC_HAVE_ISSETUGID if (issetugid() != 0) { return NULL; } # endif return getenv(name); -} #endif +} static unsigned malloc_ncpus(void) { @@ -908,7 +910,7 @@ malloc_conf_init(void) { #endif ; - if ((opts = secure_getenv(envname)) != NULL) { + if ((opts = jemalloc_secure_getenv(envname)) != NULL) { /* * Do nothing; opts is already initialized to * the value of the MALLOC_CONF environment -- GitLab From 85d284181872d9a6fb813b184cad2cd0a77fc249 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 25 Jan 2017 15:50:59 -0800 Subject: [PATCH 243/544] Fix a bug in which a potentially invalid usize replaced size In the refactoring that unified the allocation paths, usize was substituted for size. This worked fine under the default test configuration, but triggered asserts when we started beefing up our CI testing. This change fixes the issue, and clarifies the comment describing the argument selection that it got wrong. --- src/jemalloc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index d0c8c037..28759bc6 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1652,10 +1652,10 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { /* * If dopts->alignment > 0, then ind is still 0, but usize was * computed in the previous if statement. Down the positive - * alignment path, imalloc_no_sample ind and size (relying only - * on usize). + * alignment path, imalloc_no_sample ignores ind and size + * (relying only on usize). */ - allocation = imalloc_no_sample(sopts, dopts, tsd, usize, usize, + allocation = imalloc_no_sample(sopts, dopts, tsd, size, usize, ind); if (unlikely(allocation == NULL)) { goto label_oom; -- GitLab From 6e7d0890cb66af3b85ab210ed781dab11c1c4614 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 25 Jan 2017 12:58:50 -0800 Subject: [PATCH 244/544] Beef up travis CI integration testing Introduces gen_travis.py, which generates .travis.yml, and updates .travis.yml to be the generated version. The travis build matrix approach doesn't play well with mixing and matching various different environment settings, so we generate every build explicitly, rather than letting them do it for us. To avoid abusing travis resources (and save us time waiting for CI results), we don't test every possible combination of options; we only check up to 2 unusual settings at a time. --- .travis.yml | 84 ++++++++++++++++++++++++++++++++++++------ scripts/gen_travis.py | 86 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 11 deletions(-) create mode 100755 scripts/gen_travis.py diff --git a/.travis.yml b/.travis.yml index 97641eca..efac8547 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,31 +3,93 @@ language: generic matrix: include: - os: linux - env: CC=gcc CXX=g++ + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" + - os: osx + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" + addons: + apt: + packages: + - gcc-multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" - os: linux - env: CC=clang CXX=clang++ + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache" + - os: osx + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" + - os: osx + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" + - os: osx + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" + - os: osx + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" + - os: osx + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache" - os: linux - env: CC=gcc CXX=g++ EXTRA_FLAGS=-m32 + env: CC=clang CXX=clang++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" addons: apt: packages: - - gcc-multilib + - gcc-multilib + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" - os: linux - env: CC=clang CXX=clang++ EXTRA_FLAGS=-m32 + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-debug" addons: apt: packages: - - gcc-multilib - - os: osx - env: CC=clang CXX=clang++ - - os: osx - env: CC=clang CXX=clang++ EXTRA_FLAGS=-m32 + - gcc-multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-prof" + addons: + apt: + packages: + - gcc-multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-stats" + addons: + apt: + packages: + - gcc-multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-tcache" + addons: + apt: + packages: + - gcc-multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-prof" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-stats" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-tcache" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-stats" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-tcache" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --disable-tcache" + before_script: - autoconf - - ./configure${EXTRA_FLAGS:+ CC="$CC $EXTRA_FLAGS" CXX="$CXX $EXTRA_FLAGS"} + - ./configure ${COMPILER_FLAGS:+ CC="$CC $COMPILER_FLAGS" CXX="$CXX $COMPILER_FLAGS" } $CONFIGURE_FLAGS - make -j3 - make -j3 tests script: - make check + diff --git a/scripts/gen_travis.py b/scripts/gen_travis.py new file mode 100755 index 00000000..93fe3283 --- /dev/null +++ b/scripts/gen_travis.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python + +from itertools import combinations + +travis_template = """\ +language: generic + +matrix: + include: +%s + +before_script: + - autoconf + - ./configure ${COMPILER_FLAGS:+ \ + CC="$CC $COMPILER_FLAGS" \ + CXX="$CXX $COMPILER_FLAGS" } \ + $CONFIGURE_FLAGS + - make -j3 + - make -j3 tests + +script: + - make check +""" + +# The 'default' configuration is gcc, on linux, with no compiler or configure +# flags. We also test with clang, -m32, --enable-debug, --enable-prof, +# --disable-stats, and --disable-tcache. To avoid abusing travis though, we +# don't test all 2**7 = 128 possible combinations of these; instead, we only +# test combinations of up to 2 'unusual' settings, under the hope that bugs +# involving interactions of such settings are rare. +# things at once, for C(7, 0) + C(7, 1) + C(7, 2) = 29 +MAX_UNUSUAL_OPTIONS = 2 + +os_default = 'linux' +os_unusual = 'osx' + +compilers_default = 'CC=gcc CXX=g++' +compilers_unusual = 'CC=clang CXX=clang++' + +compiler_flag_unusuals = ['-m32'] + +configure_flag_unusuals = [ + '--enable-debug', '--enable-prof', '--disable-stats', '--disable-tcache', +] + +all_unusuals = ( + [os_unusual] + [compilers_unusual] + compiler_flag_unusuals + + configure_flag_unusuals +) + +unusual_combinations_to_test = [] +for i in xrange(MAX_UNUSUAL_OPTIONS + 1): + unusual_combinations_to_test += combinations(all_unusuals, i) + +include_rows = "" +for unusual_combination in unusual_combinations_to_test: + os = os_default + if os_unusual in unusual_combination: + os = os_unusual + + compilers = compilers_default + if compilers_unusual in unusual_combination: + compilers = compilers_unusual + + compiler_flags = [ + x for x in unusual_combination if x in compiler_flag_unusuals] + + configure_flags = [ + x for x in unusual_combination if x in configure_flag_unusuals] + + # Filter out an unsupported configuration - heap profiling on OS X. + if os == 'osx' and '--enable-prof' in configure_flags: + continue + + env_string = '{} COMPILER_FLAGS="{}" CONFIGURE_FLAGS="{}"'.format( + compilers, " ".join(compiler_flags), " ".join(configure_flags)) + + include_rows += ' - os: %s\n' % os + include_rows += ' env: %s\n' % env_string + if '-m32' in unusual_combination and os == 'linux': + include_rows += ' addons:\n' + include_rows += ' apt:\n' + include_rows += ' packages:\n' + include_rows += ' - gcc-multilib\n' + +print travis_template % include_rows -- GitLab From 5260d9c12f8f83e4f37a28593d197638ad3d4e56 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Fri, 27 Jan 2017 13:16:56 -0800 Subject: [PATCH 245/544] Introduce scripts to run all possible tests In 6e7d0890 we added better travis continuous integration tests. This is nice, but has two problems: - We run only a subset of interesting tests. - The travis builds can take hours to give us back results (especially on OS X). This adds scripts/gen_run_tests.py, and its output, run_tests.sh, which builds and runs a larger portion of possible configurations on the local machine. While a travis run takes several hours to complete , I can run these scripts on my (OS X) latop and (Linux) devserve, and get a more exhaustive set of results back in around 10 minutes. --- run_tests.sh | 1 + scripts/gen_run_tests.py | 44 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100755 run_tests.sh create mode 100755 scripts/gen_run_tests.py diff --git a/run_tests.sh b/run_tests.sh new file mode 100755 index 00000000..b434f15b --- /dev/null +++ b/run_tests.sh @@ -0,0 +1 @@ +$(dirname "$)")/scripts/gen_run_tests.py | bash diff --git a/scripts/gen_run_tests.py b/scripts/gen_run_tests.py new file mode 100755 index 00000000..694685cb --- /dev/null +++ b/scripts/gen_run_tests.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +from itertools import combinations + +def powerset(items): + result = [] + for i in xrange(len(items) + 1): + result += combinations(items, i) + return result + +MAKE_J_VAL = 32 + +possible_compilers = [('gcc', 'g++'), ('clang', 'clang++')] +possible_compiler_opts = [ + '-m32', +] +possible_config_opts = [ + '--enable-debug', + '--enable-prof', + '--disable-stats', + '--disable-tcache', +] + +print 'set -e' +print 'autoconf' +print 'unamestr=`uname`' + +for cc, cxx in possible_compilers: + for compiler_opts in powerset(possible_compiler_opts): + for config_opts in powerset(possible_config_opts): + config_line = ( + './configure ' + + 'CC="{} {}" '.format(cc, " ".join(compiler_opts)) + + 'CXX="{} {}" '.format(cxx, " ".join(compiler_opts)) + + " ".join(config_opts) + ) + # Heap profiling is not supported on OS X. + if '--enable-prof' in config_opts: + print 'if [[ "$unamestr" != "Darwin" ]]; then' + print config_line + print "make clean" + print "make -j" + str(MAKE_J_VAL) + " check" + if '--enable-prof' in config_opts: + print 'fi' -- GitLab From 449b7f486777d14f5aaa84b6822221915e1405e6 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 31 Jan 2017 16:44:57 -0800 Subject: [PATCH 246/544] CI: Run --enable-debug builds on windows This will hopefully catch some windows-specific bugs. --- .appveyor.yml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index ddd5c571..510815dc 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -12,6 +12,20 @@ environment: CPU: x86_64 - MSYSTEM: MINGW32 CPU: i686 + - MSYSTEM: MINGW64 + CPU: x86_64 + MSVC: amd64 + CONFIG_FLAGS: --enable-debug + - MSYSTEM: MINGW32 + CPU: i686 + MSVC: x86 + CONFIG_FLAGS: --enable-debug + - MSYSTEM: MINGW64 + CPU: x86_64 + CONFIG_FLAGS: --enable-debug + - MSYSTEM: MINGW32 + CPU: i686 + CONFIG_FLAGS: --enable-debug install: - set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH% @@ -21,7 +35,7 @@ install: build_script: - bash -c "autoconf" - - bash -c "./configure" + - bash -c "./configure $CONFIG_FLAGS" - mingw32-make -j3 - file lib/jemalloc.dll - mingw32-make -j3 tests -- GitLab From 190f81c6d5676efd321701dd9b8918a24da2f783 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Feb 2017 10:03:04 -0800 Subject: [PATCH 247/544] Silence harmless warnings discovered via run_tests.sh. --- test/unit/stats_print.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/unit/stats_print.c b/test/unit/stats_print.c index 5a11b503..f0437891 100644 --- a/test/unit/stats_print.c +++ b/test/unit/stats_print.c @@ -65,7 +65,8 @@ token_error(token_t *token) { token->col); break; } - write(STDERR_FILENO, &token->parser->buf[token->pos], token->len); + UNUSED ssize_t err = write(STDERR_FILENO, + &token->parser->buf[token->pos], token->len); malloc_printf("\n"); } @@ -129,7 +130,9 @@ parser_tokenize(parser_t *parser) { STATE_EXP_DIGITS, STATE_ACCEPT } state = STATE_START; - size_t token_pos, token_line, token_col; + size_t token_pos JEMALLOC_CC_SILENCE_INIT(0); + size_t token_line JEMALLOC_CC_SILENCE_INIT(1); + size_t token_col JEMALLOC_CC_SILENCE_INIT(0); assert_zu_le(parser->pos, parser->len, "Position is past end of buffer"); -- GitLab From bbff6ca6740c27737378f6c2dec3a13053a5a150 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 30 Jan 2017 15:54:16 -0800 Subject: [PATCH 248/544] Handle race in stats_arena_bins_print When multiple threads calling stats_print, race could happen as we read the counters in separate mallctl calls; and the removed assertion could fail when other operations happened in between the mallctl calls. For simplicity, output "race" in the utilization field in this case. --- src/stats.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/stats.c b/src/stats.c index 2a424a73..ae360e1b 100644 --- a/src/stats.c +++ b/src/stats.c @@ -133,8 +133,16 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, availregs = nregs * curslabs; milli = (availregs != 0) ? (1000 * curregs) / availregs : 1000; - assert(milli <= 1000); - if (milli < 10) { + + if (milli > 1000) { + /* + * Race detected: the counters were read in + * separate mallctl calls and concurrent + * operations happened in between. In this case + * no meaningful utilization can be computed. + */ + malloc_snprintf(util, sizeof(util), " race"); + } else if (milli < 10) { malloc_snprintf(util, sizeof(util), "0.00%zu", milli); } else if (milli < 100) { @@ -144,6 +152,7 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_snprintf(util, sizeof(util), "0.%zu", milli); } else { + assert(milli == 1000); malloc_snprintf(util, sizeof(util), "1"); } -- GitLab From 397f54aa460593295139e94c81e8f5b2152a088f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 29 Jan 2017 17:35:57 -0800 Subject: [PATCH 249/544] Conditionalize prof fork handling on config_prof. This allows the compiler to completely remove dead code. --- src/prof.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/prof.c b/src/prof.c index 1dd0f54d..28d30f29 100644 --- a/src/prof.c +++ b/src/prof.c @@ -2353,7 +2353,7 @@ prof_boot2(tsd_t *tsd) { void prof_prefork0(tsdn_t *tsdn) { - if (opt_prof) { + if (config_prof && opt_prof) { unsigned i; malloc_mutex_prefork(tsdn, &prof_dump_mtx); @@ -2370,7 +2370,7 @@ prof_prefork0(tsdn_t *tsdn) { void prof_prefork1(tsdn_t *tsdn) { - if (opt_prof) { + if (config_prof && opt_prof) { malloc_mutex_prefork(tsdn, &prof_active_mtx); malloc_mutex_prefork(tsdn, &prof_dump_seq_mtx); malloc_mutex_prefork(tsdn, &prof_gdump_mtx); @@ -2381,7 +2381,7 @@ prof_prefork1(tsdn_t *tsdn) { void prof_postfork_parent(tsdn_t *tsdn) { - if (opt_prof) { + if (config_prof && opt_prof) { unsigned i; malloc_mutex_postfork_parent(tsdn, @@ -2404,7 +2404,7 @@ prof_postfork_parent(tsdn_t *tsdn) { void prof_postfork_child(tsdn_t *tsdn) { - if (opt_prof) { + if (config_prof && opt_prof) { unsigned i; malloc_mutex_postfork_child(tsdn, &prof_thread_active_init_mtx); -- GitLab From 5033a9176ac9489805a387c040008b088cf15bda Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 29 Jan 2017 21:51:30 -0800 Subject: [PATCH 250/544] Call prof_gctx_create() without owing bt2gctx_mtx. This reduces the probability of allocating (and thereby indirectly making a system call) while owning bt2gctx_mtx. Unfortunately it is an incomplete solution, because ckh insertion/deletion can also allocate/deallocate, which requires more extensive changes to address. --- src/prof.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/prof.c b/src/prof.c index 28d30f29..5aeefb28 100644 --- a/src/prof.c +++ b/src/prof.c @@ -708,7 +708,7 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, union { prof_gctx_t *p; void *v; - } gctx; + } gctx, tgctx; union { prof_bt_t *p; void *v; @@ -718,21 +718,32 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, prof_enter(tsd, tdata); if (ckh_search(&bt2gctx, bt, &btkey.v, &gctx.v)) { /* bt has never been seen before. Insert it. */ - gctx.p = prof_gctx_create(tsd_tsdn(tsd), bt); - if (gctx.v == NULL) { - prof_leave(tsd, tdata); + prof_leave(tsd, tdata); + tgctx.p = prof_gctx_create(tsd_tsdn(tsd), bt); + if (tgctx.v == NULL) { return true; } - btkey.p = &gctx.p->bt; - if (ckh_insert(tsd, &bt2gctx, btkey.v, gctx.v)) { - /* OOM. */ - prof_leave(tsd, tdata); - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), gctx.v), - gctx.v, NULL, true, true); - return true; + prof_enter(tsd, tdata); + if (ckh_search(&bt2gctx, bt, &btkey.v, &gctx.v)) { + gctx.p = tgctx.p; + btkey.p = &gctx.p->bt; + if (ckh_insert(tsd, &bt2gctx, btkey.v, gctx.v)) { + /* OOM. */ + prof_leave(tsd, tdata); + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), + gctx.v), gctx.v, NULL, true, true); + return true; + } + new_gctx = true; + } else { + new_gctx = false; } - new_gctx = true; } else { + tgctx.v = NULL; + new_gctx = false; + } + + if (!new_gctx) { /* * Increment nlimbo, in order to avoid a race condition with * prof_tctx_destroy()/prof_gctx_try_destroy(). @@ -741,6 +752,12 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, gctx.p->nlimbo++; malloc_mutex_unlock(tsd_tsdn(tsd), gctx.p->lock); new_gctx = false; + + if (tgctx.v != NULL) { + /* Lost race to insert. */ + idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), + tgctx.v), tgctx.v, NULL, true, true); + } } prof_leave(tsd, tdata); -- GitLab From ace679ce7435e990df6b789fde4cefeb0e6b992b Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 27 Jan 2017 15:03:11 -0800 Subject: [PATCH 251/544] Synchronize extent_grow_next accesses. This should have been part of 411697adcda2fd75e135cdcdafb95f2bd295dc7f (Use exponential series to size extents.), which introduced extent_grow_next. --- src/extent.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/extent.c b/src/extent.c index 0dbde72a..e2af2b50 100644 --- a/src/extent.c +++ b/src/extent.c @@ -710,7 +710,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, * extent creation as a side effect. */ size = usize + pad; - alloc_size = pind2sz(arena->extent_grow_next); + alloc_size = pind2sz(atomic_read_u(&arena->extent_grow_next)); alloc_size_min = size + PAGE_CEILING(alignment) - PAGE; /* Beware size_t wrap-around. */ if (alloc_size_min < usize) { @@ -809,8 +809,20 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, if (*zero && !extent_zeroed_get(extent)) { memset(extent_addr_get(extent), 0, extent_usize_get(extent)); } - if (arena->extent_grow_next + 1 < NPSIZES) { - arena->extent_grow_next++; + /* + * Increment extent_grow_next, but take care to do so atomically and + * bail out if the increment would exceed the legal range. + */ + while (true) { + pszind_t egn = atomic_read_u(&arena->extent_grow_next); + + if (egn + 1 == NPSIZES) { + break; + } + assert(egn + 1 < NPSIZES); + if (!atomic_cas_u(&arena->extent_grow_next, egn, egn + 1)) { + break; + } } return extent; } -- GitLab From d0e93ada51e20f4ae394ff4dbdcf96182767c89c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 21 Jan 2017 15:12:03 -0800 Subject: [PATCH 252/544] Add witness_assert_depth[_to_rank](). This makes it possible to make lock state assertions about precisely which locks are held. --- include/jemalloc/internal/private_symbols.txt | 4 +- include/jemalloc/internal/witness_externs.h | 8 +-- include/jemalloc/internal/witness_inlines.h | 28 +++++++++- include/jemalloc/internal/witness_types.h | 2 + src/witness.c | 17 ++++--- test/unit/witness.c | 51 ++++++++++++++----- 6 files changed, 84 insertions(+), 26 deletions(-) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 745220e3..2567f56c 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -549,13 +549,15 @@ tsdn_fetch tsdn_null tsdn_rtree_ctx tsdn_tsd +witness_assert_depth +witness_assert_depth_to_rank witness_assert_lockless witness_assert_not_owner witness_assert_owner +witness_depth_error witness_init witness_lock witness_lock_error -witness_lockless_error witness_not_owner_error witness_owner witness_owner_error diff --git a/include/jemalloc/internal/witness_externs.h b/include/jemalloc/internal/witness_externs.h index dcd987cc..5d91fde2 100644 --- a/include/jemalloc/internal/witness_externs.h +++ b/include/jemalloc/internal/witness_externs.h @@ -23,10 +23,12 @@ extern witness_not_owner_error_t *witness_not_owner_error; void witness_not_owner_error(const witness_t *witness); #endif #ifdef JEMALLOC_JET -typedef void (witness_lockless_error_t)(const witness_list_t *); -extern witness_lockless_error_t *witness_lockless_error; +typedef void (witness_depth_error_t)(const witness_list_t *, + witness_rank_t rank_inclusive, unsigned depth); +extern witness_depth_error_t *witness_depth_error; #else -void witness_lockless_error(const witness_list_t *witnesses); +void witness_depth_error(const witness_list_t *witnesses, + witness_rank_t rank_inclusive, unsigned depth); #endif void witnesses_cleanup(tsd_t *tsd); diff --git a/include/jemalloc/internal/witness_inlines.h b/include/jemalloc/internal/witness_inlines.h index c2a27812..51f3f6e7 100644 --- a/include/jemalloc/internal/witness_inlines.h +++ b/include/jemalloc/internal/witness_inlines.h @@ -5,6 +5,9 @@ bool witness_owner(tsd_t *tsd, const witness_t *witness); void witness_assert_owner(tsdn_t *tsdn, const witness_t *witness); void witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness); +void witness_assert_depth_to_rank(tsdn_t *tsdn, witness_rank_t rank_inclusive, + unsigned depth); +void witness_assert_depth(tsdn_t *tsdn, unsigned depth); void witness_assert_lockless(tsdn_t *tsdn); void witness_lock(tsdn_t *tsdn, witness_t *witness); void witness_unlock(tsdn_t *tsdn, witness_t *witness); @@ -78,8 +81,10 @@ witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness) { } JEMALLOC_INLINE void -witness_assert_lockless(tsdn_t *tsdn) { +witness_assert_depth_to_rank(tsdn_t *tsdn, witness_rank_t rank_inclusive, + unsigned depth) { tsd_t *tsd; + unsigned d; witness_list_t *witnesses; witness_t *w; @@ -92,13 +97,32 @@ witness_assert_lockless(tsdn_t *tsdn) { } tsd = tsdn_tsd(tsdn); + d = 0; witnesses = tsd_witnessesp_get(tsd); w = ql_last(witnesses, link); if (w != NULL) { - witness_lockless_error(witnesses); + ql_reverse_foreach(w, witnesses, link) { + if (w->rank < rank_inclusive) { + break; + } + d++; + } + } + if (d != depth) { + witness_depth_error(witnesses, rank_inclusive, depth); } } +JEMALLOC_INLINE void +witness_assert_depth(tsdn_t *tsdn, unsigned depth) { + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_MIN, depth); +} + +JEMALLOC_INLINE void +witness_assert_lockless(tsdn_t *tsdn) { + witness_assert_depth(tsdn, 0); +} + JEMALLOC_INLINE void witness_lock(tsdn_t *tsdn, witness_t *witness) { tsd_t *tsd; diff --git a/include/jemalloc/internal/witness_types.h b/include/jemalloc/internal/witness_types.h index c2a73f2e..f765d7b3 100644 --- a/include/jemalloc/internal/witness_types.h +++ b/include/jemalloc/internal/witness_types.h @@ -13,6 +13,8 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *, */ #define WITNESS_RANK_OMIT 0U +#define WITNESS_RANK_MIN 1U + #define WITNESS_RANK_INIT 1U #define WITNESS_RANK_CTL 1U #define WITNESS_RANK_ARENAS 2U diff --git a/src/witness.c b/src/witness.c index 1c03457e..034ea92b 100644 --- a/src/witness.c +++ b/src/witness.c @@ -65,14 +65,16 @@ witness_not_owner_error_t *witness_not_owner_error = #endif #ifdef JEMALLOC_JET -#undef witness_lockless_error -#define witness_lockless_error JEMALLOC_N(n_witness_lockless_error) +#undef witness_depth_error +#define witness_depth_error JEMALLOC_N(n_witness_depth_error) #endif void -witness_lockless_error(const witness_list_t *witnesses) { +witness_depth_error(const witness_list_t *witnesses, + witness_rank_t rank_inclusive, unsigned depth) { witness_t *w; - malloc_printf(": Should not own any locks:"); + malloc_printf(": Should own %u lock%s of rank >= %u:", depth, + (depth != 1) ? "s" : "", rank_inclusive); ql_foreach(w, witnesses, link) { malloc_printf(" %s(%u)", w->name, w->rank); } @@ -80,10 +82,9 @@ witness_lockless_error(const witness_list_t *witnesses) { abort(); } #ifdef JEMALLOC_JET -#undef witness_lockless_error -#define witness_lockless_error JEMALLOC_N(witness_lockless_error) -witness_lockless_error_t *witness_lockless_error = - JEMALLOC_N(n_witness_lockless_error); +#undef witness_depth_error +#define witness_depth_error JEMALLOC_N(witness_depth_error) +witness_depth_error_t *witness_depth_error = JEMALLOC_N(n_witness_depth_error); #endif void diff --git a/test/unit/witness.c b/test/unit/witness.c index c914e4b3..de2e6028 100644 --- a/test/unit/witness.c +++ b/test/unit/witness.c @@ -3,12 +3,12 @@ static witness_lock_error_t *witness_lock_error_orig; static witness_owner_error_t *witness_owner_error_orig; static witness_not_owner_error_t *witness_not_owner_error_orig; -static witness_lockless_error_t *witness_lockless_error_orig; +static witness_depth_error_t *witness_depth_error_orig; static bool saw_lock_error; static bool saw_owner_error; static bool saw_not_owner_error; -static bool saw_lockless_error; +static bool saw_depth_error; static void witness_lock_error_intercept(const witness_list_t *witnesses, @@ -27,8 +27,9 @@ witness_not_owner_error_intercept(const witness_t *witness) { } static void -witness_lockless_error_intercept(const witness_list_t *witnesses) { - saw_lockless_error = true; +witness_depth_error_intercept(const witness_list_t *witnesses, + witness_rank_t rank_inclusive, unsigned depth) { + saw_depth_error = true; } static int @@ -61,21 +62,36 @@ TEST_BEGIN(test_witness) { tsdn = tsdn_fetch(); witness_assert_lockless(tsdn); + witness_assert_depth(tsdn, 0); + witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 0); witness_init(&a, "a", 1, NULL, NULL); witness_assert_not_owner(tsdn, &a); witness_lock(tsdn, &a); witness_assert_owner(tsdn, &a); + witness_assert_depth(tsdn, 1); + witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 1); + witness_assert_depth_to_rank(tsdn, (witness_rank_t)2U, 0); witness_init(&b, "b", 2, NULL, NULL); witness_assert_not_owner(tsdn, &b); witness_lock(tsdn, &b); witness_assert_owner(tsdn, &b); + witness_assert_depth(tsdn, 2); + witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 2); + witness_assert_depth_to_rank(tsdn, (witness_rank_t)2U, 1); + witness_assert_depth_to_rank(tsdn, (witness_rank_t)3U, 0); witness_unlock(tsdn, &a); + witness_assert_depth(tsdn, 1); + witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 1); + witness_assert_depth_to_rank(tsdn, (witness_rank_t)2U, 1); + witness_assert_depth_to_rank(tsdn, (witness_rank_t)3U, 0); witness_unlock(tsdn, &b); witness_assert_lockless(tsdn); + witness_assert_depth(tsdn, 0); + witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 0); } TEST_END @@ -93,12 +109,15 @@ TEST_BEGIN(test_witness_comp) { witness_assert_not_owner(tsdn, &a); witness_lock(tsdn, &a); witness_assert_owner(tsdn, &a); + witness_assert_depth(tsdn, 1); witness_init(&b, "b", 1, witness_comp, &b); witness_assert_not_owner(tsdn, &b); witness_lock(tsdn, &b); witness_assert_owner(tsdn, &b); + witness_assert_depth(tsdn, 2); witness_unlock(tsdn, &b); + witness_assert_depth(tsdn, 1); witness_lock_error_orig = witness_lock_error; witness_lock_error = witness_lock_error_intercept; @@ -110,6 +129,7 @@ TEST_BEGIN(test_witness_comp) { witness_lock(tsdn, &c); assert_true(saw_lock_error, "Expected witness lock error"); witness_unlock(tsdn, &c); + witness_assert_depth(tsdn, 1); saw_lock_error = false; @@ -119,6 +139,7 @@ TEST_BEGIN(test_witness_comp) { witness_lock(tsdn, &d); assert_true(saw_lock_error, "Expected witness lock error"); witness_unlock(tsdn, &d); + witness_assert_depth(tsdn, 1); witness_unlock(tsdn, &a); @@ -146,11 +167,13 @@ TEST_BEGIN(test_witness_reversal) { witness_init(&b, "b", 2, NULL, NULL); witness_lock(tsdn, &b); + witness_assert_depth(tsdn, 1); assert_false(saw_lock_error, "Unexpected witness lock error"); witness_lock(tsdn, &a); assert_true(saw_lock_error, "Expected witness lock error"); witness_unlock(tsdn, &a); + witness_assert_depth(tsdn, 1); witness_unlock(tsdn, &b); witness_assert_lockless(tsdn); @@ -222,34 +245,38 @@ TEST_BEGIN(test_witness_unlock_not_owned) { } TEST_END -TEST_BEGIN(test_witness_lockful) { +TEST_BEGIN(test_witness_depth) { witness_t a; tsdn_t *tsdn; test_skip_if(!config_debug); - witness_lockless_error_orig = witness_lockless_error; - witness_lockless_error = witness_lockless_error_intercept; - saw_lockless_error = false; + witness_depth_error_orig = witness_depth_error; + witness_depth_error = witness_depth_error_intercept; + saw_depth_error = false; tsdn = tsdn_fetch(); witness_assert_lockless(tsdn); + witness_assert_depth(tsdn, 0); witness_init(&a, "a", 1, NULL, NULL); - assert_false(saw_lockless_error, "Unexpected lockless error"); + assert_false(saw_depth_error, "Unexpected depth error"); witness_assert_lockless(tsdn); + witness_assert_depth(tsdn, 0); witness_lock(tsdn, &a); witness_assert_lockless(tsdn); - assert_true(saw_lockless_error, "Expected lockless error"); + witness_assert_depth(tsdn, 0); + assert_true(saw_depth_error, "Expected depth error"); witness_unlock(tsdn, &a); witness_assert_lockless(tsdn); + witness_assert_depth(tsdn, 0); - witness_lockless_error = witness_lockless_error_orig; + witness_depth_error = witness_depth_error_orig; } TEST_END @@ -261,5 +288,5 @@ main(void) { test_witness_reversal, test_witness_recursive, test_witness_unlock_not_owned, - test_witness_lockful); + test_witness_depth); } -- GitLab From 1b6e43507ed330314fffe0872f48a95a9fe502fe Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 29 Jan 2017 21:32:39 -0800 Subject: [PATCH 253/544] Fix/refactor tcaches synchronization. Synchronize tcaches with tcaches_mtx rather than ctl_mtx. Add missing synchronization for tcache flushing. This bug was introduced by 1cb181ed632e7573fb4eab194e4d216867222d27 (Implement explicit tcache support.), which was first released in 4.0.0. --- include/jemalloc/internal/private_symbols.txt | 3 + include/jemalloc/internal/tcache_externs.h | 3 + include/jemalloc/internal/witness_types.h | 31 +++---- src/ctl.c | 2 - src/jemalloc.c | 3 + src/tcache.c | 88 ++++++++++++++++--- 6 files changed, 101 insertions(+), 29 deletions(-) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 2567f56c..36bcda24 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -469,6 +469,9 @@ tcache_flush tcache_get tcache_get_hard tcache_maxclass +tcache_prefork +tcache_postfork_child +tcache_postfork_parent tcache_salloc tcache_stats_merge tcaches diff --git a/include/jemalloc/internal/tcache_externs.h b/include/jemalloc/internal/tcache_externs.h index ead90afc..3e4a7511 100644 --- a/include/jemalloc/internal/tcache_externs.h +++ b/include/jemalloc/internal/tcache_externs.h @@ -43,5 +43,8 @@ bool tcaches_create(tsd_t *tsd, unsigned *r_ind); void tcaches_flush(tsd_t *tsd, unsigned ind); void tcaches_destroy(tsd_t *tsd, unsigned ind); bool tcache_boot(tsdn_t *tsdn); +void tcache_prefork(tsdn_t *tsdn); +void tcache_postfork_parent(tsdn_t *tsdn); +void tcache_postfork_child(tsdn_t *tsdn); #endif /* JEMALLOC_INTERNAL_TCACHE_EXTERNS_H */ diff --git a/include/jemalloc/internal/witness_types.h b/include/jemalloc/internal/witness_types.h index f765d7b3..dfcf1621 100644 --- a/include/jemalloc/internal/witness_types.h +++ b/include/jemalloc/internal/witness_types.h @@ -17,21 +17,22 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *, #define WITNESS_RANK_INIT 1U #define WITNESS_RANK_CTL 1U -#define WITNESS_RANK_ARENAS 2U - -#define WITNESS_RANK_PROF_DUMP 3U -#define WITNESS_RANK_PROF_BT2GCTX 4U -#define WITNESS_RANK_PROF_TDATAS 5U -#define WITNESS_RANK_PROF_TDATA 6U -#define WITNESS_RANK_PROF_GCTX 7U - -#define WITNESS_RANK_ARENA 8U -#define WITNESS_RANK_ARENA_EXTENTS 9U -#define WITNESS_RANK_ARENA_EXTENT_CACHE 10 - -#define WITNESS_RANK_RTREE_ELM 11U -#define WITNESS_RANK_RTREE 12U -#define WITNESS_RANK_BASE 13U +#define WITNESS_RANK_TCACHES 2U +#define WITNESS_RANK_ARENAS 3U + +#define WITNESS_RANK_PROF_DUMP 4U +#define WITNESS_RANK_PROF_BT2GCTX 5U +#define WITNESS_RANK_PROF_TDATAS 6U +#define WITNESS_RANK_PROF_TDATA 7U +#define WITNESS_RANK_PROF_GCTX 8U + +#define WITNESS_RANK_ARENA 9U +#define WITNESS_RANK_ARENA_EXTENTS 10U +#define WITNESS_RANK_ARENA_EXTENT_CACHE 11U + +#define WITNESS_RANK_RTREE_ELM 12U +#define WITNESS_RANK_RTREE 13U +#define WITNESS_RANK_BASE 14U #define WITNESS_RANK_LEAF 0xffffffffU #define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF diff --git a/src/ctl.c b/src/ctl.c index 64b74263..403bc30c 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1477,7 +1477,6 @@ tcache_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, return ENOENT; } - malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); READONLY(); if (tcaches_create(tsd, &tcache_ind)) { ret = EFAULT; @@ -1487,7 +1486,6 @@ tcache_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = 0; label_return: - malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); return ret; } diff --git a/src/jemalloc.c b/src/jemalloc.c index 28759bc6..45e9aea7 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -2765,6 +2765,7 @@ _malloc_prefork(void) witness_prefork(tsd); /* Acquire all mutexes in a safe order. */ ctl_prefork(tsd_tsdn(tsd)); + tcache_prefork(tsd_tsdn(tsd)); malloc_mutex_prefork(tsd_tsdn(tsd), &arenas_lock); prof_prefork0(tsd_tsdn(tsd)); for (i = 0; i < 3; i++) { @@ -2825,6 +2826,7 @@ _malloc_postfork(void) } prof_postfork_parent(tsd_tsdn(tsd)); malloc_mutex_postfork_parent(tsd_tsdn(tsd), &arenas_lock); + tcache_postfork_parent(tsd_tsdn(tsd)); ctl_postfork_parent(tsd_tsdn(tsd)); } @@ -2848,6 +2850,7 @@ jemalloc_postfork_child(void) { } prof_postfork_child(tsd_tsdn(tsd)); malloc_mutex_postfork_child(tsd_tsdn(tsd), &arenas_lock); + tcache_postfork_child(tsd_tsdn(tsd)); ctl_postfork_child(tsd_tsdn(tsd)); } diff --git a/src/tcache.c b/src/tcache.c index 96a42add..76277f06 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -21,6 +21,9 @@ static unsigned tcaches_past; /* Head of singly linked list tracking available tcaches elements. */ static tcaches_t *tcaches_avail; +/* Protects tcaches{,_past,_avail}. */ +static malloc_mutex_t tcaches_mtx; + /******************************************************************************/ size_t @@ -422,32 +425,56 @@ tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { } } -bool -tcaches_create(tsd_t *tsd, unsigned *r_ind) { - arena_t *arena; - tcache_t *tcache; - tcaches_t *elm; +static bool +tcaches_create_prep(tsd_t *tsd) { + bool err; + + malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx); if (tcaches == NULL) { tcaches = base_alloc(tsd_tsdn(tsd), b0get(), sizeof(tcache_t *) * (MALLOCX_TCACHE_MAX+1), CACHELINE); if (tcaches == NULL) { - return true; + err = true; + goto label_return; } } if (tcaches_avail == NULL && tcaches_past > MALLOCX_TCACHE_MAX) { - return true; + err = true; + goto label_return; } - arena = arena_ichoose(tsd, NULL); + + err = false; +label_return: + malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx); + return err; +} + +bool +tcaches_create(tsd_t *tsd, unsigned *r_ind) { + witness_assert_depth(tsd_tsdn(tsd), 0); + + bool err; + + if (tcaches_create_prep(tsd)) { + err = true; + goto label_return; + } + + arena_t *arena = arena_ichoose(tsd, NULL); if (unlikely(arena == NULL)) { - return true; + err = true; + goto label_return; } - tcache = tcache_create(tsd_tsdn(tsd), arena); + tcache_t *tcache = tcache_create(tsd_tsdn(tsd), arena); if (tcache == NULL) { - return true; + err = true; + goto label_return; } + tcaches_t *elm; + malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx); if (tcaches_avail != NULL) { elm = tcaches_avail; tcaches_avail = tcaches_avail->next; @@ -459,12 +486,18 @@ tcaches_create(tsd_t *tsd, unsigned *r_ind) { *r_ind = tcaches_past; tcaches_past++; } + malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx); - return false; + err = false; +label_return: + witness_assert_depth(tsd_tsdn(tsd), 0); + return err; } static void tcaches_elm_flush(tsd_t *tsd, tcaches_t *elm) { + malloc_mutex_assert_owner(tsd_tsdn(tsd), &tcaches_mtx); + if (elm->tcache == NULL) { return; } @@ -474,19 +507,25 @@ tcaches_elm_flush(tsd_t *tsd, tcaches_t *elm) { void tcaches_flush(tsd_t *tsd, unsigned ind) { + malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx); tcaches_elm_flush(tsd, &tcaches[ind]); + malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx); } void tcaches_destroy(tsd_t *tsd, unsigned ind) { + malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx); tcaches_t *elm = &tcaches[ind]; tcaches_elm_flush(tsd, elm); elm->next = tcaches_avail; tcaches_avail = elm; + malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx); } bool tcache_boot(tsdn_t *tsdn) { + cassert(config_tcache); + unsigned i; /* If necessary, clamp opt_lg_tcache_max. */ @@ -497,6 +536,10 @@ tcache_boot(tsdn_t *tsdn) { tcache_maxclass = (ZU(1) << opt_lg_tcache_max); } + if (malloc_mutex_init(&tcaches_mtx, "tcaches", WITNESS_RANK_TCACHES)) { + return true; + } + nhbins = size2index(tcache_maxclass) + 1; /* Initialize tcache_bin_info. */ @@ -527,3 +570,24 @@ tcache_boot(tsdn_t *tsdn) { return false; } + +void +tcache_prefork(tsdn_t *tsdn) { + if (!config_prof && opt_tcache) { + malloc_mutex_prefork(tsdn, &tcaches_mtx); + } +} + +void +tcache_postfork_parent(tsdn_t *tsdn) { + if (!config_prof && opt_tcache) { + malloc_mutex_postfork_parent(tsdn, &tcaches_mtx); + } +} + +void +tcache_postfork_child(tsdn_t *tsdn) { + if (!config_prof && opt_tcache) { + malloc_mutex_postfork_child(tsdn, &tcaches_mtx); + } +} -- GitLab From d27f29b468ae3e9d2b1da4a9880351d76e5a1662 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 29 Jan 2017 21:57:14 -0800 Subject: [PATCH 254/544] Disentangle arena and extent locking. Refactor arena and extent locking protocols such that arena and extent locks are never held when calling into the extent_*_wrapper() API. This requires extra care during purging since the arena lock no longer protects the inner purging logic. It also requires extra care to protect extents from being merged with adjacent extents. Convert extent_t's 'active' flag to an enumerated 'state', so that retained extents are explicitly marked as such, rather than depending on ring linkage state. Refactor the extent collections (and their synchronization) for cached and retained extents into extents_t. Incorporate LRU functionality to support purging. Incorporate page count accounting, which replaces arena->ndirty and arena->stats.retained. Assert that no core locks are held when entering any internal [de]allocation functions. This is in addition to existing assertions that no locks are held when entering external [de]allocation functions. Audit and document synchronization protocols for all arena_t fields. This fixes a potential deadlock due to recursive allocation during gdump, in a similar fashion to b49c649bc18fff4bd10a1c8adbaf1f25f6453cb6 (Fix lock order reversal during gdump.), but with a necessarily much broader code impact. --- include/jemalloc/internal/arena_externs.h | 11 +- include/jemalloc/internal/arena_structs_b.h | 117 ++-- include/jemalloc/internal/extent_externs.h | 10 +- include/jemalloc/internal/extent_inlines.h | 58 +- include/jemalloc/internal/extent_structs.h | 58 +- include/jemalloc/internal/extent_types.h | 1 + .../jemalloc/internal/jemalloc_internal.h.in | 9 +- include/jemalloc/internal/large_externs.h | 3 +- include/jemalloc/internal/private_symbols.txt | 28 +- include/jemalloc/internal/stats_structs.h | 17 +- include/jemalloc/internal/witness_types.h | 12 +- src/arena.c | 377 ++++------- src/base.c | 5 +- src/extent.c | 618 +++++++++++------- src/extent_dss.c | 5 +- src/large.c | 46 +- src/tcache.c | 31 +- test/unit/arena_reset.c | 2 +- test/unit/slab.c | 4 +- 19 files changed, 767 insertions(+), 645 deletions(-) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index ecc82304..d0af91bf 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -13,22 +13,17 @@ extern ssize_t opt_decay_time; extern const arena_bin_info_t arena_bin_info[NBINS]; -extent_t *arena_extent_cache_alloc(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, - size_t alignment, bool *zero); void arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent); -void arena_extent_cache_maybe_insert(tsdn_t *tsdn, arena_t *arena, - extent_t *extent, bool cache); -void arena_extent_cache_maybe_remove(tsdn_t *tsdn, arena_t *arena, - extent_t *extent, bool cache); #ifdef JEMALLOC_JET size_t arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr); #endif extent_t *arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero); -void arena_extent_dalloc_large(tsdn_t *tsdn, arena_t *arena, +void arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena, extent_t *extent, bool locked); +void arena_extent_dalloc_large_finish(tsdn_t *tsdn, arena_t *arena, + extent_t *extent); void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index c1c20731..8629446d 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -66,8 +66,8 @@ struct arena_decay_s { /* * Number of dirty pages at beginning of current epoch. During epoch * advancement we use the delta between arena->decay.ndirty and - * arena->ndirty to determine how many dirty pages, if any, were - * generated. + * extents_npages_get(&arena->extents_cached) to determine how many + * dirty pages, if any, were generated. */ size_t nunpurged; /* @@ -98,8 +98,8 @@ struct arena_bin_s { */ extent_heap_t slabs_nonfull; - /* Ring sentinel used to track full slabs. */ - extent_t slabs_full; + /* List used to track full slabs. */ + extent_list_t slabs_full; /* Bin statistics. */ malloc_bin_stats_t stats; @@ -107,84 +107,97 @@ struct arena_bin_s { struct arena_s { /* - * Number of threads currently assigned to this arena, synchronized via - * atomic operations. Each thread has two distinct assignments, one for - * application-serving allocation, and the other for internal metadata - * allocation. Internal metadata must not be allocated from arenas - * explicitly created via the arenas.create mallctl, because the - * arena..reset mallctl indiscriminately discards all allocations for - * the affected arena. + * Number of threads currently assigned to this arena. Each thread has + * two distinct assignments, one for application-serving allocation, and + * the other for internal metadata allocation. Internal metadata must + * not be allocated from arenas explicitly created via the arenas.create + * mallctl, because the arena..reset mallctl indiscriminately + * discards all allocations for the affected arena. * * 0: Application allocation. * 1: Internal metadata allocation. + * + * Synchronization: atomic. */ unsigned nthreads[2]; /* - * There are three classes of arena operations from a locking - * perspective: - * 1) Thread assignment (modifies nthreads) is synchronized via atomics. - * 2) Bin-related operations are protected by bin locks. - * 3) Extent-related operations are protected by this mutex. + * Synchronizes various arena operations, as indicated in field-specific + * comments. */ malloc_mutex_t lock; + /* Synchronization: lock. */ arena_stats_t stats; /* * List of tcaches for extant threads associated with this arena. * Stats from these are merged incrementally, and at exit if * opt_stats_print is enabled. + * + * Synchronization: lock. */ ql_head(tcache_t) tcache_ql; + /* Synchronization: lock. */ uint64_t prof_accumbytes; /* * PRNG state for cache index randomization of large allocation base * pointers. + * + * Synchronization: atomic. */ size_t offset_state; - /* Extent serial number generator state. */ + /* + * Extent serial number generator state. + * + * Synchronization: atomic. + */ size_t extent_sn_next; + /* Synchronization: lock. */ dss_prec_t dss_prec; - /* True if a thread is currently executing arena_purge_to_limit(). */ - bool purging; + /* + * 1/0 (true/false) if a thread is currently executing + * arena_purge_to_limit(). + * + * Synchronization: atomic. + */ + unsigned purging; - /* Number of pages in active extents. */ + /* + * Number of pages in active extents. + * + * Synchronization: atomic. + */ size_t nactive; /* - * Current count of pages within unused extents that are potentially - * dirty, and for which pages_purge_*() has not been called. By - * tracking this, we can institute a limit on how much dirty unused - * memory is mapped for each arena. + * Decay-based purging state. + * + * Synchronization: lock. */ - size_t ndirty; - - /* Decay-based purging state. */ arena_decay_t decay; - /* Extant large allocations. */ - ql_head(extent_t) large; + /* + * Extant large allocations. + * + * Synchronization: large_mtx. + */ + extent_list_t large; /* Synchronizes all large allocation/update/deallocation. */ malloc_mutex_t large_mtx; /* - * Heaps of extents that were previously allocated. These are used when - * allocating extents, in an attempt to re-use address space. - */ - extent_heap_t extents_cached[NPSIZES+1]; - extent_heap_t extents_retained[NPSIZES+1]; - /* - * Ring sentinel used to track unused dirty memory. Dirty memory is - * managed as an LRU of cached extents. + * Collections of extents that were previously allocated. These are + * used when allocating extents, in an attempt to re-use address space. + * + * Synchronization: internal. */ - extent_t extents_dirty; - /* Protects extents_{cached,retained,dirty}. */ - malloc_mutex_t extents_mtx; + extents_t extents_cached; + extents_t extents_retained; /* * Next extent size class in a growing series to use when satisfying a @@ -192,17 +205,31 @@ struct arena_s { * the number of disjoint virtual memory ranges so that extent merging * can be effective even if multiple arenas' extent allocation requests * are highly interleaved. + * + * Synchronization: atomic. */ pszind_t extent_grow_next; - /* Cache of extent structures that were allocated via base_alloc(). */ - ql_head(extent_t) extent_cache; - malloc_mutex_t extent_cache_mtx; + /* + * Freelist of extent structures that were allocated via base_alloc(). + * + * Synchronization: extent_freelist_mtx. + */ + extent_list_t extent_freelist; + malloc_mutex_t extent_freelist_mtx; - /* bins is used to store heaps of free regions. */ + /* + * bins is used to store heaps of free regions. + * + * Synchronization: internal. + */ arena_bin_t bins[NBINS]; - /* Base allocator, from which arena metadata are allocated. */ + /* + * Base allocator, from which arena metadata are allocated. + * + * Synchronization: internal. + */ base_t *base; }; diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index 59f3c7ca..a3556118 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -21,9 +21,13 @@ size_t extent_size_quantize_ceil(size_t size); ph_proto(, extent_heap_, extent_heap_t, extent_t) -extent_t *extent_alloc_cache_locked(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab); +bool extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state); +extent_state_t extents_state_get(const extents_t *extents); +size_t extents_npages_get(extents_t *extents); +extent_t *extents_evict(tsdn_t *tsdn, extents_t *extents, size_t npages_min); +void extents_prefork(tsdn_t *tsdn, extents_t *extents); +void extents_postfork_parent(tsdn_t *tsdn, extents_t *extents); +void extents_postfork_child(tsdn_t *tsdn, extents_t *extents); extent_t *extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab); diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index 379dd290..473aad71 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -12,8 +12,7 @@ void *extent_before_get(const extent_t *extent); void *extent_last_get(const extent_t *extent); void *extent_past_get(const extent_t *extent); size_t extent_sn_get(const extent_t *extent); -bool extent_active_get(const extent_t *extent); -bool extent_retained_get(const extent_t *extent); +extent_state_t extent_state_get(const extent_t *extent); bool extent_zeroed_get(const extent_t *extent); bool extent_committed_get(const extent_t *extent); bool extent_slab_get(const extent_t *extent); @@ -26,16 +25,19 @@ void extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment); void extent_size_set(extent_t *extent, size_t size); void extent_usize_set(extent_t *extent, size_t usize); void extent_sn_set(extent_t *extent, size_t sn); -void extent_active_set(extent_t *extent, bool active); +void extent_state_set(extent_t *extent, extent_state_t state); void extent_zeroed_set(extent_t *extent, bool zeroed); void extent_committed_set(extent_t *extent, bool committed); void extent_slab_set(extent_t *extent, bool slab); void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx); void extent_init(extent_t *extent, arena_t *arena, void *addr, - size_t size, size_t usize, size_t sn, bool active, bool zeroed, + size_t size, size_t usize, size_t sn, extent_state_t state, bool zeroed, bool committed, bool slab); -void extent_ring_insert(extent_t *sentinel, extent_t *extent); -void extent_ring_remove(extent_t *extent); +void extent_list_init(extent_list_t *list); +extent_t *extent_list_first(const extent_list_t *list); +extent_t *extent_list_last(const extent_list_t *list); +void extent_list_append(extent_list_t *list, extent_t *extent); +void extent_list_remove(extent_list_t *list, extent_t *extent); int extent_sn_comp(const extent_t *a, const extent_t *b); int extent_ad_comp(const extent_t *a, const extent_t *b); int extent_snad_comp(const extent_t *a, const extent_t *b); @@ -103,14 +105,9 @@ extent_sn_get(const extent_t *extent) { return extent->e_sn; } -JEMALLOC_INLINE bool -extent_active_get(const extent_t *extent) { - return extent->e_active; -} - -JEMALLOC_INLINE bool -extent_retained_get(const extent_t *extent) { - return (qr_next(extent, qr_link) == extent); +JEMALLOC_INLINE extent_state_t +extent_state_get(const extent_t *extent) { + return extent->e_state; } JEMALLOC_INLINE bool @@ -191,8 +188,8 @@ extent_sn_set(extent_t *extent, size_t sn) { } JEMALLOC_INLINE void -extent_active_set(extent_t *extent, bool active) { - extent->e_active = active; +extent_state_set(extent_t *extent, extent_state_t state) { + extent->e_state = state; } JEMALLOC_INLINE void @@ -217,7 +214,7 @@ extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) { JEMALLOC_INLINE void extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, - size_t usize, size_t sn, bool active, bool zeroed, bool committed, + size_t usize, size_t sn, extent_state_t state, bool zeroed, bool committed, bool slab) { assert(addr == PAGE_ADDR2BASE(addr) || !slab); @@ -226,24 +223,39 @@ extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, extent_size_set(extent, size); extent_usize_set(extent, usize); extent_sn_set(extent, sn); - extent_active_set(extent, active); + extent_state_set(extent, state); extent_zeroed_set(extent, zeroed); extent_committed_set(extent, committed); extent_slab_set(extent, slab); if (config_prof) { extent_prof_tctx_set(extent, NULL); } - qr_new(extent, qr_link); + ql_elm_new(extent, ql_link); +} + +JEMALLOC_INLINE void +extent_list_init(extent_list_t *list) { + ql_new(list); +} + +JEMALLOC_INLINE extent_t * +extent_list_first(const extent_list_t *list) { + return ql_first(list); +} + +JEMALLOC_INLINE extent_t * +extent_list_last(const extent_list_t *list) { + return ql_last(list, ql_link); } JEMALLOC_INLINE void -extent_ring_insert(extent_t *sentinel, extent_t *extent) { - qr_meld(sentinel, extent, extent_t, qr_link); +extent_list_append(extent_list_t *list, extent_t *extent) { + ql_tail_insert(list, extent, ql_link); } JEMALLOC_INLINE void -extent_ring_remove(extent_t *extent) { - qr_remove(extent, qr_link); +extent_list_remove(extent_list_t *list, extent_t *extent) { + ql_remove(list, extent, ql_link); } JEMALLOC_INLINE int diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index de31317c..33ca4ac7 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -1,6 +1,12 @@ #ifndef JEMALLOC_INTERNAL_EXTENT_STRUCTS_H #define JEMALLOC_INTERNAL_EXTENT_STRUCTS_H +typedef enum { + extent_state_active = 0, + extent_state_dirty = 1, + extent_state_retained = 2 +} extent_state_t; + /* Extent (span of pages). Use accessor functions for e_* fields. */ struct extent_s { /* Arena from which this extent came, if any. */ @@ -32,8 +38,8 @@ struct extent_s { */ size_t e_sn; - /* True if extent is active (in use). */ - bool e_active; + /* Extent state. */ + extent_state_t e_state; /* * The zeroed flag is used by extent recycling code to track whether @@ -67,18 +73,48 @@ struct extent_s { }; /* - * Linkage for arena's extents_dirty and arena_bin_t's slabs_full rings. + * List linkage, used by a variety of lists: + * - arena_bin_t's slabs_full + * - extents_t's LRU + * - stashed dirty extents + * - arena's large allocations + * - arena's extent structure freelist */ - qr(extent_t) qr_link; - - union { - /* Linkage for per size class sn/address-ordered heaps. */ - phn(extent_t) ph_link; + ql_elm(extent_t) ql_link; - /* Linkage for arena's large and extent_cache lists. */ - ql_elm(extent_t) ql_link; - }; + /* Linkage for per size class sn/address-ordered heaps. */ + phn(extent_t) ph_link; }; +typedef ql_head(extent_t) extent_list_t; typedef ph(extent_t) extent_heap_t; +/* Quantized collection of extents, with built-in LRU queue. */ +struct extents_s { + malloc_mutex_t mtx; + + /* + * Quantized per size class heaps of extents. + * + * Synchronization: mtx. + */ + extent_heap_t heaps[NPSIZES+1]; + + /* + * LRU of all extents in heaps. + * + * Synchronization: mtx. + */ + extent_list_t lru; + + /* + * Page sum for all extents in heaps. + * + * Synchronization: atomic. + */ + size_t npages; + + /* All stored extents must be in the same state. */ + extent_state_t state; +}; + #endif /* JEMALLOC_INTERNAL_EXTENT_STRUCTS_H */ diff --git a/include/jemalloc/internal/extent_types.h b/include/jemalloc/internal/extent_types.h index 53db1c36..b6905ce1 100644 --- a/include/jemalloc/internal/extent_types.h +++ b/include/jemalloc/internal/extent_types.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_EXTENT_TYPES_H typedef struct extent_s extent_t; +typedef struct extents_s extents_t; #define EXTENT_HOOKS_INITIALIZER NULL diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 33fd2fac..bace9c46 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -979,6 +979,7 @@ iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, assert(!is_internal || tcache == NULL); assert(!is_internal || arena == NULL || arena_ind_get(arena) < narenas_auto); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); ret = arena_malloc(tsdn, arena, size, ind, zero, tcache, slow_path); if (config_stats && is_internal && likely(ret != NULL)) { @@ -1004,6 +1005,7 @@ ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, assert(!is_internal || tcache == NULL); assert(!is_internal || arena == NULL || arena_ind_get(arena) < narenas_auto); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); ret = arena_palloc(tsdn, arena, usize, alignment, zero, tcache); assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret); @@ -1042,7 +1044,7 @@ ivsalloc(tsdn_t *tsdn, const void *ptr) { if (extent == NULL) { return 0; } - assert(extent_active_get(extent)); + assert(extent_state_get(extent) == extent_state_active); /* Only slab members should be looked up via interior pointers. */ assert(extent_addr_get(extent) == ptr || extent_slab_get(extent)); @@ -1056,6 +1058,7 @@ idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, assert(!is_internal || tcache == NULL); assert(!is_internal || arena_ind_get(iaalloc(tsdn, ptr)) < narenas_auto); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); if (config_stats && is_internal) { arena_internal_sub(iaalloc(tsdn, ptr), isalloc(tsdn, extent, ptr)); @@ -1073,6 +1076,7 @@ idalloc(tsd_t *tsd, extent_t *extent, void *ptr) { JEMALLOC_ALWAYS_INLINE void isdalloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, tcache_t *tcache, bool slow_path) { + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); arena_sdalloc(tsdn, extent, ptr, size, tcache, slow_path); } @@ -1080,6 +1084,7 @@ JEMALLOC_ALWAYS_INLINE void * iralloct_realign(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t extra, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) { + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); void *p; size_t usize, copysize; @@ -1117,6 +1122,7 @@ iralloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) { assert(ptr != NULL); assert(size != 0); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1)) != 0) { @@ -1144,6 +1150,7 @@ ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t extra, size_t alignment, bool zero) { assert(ptr != NULL); assert(size != 0); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1)) != 0) { diff --git a/include/jemalloc/internal/large_externs.h b/include/jemalloc/internal/large_externs.h index f0a03399..66aa755c 100644 --- a/include/jemalloc/internal/large_externs.h +++ b/include/jemalloc/internal/large_externs.h @@ -17,7 +17,8 @@ extern large_dalloc_maybe_junk_t *large_dalloc_maybe_junk; void large_dalloc_junk(void *ptr, size_t usize); void large_dalloc_maybe_junk(void *ptr, size_t usize); #endif -void large_dalloc_junked_locked(tsdn_t *tsdn, extent_t *extent); +void large_dalloc_prep_junked_locked(tsdn_t *tsdn, extent_t *extent); +void large_dalloc_finish(tsdn_t *tsdn, extent_t *extent); void large_dalloc(tsdn_t *tsdn, extent_t *extent); size_t large_salloc(tsdn_t *tsdn, const extent_t *extent); prof_tctx_t *large_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 36bcda24..d1166b20 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -25,11 +25,9 @@ arena_destroy arena_dss_prec_get arena_dss_prec_set arena_extent_alloc_large -arena_extent_cache_alloc arena_extent_cache_dalloc -arena_extent_cache_maybe_insert -arena_extent_cache_maybe_remove -arena_extent_dalloc_large +arena_extent_dalloc_large_finish +arena_extent_dalloc_large_prep arena_extent_ralloc_large_expand arena_extent_ralloc_large_shrink arena_extent_sn_next @@ -141,15 +139,12 @@ ctl_postfork_parent ctl_prefork decay_ticker_get dss_prec_names -extent_active_get -extent_active_set extent_ad_comp extent_addr_get extent_addr_randomize extent_addr_set extent_alloc extent_alloc_cache -extent_alloc_cache_locked extent_alloc_dss extent_alloc_mmap extent_alloc_wrapper @@ -184,6 +179,10 @@ extent_hooks_set extent_in_dss extent_init extent_last_get +extent_list_append +extent_list_first +extent_list_last +extent_list_remove extent_lookup extent_merge_wrapper extent_past_get @@ -191,9 +190,6 @@ extent_prof_tctx_get extent_prof_tctx_set extent_purge_forced_wrapper extent_purge_lazy_wrapper -extent_retained_get -extent_ring_insert -extent_ring_remove extent_size_get extent_size_quantize_ceil extent_size_quantize_floor @@ -207,11 +203,20 @@ extent_sn_get extent_sn_set extent_snad_comp extent_split_wrapper +extent_state_get +extent_state_set extent_usize_get extent_usize_set extent_zeroed_get extent_zeroed_set +extents_evict +extents_init +extents_npages_get +extents_prefork +extents_postfork_child +extents_postfork_parent extents_rtree +extents_state_get ffs_llu ffs_lu ffs_u @@ -255,9 +260,10 @@ jemalloc_postfork_child jemalloc_postfork_parent jemalloc_prefork large_dalloc +large_dalloc_finish large_dalloc_junk -large_dalloc_junked_locked large_dalloc_maybe_junk +large_dalloc_prep_junked_locked large_malloc large_palloc large_prof_tctx_get diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index 32ef6118..5cdb0cd9 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -70,9 +70,14 @@ struct malloc_large_stats_s { size_t curlextents; }; +/* + * Arena stats. Note that fields marked "derived" are not directly maintained + * within the arena code; rather their values are derived during stats merge + * requests. + */ struct arena_stats_s { - /* Number of bytes currently mapped. */ - size_t mapped; + /* Number of bytes currently mapped, excluding retained memory. */ + size_t mapped; /* Derived. */ /* * Number of bytes currently retained as a side effect of munmap() being @@ -80,7 +85,7 @@ struct arena_stats_s { * always decommitted or purged), but they are excluded from the mapped * statistic (above). */ - size_t retained; + size_t retained; /* Derived. */ /* * Total number of purge sweeps, total number of madvise calls made, @@ -91,9 +96,9 @@ struct arena_stats_s { uint64_t nmadvise; uint64_t purged; - size_t base; + size_t base; /* Derived. */ size_t internal; /* Protected via atomic_*_zu(). */ - size_t resident; + size_t resident; /* Derived. */ size_t allocated_large; uint64_t nmalloc_large; @@ -101,7 +106,7 @@ struct arena_stats_s { uint64_t nrequests_large; /* Number of bytes cached in tcache associated with this arena. */ - size_t tcache_bytes; + size_t tcache_bytes; /* Derived. */ /* One element for each large size class. */ malloc_large_stats_t lstats[NSIZES - NBINS]; diff --git a/include/jemalloc/internal/witness_types.h b/include/jemalloc/internal/witness_types.h index dfcf1621..29299168 100644 --- a/include/jemalloc/internal/witness_types.h +++ b/include/jemalloc/internal/witness_types.h @@ -26,9 +26,17 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *, #define WITNESS_RANK_PROF_TDATA 7U #define WITNESS_RANK_PROF_GCTX 8U +/* + * Used as an argument to witness_depth_to_rank() in order to validate depth + * excluding non-core locks with lower ranks. Since the rank argument to + * witness_depth_to_rank() is inclusive rather than exclusive, this definition + * can have the same value as the minimally ranked core lock. + */ +#define WITNESS_RANK_CORE 9U + #define WITNESS_RANK_ARENA 9U -#define WITNESS_RANK_ARENA_EXTENTS 10U -#define WITNESS_RANK_ARENA_EXTENT_CACHE 11U +#define WITNESS_RANK_EXTENTS 10U +#define WITNESS_RANK_EXTENT_FREELIST 11U #define WITNESS_RANK_RTREE_ELM 12U #define WITNESS_RANK_RTREE 13U diff --git a/src/arena.c b/src/arena.c index b0da9a03..5905306c 100644 --- a/src/arena.c +++ b/src/arena.c @@ -37,75 +37,13 @@ static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, /******************************************************************************/ -static size_t -arena_extent_dirty_npages(const extent_t *extent) { - return (extent_size_get(extent) >> LG_PAGE); -} - -static extent_t * -arena_extent_cache_alloc_locked(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool slab) { - bool commit = true; - - malloc_mutex_assert_owner(tsdn, &arena->lock); - - return extent_alloc_cache(tsdn, arena, r_extent_hooks, new_addr, usize, - pad, alignment, zero, &commit, slab); -} - -extent_t * -arena_extent_cache_alloc(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, - size_t alignment, bool *zero) { - extent_t *extent; - - malloc_mutex_lock(tsdn, &arena->lock); - extent = arena_extent_cache_alloc_locked(tsdn, arena, r_extent_hooks, - new_addr, size, 0, alignment, zero, false); - malloc_mutex_unlock(tsdn, &arena->lock); - - return extent; -} - -static void -arena_extent_cache_dalloc_locked(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent) { - malloc_mutex_assert_owner(tsdn, &arena->lock); - - extent_dalloc_cache(tsdn, arena, r_extent_hooks, extent); - arena_maybe_purge(tsdn, arena); -} - void arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { - malloc_mutex_lock(tsdn, &arena->lock); - arena_extent_cache_dalloc_locked(tsdn, arena, r_extent_hooks, extent); - malloc_mutex_unlock(tsdn, &arena->lock); -} - -void -arena_extent_cache_maybe_insert(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - bool cache) { - malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); - - if (cache) { - extent_ring_insert(&arena->extents_dirty, extent); - arena->ndirty += arena_extent_dirty_npages(extent); - } -} + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); -void -arena_extent_cache_maybe_remove(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - bool dirty) { - malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); - - if (dirty) { - extent_ring_remove(extent); - assert(arena->ndirty >= arena_extent_dirty_npages(extent)); - arena->ndirty -= arena_extent_dirty_npages(extent); - } + extent_dalloc_cache(tsdn, arena, r_extent_hooks, extent); + arena_purge(tsdn, arena, false); } JEMALLOC_INLINE_C void * @@ -180,13 +118,13 @@ arena_slab_reg_dalloc(tsdn_t *tsdn, extent_t *slab, static void arena_nactive_add(arena_t *arena, size_t add_pages) { - arena->nactive += add_pages; + atomic_add_zu(&arena->nactive, add_pages); } static void arena_nactive_sub(arena_t *arena, size_t sub_pages) { - assert(arena->nactive >= sub_pages); - arena->nactive -= sub_pages; + assert(atomic_read_zu(&arena->nactive) >= sub_pages); + atomic_sub_zu(&arena->nactive, sub_pages); } static void @@ -269,6 +207,8 @@ arena_extent_alloc_large_hard(tsdn_t *tsdn, arena_t *arena, extent_t *extent; bool commit = true; + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + extent = extent_alloc_wrapper(tsdn, arena, r_extent_hooks, NULL, usize, large_pad, alignment, zero, &commit, false); if (extent == NULL) { @@ -291,6 +231,8 @@ arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, extent_t *extent; extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + malloc_mutex_lock(tsdn, &arena->lock); /* Optimistically update stats. */ @@ -300,9 +242,11 @@ arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, } arena_nactive_add(arena, (usize + large_pad) >> LG_PAGE); - extent = arena_extent_cache_alloc_locked(tsdn, arena, &extent_hooks, - NULL, usize, large_pad, alignment, zero, false); malloc_mutex_unlock(tsdn, &arena->lock); + + bool commit = true; + extent = extent_alloc_cache(tsdn, arena, &extent_hooks, NULL, usize, + large_pad, alignment, zero, &commit, false); if (extent == NULL) { extent = arena_extent_alloc_large_hard(tsdn, arena, &extent_hooks, usize, alignment, zero); @@ -312,10 +256,8 @@ arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, } void -arena_extent_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, +arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena, extent_t *extent, bool locked) { - extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; - if (!locked) { malloc_mutex_lock(tsdn, &arena->lock); } else { @@ -326,12 +268,17 @@ arena_extent_dalloc_large(tsdn_t *tsdn, arena_t *arena, extent_t *extent, extent_usize_get(extent)); arena->stats.mapped -= extent_size_get(extent); } - arena_nactive_sub(arena, extent_size_get(extent) >> LG_PAGE); - - arena_extent_cache_dalloc_locked(tsdn, arena, &extent_hooks, extent); if (!locked) { malloc_mutex_unlock(tsdn, &arena->lock); } + arena_nactive_sub(arena, extent_size_get(extent) >> LG_PAGE); +} + +void +arena_extent_dalloc_large_finish(tsdn_t *tsdn, arena_t *arena, + extent_t *extent) { + extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; + extent_dalloc_cache(tsdn, arena, &extent_hooks, extent); } void @@ -414,8 +361,9 @@ arena_decay_backlog_npages_limit(const arena_t *arena) { static void arena_decay_backlog_update_last(arena_t *arena) { - size_t ndirty_delta = (arena->ndirty > arena->decay.nunpurged) ? - arena->ndirty - arena->decay.nunpurged : 0; + size_t ndirty = extents_npages_get(&arena->extents_cached); + size_t ndirty_delta = (ndirty > arena->decay.nunpurged) ? ndirty - + arena->decay.nunpurged : 0; arena->decay.backlog[SMOOTHSTEP_NSTEPS-1] = ndirty_delta; } @@ -468,10 +416,15 @@ static void arena_decay_epoch_advance_purge(tsdn_t *tsdn, arena_t *arena) { size_t ndirty_limit = arena_decay_backlog_npages_limit(arena); - if (arena->ndirty > ndirty_limit) { + if (extents_npages_get(&arena->extents_cached) > ndirty_limit) { arena_purge_to_limit(tsdn, arena, ndirty_limit); } - arena->decay.nunpurged = arena->ndirty; + /* + * There may be concurrent ndirty fluctuation between the purge above + * and the nunpurged update below, but this is inconsequential to decay + * machinery correctness. + */ + arena->decay.nunpurged = extents_npages_get(&arena->extents_cached); } static void @@ -492,7 +445,7 @@ arena_decay_init(arena_t *arena, ssize_t decay_time) { nstime_update(&arena->decay.epoch); arena->decay.jitter_state = (uint64_t)(uintptr_t)arena; arena_decay_deadline_init(arena); - arena->decay.nunpurged = arena->ndirty; + arena->decay.nunpurged = extents_npages_get(&arena->extents_cached); memset(arena->decay.backlog, 0, SMOOTHSTEP_NSTEPS * sizeof(size_t)); } @@ -540,9 +493,9 @@ arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { return false; } -static void -arena_maybe_purge_helper(tsdn_t *tsdn, arena_t *arena) { - nstime_t time; +void +arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) { + malloc_mutex_assert_owner(tsdn, &arena->lock); /* Purge all or nothing if the option is disabled. */ if (arena->decay.time <= 0) { @@ -552,6 +505,7 @@ arena_maybe_purge_helper(tsdn_t *tsdn, arena_t *arena) { return; } + nstime_t time; nstime_init(&time, 0); nstime_update(&time); if (unlikely(!nstime_monotonic() && nstime_compare(&arena->decay.epoch, @@ -583,95 +537,40 @@ arena_maybe_purge_helper(tsdn_t *tsdn, arena_t *arena) { } } -void -arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_assert_owner(tsdn, &arena->lock); - - /* Don't recursively purge. */ - if (arena->purging) { - return; - } - - arena_maybe_purge_helper(tsdn, arena); -} - -static size_t -arena_dirty_count(tsdn_t *tsdn, arena_t *arena) { - extent_t *extent; - size_t ndirty = 0; - - malloc_mutex_lock(tsdn, &arena->extents_mtx); - - for (extent = qr_next(&arena->extents_dirty, qr_link); extent != - &arena->extents_dirty; extent = qr_next(extent, qr_link)) { - ndirty += extent_size_get(extent) >> LG_PAGE; - } - - malloc_mutex_unlock(tsdn, &arena->extents_mtx); - - return ndirty; -} - static size_t arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - size_t ndirty_limit, extent_t *purge_extents_sentinel) { - extent_t *extent, *next; - size_t nstashed = 0; - - malloc_mutex_lock(tsdn, &arena->extents_mtx); + size_t ndirty_limit, extent_list_t *purge_extents) { + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); /* Stash extents according to ndirty_limit. */ - for (extent = qr_next(&arena->extents_dirty, qr_link); extent != - &arena->extents_dirty; extent = next) { - size_t npages; - bool zero, commit; - UNUSED extent_t *textent; - - npages = extent_size_get(extent) >> LG_PAGE; - if (arena->ndirty - (nstashed + npages) < ndirty_limit) { - break; - } - - next = qr_next(extent, qr_link); - /* Allocate. */ - zero = false; - commit = false; - textent = extent_alloc_cache_locked(tsdn, arena, r_extent_hooks, - extent_base_get(extent), extent_size_get(extent), 0, PAGE, - &zero, &commit, false); - assert(textent == extent); - assert(zero == extent_zeroed_get(extent)); - extent_ring_remove(extent); - extent_ring_insert(purge_extents_sentinel, extent); - - nstashed += npages; + size_t nstashed = 0; + for (extent_t *extent = extents_evict(tsdn, &arena->extents_cached, + ndirty_limit); extent != NULL; extent = extents_evict(tsdn, + &arena->extents_cached, ndirty_limit)) { + extent_list_append(purge_extents, extent); + nstashed += extent_size_get(extent) >> LG_PAGE; } - - malloc_mutex_unlock(tsdn, &arena->extents_mtx); return nstashed; } static size_t arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *purge_extents_sentinel) { + extent_hooks_t **r_extent_hooks, extent_list_t *purge_extents) { UNUSED size_t nmadvise; size_t npurged; - extent_t *extent, *next; if (config_stats) { nmadvise = 0; } npurged = 0; - for (extent = qr_next(purge_extents_sentinel, qr_link); extent != - purge_extents_sentinel; extent = next) { + for (extent_t *extent = extent_list_first(purge_extents); extent != + NULL; extent = extent_list_first(purge_extents)) { if (config_stats) { nmadvise++; } npurged += extent_size_get(extent) >> LG_PAGE; - - next = qr_next(extent, qr_link); - extent_ring_remove(extent); + extent_list_remove(purge_extents, extent); extent_dalloc_wrapper(tsdn, arena, r_extent_hooks, extent); } @@ -684,43 +583,44 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, } /* - * ndirty_limit: Purge as many dirty extents as possible without violating the - * invariant: (arena->ndirty >= ndirty_limit) + * ndirty_limit: Purge as many dirty extents as possible without violating the + * invariant: (extents_npages_get(&arena->extents_cached) >= ndirty_limit) */ static void arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) { + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 1); + malloc_mutex_assert_owner(tsdn, &arena->lock); + + if (atomic_cas_u(&arena->purging, 0, 1)) { + return; + } + extent_hooks_t *extent_hooks = extent_hooks_get(arena); size_t npurge, npurged; - extent_t purge_extents_sentinel; + extent_list_t purge_extents; - arena->purging = true; + extent_list_init(&purge_extents); - /* - * Calls to arena_dirty_count() are disabled even for debug builds - * because overhead grows nonlinearly as memory usage increases. - */ - if (false && config_debug) { - size_t ndirty = arena_dirty_count(tsdn, arena); - assert(ndirty == arena->ndirty); - } - extent_init(&purge_extents_sentinel, arena, NULL, 0, 0, 0, false, false, - false, false); + malloc_mutex_unlock(tsdn, &arena->lock); npurge = arena_stash_dirty(tsdn, arena, &extent_hooks, ndirty_limit, - &purge_extents_sentinel); + &purge_extents); if (npurge == 0) { + malloc_mutex_lock(tsdn, &arena->lock); goto label_return; } npurged = arena_purge_stashed(tsdn, arena, &extent_hooks, - &purge_extents_sentinel); + &purge_extents); assert(npurged == npurge); + malloc_mutex_lock(tsdn, &arena->lock); + if (config_stats) { arena->stats.npurge++; } label_return: - arena->purging = false; + atomic_write_u(&arena->purging, 0); } void @@ -737,9 +637,14 @@ arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) { static void arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) { extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; + size_t npages = extent_size_get(slab) >> LG_PAGE; + + extent_dalloc_cache(tsdn, arena, &extent_hooks, slab); - arena_nactive_sub(arena, extent_size_get(slab) >> LG_PAGE); - arena_extent_cache_dalloc_locked(tsdn, arena, &extent_hooks, slab); + arena_nactive_sub(arena, npages); + malloc_mutex_lock(tsdn, &arena->lock); + arena_maybe_purge(tsdn, arena); + malloc_mutex_unlock(tsdn, &arena->lock); } static void @@ -768,19 +673,16 @@ arena_bin_slabs_nonfull_tryget(arena_bin_t *bin) { static void arena_bin_slabs_full_insert(arena_bin_t *bin, extent_t *slab) { assert(extent_slab_data_get(slab)->nfree == 0); - extent_ring_insert(&bin->slabs_full, slab); + extent_list_append(&bin->slabs_full, slab); } static void -arena_bin_slabs_full_remove(extent_t *slab) { - extent_ring_remove(slab); +arena_bin_slabs_full_remove(arena_bin_t *bin, extent_t *slab) { + extent_list_remove(&bin->slabs_full, slab); } void arena_reset(tsd_t *tsd, arena_t *arena) { - unsigned i; - extent_t *extent; - /* * Locking in this function is unintuitive. The caller guarantees that * no concurrent operations are happening in this arena, but there are @@ -797,8 +699,9 @@ arena_reset(tsd_t *tsd, arena_t *arena) { /* Large allocations. */ malloc_mutex_lock(tsd_tsdn(tsd), &arena->large_mtx); - for (extent = ql_last(&arena->large, ql_link); extent != NULL; extent = - ql_last(&arena->large, ql_link)) { + + for (extent_t *extent = extent_list_first(&arena->large); extent != + NULL; extent = extent_list_first(&arena->large)) { void *ptr = extent_base_get(extent); size_t usize; @@ -819,10 +722,8 @@ arena_reset(tsd_t *tsd, arena_t *arena) { } malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx); - malloc_mutex_lock(tsd_tsdn(tsd), &arena->lock); - /* Bins. */ - for (i = 0; i < NBINS; i++) { + for (unsigned i = 0; i < NBINS; i++) { extent_t *slab; arena_bin_t *bin = &arena->bins[i]; malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); @@ -839,10 +740,9 @@ arena_reset(tsd_t *tsd, arena_t *arena) { arena_slab_dalloc(tsd_tsdn(tsd), arena, slab); malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); } - for (slab = qr_next(&bin->slabs_full, qr_link); slab != - &bin->slabs_full; slab = qr_next(&bin->slabs_full, - qr_link)) { - arena_bin_slabs_full_remove(slab); + for (slab = extent_list_first(&bin->slabs_full); slab != NULL; + slab = extent_list_first(&bin->slabs_full)) { + arena_bin_slabs_full_remove(bin, slab); malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); arena_slab_dalloc(tsd_tsdn(tsd), arena, slab); malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); @@ -854,17 +754,12 @@ arena_reset(tsd_t *tsd, arena_t *arena) { malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); } - assert(!arena->purging); - arena->nactive = 0; - - malloc_mutex_unlock(tsd_tsdn(tsd), &arena->lock); + assert(atomic_read_u(&arena->purging) == 0); + atomic_write_zu(&arena->nactive, 0); } static void arena_destroy_retained(tsdn_t *tsdn, arena_t *arena) { - extent_hooks_t *extent_hooks = extent_hooks_get(arena); - size_t i; - /* * Iterate over the retained extents and blindly attempt to deallocate * them. This gives the extent allocator underlying the extent hooks an @@ -876,15 +771,11 @@ arena_destroy_retained(tsdn_t *tsdn, arena_t *arena) { * dss for arenas to be destroyed), or provide custom extent hooks that * either unmap retained extents or track them for later use. */ - for (i = 0; i < sizeof(arena->extents_retained)/sizeof(extent_heap_t); - i++) { - extent_heap_t *extents = &arena->extents_retained[i]; - extent_t *extent; - - while ((extent = extent_heap_remove_first(extents)) != NULL) { - extent_dalloc_wrapper_try(tsdn, arena, &extent_hooks, - extent); - } + extent_hooks_t *extent_hooks = extent_hooks_get(arena); + for (extent_t *extent = extents_evict(tsdn, &arena->extents_retained, + 0); extent != NULL; extent = extents_evict(tsdn, + &arena->extents_retained, 0)) { + extent_dalloc_wrapper_try(tsdn, arena, &extent_hooks, extent); } } @@ -899,7 +790,7 @@ arena_destroy(tsd_t *tsd, arena_t *arena) { * Furthermore, the caller (arena_i_destroy_ctl()) purged all cached * extents, so only retained extents may remain. */ - assert(arena->ndirty == 0); + assert(extents_npages_get(&arena->extents_cached) == 0); /* Attempt to deallocate retained memory. */ arena_destroy_retained(tsd_tsdn(tsd), arena); @@ -929,12 +820,12 @@ arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, extent_t *slab; bool zero, commit; + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + zero = false; commit = true; - malloc_mutex_unlock(tsdn, &arena->lock); slab = extent_alloc_wrapper(tsdn, arena, r_extent_hooks, NULL, bin_info->slab_size, 0, PAGE, &zero, &commit, true); - malloc_mutex_lock(tsdn, &arena->lock); return slab; } @@ -942,13 +833,13 @@ arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, static extent_t * arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, const arena_bin_info_t *bin_info) { - extent_t *slab; - arena_slab_data_t *slab_data; + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; bool zero = false; - - slab = arena_extent_cache_alloc_locked(tsdn, arena, &extent_hooks, NULL, - bin_info->slab_size, 0, PAGE, &zero, true); + bool commit = true; + extent_t *slab = extent_alloc_cache(tsdn, arena, &extent_hooks, NULL, + bin_info->slab_size, 0, PAGE, &zero, &commit, true); if (slab == NULL) { slab = arena_slab_alloc_hard(tsdn, arena, &extent_hooks, bin_info); @@ -958,10 +849,12 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, } assert(extent_slab_get(slab)); + malloc_mutex_lock(tsdn, &arena->lock); + arena_nactive_add(arena, extent_size_get(slab) >> LG_PAGE); /* Initialize slab internals. */ - slab_data = extent_slab_data_get(slab); + arena_slab_data_t *slab_data = extent_slab_data_get(slab); slab_data->binind = binind; slab_data->nfree = bin_info->nregs; bitmap_init(slab_data->bitmap, &bin_info->bitmap_info); @@ -969,6 +862,7 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, if (config_stats) { arena->stats.mapped += extent_size_get(slab); } + malloc_mutex_unlock(tsdn, &arena->lock); return slab; } @@ -991,9 +885,7 @@ arena_bin_nonfull_slab_get(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, /* Allocate a new slab. */ malloc_mutex_unlock(tsdn, &bin->lock); /******************************/ - malloc_mutex_lock(tsdn, &arena->lock); slab = arena_slab_alloc(tsdn, arena, binind, bin_info); - malloc_mutex_unlock(tsdn, &arena->lock); /********************************/ malloc_mutex_lock(tsdn, &bin->lock); if (slab != NULL) { @@ -1317,7 +1209,7 @@ arena_dissociate_bin_slab(extent_t *slab, arena_bin_t *bin) { * into the non-full slabs heap. */ if (bin_info->nregs == 1) { - arena_bin_slabs_full_remove(slab); + arena_bin_slabs_full_remove(bin, slab); } else { arena_bin_slabs_nonfull_remove(bin, slab); } @@ -1331,9 +1223,7 @@ arena_dalloc_bin_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, malloc_mutex_unlock(tsdn, &bin->lock); /******************************/ - malloc_mutex_lock(tsdn, &arena->lock); arena_slab_dalloc(tsdn, arena, slab); - malloc_mutex_unlock(tsdn, &arena->lock); /****************************/ malloc_mutex_lock(tsdn, &bin->lock); if (config_stats) { @@ -1385,7 +1275,7 @@ arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, extent_t *slab, arena_dissociate_bin_slab(slab, bin); arena_dalloc_bin_slab(tsdn, arena, slab, bin); } else if (slab_data->nfree == 1 && slab != bin->slabcur) { - arena_bin_slabs_full_remove(slab); + arena_bin_slabs_full_remove(bin, slab); arena_bin_lower_slab(tsdn, arena, slab, bin); } @@ -1554,8 +1444,8 @@ arena_basic_stats_merge_locked(arena_t *arena, unsigned *nthreads, *nthreads += arena_nthreads_get(arena, false); *dss = dss_prec_names[arena->dss_prec]; *decay_time = arena->decay.time; - *nactive += arena->nactive; - *ndirty += arena->ndirty; + *nactive += atomic_read_zu(&arena->nactive); + *ndirty += extents_npages_get(&arena->extents_cached); } void @@ -1585,14 +1475,15 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, &base_mapped); astats->mapped += base_mapped + arena->stats.mapped; - astats->retained += arena->stats.retained; + astats->retained += (extents_npages_get(&arena->extents_retained) << + LG_PAGE); astats->npurge += arena->stats.npurge; astats->nmadvise += arena->stats.nmadvise; astats->purged += arena->stats.purged; astats->base += base_allocated; astats->internal += arena_internal_get(arena); - astats->resident += base_resident + (((arena->nactive + arena->ndirty) - << LG_PAGE)); + astats->resident += base_resident + (((atomic_read_zu(&arena->nactive) + + extents_npages_get(&arena->extents_cached)) << LG_PAGE)); astats->allocated_large += arena->stats.allocated_large; astats->nmalloc_large += arena->stats.nmalloc_large; astats->ndalloc_large += arena->stats.ndalloc_large; @@ -1709,28 +1600,22 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena->dss_prec = extent_dss_prec_get(); - arena->purging = false; - arena->nactive = 0; - arena->ndirty = 0; + atomic_write_u(&arena->purging, 0); + atomic_write_zu(&arena->nactive, 0); arena_decay_init(arena, arena_decay_time_default_get()); - ql_new(&arena->large); + extent_list_init(&arena->large); if (malloc_mutex_init(&arena->large_mtx, "arena_large", WITNESS_RANK_ARENA_LARGE)) { goto label_error; } - for (i = 0; i < NPSIZES+1; i++) { - extent_heap_new(&arena->extents_cached[i]); - extent_heap_new(&arena->extents_retained[i]); + if (extents_init(tsdn, &arena->extents_cached, extent_state_dirty)) { + goto label_error; } - - extent_init(&arena->extents_dirty, arena, NULL, 0, 0, 0, false, false, - false, false); - - if (malloc_mutex_init(&arena->extents_mtx, "arena_extents", - WITNESS_RANK_ARENA_EXTENTS)) { + if (extents_init(tsdn, &arena->extents_retained, + extent_state_retained)) { goto label_error; } @@ -1738,9 +1623,9 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena->extent_grow_next = psz2ind(HUGEPAGE); } - ql_new(&arena->extent_cache); - if (malloc_mutex_init(&arena->extent_cache_mtx, "arena_extent_cache", - WITNESS_RANK_ARENA_EXTENT_CACHE)) { + extent_list_init(&arena->extent_freelist); + if (malloc_mutex_init(&arena->extent_freelist_mtx, "extent_freelist", + WITNESS_RANK_EXTENT_FREELIST)) { goto label_error; } @@ -1753,8 +1638,7 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { } bin->slabcur = NULL; extent_heap_new(&bin->slabs_nonfull); - extent_init(&bin->slabs_full, arena, NULL, 0, 0, 0, false, - false, false, false); + extent_list_init(&bin->slabs_full); if (config_stats) { memset(&bin->stats, 0, sizeof(malloc_bin_stats_t)); } @@ -1782,12 +1666,13 @@ arena_prefork0(tsdn_t *tsdn, arena_t *arena) { void arena_prefork1(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_prefork(tsdn, &arena->extents_mtx); + extents_prefork(tsdn, &arena->extents_cached); + extents_prefork(tsdn, &arena->extents_retained); } void arena_prefork2(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_prefork(tsdn, &arena->extent_cache_mtx); + malloc_mutex_prefork(tsdn, &arena->extent_freelist_mtx); } void @@ -1810,8 +1695,9 @@ arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_postfork_parent(tsdn, &arena->bins[i].lock); } base_postfork_parent(tsdn, arena->base); - malloc_mutex_postfork_parent(tsdn, &arena->extent_cache_mtx); - malloc_mutex_postfork_parent(tsdn, &arena->extents_mtx); + malloc_mutex_postfork_parent(tsdn, &arena->extent_freelist_mtx); + extents_postfork_parent(tsdn, &arena->extents_cached); + extents_postfork_parent(tsdn, &arena->extents_retained); malloc_mutex_postfork_parent(tsdn, &arena->lock); } @@ -1824,7 +1710,8 @@ arena_postfork_child(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_postfork_child(tsdn, &arena->bins[i].lock); } base_postfork_child(tsdn, arena->base); - malloc_mutex_postfork_child(tsdn, &arena->extent_cache_mtx); - malloc_mutex_postfork_child(tsdn, &arena->extents_mtx); + malloc_mutex_postfork_child(tsdn, &arena->extent_freelist_mtx); + extents_postfork_child(tsdn, &arena->extents_cached); + extents_postfork_child(tsdn, &arena->extents_retained); malloc_mutex_postfork_child(tsdn, &arena->lock); } diff --git a/src/base.c b/src/base.c index 9fb1f14f..e7712a64 100644 --- a/src/base.c +++ b/src/base.c @@ -87,7 +87,8 @@ base_extent_init(size_t *extent_sn_next, extent_t *extent, void *addr, sn = *extent_sn_next; (*extent_sn_next)++; - extent_init(extent, NULL, addr, size, 0, sn, true, true, true, false); + extent_init(extent, NULL, addr, size, 0, sn, extent_state_active, true, + true, false); } static void * @@ -104,7 +105,7 @@ base_extent_bump_alloc_helper(extent_t *extent, size_t *gap_size, size_t size, assert(extent_size_get(extent) >= *gap_size + size); extent_init(extent, NULL, (void *)((uintptr_t)extent_addr_get(extent) + *gap_size + size), extent_size_get(extent) - *gap_size - size, 0, - extent_sn_get(extent), true, true, true, false); + extent_sn_get(extent), extent_state_active, true, true, false); return ret; } diff --git a/src/extent.c b/src/extent.c index e2af2b50..293b96e5 100644 --- a/src/extent.c +++ b/src/extent.c @@ -68,9 +68,9 @@ static size_t highpages; * definition. */ -static void extent_record(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_heap_t extent_heaps[NPSIZES+1], - bool cache, extent_t *extent); +static void extent_deregister(tsdn_t *tsdn, extent_t *extent); +static void extent_record(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extents_t *extents, extent_t *extent); /******************************************************************************/ @@ -78,24 +78,26 @@ extent_t * extent_alloc(tsdn_t *tsdn, arena_t *arena) { extent_t *extent; - malloc_mutex_lock(tsdn, &arena->extent_cache_mtx); - extent = ql_last(&arena->extent_cache, ql_link); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + + malloc_mutex_lock(tsdn, &arena->extent_freelist_mtx); + extent = extent_list_last(&arena->extent_freelist); if (extent == NULL) { - malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); - return base_alloc(tsdn, arena->base, sizeof(extent_t), - QUANTUM); + malloc_mutex_unlock(tsdn, &arena->extent_freelist_mtx); + return base_alloc(tsdn, arena->base, sizeof(extent_t), QUANTUM); } - ql_tail_remove(&arena->extent_cache, extent_t, ql_link); - malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); + extent_list_remove(&arena->extent_freelist, extent); + malloc_mutex_unlock(tsdn, &arena->extent_freelist_mtx); return extent; } void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { - malloc_mutex_lock(tsdn, &arena->extent_cache_mtx); - ql_elm_new(extent, ql_link); - ql_tail_insert(&arena->extent_cache, extent, ql_link); - malloc_mutex_unlock(tsdn, &arena->extent_cache_mtx); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + + malloc_mutex_lock(tsdn, &arena->extent_freelist_mtx); + extent_list_append(&arena->extent_freelist, extent); + malloc_mutex_unlock(tsdn, &arena->extent_freelist_mtx); } extent_hooks_t * @@ -188,26 +190,174 @@ extent_size_quantize_t *extent_size_quantize_ceil = /* Generate pairing heap functions. */ ph_gen(, extent_heap_, extent_heap_t, extent_t, ph_link, extent_snad_comp) +bool +extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state) { + if (malloc_mutex_init(&extents->mtx, "extents", WITNESS_RANK_EXTENTS)) { + return true; + } + for (unsigned i = 0; i < NPSIZES+1; i++) { + extent_heap_new(&extents->heaps[i]); + } + extent_list_init(&extents->lru); + extents->npages = 0; + extents->state = state; + return false; +} + +extent_state_t +extents_state_get(const extents_t *extents) { + return extents->state; +} + +size_t +extents_npages_get(extents_t *extents) { + return atomic_read_zu(&extents->npages); +} + static void -extent_heaps_insert(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES+1], - extent_t *extent) { - size_t psz = extent_size_quantize_floor(extent_size_get(extent)); +extents_insert_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent) { + malloc_mutex_assert_owner(tsdn, &extents->mtx); + assert(extent_state_get(extent) == extents->state); + + size_t size = extent_size_get(extent); + size_t psz = extent_size_quantize_floor(size); pszind_t pind = psz2ind(psz); + extent_heap_insert(&extents->heaps[pind], extent); + extent_list_append(&extents->lru, extent); + size_t npages = size >> LG_PAGE; + atomic_add_zu(&extents->npages, npages); +} + +static void +extents_remove_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent) { + malloc_mutex_assert_owner(tsdn, &extents->mtx); + assert(extent_state_get(extent) == extents->state); + + size_t size = extent_size_get(extent); + size_t psz = extent_size_quantize_floor(size); + pszind_t pind = psz2ind(psz); + extent_heap_remove(&extents->heaps[pind], extent); + extent_list_remove(&extents->lru, extent); + size_t npages = size >> LG_PAGE; + assert(atomic_read_zu(&extents->npages) >= npages); + atomic_sub_zu(&extents->npages, size >> LG_PAGE); +} + +/* + * Do first-best-fit extent selection, i.e. select the oldest/lowest extent that + * best fits. + */ +static extent_t * +extents_first_best_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, + size_t size) { + malloc_mutex_assert_owner(tsdn, &extents->mtx); + + pszind_t pind = psz2ind(extent_size_quantize_ceil(size)); + for (pszind_t i = pind; i < NPSIZES+1; i++) { + extent_t *extent = extent_heap_first(&extents->heaps[i]); + if (extent != NULL) { + return extent; + } + } + + return NULL; +} + +extent_t * +extents_evict(tsdn_t *tsdn, extents_t *extents, size_t npages_min) { + malloc_mutex_lock(tsdn, &extents->mtx); + + /* Get the LRU extent, if any. */ + extent_t *extent = extent_list_first(&extents->lru); + if (extent == NULL) { + goto label_return; + } + /* Check the eviction limit. */ + size_t npages = extent_size_get(extent) >> LG_PAGE; + if (atomic_read_zu(&extents->npages) - npages < npages_min) { + extent = NULL; + goto label_return; + } + extents_remove_locked(tsdn, extents, extent); + + /* + * Either mark the extent active or deregister it to protect against + * concurrent operations. + */ + switch (extents_state_get(extents)) { + case extent_state_dirty: + extent_state_set(extent, extent_state_active); + break; + case extent_state_retained: + extent_deregister(tsdn, extent); + break; + default: + not_reached(); + } + +label_return: + malloc_mutex_unlock(tsdn, &extents->mtx); + return extent; +} + +static void +extents_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, + extents_t *extents, extent_t *extent) { + /* + * Leak extent after making sure its pages have already been purged, so + * that this is only a virtual memory leak. + */ + if (extents_state_get(extents) == extent_state_dirty) { + if (extent_purge_lazy_wrapper(tsdn, arena, r_extent_hooks, + extent, 0, extent_size_get(extent))) { + extent_purge_forced_wrapper(tsdn, arena, r_extent_hooks, + extent, 0, extent_size_get(extent)); + } + } + extent_dalloc(tsdn, arena, extent); +} - malloc_mutex_assert_owner(tsdn, &extent_arena_get(extent)->extents_mtx); +void +extents_prefork(tsdn_t *tsdn, extents_t *extents) { + malloc_mutex_prefork(tsdn, &extents->mtx); +} - extent_heap_insert(&extent_heaps[pind], extent); +void +extents_postfork_parent(tsdn_t *tsdn, extents_t *extents) { + malloc_mutex_postfork_parent(tsdn, &extents->mtx); +} + +void +extents_postfork_child(tsdn_t *tsdn, extents_t *extents) { + malloc_mutex_postfork_child(tsdn, &extents->mtx); } static void -extent_heaps_remove(tsdn_t *tsdn, extent_heap_t extent_heaps[NPSIZES+1], +extent_deactivate_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, extent_t *extent) { - size_t psz = extent_size_quantize_floor(extent_size_get(extent)); - pszind_t pind = psz2ind(psz); + assert(extent_arena_get(extent) == arena); + assert(extent_state_get(extent) == extent_state_active); - malloc_mutex_assert_owner(tsdn, &extent_arena_get(extent)->extents_mtx); + extent_state_set(extent, extents_state_get(extents)); + extents_insert_locked(tsdn, extents, extent); +} - extent_heap_remove(&extent_heaps[pind], extent); +static void +extent_deactivate(tsdn_t *tsdn, arena_t *arena, extents_t *extents, + extent_t *extent) { + malloc_mutex_lock(tsdn, &extents->mtx); + extent_deactivate_locked(tsdn, arena, extents, extent); + malloc_mutex_unlock(tsdn, &extents->mtx); +} + +static void +extent_activate_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, + extent_t *extent) { + assert(extent_arena_get(extent) == arena); + assert(extent_state_get(extent) == extents_state_get(extents)); + + extents_remove_locked(tsdn, extents, extent); + extent_state_set(extent, extent_state_active); } static bool @@ -269,10 +419,12 @@ extent_interior_register(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, } static void -extent_gprof_add(tsdn_t *tsdn, const extent_t *extent) { +extent_gdump_add(tsdn_t *tsdn, const extent_t *extent) { cassert(config_prof); + /* prof_gdump() requirement. */ + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - if (opt_prof && extent_active_get(extent)) { + if (opt_prof && extent_state_get(extent) == extent_state_active) { size_t nadd = extent_size_get(extent) >> LG_PAGE; size_t cur = atomic_add_zu(&curpages, nadd); size_t high = atomic_read_zu(&highpages); @@ -290,10 +442,10 @@ extent_gprof_add(tsdn_t *tsdn, const extent_t *extent) { } static void -extent_gprof_sub(tsdn_t *tsdn, const extent_t *extent) { +extent_gdump_sub(tsdn_t *tsdn, const extent_t *extent) { cassert(config_prof); - if (opt_prof && extent_active_get(extent)) { + if (opt_prof && extent_state_get(extent) == extent_state_active) { size_t nsub = extent_size_get(extent) >> LG_PAGE; assert(atomic_read_zu(&curpages) >= nsub); atomic_sub_zu(&curpages, nsub); @@ -317,7 +469,7 @@ extent_register(tsdn_t *tsdn, const extent_t *extent) { extent_rtree_release(tsdn, elm_a, elm_b); if (config_prof) { - extent_gprof_add(tsdn, extent); + extent_gdump_add(tsdn, extent); } return false; @@ -359,68 +511,21 @@ extent_deregister(tsdn_t *tsdn, extent_t *extent) { extent_rtree_release(tsdn, elm_a, elm_b); if (config_prof) { - extent_gprof_sub(tsdn, extent); - } -} - -/* - * Do first-best-fit extent selection, i.e. select the oldest/lowest extent that - * best fits. - */ -static extent_t * -extent_first_best_fit(tsdn_t *tsdn, arena_t *arena, - extent_heap_t extent_heaps[NPSIZES+1], size_t size) { - pszind_t pind, i; - - malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); - - pind = psz2ind(extent_size_quantize_ceil(size)); - for (i = pind; i < NPSIZES+1; i++) { - extent_t *extent = extent_heap_first(&extent_heaps[i]); - if (extent != NULL) { - return extent; - } + extent_gdump_sub(tsdn, extent); } - - return NULL; -} - -static void -extent_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - bool cache, extent_t *extent) { - /* - * Leak extent after making sure its pages have already been purged, so - * that this is only a virtual memory leak. - */ - if (cache) { - if (extent_purge_lazy_wrapper(tsdn, arena, r_extent_hooks, - extent, 0, extent_size_get(extent))) { - extent_purge_forced_wrapper(tsdn, arena, r_extent_hooks, - extent, 0, extent_size_get(extent)); - } - } - extent_dalloc(tsdn, arena, extent); } static extent_t * -extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extent_heap_t extent_heaps[NPSIZES+1], bool locked, bool cache, - void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, - bool *commit, bool slab) { - extent_t *extent; - rtree_ctx_t rtree_ctx_fallback; - rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - size_t size, alloc_size, leadsize, trailsize; - +extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, + bool locked, void *new_addr, size_t usize, size_t pad, size_t alignment, + bool *zero, bool *commit) { + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, locked ? 1 : 0); if (locked) { - malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); + malloc_mutex_assert_owner(tsdn, &extents->mtx); } - assert(new_addr == NULL || !slab); - assert(pad == 0 || !slab); assert(alignment > 0); if (config_debug && new_addr != NULL) { - extent_t *prev; - /* * Non-NULL new_addr has two use cases: * @@ -435,21 +540,19 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, assert(PAGE_ADDR2BASE(new_addr) == new_addr); assert(pad == 0); assert(alignment <= PAGE); - prev = extent_lookup(tsdn, (void *)((uintptr_t)new_addr - PAGE), - false); - assert(prev == NULL || extent_past_get(prev) == new_addr); } - size = usize + pad; - alloc_size = size + PAGE_CEILING(alignment) - PAGE; + size_t size = usize + pad; + size_t alloc_size = size + PAGE_CEILING(alignment) - PAGE; /* Beware size_t wrap-around. */ if (alloc_size < usize) { return NULL; } if (!locked) { - malloc_mutex_lock(tsdn, &arena->extents_mtx); + malloc_mutex_lock(tsdn, &extents->mtx); } extent_hooks_assure_initialized(arena, r_extent_hooks); + extent_t *extent; if (new_addr != NULL) { rtree_elm_t *elm; @@ -462,8 +565,8 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, assert(extent_base_get(extent) == new_addr); if (extent_arena_get(extent) != arena || extent_size_get(extent) < size || - extent_active_get(extent) || - extent_retained_get(extent) == cache) { + extent_state_get(extent) != + extents_state_get(extents)) { extent = NULL; } } @@ -472,23 +575,21 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent = NULL; } } else { - extent = extent_first_best_fit(tsdn, arena, extent_heaps, + extent = extents_first_best_fit_locked(tsdn, arena, extents, alloc_size); } if (extent == NULL) { if (!locked) { - malloc_mutex_unlock(tsdn, &arena->extents_mtx); + malloc_mutex_unlock(tsdn, &extents->mtx); } return NULL; } - extent_heaps_remove(tsdn, extent_heaps, extent); - arena_extent_cache_maybe_remove(tsdn, arena, extent, cache); - leadsize = ALIGNMENT_CEILING((uintptr_t)extent_base_get(extent), - PAGE_CEILING(alignment)) - (uintptr_t)extent_base_get(extent); - assert(new_addr == NULL || leadsize == 0); - assert(extent_size_get(extent) >= leadsize + size); - trailsize = extent_size_get(extent) - leadsize - size; + extent_activate_locked(tsdn, arena, extents, extent); + if (!locked) { + malloc_mutex_unlock(tsdn, &extents->mtx); + } + if (extent_zeroed_get(extent)) { *zero = true; } @@ -496,6 +597,21 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, *commit = true; } + return extent; +} + +static extent_t * +extent_recycle_split(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, + void *new_addr, size_t usize, size_t pad, size_t alignment, + extent_t *extent) { + size_t size = usize + pad; + size_t leadsize = ALIGNMENT_CEILING((uintptr_t)extent_base_get(extent), + PAGE_CEILING(alignment)) - (uintptr_t)extent_base_get(extent); + assert(new_addr == NULL || leadsize == 0); + assert(extent_size_get(extent) >= leadsize + size); + size_t trailsize = extent_size_get(extent) - leadsize - size; + /* Split the lead. */ if (leadsize != 0) { extent_t *lead = extent; @@ -504,14 +620,11 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, trailsize); if (extent == NULL) { extent_deregister(tsdn, lead); - extent_leak(tsdn, arena, r_extent_hooks, cache, lead); - if (!locked) { - malloc_mutex_unlock(tsdn, &arena->extents_mtx); - } + extents_leak(tsdn, arena, r_extent_hooks, extents, + lead); return NULL; } - extent_heaps_insert(tsdn, extent_heaps, lead); - arena_extent_cache_maybe_insert(tsdn, arena, lead, cache); + extent_deactivate(tsdn, arena, extents, lead); } /* Split the trail. */ @@ -520,15 +633,11 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, r_extent_hooks, extent, size, usize, trailsize, trailsize); if (trail == NULL) { extent_deregister(tsdn, extent); - extent_leak(tsdn, arena, r_extent_hooks, cache, + extents_leak(tsdn, arena, r_extent_hooks, extents, extent); - if (!locked) { - malloc_mutex_unlock(tsdn, &arena->extents_mtx); - } return NULL; } - extent_heaps_insert(tsdn, extent_heaps, trail); - arena_extent_cache_maybe_insert(tsdn, arena, trail, cache); + extent_deactivate(tsdn, arena, extents, trail); } else if (leadsize == 0) { /* * Splitting causes usize to be set as a side effect, but no @@ -537,14 +646,38 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_usize_set(extent, usize); } + return extent; +} + +static extent_t * +extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, + extents_t *extents, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool *commit, bool slab) { + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + assert(new_addr == NULL || !slab); + assert(pad == 0 || !slab); + + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + + extent_t *extent = extent_recycle_extract(tsdn, arena, r_extent_hooks, + rtree_ctx, extents, false, new_addr, usize, pad, alignment, zero, + commit); + if (extent == NULL) { + return NULL; + } + + extent = extent_recycle_split(tsdn, arena, r_extent_hooks, rtree_ctx, + extents, new_addr, usize, pad, alignment, extent); + if (extent == NULL) { + return NULL; + } + if (*commit && !extent_committed_get(extent)) { if (extent_commit_wrapper(tsdn, arena, r_extent_hooks, extent, 0, extent_size_get(extent))) { - if (!locked) { - malloc_mutex_unlock(tsdn, &arena->extents_mtx); - } - extent_record(tsdn, arena, r_extent_hooks, extent_heaps, - cache, extent); + extent_record(tsdn, arena, r_extent_hooks, extents, + extent); return NULL; } extent_zeroed_set(extent, true); @@ -553,16 +686,12 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, if (pad != 0) { extent_addr_randomize(tsdn, extent, alignment); } - extent_active_set(extent, true); + assert(extent_state_get(extent) == extent_state_active); if (slab) { extent_slab_set(extent, slab); extent_interior_register(tsdn, rtree_ctx, extent); } - if (!locked) { - malloc_mutex_unlock(tsdn, &arena->extents_mtx); - } - if (*zero) { if (!extent_zeroed_get(extent)) { memset(extent_addr_get(extent), 0, @@ -616,37 +745,17 @@ extent_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, return NULL; } -static extent_t * -extent_alloc_cache_impl(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, bool locked, void *new_addr, size_t usize, - size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) { - extent_t *extent; - - assert(usize + pad != 0); - assert(alignment != 0); - - extent = extent_recycle(tsdn, arena, r_extent_hooks, - arena->extents_cached, locked, true, new_addr, usize, pad, - alignment, zero, commit, slab); - return extent; -} - -extent_t * -extent_alloc_cache_locked(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) { - malloc_mutex_assert_owner(tsdn, &arena->extents_mtx); - - return extent_alloc_cache_impl(tsdn, arena, r_extent_hooks, true, - new_addr, usize, pad, alignment, zero, commit, slab); -} - extent_t * extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) { - return extent_alloc_cache_impl(tsdn, arena, r_extent_hooks, false, - new_addr, usize, pad, alignment, zero, commit, slab); + assert(usize + pad != 0); + assert(alignment != 0); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + + return extent_recycle(tsdn, arena, r_extent_hooks, + &arena->extents_cached, new_addr, usize, pad, alignment, zero, + commit, slab); } static void * @@ -679,16 +788,6 @@ extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, size_t size, alignment, zero, commit); } -static void -extent_retain(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extent_t *extent) { - if (config_stats) { - arena->stats.retained += extent_size_get(extent); - } - extent_record(tsdn, arena, r_extent_hooks, arena->extents_retained, - false, extent); -} - /* * If virtual memory is retained, create increasingly larger extents from which * to split requested extents in order to limit the total number of disjoint @@ -728,16 +827,17 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, ptr = extent_alloc_core(tsdn, arena, new_addr, alloc_size, PAGE, &zeroed, &committed, arena->dss_prec); extent_init(extent, arena, ptr, alloc_size, alloc_size, - arena_extent_sn_next(arena), false, zeroed, committed, false); + arena_extent_sn_next(arena), extent_state_retained, zeroed, + committed, false); if (ptr == NULL || extent_register(tsdn, extent)) { extent_dalloc(tsdn, arena, extent); return NULL; } /* - * Set the extent as active *after registration so that no gprof-related + * Set the extent as active *after registration so that no gdump-related * accounting occurs during registration. */ - extent_active_set(extent, true); + extent_state_set(extent, extent_state_active); leadsize = ALIGNMENT_CEILING((uintptr_t)ptr, PAGE_CEILING(alignment)) - (uintptr_t)ptr; @@ -758,10 +858,11 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, leadsize, leadsize, size + trailsize, usize + trailsize); if (extent == NULL) { extent_deregister(tsdn, lead); - extent_leak(tsdn, arena, r_extent_hooks, false, lead); + extents_leak(tsdn, arena, r_extent_hooks, false, lead); return NULL; } - extent_retain(tsdn, arena, r_extent_hooks, lead); + extent_record(tsdn, arena, r_extent_hooks, + &arena->extents_retained, lead); } /* Split the trail. */ @@ -770,10 +871,12 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, r_extent_hooks, extent, size, usize, trailsize, trailsize); if (trail == NULL) { extent_deregister(tsdn, extent); - extent_leak(tsdn, arena, r_extent_hooks, false, extent); + extents_leak(tsdn, arena, r_extent_hooks, + &arena->extents_retained, extent); return NULL; } - extent_retain(tsdn, arena, r_extent_hooks, trail); + extent_record(tsdn, arena, r_extent_hooks, + &arena->extents_retained, trail); } else if (leadsize == 0) { /* * Splitting causes usize to be set as a side effect, but no @@ -785,15 +888,16 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, if (*commit && !extent_committed_get(extent)) { if (extent_commit_wrapper(tsdn, arena, r_extent_hooks, extent, 0, extent_size_get(extent))) { - extent_retain(tsdn, arena, r_extent_hooks, extent); + extent_record(tsdn, arena, r_extent_hooks, + &arena->extents_retained, extent); return NULL; } extent_zeroed_set(extent, true); } if (config_prof) { - /* Adjust gprof stats now that extent is final size. */ - extent_gprof_add(tsdn, extent); + /* Adjust gdump stats now that extent is final size. */ + extent_gdump_add(tsdn, extent); } if (pad != 0) { extent_addr_randomize(tsdn, extent, alignment); @@ -837,15 +941,11 @@ extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, assert(alignment != 0); extent = extent_recycle(tsdn, arena, r_extent_hooks, - arena->extents_retained, false, false, new_addr, usize, pad, - alignment, zero, commit, slab); + &arena->extents_retained, new_addr, usize, pad, alignment, zero, + commit, slab); if (extent != NULL) { - if (config_stats) { - size_t size = usize + pad; - arena->stats.retained -= size; - } if (config_prof) { - extent_gprof_add(tsdn, extent); + extent_gdump_add(tsdn, extent); } } if (!config_munmap && extent == NULL) { @@ -882,12 +982,14 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, return NULL; } extent_init(extent, arena, addr, size, usize, - arena_extent_sn_next(arena), true, zero, commit, slab); + arena_extent_sn_next(arena), extent_state_active, zero, commit, + slab); if (pad != 0) { extent_addr_randomize(tsdn, extent, alignment); } if (extent_register(tsdn, extent)) { - extent_leak(tsdn, arena, r_extent_hooks, false, extent); + extents_leak(tsdn, arena, r_extent_hooks, + &arena->extents_retained, extent); return NULL; } @@ -898,12 +1000,12 @@ extent_t * extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab) { - extent_t *extent; + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); extent_hooks_assure_initialized(arena, r_extent_hooks); - extent = extent_alloc_retained(tsdn, arena, r_extent_hooks, new_addr, - usize, pad, alignment, zero, commit, slab); + extent_t *extent = extent_alloc_retained(tsdn, arena, r_extent_hooks, + new_addr, usize, pad, alignment, zero, commit, slab); if (extent == NULL) { extent = extent_alloc_wrapper_hard(tsdn, arena, r_extent_hooks, new_addr, usize, pad, alignment, zero, commit, slab); @@ -917,96 +1019,103 @@ extent_can_coalesce(const extent_t *a, const extent_t *b) { if (extent_arena_get(a) != extent_arena_get(b)) { return false; } - if (extent_active_get(a) != extent_active_get(b)) { + if (extent_state_get(a) != extent_state_get(b)) { return false; } if (extent_committed_get(a) != extent_committed_get(b)) { return false; } - if (extent_retained_get(a) != extent_retained_get(b)) { - return false; - } return true; } -static void +static bool extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b, - extent_heap_t extent_heaps[NPSIZES+1], bool cache) { + extents_t *extents) { if (!extent_can_coalesce(a, b)) { - return; + return true; } + assert(extent_arena_get(a) == arena); + assert(extent_arena_get(b) == arena); - extent_heaps_remove(tsdn, extent_heaps, a); - extent_heaps_remove(tsdn, extent_heaps, b); - - arena_extent_cache_maybe_remove(tsdn, extent_arena_get(a), a, cache); - arena_extent_cache_maybe_remove(tsdn, extent_arena_get(b), b, cache); + extent_activate_locked(tsdn, arena, extents, a); + extent_activate_locked(tsdn, arena, extents, b); - if (extent_merge_wrapper(tsdn, arena, r_extent_hooks, a, b)) { - extent_heaps_insert(tsdn, extent_heaps, a); - extent_heaps_insert(tsdn, extent_heaps, b); - arena_extent_cache_maybe_insert(tsdn, extent_arena_get(a), a, - cache); - arena_extent_cache_maybe_insert(tsdn, extent_arena_get(b), b, - cache); - return; + malloc_mutex_unlock(tsdn, &extents->mtx); + bool err = extent_merge_wrapper(tsdn, arena, r_extent_hooks, a, b); + malloc_mutex_lock(tsdn, &extents->mtx); + extent_deactivate_locked(tsdn, arena, extents, a); + if (err) { + extent_deactivate_locked(tsdn, arena, extents, b); + return true; } - extent_heaps_insert(tsdn, extent_heaps, a); - arena_extent_cache_maybe_insert(tsdn, extent_arena_get(a), a, cache); + return false; } static void extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extent_heap_t extent_heaps[NPSIZES+1], bool cache, extent_t *extent) { + extents_t *extents, extent_t *extent) { extent_t *prev, *next; rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - assert(!cache || !extent_zeroed_get(extent)); + assert(extents_state_get(extents) != extent_state_dirty || + !extent_zeroed_get(extent)); - malloc_mutex_lock(tsdn, &arena->extents_mtx); + malloc_mutex_lock(tsdn, &extents->mtx); extent_hooks_assure_initialized(arena, r_extent_hooks); extent_usize_set(extent, 0); - extent_active_set(extent, false); - extent_zeroed_set(extent, !cache && extent_zeroed_get(extent)); if (extent_slab_get(extent)) { extent_interior_deregister(tsdn, rtree_ctx, extent); extent_slab_set(extent, false); } assert(extent_lookup(tsdn, extent_base_get(extent), true) == extent); - extent_heaps_insert(tsdn, extent_heaps, extent); - arena_extent_cache_maybe_insert(tsdn, arena, extent, cache); + extent_deactivate_locked(tsdn, arena, extents, extent); - /* Try to coalesce forward. */ - next = rtree_read(tsdn, &extents_rtree, rtree_ctx, - (uintptr_t)extent_past_get(extent), false); - if (next != NULL) { - extent_try_coalesce(tsdn, arena, r_extent_hooks, extent, next, - extent_heaps, cache); - } + /* + * Continue attempting to coalesce until failure, to protect against + * races with other threads that are thwarted by this one. + */ + bool coalesced; + do { + coalesced = false; + + /* Try to coalesce forward. */ + next = rtree_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)extent_past_get(extent), false); + if (next != NULL) { + coalesced = !extent_try_coalesce(tsdn, arena, + r_extent_hooks, extent, next, extents); + } - /* Try to coalesce backward. */ - prev = rtree_read(tsdn, &extents_rtree, rtree_ctx, - (uintptr_t)extent_before_get(extent), false); - if (prev != NULL) { - extent_try_coalesce(tsdn, arena, r_extent_hooks, prev, extent, - extent_heaps, cache); - } + /* Try to coalesce backward. */ + prev = rtree_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)extent_before_get(extent), false); + if (prev != NULL) { + coalesced = !extent_try_coalesce(tsdn, arena, + r_extent_hooks, prev, extent, extents); + if (coalesced) { + extent = prev; + } + } + } while (coalesced); - malloc_mutex_unlock(tsdn, &arena->extents_mtx); + malloc_mutex_unlock(tsdn, &extents->mtx); } void extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + if (extent_register(tsdn, extent)) { - extent_leak(tsdn, arena, &extent_hooks, false, extent); + extents_leak(tsdn, arena, &extent_hooks, + &arena->extents_retained, extent); return; } extent_dalloc_wrapper(tsdn, arena, &extent_hooks, extent); @@ -1017,11 +1126,12 @@ extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { assert(extent_base_get(extent) != NULL); assert(extent_size_get(extent) != 0); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); extent_addr_set(extent, extent_base_get(extent)); extent_zeroed_set(extent, false); - extent_record(tsdn, arena, r_extent_hooks, arena->extents_cached, true, + extent_record(tsdn, arena, r_extent_hooks, &arena->extents_cached, extent); } @@ -1048,15 +1158,12 @@ extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, assert(extent_base_get(extent) != NULL); assert(extent_size_get(extent) != 0); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); extent_addr_set(extent, extent_base_get(extent)); extent_hooks_assure_initialized(arena, r_extent_hooks); - /* - * Try to deallocate. Deregister first to avoid a race with other - * allocating threads, and reregister if deallocation fails. - */ - extent_deregister(tsdn, extent); + /* Try to deallocate. */ if (*r_extent_hooks == &extent_hooks_default) { /* Call directly to propagate tsdn. */ err = extent_dalloc_default_impl(extent_base_get(extent), @@ -1078,14 +1185,20 @@ extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { - bool zeroed; + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + /* + * Deregister first to avoid a race with other allocating threads, and + * reregister if deallocation fails. + */ + extent_deregister(tsdn, extent); if (!extent_dalloc_wrapper_try(tsdn, arena, r_extent_hooks, extent)) { return; } extent_reregister(tsdn, extent); /* Try to decommit; purge if that fails. */ + bool zeroed; if (!extent_committed_get(extent)) { zeroed = true; } else if (!extent_decommit_wrapper(tsdn, arena, r_extent_hooks, extent, @@ -1106,15 +1219,12 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, } extent_zeroed_set(extent, zeroed); - if (config_stats) { - arena->stats.retained += extent_size_get(extent); - } if (config_prof) { - extent_gprof_sub(tsdn, extent); + extent_gdump_sub(tsdn, extent); } - extent_record(tsdn, arena, r_extent_hooks, arena->extents_retained, - false, extent); + extent_record(tsdn, arena, r_extent_hooks, &arena->extents_retained, + extent); } static bool @@ -1130,10 +1240,10 @@ bool extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { - bool err; + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); extent_hooks_assure_initialized(arena, r_extent_hooks); - err = ((*r_extent_hooks)->commit == NULL || + bool err = ((*r_extent_hooks)->commit == NULL || (*r_extent_hooks)->commit(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), offset, length, arena_ind_get(arena))); extent_committed_set(extent, extent_committed_get(extent) || !err); @@ -1153,11 +1263,11 @@ bool extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { - bool err; + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); extent_hooks_assure_initialized(arena, r_extent_hooks); - err = ((*r_extent_hooks)->decommit == NULL || + bool err = ((*r_extent_hooks)->decommit == NULL || (*r_extent_hooks)->decommit(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), offset, length, arena_ind_get(arena))); @@ -1184,6 +1294,8 @@ bool extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + extent_hooks_assure_initialized(arena, r_extent_hooks); return ((*r_extent_hooks)->purge_lazy == NULL || (*r_extent_hooks)->purge_lazy(*r_extent_hooks, @@ -1210,6 +1322,8 @@ bool extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + extent_hooks_assure_initialized(arena, r_extent_hooks); return ((*r_extent_hooks)->purge_forced == NULL || (*r_extent_hooks)->purge_forced(*r_extent_hooks, @@ -1231,13 +1345,14 @@ extent_t * extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a, size_t usize_a, size_t size_b, size_t usize_b) { + assert(extent_size_get(extent) == size_a + size_b); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + extent_t *trail; rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_elm_t *lead_elm_a, *lead_elm_b, *trail_elm_a, *trail_elm_b; - assert(extent_size_get(extent) == size_a + size_b); - extent_hooks_assure_initialized(arena, r_extent_hooks); if ((*r_extent_hooks)->split == NULL) { @@ -1253,7 +1368,7 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_t lead; extent_init(&lead, arena, extent_addr_get(extent), size_a, - usize_a, extent_sn_get(extent), extent_active_get(extent), + usize_a, extent_sn_get(extent), extent_state_get(extent), extent_zeroed_get(extent), extent_committed_get(extent), extent_slab_get(extent)); @@ -1265,7 +1380,7 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) + size_a), size_b, usize_b, extent_sn_get(extent), - extent_active_get(extent), extent_zeroed_get(extent), + extent_state_get(extent), extent_zeroed_get(extent), extent_committed_get(extent), extent_slab_get(extent)); if (extent_rtree_acquire(tsdn, rtree_ctx, trail, false, true, &trail_elm_a, &trail_elm_b)) { @@ -1323,10 +1438,7 @@ extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b) { - bool err; - rtree_ctx_t rtree_ctx_fallback; - rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); extent_hooks_assure_initialized(arena, r_extent_hooks); @@ -1334,6 +1446,7 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, return true; } + bool err; if (*r_extent_hooks == &extent_hooks_default) { /* Call directly to propagate tsdn. */ err = extent_merge_default_impl(extent_base_get(a), @@ -1354,6 +1467,9 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, * owned, so the following code uses decomposed helper functions rather * than extent_{,de}register() to do things in the right order. */ + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; extent_rtree_acquire(tsdn, rtree_ctx, a, true, false, &a_elm_a, &a_elm_b); extent_rtree_acquire(tsdn, rtree_ctx, b, true, false, &b_elm_a, diff --git a/src/extent_dss.c b/src/extent_dss.c index ed4140e7..a3cfab26 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -143,7 +143,7 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, if (gap_size != 0) { extent_init(gap, arena, gap_addr, gap_size, gap_size, arena_extent_sn_next(arena), - false, false, true, false); + extent_state_active, false, true, false); } dss_next = (void *)((uintptr_t)ret + size); if ((uintptr_t)ret < (uintptr_t)max_cur || @@ -180,7 +180,8 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, extent_t extent; extent_init(&extent, arena, ret, size, - size, 0, true, false, true, false); + size, 0, extent_state_active, false, + true, false); if (extent_purge_forced_wrapper(tsdn, arena, &extent_hooks, &extent, 0, size)) { diff --git a/src/large.c b/src/large.c index 6458d81a..bfe2f714 100644 --- a/src/large.c +++ b/src/large.c @@ -40,8 +40,7 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, /* Insert extent into large. */ malloc_mutex_lock(tsdn, &arena->large_mtx); - ql_elm_new(extent, ql_link); - ql_tail_insert(&arena->large, extent, ql_link); + extent_list_append(&arena->large, extent); malloc_mutex_unlock(tsdn, &arena->large_mtx); if (config_prof && arena_prof_accum(tsdn, arena, usize)) { prof_idump(tsdn); @@ -138,19 +137,19 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, bool zero) { arena_t *arena = extent_arena_get(extent); size_t oldusize = extent_usize_get(extent); - bool is_zeroed_trail = false; extent_hooks_t *extent_hooks = extent_hooks_get(arena); size_t trailsize = usize - extent_usize_get(extent); - extent_t *trail; if (extent_hooks->merge == NULL) { return true; } - if ((trail = arena_extent_cache_alloc(tsdn, arena, &extent_hooks, - extent_past_get(extent), trailsize, CACHELINE, &is_zeroed_trail)) == - NULL) { - bool commit = true; + bool is_zeroed_trail = false; + bool commit = true; + extent_t *trail; + if ((trail = extent_alloc_cache(tsdn, arena, &extent_hooks, + extent_past_get(extent), trailsize, 0, CACHELINE, &is_zeroed_trail, + &commit, false)) == NULL) { if ((trail = extent_alloc_wrapper(tsdn, arena, &extent_hooks, extent_past_get(extent), trailsize, 0, CACHELINE, &is_zeroed_trail, &commit, false)) == NULL) { @@ -291,32 +290,39 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, * independent of these considerations. */ static void -large_dalloc_impl(tsdn_t *tsdn, extent_t *extent, bool junked_locked) { - arena_t *arena; - - arena = extent_arena_get(extent); +large_dalloc_prep_impl(tsdn_t *tsdn, arena_t *arena, extent_t *extent, + bool junked_locked) { malloc_mutex_lock(tsdn, &arena->large_mtx); - ql_remove(&arena->large, extent, ql_link); + extent_list_remove(&arena->large, extent); malloc_mutex_unlock(tsdn, &arena->large_mtx); if (!junked_locked) { large_dalloc_maybe_junk(extent_addr_get(extent), extent_usize_get(extent)); } - arena_extent_dalloc_large(tsdn, arena, extent, junked_locked); + arena_extent_dalloc_large_prep(tsdn, arena, extent, junked_locked); +} - if (!junked_locked) { - arena_decay_tick(tsdn, arena); - } +static void +large_dalloc_finish_impl(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { + arena_extent_dalloc_large_finish(tsdn, arena, extent); } void -large_dalloc_junked_locked(tsdn_t *tsdn, extent_t *extent) { - large_dalloc_impl(tsdn, extent, true); +large_dalloc_prep_junked_locked(tsdn_t *tsdn, extent_t *extent) { + large_dalloc_prep_impl(tsdn, extent_arena_get(extent), extent, true); +} + +void +large_dalloc_finish(tsdn_t *tsdn, extent_t *extent) { + large_dalloc_finish_impl(tsdn, extent_arena_get(extent), extent); } void large_dalloc(tsdn_t *tsdn, extent_t *extent) { - large_dalloc_impl(tsdn, extent, false); + arena_t *arena = extent_arena_get(extent); + large_dalloc_prep_impl(tsdn, arena, extent, false); + large_dalloc_finish_impl(tsdn, arena, extent); + arena_decay_tick(tsdn, arena); } size_t diff --git a/src/tcache.c b/src/tcache.c index 76277f06..94c45707 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -170,17 +170,15 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, void tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, unsigned rem, tcache_t *tcache) { - arena_t *arena; - void *ptr; - unsigned i, nflush, ndeferred; bool merged_stats = false; assert(binind < nhbins); assert(rem <= tbin->ncached); - arena = arena_choose(tsd, NULL); + arena_t *arena = arena_choose(tsd, NULL); assert(arena != NULL); - for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) { + unsigned nflush = tbin->ncached - rem; + while (nflush > 0) { /* Lock the arena associated with the first object. */ extent_t *extent = iealloc(tsd_tsdn(tsd), *(tbin->avail - 1)); arena_t *locked_arena = extent_arena_get(extent); @@ -189,7 +187,17 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, if (config_prof) { idump = false; } + malloc_mutex_lock(tsd_tsdn(tsd), &locked_arena->lock); + for (unsigned i = 0; i < nflush; i++) { + void *ptr = *(tbin->avail - 1 - i); + assert(ptr != NULL); + extent = iealloc(tsd_tsdn(tsd), ptr); + if (extent_arena_get(extent) == locked_arena) { + large_dalloc_prep_junked_locked(tsd_tsdn(tsd), + extent); + } + } if ((config_prof || config_stats) && locked_arena == arena) { if (config_prof) { idump = arena_prof_accum_locked(arena, @@ -205,14 +213,15 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, tbin->tstats.nrequests = 0; } } - ndeferred = 0; - for (i = 0; i < nflush; i++) { - ptr = *(tbin->avail - 1 - i); + malloc_mutex_unlock(tsd_tsdn(tsd), &locked_arena->lock); + + unsigned ndeferred = 0; + for (unsigned i = 0; i < nflush; i++) { + void *ptr = *(tbin->avail - 1 - i); assert(ptr != NULL); extent = iealloc(tsd_tsdn(tsd), ptr); if (extent_arena_get(extent) == locked_arena) { - large_dalloc_junked_locked(tsd_tsdn(tsd), - extent); + large_dalloc_finish(tsd_tsdn(tsd), extent); } else { /* * This object was allocated via a different @@ -224,12 +233,12 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, ndeferred++; } } - malloc_mutex_unlock(tsd_tsdn(tsd), &locked_arena->lock); if (config_prof && idump) { prof_idump(tsd_tsdn(tsd)); } arena_decay_ticks(tsd_tsdn(tsd), locked_arena, nflush - ndeferred); + nflush = ndeferred; } if (config_stats && !merged_stats) { /* diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index d2a9bb4f..24c7f526 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -63,7 +63,7 @@ vsalloc(tsdn_t *tsdn, const void *ptr) { if (extent == NULL) { return 0; } - if (!extent_active_get(extent)) { + if (extent_state_get(extent) != extent_state_active) { return 0; } diff --git a/test/unit/slab.c b/test/unit/slab.c index d3b45e80..1f2a260c 100644 --- a/test/unit/slab.c +++ b/test/unit/slab.c @@ -8,8 +8,8 @@ TEST_BEGIN(test_arena_slab_regind) { extent_t slab; const arena_bin_info_t *bin_info = &arena_bin_info[binind]; extent_init(&slab, NULL, mallocx(bin_info->slab_size, - MALLOCX_LG_ALIGN(LG_PAGE)), bin_info->slab_size, 0, 0, true, - false, true, true); + MALLOCX_LG_ALIGN(LG_PAGE)), bin_info->slab_size, 0, 0, + extent_state_active, false, true, true); assert_ptr_not_null(extent_addr_get(&slab), "Unexpected malloc() failure"); for (regind = 0; regind < bin_info->nregs; regind++) { -- GitLab From 767ffa2b5f79d0f8458aceab3e628e27fe7a88dc Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 3 Feb 2017 15:30:42 -0800 Subject: [PATCH 255/544] Fix compute_size_with_overflow(). Fix compute_size_with_overflow() to use a high_bits mask that has the high bits set, rather than the low bits. This regression was introduced by 5154ff32ee8c37bacb6afd8a07b923eb33228357 (Unify the allocation paths). --- src/jemalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index 45e9aea7..af410958 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1521,7 +1521,7 @@ compute_size_with_overflow(dynamic_opts_t *dopts, size_t *size) { */ /* A size_t with its high-half bits all set to 1. */ - const static size_t high_bits = SIZE_T_MAX >> (sizeof(size_t) * 8 / 2); + const static size_t high_bits = SIZE_T_MAX << (sizeof(size_t) * 8 / 2); *size = dopts->item_size * dopts->num_items; -- GitLab From 1bac516aaae4582eb1a6f58ae58fa13c27de95a6 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 3 Feb 2017 15:33:37 -0800 Subject: [PATCH 256/544] Optimize compute_size_with_overflow(). Do not check for overflow unless it is actually a possibility. --- src/jemalloc.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index af410958..48be4a3f 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1362,6 +1362,8 @@ malloc_init_hard(void) { */ typedef struct static_opts_s static_opts_t; struct static_opts_s { + /* Whether or not allocation size may overflow. */ + bool may_overflow; /* Whether or not allocations of size 0 should be treated as size 1. */ bool bump_empty_alloc; /* @@ -1400,6 +1402,7 @@ struct static_opts_s { JEMALLOC_ALWAYS_INLINE_C void static_opts_init(static_opts_t *static_opts) { + static_opts->may_overflow = false; static_opts->bump_empty_alloc = false; static_opts->assert_nonempty_alloc = false; static_opts->null_out_result_on_error = false; @@ -1514,12 +1517,19 @@ imalloc_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd, * *size to the product either way. */ JEMALLOC_ALWAYS_INLINE_C bool -compute_size_with_overflow(dynamic_opts_t *dopts, size_t *size) { +compute_size_with_overflow(bool may_overflow, dynamic_opts_t *dopts, + size_t *size) { /* - * This function is just num_items * item_size, except that we have to - * check for overflow. + * This function is just num_items * item_size, except that we may have + * to check for overflow. */ + if (!may_overflow) { + assert(dopts->num_items == 1); + *size = dopts->item_size; + return false; + } + /* A size_t with its high-half bits all set to 1. */ const static size_t high_bits = SIZE_T_MAX << (sizeof(size_t) * 8 / 2); @@ -1572,8 +1582,8 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { } /* Compute the amount of memory the user wants. */ - bool overflow = compute_size_with_overflow(dopts, &size); - if (unlikely(overflow)) { + if (unlikely(compute_size_with_overflow(sopts->may_overflow, dopts, + &size))) { goto label_oom; } @@ -1843,6 +1853,7 @@ je_calloc(size_t num, size_t size) { static_opts_init(&sopts); dynamic_opts_init(&dopts); + sopts.may_overflow = true; sopts.bump_empty_alloc = true; sopts.null_out_result_on_error = true; sopts.set_errno_on_error = true; -- GitLab From 6737d5f61ee2fa5073bf20a8387e8c261e2a29f8 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 4 Feb 2017 00:43:32 -0800 Subject: [PATCH 257/544] Fix a race in extent_grow_retained(). Set extent as active prior to registration so that other threads can't modify it in the absence of locking. This regression was introduced by d27f29b468ae3e9d2b1da4a9880351d76e5a1662 (Disentangle arena and extent locking.), via non-obvious means. Removal of extents_mtx protection during extent_grow_retained() execution opened up the race, but in the presence of that locking, the code was safe. This resolves #599. --- src/extent.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/extent.c b/src/extent.c index 293b96e5..234be54b 100644 --- a/src/extent.c +++ b/src/extent.c @@ -453,7 +453,7 @@ extent_gdump_sub(tsdn_t *tsdn, const extent_t *extent) { } static bool -extent_register(tsdn_t *tsdn, const extent_t *extent) { +extent_register_impl(tsdn_t *tsdn, const extent_t *extent, bool gdump_add) { rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_elm_t *elm_a, *elm_b; @@ -468,13 +468,23 @@ extent_register(tsdn_t *tsdn, const extent_t *extent) { } extent_rtree_release(tsdn, elm_a, elm_b); - if (config_prof) { + if (config_prof && gdump_add) { extent_gdump_add(tsdn, extent); } return false; } +static bool +extent_register(tsdn_t *tsdn, const extent_t *extent) { + return extent_register_impl(tsdn, extent, true); +} + +static bool +extent_register_no_gdump_add(tsdn_t *tsdn, const extent_t *extent) { + return extent_register_impl(tsdn, extent, false); +} + static void extent_reregister(tsdn_t *tsdn, const extent_t *extent) { bool err = extent_register(tsdn, extent); @@ -827,17 +837,12 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, ptr = extent_alloc_core(tsdn, arena, new_addr, alloc_size, PAGE, &zeroed, &committed, arena->dss_prec); extent_init(extent, arena, ptr, alloc_size, alloc_size, - arena_extent_sn_next(arena), extent_state_retained, zeroed, + arena_extent_sn_next(arena), extent_state_active, zeroed, committed, false); - if (ptr == NULL || extent_register(tsdn, extent)) { + if (ptr == NULL || extent_register_no_gdump_add(tsdn, extent)) { extent_dalloc(tsdn, arena, extent); return NULL; } - /* - * Set the extent as active *after registration so that no gdump-related - * accounting occurs during registration. - */ - extent_state_set(extent, extent_state_active); leadsize = ALIGNMENT_CEILING((uintptr_t)ptr, PAGE_CEILING(alignment)) - (uintptr_t)ptr; -- GitLab From 5177995530557521d330486a3971469e1573d6fc Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 5 Feb 2017 23:59:53 -0800 Subject: [PATCH 258/544] Fix extent_record(). Read adjacent rtree elements while holding element locks, since the extents mutex only protects against relevant like-state extent mutation. Fix management of the 'coalesced' loop state variable to merge forward/backward results, rather than overwriting the result of forward coalescing if attempting to coalesce backward. In practice this caused no correctness issues, but could cause extra iterations in rare cases. These regressions were introduced by d27f29b468ae3e9d2b1da4a9880351d76e5a1662 (Disentangle arena and extent locking.). --- src/extent.c | 51 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/extent.c b/src/extent.c index 234be54b..4a83f694 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1035,12 +1035,9 @@ extent_can_coalesce(const extent_t *a, const extent_t *b) { } static bool -extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b, - extents_t *extents) { - if (!extent_can_coalesce(a, b)) { - return true; - } +extent_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, + extent_t *a, extent_t *b, extents_t *extents) { + assert(extent_can_coalesce(a, b)); assert(extent_arena_get(a) == arena); assert(extent_arena_get(b) == arena); @@ -1062,7 +1059,6 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, static void extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extents_t *extents, extent_t *extent) { - extent_t *prev, *next; rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); @@ -1090,21 +1086,40 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, coalesced = false; /* Try to coalesce forward. */ - next = rtree_read(tsdn, &extents_rtree, rtree_ctx, - (uintptr_t)extent_past_get(extent), false); - if (next != NULL) { - coalesced = !extent_try_coalesce(tsdn, arena, - r_extent_hooks, extent, next, extents); + rtree_elm_t *next_elm = rtree_elm_acquire(tsdn, &extents_rtree, + rtree_ctx, (uintptr_t)extent_past_get(extent), false, + false); + if (next_elm != NULL) { + extent_t *next = rtree_elm_read_acquired(tsdn, + &extents_rtree, next_elm); + /* + * extents->mtx only protects against races for + * like-state extents, so call extent_can_coalesce() + * before releasing the next_elm lock. + */ + bool can_coalesce = (next != NULL && + extent_can_coalesce(extent, next)); + rtree_elm_release(tsdn, &extents_rtree, next_elm); + if (can_coalesce && !extent_coalesce(tsdn, arena, + r_extent_hooks, extent, next, extents)) { + coalesced = true; + } } /* Try to coalesce backward. */ - prev = rtree_read(tsdn, &extents_rtree, rtree_ctx, - (uintptr_t)extent_before_get(extent), false); - if (prev != NULL) { - coalesced = !extent_try_coalesce(tsdn, arena, - r_extent_hooks, prev, extent, extents); - if (coalesced) { + rtree_elm_t *prev_elm = rtree_elm_acquire(tsdn, &extents_rtree, + rtree_ctx, (uintptr_t)extent_before_get(extent), false, + false); + if (prev_elm != NULL) { + extent_t *prev = rtree_elm_read_acquired(tsdn, + &extents_rtree, prev_elm); + bool can_coalesce = (prev != NULL && + extent_can_coalesce(prev, extent)); + rtree_elm_release(tsdn, &extents_rtree, prev_elm); + if (can_coalesce && !extent_coalesce(tsdn, arena, + r_extent_hooks, prev, extent, extents)) { extent = prev; + coalesced = true; } } } while (coalesced); -- GitLab From 3bd6d8e41d524737845949c44bd4961b0930965c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 6 Feb 2017 12:54:41 -0800 Subject: [PATCH 259/544] Conditianalize lg_tcache_max use on JEMALLOC_TCACHE. --- test/unit/decay.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/unit/decay.c b/test/unit/decay.c index 4d172a54..fc8fabcf 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -1,6 +1,10 @@ #include "test/jemalloc_test.h" -const char *malloc_conf = "decay_time:1,lg_tcache_max:0"; +const char *malloc_conf = "decay_time:1" +#ifdef JEMALLOC_TCACHE + ",lg_tcache_max:0" +#endif + ; static nstime_monotonic_t *nstime_monotonic_orig; static nstime_update_t *nstime_update_orig; -- GitLab From 0ecf692726f7d496e105be39772c4a1bfd74c660 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 3 Feb 2017 20:17:47 -0800 Subject: [PATCH 260/544] Optimize a branch out of rtree_read() if !dependent. --- include/jemalloc/internal/rtree_inlines.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 795a88f7..3316ea37 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -348,7 +348,7 @@ rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, rtree_elm_t *elm; elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, dependent, false); - if (elm == NULL) { + if (!dependent && elm == NULL) { return NULL; } -- GitLab From 4a346f55939af4f200121cc4454089592d952f18 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 3 Feb 2017 20:21:56 -0800 Subject: [PATCH 261/544] Replace rtree path cache with LRU cache. Rework rtree_ctx_t to encapsulate an rtree leaf LRU lookup cache rather than a single-path element lookup cache. The replacement is logically much simpler, as well as slightly faster in the fast path case and less prone to degraded performance during non-trivial sequences of lookups. --- include/jemalloc/internal/private_symbols.txt | 2 +- include/jemalloc/internal/rtree_inlines.h | 184 ++++++++---------- include/jemalloc/internal/rtree_structs.h | 24 +-- include/jemalloc/internal/rtree_types.h | 22 ++- 4 files changed, 108 insertions(+), 124 deletions(-) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index d1166b20..8c8653f0 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -419,7 +419,6 @@ rtree_child_read rtree_child_read_hard rtree_child_tryread rtree_clear -rtree_ctx_start_level rtree_delete rtree_elm_acquire rtree_elm_lookup @@ -431,6 +430,7 @@ rtree_elm_witness_acquire rtree_elm_witness_release rtree_elm_write rtree_elm_write_acquired +rtree_leafkey rtree_new rtree_node_alloc rtree_node_dalloc diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 3316ea37..88d6ee00 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -3,8 +3,7 @@ #ifndef JEMALLOC_ENABLE_INLINE unsigned rtree_start_level(const rtree_t *rtree, uintptr_t key); -unsigned rtree_ctx_start_level(const rtree_t *rtree, - const rtree_ctx_t *rtree_ctx, uintptr_t key); +uintptr_t rtree_leafkey(rtree_t *rtree, uintptr_t key); uintptr_t rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level); bool rtree_node_valid(rtree_elm_t *node); @@ -50,31 +49,24 @@ rtree_start_level(const rtree_t *rtree, uintptr_t key) { return start_level; } -JEMALLOC_ALWAYS_INLINE unsigned -rtree_ctx_start_level(const rtree_t *rtree, const rtree_ctx_t *rtree_ctx, - uintptr_t key) { - unsigned start_level; - uintptr_t key_diff; - - /* Compute the difference between old and new lookup keys. */ - key_diff = key ^ rtree_ctx->key; - assert(key_diff != 0); /* Handled in rtree_elm_lookup(). */ - - /* - * Compute the last traversal path element at which the keys' paths - * are the same. - */ - start_level = rtree->start_level[(lg_floor(key_diff) + 1) >> - LG_RTREE_BITS_PER_LEVEL]; - assert(start_level < rtree->height); - return start_level; +JEMALLOC_ALWAYS_INLINE uintptr_t +rtree_leafkey(rtree_t *rtree, uintptr_t key) { + unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR+3); + unsigned cumbits = (rtree->levels[rtree->height-1].cumbits - + rtree->levels[rtree->height-1].bits); + unsigned maskbits = ptrbits - cumbits; + uintptr_t mask = ~((ZU(1) << maskbits) - 1); + return (key & mask); } JEMALLOC_ALWAYS_INLINE uintptr_t rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level) { - return ((key >> ((ZU(1) << (LG_SIZEOF_PTR+3)) - - rtree->levels[level].cumbits)) & ((ZU(1) << - rtree->levels[level].bits) - 1)); + unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR+3); + unsigned cumbits = rtree->levels[level].cumbits; + unsigned shiftbits = ptrbits - cumbits; + unsigned maskbits = rtree->levels[level].bits; + unsigned mask = (ZU(1) << maskbits) - 1; + return ((key >> shiftbits) & mask); } JEMALLOC_ALWAYS_INLINE bool @@ -170,103 +162,89 @@ rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, unsigned level, JEMALLOC_ALWAYS_INLINE rtree_elm_t * rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing) { - uintptr_t subkey; - unsigned start_level; - rtree_elm_t *node; - assert(!dependent || !init_missing); - if (dependent || init_missing) { - if (likely(rtree_ctx->valid)) { - if (key == rtree_ctx->key) { - return rtree_ctx->elms[rtree->height]; - } else { - unsigned no_ctx_start_level = - rtree_start_level(rtree, key); - unsigned ctx_start_level; - - if (likely(no_ctx_start_level <= - rtree_ctx->start_level && (ctx_start_level = - rtree_ctx_start_level(rtree, rtree_ctx, - key)) >= rtree_ctx->start_level)) { - start_level = ctx_start_level; - node = rtree_ctx->elms[ctx_start_level]; - } else { - start_level = no_ctx_start_level; - node = init_missing ? - rtree_subtree_read(tsdn, rtree, - no_ctx_start_level, dependent) : - rtree_subtree_tryread(rtree, - no_ctx_start_level, dependent); - rtree_ctx->start_level = - no_ctx_start_level; - rtree_ctx->elms[no_ctx_start_level] = - node; - } - } - } else { - unsigned no_ctx_start_level = rtree_start_level(rtree, - key); - - start_level = no_ctx_start_level; - node = init_missing ? rtree_subtree_read(tsdn, rtree, - no_ctx_start_level, dependent) : - rtree_subtree_tryread(rtree, no_ctx_start_level, - dependent); - rtree_ctx->valid = true; - rtree_ctx->start_level = no_ctx_start_level; - rtree_ctx->elms[no_ctx_start_level] = node; + /* Search the cache. */ + uintptr_t leafkey = rtree_leafkey(rtree, key); + if (likely(key != 0)) { +#define RTREE_CACHE_CHECK(i) do { \ + if (likely(rtree_ctx->cache[i].leafkey == leafkey)) { \ + rtree_elm_t *leaf = rtree_ctx->cache[i].leaf; \ + if (likely(leaf != NULL)) { \ + /* Reorder. */ \ + memmove(&rtree_ctx->cache[1], \ + &rtree_ctx->cache[0], \ + sizeof(rtree_ctx_cache_elm_t) * i); \ + rtree_ctx->cache[0].leafkey = leafkey; \ + rtree_ctx->cache[0].leaf = leaf; \ + \ + uintptr_t subkey = rtree_subkey(rtree, \ + key, rtree->height-1); \ + return &leaf[subkey]; \ + } \ + } \ +} while (0) + /* Check the MRU cache entry. */ + RTREE_CACHE_CHECK(0); + /* + * Search the remaining cache elements, and on success move the + * matching element to the front. Unroll the first iteration to + * avoid calling memmove() (the compiler typically optimizes it + * into raw moves). + */ + if (RTREE_CTX_NCACHE > 1) { + RTREE_CACHE_CHECK(1); } - rtree_ctx->key = key; - } else { - start_level = rtree_start_level(rtree, key); - node = init_missing ? rtree_subtree_read(tsdn, rtree, - start_level, dependent) : rtree_subtree_tryread(rtree, - start_level, dependent); + for (unsigned i = 2; i < RTREE_CTX_NCACHE; i++) { + RTREE_CACHE_CHECK(i); + } +#undef RTREE_CACHE_CHECK } + unsigned start_level = rtree_start_level(rtree, key); + rtree_elm_t *node = init_missing ? rtree_subtree_read(tsdn, rtree, + start_level, dependent) : rtree_subtree_tryread(rtree, start_level, + dependent); + #define RTREE_GET_BIAS (RTREE_HEIGHT_MAX - rtree->height) switch (start_level + RTREE_GET_BIAS) { #define RTREE_GET_SUBTREE(level) \ - case level: \ + case level: { \ assert(level < (RTREE_HEIGHT_MAX-1)); \ if (!dependent && unlikely(!rtree_node_valid(node))) { \ - if (init_missing) { \ - rtree_ctx->valid = false; \ - } \ return NULL; \ } \ - subkey = rtree_subkey(rtree, key, level - \ + uintptr_t subkey = rtree_subkey(rtree, key, level - \ RTREE_GET_BIAS); \ node = init_missing ? rtree_child_read(tsdn, rtree, \ &node[subkey], level - RTREE_GET_BIAS, dependent) : \ rtree_child_tryread(&node[subkey], dependent); \ - if (dependent || init_missing) { \ - rtree_ctx->elms[level - RTREE_GET_BIAS + 1] = \ - node; \ - } \ - /* Fall through. */ + /* Fall through. */ \ + } #define RTREE_GET_LEAF(level) \ - case level: \ + case level: { \ assert(level == (RTREE_HEIGHT_MAX-1)); \ if (!dependent && unlikely(!rtree_node_valid(node))) { \ - if (init_missing) { \ - rtree_ctx->valid = false; \ - } \ return NULL; \ } \ - subkey = rtree_subkey(rtree, key, level - \ - RTREE_GET_BIAS); \ /* \ * node is a leaf, so it contains values rather than \ * child pointers. \ */ \ - node = &node[subkey]; \ - if (dependent || init_missing) { \ - rtree_ctx->elms[level - RTREE_GET_BIAS + 1] = \ - node; \ + if (likely(key != 0)) { \ + if (RTREE_CTX_NCACHE > 1) { \ + memmove(&rtree_ctx->cache[1], \ + &rtree_ctx->cache[0], \ + sizeof(rtree_ctx_cache_elm_t) * \ + (RTREE_CTX_NCACHE-1)); \ + } \ + rtree_ctx->cache[0].leafkey = leafkey; \ + rtree_ctx->cache[0].leaf = node; \ } \ - return node; + uintptr_t subkey = rtree_subkey(rtree, key, level - \ + RTREE_GET_BIAS); \ + return &node[subkey]; \ + } #if RTREE_HEIGHT_MAX > 1 RTREE_GET_SUBTREE(0) #endif @@ -365,16 +343,14 @@ rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, if (!dependent && elm == NULL) { return NULL; } - { - extent_t *extent; - void *s; - - do { - extent = rtree_elm_read(elm, false); - /* The least significant bit serves as a lock. */ - s = (void *)((uintptr_t)extent | (uintptr_t)0x1); - } while (atomic_cas_p(&elm->pun, (void *)extent, s)); - } + + extent_t *extent; + void *s; + do { + extent = rtree_elm_read(elm, false); + /* The least significant bit serves as a lock. */ + s = (void *)((uintptr_t)extent | (uintptr_t)0x1); + } while (atomic_cas_p(&elm->pun, (void *)extent, s)); if (config_debug) { rtree_elm_witness_acquire(tsdn, rtree, key, elm); diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h index 5a7a23c7..892156b1 100644 --- a/include/jemalloc/internal/rtree_structs.h +++ b/include/jemalloc/internal/rtree_structs.h @@ -54,22 +54,16 @@ struct rtree_level_s { unsigned cumbits; }; +struct rtree_ctx_cache_elm_s { + uintptr_t leafkey; + rtree_elm_t *leaf; +}; + struct rtree_ctx_s { - /* If false, key/elms have not yet been initialized by a lookup. */ - bool valid; - /* Key that corresponds to the tree path recorded in elms. */ - uintptr_t key; - /* Memoized rtree_start_level(key). */ - unsigned start_level; - /* - * A path through rtree, driven by key. Only elements that could - * actually be used for subsequent lookups are initialized, i.e. if - * start_level = rtree_start_level(key) is non-zero, the first - * start_level elements are uninitialized. The last element contains a - * pointer to the leaf node element that corresponds to key, so that - * exact matches require no tree node offset computation. - */ - rtree_elm_t *elms[RTREE_HEIGHT_MAX + 1]; +#ifndef _MSC_VER + JEMALLOC_ALIGNED(CACHELINE) +#endif + rtree_ctx_cache_elm_t cache[RTREE_CTX_NCACHE]; }; struct rtree_s { diff --git a/include/jemalloc/internal/rtree_types.h b/include/jemalloc/internal/rtree_types.h index 122d5cef..b4ab018d 100644 --- a/include/jemalloc/internal/rtree_types.h +++ b/include/jemalloc/internal/rtree_types.h @@ -12,6 +12,7 @@ typedef struct rtree_elm_s rtree_elm_t; typedef struct rtree_elm_witness_s rtree_elm_witness_t; typedef struct rtree_elm_witness_tsd_s rtree_elm_witness_tsd_t; typedef struct rtree_level_s rtree_level_t; +typedef struct rtree_ctx_cache_elm_s rtree_ctx_cache_elm_t; typedef struct rtree_ctx_s rtree_ctx_t; typedef struct rtree_s rtree_t; @@ -25,11 +26,24 @@ typedef struct rtree_s rtree_t; #define RTREE_HEIGHT_MAX \ ((1U << (LG_SIZEOF_PTR+3)) / RTREE_BITS_PER_LEVEL) +/* + * Number of leafkey/leaf pairs to cache. Each entry supports an entire leaf, + * so the cache hit rate is typically high even with a small number of entries. + * In rare cases extent activity will straddle the boundary between two leaf + * nodes. Furthermore, an arena may use a combination of dss and mmap. Four + * entries covers both of these considerations as long as locality of reference + * is high, and/or total memory usage doesn't exceed the range supported by + * those entries. Note that as memory usage grows past the amount that this + * cache can directly cover, the cache will become less effective if locality of + * reference is low, but the consequence is merely cache misses while traversing + * the tree nodes, and the cache will itself suffer cache misses if made overly + * large, not to mention the cost of linear search. + */ +#define RTREE_CTX_NCACHE 8 + +/* Static initializer for rtree_ctx_t. */ #define RTREE_CTX_INITIALIZER { \ - false, \ - 0, \ - 0, \ - {NULL /* C initializes all trailing elements to NULL. */} \ + {{0, NULL} /* C initializes all trailing elements to NULL. */} \ } /* -- GitLab From c511a44e99a2d92893d028854eabd2cd4b2c1fe1 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 3 Feb 2017 20:12:49 -0800 Subject: [PATCH 262/544] Split rtree_elm_lookup_hard() out of rtree_elm_lookup(). Anything but a hit in the first element of the lookup cache is expensive enough to negate the benefits of inlining. --- include/jemalloc/internal/private_symbols.txt | 1 + include/jemalloc/internal/rtree_externs.h | 2 + include/jemalloc/internal/rtree_inlines.h | 104 +---------------- src/rtree.c | 105 ++++++++++++++++++ 4 files changed, 111 insertions(+), 101 deletions(-) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 8c8653f0..a60634ce 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -422,6 +422,7 @@ rtree_clear rtree_delete rtree_elm_acquire rtree_elm_lookup +rtree_elm_lookup_hard rtree_elm_read rtree_elm_read_acquired rtree_elm_release diff --git a/include/jemalloc/internal/rtree_externs.h b/include/jemalloc/internal/rtree_externs.h index db8e8b12..7fc68fc9 100644 --- a/include/jemalloc/internal/rtree_externs.h +++ b/include/jemalloc/internal/rtree_externs.h @@ -13,6 +13,8 @@ rtree_elm_t *rtree_subtree_read_hard(tsdn_t *tsdn, rtree_t *rtree, unsigned level); rtree_elm_t *rtree_child_read_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level); +rtree_elm_t *rtree_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, + rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); void rtree_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, uintptr_t key, const rtree_elm_t *elm); void rtree_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 88d6ee00..372b7465 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -164,9 +164,8 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing) { assert(!dependent || !init_missing); - /* Search the cache. */ - uintptr_t leafkey = rtree_leafkey(rtree, key); if (likely(key != 0)) { + uintptr_t leafkey = rtree_leafkey(rtree, key); #define RTREE_CACHE_CHECK(i) do { \ if (likely(rtree_ctx->cache[i].leafkey == leafkey)) { \ rtree_elm_t *leaf = rtree_ctx->cache[i].leaf; \ @@ -201,105 +200,8 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, #undef RTREE_CACHE_CHECK } - unsigned start_level = rtree_start_level(rtree, key); - rtree_elm_t *node = init_missing ? rtree_subtree_read(tsdn, rtree, - start_level, dependent) : rtree_subtree_tryread(rtree, start_level, - dependent); - -#define RTREE_GET_BIAS (RTREE_HEIGHT_MAX - rtree->height) - switch (start_level + RTREE_GET_BIAS) { -#define RTREE_GET_SUBTREE(level) \ - case level: { \ - assert(level < (RTREE_HEIGHT_MAX-1)); \ - if (!dependent && unlikely(!rtree_node_valid(node))) { \ - return NULL; \ - } \ - uintptr_t subkey = rtree_subkey(rtree, key, level - \ - RTREE_GET_BIAS); \ - node = init_missing ? rtree_child_read(tsdn, rtree, \ - &node[subkey], level - RTREE_GET_BIAS, dependent) : \ - rtree_child_tryread(&node[subkey], dependent); \ - /* Fall through. */ \ - } -#define RTREE_GET_LEAF(level) \ - case level: { \ - assert(level == (RTREE_HEIGHT_MAX-1)); \ - if (!dependent && unlikely(!rtree_node_valid(node))) { \ - return NULL; \ - } \ - /* \ - * node is a leaf, so it contains values rather than \ - * child pointers. \ - */ \ - if (likely(key != 0)) { \ - if (RTREE_CTX_NCACHE > 1) { \ - memmove(&rtree_ctx->cache[1], \ - &rtree_ctx->cache[0], \ - sizeof(rtree_ctx_cache_elm_t) * \ - (RTREE_CTX_NCACHE-1)); \ - } \ - rtree_ctx->cache[0].leafkey = leafkey; \ - rtree_ctx->cache[0].leaf = node; \ - } \ - uintptr_t subkey = rtree_subkey(rtree, key, level - \ - RTREE_GET_BIAS); \ - return &node[subkey]; \ - } -#if RTREE_HEIGHT_MAX > 1 - RTREE_GET_SUBTREE(0) -#endif -#if RTREE_HEIGHT_MAX > 2 - RTREE_GET_SUBTREE(1) -#endif -#if RTREE_HEIGHT_MAX > 3 - RTREE_GET_SUBTREE(2) -#endif -#if RTREE_HEIGHT_MAX > 4 - RTREE_GET_SUBTREE(3) -#endif -#if RTREE_HEIGHT_MAX > 5 - RTREE_GET_SUBTREE(4) -#endif -#if RTREE_HEIGHT_MAX > 6 - RTREE_GET_SUBTREE(5) -#endif -#if RTREE_HEIGHT_MAX > 7 - RTREE_GET_SUBTREE(6) -#endif -#if RTREE_HEIGHT_MAX > 8 - RTREE_GET_SUBTREE(7) -#endif -#if RTREE_HEIGHT_MAX > 9 - RTREE_GET_SUBTREE(8) -#endif -#if RTREE_HEIGHT_MAX > 10 - RTREE_GET_SUBTREE(9) -#endif -#if RTREE_HEIGHT_MAX > 11 - RTREE_GET_SUBTREE(10) -#endif -#if RTREE_HEIGHT_MAX > 12 - RTREE_GET_SUBTREE(11) -#endif -#if RTREE_HEIGHT_MAX > 13 - RTREE_GET_SUBTREE(12) -#endif -#if RTREE_HEIGHT_MAX > 14 - RTREE_GET_SUBTREE(13) -#endif -#if RTREE_HEIGHT_MAX > 15 - RTREE_GET_SUBTREE(14) -#endif -#if RTREE_HEIGHT_MAX > 16 -# error Unsupported RTREE_HEIGHT_MAX -#endif - RTREE_GET_LEAF(RTREE_HEIGHT_MAX-1) -#undef RTREE_GET_SUBTREE -#undef RTREE_GET_LEAF - default: not_reached(); - } -#undef RTREE_GET_BIAS - not_reached(); + return rtree_elm_lookup_hard(tsdn, rtree, rtree_ctx, key, dependent, + init_missing); } JEMALLOC_INLINE bool diff --git a/src/rtree.c b/src/rtree.c index d760816e..41bce5df 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -158,6 +158,111 @@ rtree_child_read_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, return rtree_node_init(tsdn, rtree, level+1, &elm->child); } +rtree_elm_t * +rtree_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, + uintptr_t key, bool dependent, bool init_missing) { + unsigned start_level = rtree_start_level(rtree, key); + rtree_elm_t *node = init_missing ? rtree_subtree_read(tsdn, rtree, + start_level, dependent) : rtree_subtree_tryread(rtree, start_level, + dependent); + +#define RTREE_GET_BIAS (RTREE_HEIGHT_MAX - rtree->height) + switch (start_level + RTREE_GET_BIAS) { +#define RTREE_GET_SUBTREE(level) \ + case level: { \ + assert(level < (RTREE_HEIGHT_MAX-1)); \ + if (!dependent && unlikely(!rtree_node_valid(node))) { \ + return NULL; \ + } \ + uintptr_t subkey = rtree_subkey(rtree, key, level - \ + RTREE_GET_BIAS); \ + node = init_missing ? rtree_child_read(tsdn, rtree, \ + &node[subkey], level - RTREE_GET_BIAS, dependent) : \ + rtree_child_tryread(&node[subkey], dependent); \ + /* Fall through. */ \ + } +#define RTREE_GET_LEAF(level) \ + case level: { \ + assert(level == (RTREE_HEIGHT_MAX-1)); \ + if (!dependent && unlikely(!rtree_node_valid(node))) { \ + return NULL; \ + } \ + /* \ + * node is a leaf, so it contains values rather than \ + * child pointers. \ + */ \ + if (likely(key != 0)) { \ + if (RTREE_CTX_NCACHE > 1) { \ + memmove(&rtree_ctx->cache[1], \ + &rtree_ctx->cache[0], \ + sizeof(rtree_ctx_cache_elm_t) * \ + (RTREE_CTX_NCACHE-1)); \ + } \ + uintptr_t leafkey = rtree_leafkey(rtree, key); \ + rtree_ctx->cache[0].leafkey = leafkey; \ + rtree_ctx->cache[0].leaf = node; \ + } \ + uintptr_t subkey = rtree_subkey(rtree, key, level - \ + RTREE_GET_BIAS); \ + return &node[subkey]; \ + } +#if RTREE_HEIGHT_MAX > 1 + RTREE_GET_SUBTREE(0) +#endif +#if RTREE_HEIGHT_MAX > 2 + RTREE_GET_SUBTREE(1) +#endif +#if RTREE_HEIGHT_MAX > 3 + RTREE_GET_SUBTREE(2) +#endif +#if RTREE_HEIGHT_MAX > 4 + RTREE_GET_SUBTREE(3) +#endif +#if RTREE_HEIGHT_MAX > 5 + RTREE_GET_SUBTREE(4) +#endif +#if RTREE_HEIGHT_MAX > 6 + RTREE_GET_SUBTREE(5) +#endif +#if RTREE_HEIGHT_MAX > 7 + RTREE_GET_SUBTREE(6) +#endif +#if RTREE_HEIGHT_MAX > 8 + RTREE_GET_SUBTREE(7) +#endif +#if RTREE_HEIGHT_MAX > 9 + RTREE_GET_SUBTREE(8) +#endif +#if RTREE_HEIGHT_MAX > 10 + RTREE_GET_SUBTREE(9) +#endif +#if RTREE_HEIGHT_MAX > 11 + RTREE_GET_SUBTREE(10) +#endif +#if RTREE_HEIGHT_MAX > 12 + RTREE_GET_SUBTREE(11) +#endif +#if RTREE_HEIGHT_MAX > 13 + RTREE_GET_SUBTREE(12) +#endif +#if RTREE_HEIGHT_MAX > 14 + RTREE_GET_SUBTREE(13) +#endif +#if RTREE_HEIGHT_MAX > 15 + RTREE_GET_SUBTREE(14) +#endif +#if RTREE_HEIGHT_MAX > 16 +# error Unsupported RTREE_HEIGHT_MAX +#endif + RTREE_GET_LEAF(RTREE_HEIGHT_MAX-1) +#undef RTREE_GET_SUBTREE +#undef RTREE_GET_LEAF + default: not_reached(); + } +#undef RTREE_GET_BIAS + not_reached(); +} + static int rtree_elm_witness_comp(const witness_t *a, void *oa, const witness_t *b, void *ob) { -- GitLab From cdc240d5019435fcb1a319fdcff6d4dc76b20143 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 3 Feb 2017 19:44:33 -0800 Subject: [PATCH 263/544] Make non-essential inline rtree functions static functions. --- include/jemalloc/internal/private_symbols.txt | 8 -- include/jemalloc/internal/rtree_externs.h | 12 +- include/jemalloc/internal/rtree_inlines.h | 107 ++---------------- src/rtree.c | 77 +++++++++++-- 4 files changed, 85 insertions(+), 119 deletions(-) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index a60634ce..3f29d3fe 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -415,9 +415,6 @@ prof_thread_name_get prof_thread_name_set psz2ind psz2u -rtree_child_read -rtree_child_read_hard -rtree_child_tryread rtree_clear rtree_delete rtree_elm_acquire @@ -435,13 +432,8 @@ rtree_leafkey rtree_new rtree_node_alloc rtree_node_dalloc -rtree_node_valid rtree_read -rtree_start_level rtree_subkey -rtree_subtree_read -rtree_subtree_read_hard -rtree_subtree_tryread rtree_write s2u s2u_compute diff --git a/include/jemalloc/internal/rtree_externs.h b/include/jemalloc/internal/rtree_externs.h index 7fc68fc9..f4f2feb5 100644 --- a/include/jemalloc/internal/rtree_externs.h +++ b/include/jemalloc/internal/rtree_externs.h @@ -7,19 +7,15 @@ typedef rtree_elm_t *(rtree_node_alloc_t)(tsdn_t *, rtree_t *, size_t); extern rtree_node_alloc_t *rtree_node_alloc; typedef void (rtree_node_dalloc_t)(tsdn_t *, rtree_t *, rtree_elm_t *); extern rtree_node_dalloc_t *rtree_node_dalloc; -void rtree_delete(tsdn_t *tsdn, rtree_t *rtree); +void rtree_delete(tsdn_t *tsdn, rtree_t *rtree); #endif -rtree_elm_t *rtree_subtree_read_hard(tsdn_t *tsdn, rtree_t *rtree, - unsigned level); -rtree_elm_t *rtree_child_read_hard(tsdn_t *tsdn, rtree_t *rtree, - rtree_elm_t *elm, unsigned level); rtree_elm_t *rtree_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); -void rtree_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, +void rtree_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, uintptr_t key, const rtree_elm_t *elm); -void rtree_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, +void rtree_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, const rtree_elm_t *elm); -void rtree_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, +void rtree_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, const rtree_elm_t *elm); #endif /* JEMALLOC_INTERNAL_RTREE_EXTERNS_H */ diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 372b7465..86aa8cd1 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -2,53 +2,28 @@ #define JEMALLOC_INTERNAL_RTREE_INLINES_H #ifndef JEMALLOC_ENABLE_INLINE -unsigned rtree_start_level(const rtree_t *rtree, uintptr_t key); uintptr_t rtree_leafkey(rtree_t *rtree, uintptr_t key); -uintptr_t rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level); - -bool rtree_node_valid(rtree_elm_t *node); -rtree_elm_t *rtree_child_tryread(rtree_elm_t *elm, bool dependent); -rtree_elm_t *rtree_child_read(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, - unsigned level, bool dependent); -extent_t *rtree_elm_read(rtree_elm_t *elm, bool dependent); -void rtree_elm_write(rtree_elm_t *elm, const extent_t *extent); -rtree_elm_t *rtree_subtree_tryread(rtree_t *rtree, unsigned level, - bool dependent); -rtree_elm_t *rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, - unsigned level, bool dependent); -rtree_elm_t *rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, +uintptr_t rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level); +extent_t *rtree_elm_read(rtree_elm_t *elm, bool dependent); +void rtree_elm_write(rtree_elm_t *elm, const extent_t *extent); +rtree_elm_t *rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); - -bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, +bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, const extent_t *extent); -extent_t *rtree_read(tsdn_t *tsdn, rtree_t *rtree, - rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent); -rtree_elm_t *rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, +extent_t *rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, + uintptr_t key, bool dependent); +rtree_elm_t *rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); -extent_t *rtree_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, +extent_t *rtree_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm); -void rtree_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, +void rtree_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm, const extent_t *extent); -void rtree_elm_release(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm); -void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, +void rtree_elm_release(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm); +void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_RTREE_C_)) -JEMALLOC_ALWAYS_INLINE unsigned -rtree_start_level(const rtree_t *rtree, uintptr_t key) { - unsigned start_level; - - if (unlikely(key == 0)) { - return rtree->height - 1; - } - - start_level = rtree->start_level[(lg_floor(key) + 1) >> - LG_RTREE_BITS_PER_LEVEL]; - assert(start_level < rtree->height); - return start_level; -} - JEMALLOC_ALWAYS_INLINE uintptr_t rtree_leafkey(rtree_t *rtree, uintptr_t key) { unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR+3); @@ -69,37 +44,6 @@ rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level) { return ((key >> shiftbits) & mask); } -JEMALLOC_ALWAYS_INLINE bool -rtree_node_valid(rtree_elm_t *node) { - return ((uintptr_t)node != (uintptr_t)0); -} - -JEMALLOC_ALWAYS_INLINE rtree_elm_t * -rtree_child_tryread(rtree_elm_t *elm, bool dependent) { - rtree_elm_t *child; - - /* Double-checked read (first read may be stale). */ - child = elm->child; - if (!dependent && !rtree_node_valid(child)) { - child = (rtree_elm_t *)atomic_read_p(&elm->pun); - } - assert(!dependent || child != NULL); - return child; -} - -JEMALLOC_ALWAYS_INLINE rtree_elm_t * -rtree_child_read(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level, - bool dependent) { - rtree_elm_t *child; - - child = rtree_child_tryread(elm, dependent); - if (!dependent && unlikely(!rtree_node_valid(child))) { - child = rtree_child_read_hard(tsdn, rtree, elm, level); - } - assert(!dependent || child != NULL); - return child; -} - JEMALLOC_ALWAYS_INLINE extent_t * rtree_elm_read(rtree_elm_t *elm, bool dependent) { extent_t *extent; @@ -132,33 +76,6 @@ rtree_elm_write(rtree_elm_t *elm, const extent_t *extent) { atomic_write_p(&elm->pun, extent); } -JEMALLOC_ALWAYS_INLINE rtree_elm_t * -rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent) { - rtree_elm_t *subtree; - - /* Double-checked read (first read may be stale). */ - subtree = rtree->levels[level].subtree; - if (!dependent && unlikely(!rtree_node_valid(subtree))) { - subtree = (rtree_elm_t *)atomic_read_p( - &rtree->levels[level].subtree_pun); - } - assert(!dependent || subtree != NULL); - return subtree; -} - -JEMALLOC_ALWAYS_INLINE rtree_elm_t * -rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, unsigned level, - bool dependent) { - rtree_elm_t *subtree; - - subtree = rtree_subtree_tryread(rtree, level, dependent); - if (!dependent && unlikely(!rtree_node_valid(subtree))) { - subtree = rtree_subtree_read_hard(tsdn, rtree, level); - } - assert(!dependent || subtree != NULL); - return subtree; -} - JEMALLOC_ALWAYS_INLINE rtree_elm_t * rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing) { diff --git a/src/rtree.c b/src/rtree.c index 41bce5df..3347340b 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -146,16 +146,77 @@ rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level, return node; } -rtree_elm_t * -rtree_subtree_read_hard(tsdn_t *tsdn, rtree_t *rtree, unsigned level) { - return rtree_node_init(tsdn, rtree, level, - &rtree->levels[level].subtree); +static unsigned +rtree_start_level(const rtree_t *rtree, uintptr_t key) { + unsigned start_level; + + if (unlikely(key == 0)) { + return rtree->height - 1; + } + + start_level = rtree->start_level[(lg_floor(key) + 1) >> + LG_RTREE_BITS_PER_LEVEL]; + assert(start_level < rtree->height); + return start_level; } -rtree_elm_t * -rtree_child_read_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, - unsigned level) { - return rtree_node_init(tsdn, rtree, level+1, &elm->child); +static bool +rtree_node_valid(rtree_elm_t *node) { + return ((uintptr_t)node != (uintptr_t)0); +} + +static rtree_elm_t * +rtree_child_tryread(rtree_elm_t *elm, bool dependent) { + rtree_elm_t *child; + + /* Double-checked read (first read may be stale). */ + child = elm->child; + if (!dependent && !rtree_node_valid(child)) { + child = (rtree_elm_t *)atomic_read_p(&elm->pun); + } + assert(!dependent || child != NULL); + return child; +} + +static rtree_elm_t * +rtree_child_read(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level, + bool dependent) { + rtree_elm_t *child; + + child = rtree_child_tryread(elm, dependent); + if (!dependent && unlikely(!rtree_node_valid(child))) { + child = rtree_node_init(tsdn, rtree, level+1, &elm->child); + } + assert(!dependent || child != NULL); + return child; +} + +static rtree_elm_t * +rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent) { + rtree_elm_t *subtree; + + /* Double-checked read (first read may be stale). */ + subtree = rtree->levels[level].subtree; + if (!dependent && unlikely(!rtree_node_valid(subtree))) { + subtree = (rtree_elm_t *)atomic_read_p( + &rtree->levels[level].subtree_pun); + } + assert(!dependent || subtree != NULL); + return subtree; +} + +static rtree_elm_t * +rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, unsigned level, + bool dependent) { + rtree_elm_t *subtree; + + subtree = rtree_subtree_tryread(rtree, level, dependent); + if (!dependent && unlikely(!rtree_node_valid(subtree))) { + subtree = rtree_node_init(tsdn, rtree, level, + &rtree->levels[level].subtree); + } + assert(!dependent || subtree != NULL); + return subtree; } rtree_elm_t * -- GitLab From ff4db5014e78a3f80e5983dc2313421e7978c792 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 4 Feb 2017 23:08:48 -0800 Subject: [PATCH 264/544] Remove rtree leading 0 bit optimization. A subsequent change instead ignores insignificant high bits. --- include/jemalloc/internal/rtree_structs.h | 35 ++---------- src/rtree.c | 65 +++++------------------ 2 files changed, 16 insertions(+), 84 deletions(-) diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h index 892156b1..713d3000 100644 --- a/include/jemalloc/internal/rtree_structs.h +++ b/include/jemalloc/internal/rtree_structs.h @@ -19,32 +19,6 @@ struct rtree_elm_witness_tsd_s { }; struct rtree_level_s { - /* - * A non-NULL subtree points to a subtree rooted along the hypothetical - * path to the leaf node corresponding to key 0. Depending on what keys - * have been used to store to the tree, an arbitrary combination of - * subtree pointers may remain NULL. - * - * Suppose keys comprise 48 bits, and LG_RTREE_BITS_PER_LEVEL is 4. - * This results in a 3-level tree, and the leftmost leaf can be directly - * accessed via levels[2], the subtree prefixed by 0x0000 (excluding - * 0x00000000) can be accessed via levels[1], and the remainder of the - * tree can be accessed via levels[0]. - * - * levels[0] : [ | 0x0001******** | 0x0002******** | ...] - * - * levels[1] : [ | 0x00000001**** | 0x00000002**** | ... ] - * - * levels[2] : [extent(0x000000000000) | extent(0x000000000001) | ...] - * - * This has practical implications on x64, which currently uses only the - * lower 47 bits of virtual address space in userland, thus leaving - * levels[0] unused and avoiding a level of tree traversal. - */ - union { - void *subtree_pun; - rtree_elm_t *subtree; - }; /* Number of key bits distinguished by this level. */ unsigned bits; /* @@ -68,11 +42,10 @@ struct rtree_ctx_s { struct rtree_s { unsigned height; - /* - * Precomputed table used to convert from the number of leading 0 key - * bits to which subtree level to start at. - */ - unsigned start_level[RTREE_HEIGHT_MAX + 1]; + union { + void *root_pun; + rtree_elm_t *root; + }; rtree_level_t levels[RTREE_HEIGHT_MAX]; malloc_mutex_t init_lock; }; diff --git a/src/rtree.c b/src/rtree.c index 3347340b..fb52cf68 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -1,11 +1,6 @@ #define JEMALLOC_RTREE_C_ #include "jemalloc/internal/jemalloc_internal.h" -static unsigned -hmin(unsigned ha, unsigned hb) { - return (ha < hb ? ha : hb); -} - /* * Only the most significant bits of keys passed to rtree_{read,write}() are * used. @@ -32,32 +27,24 @@ rtree_new(rtree_t *rtree, unsigned bits) { rtree->height = height; + rtree->root_pun = NULL; + /* Root level. */ - rtree->levels[0].subtree = NULL; rtree->levels[0].bits = (height > 1) ? RTREE_BITS_PER_LEVEL : bits_in_leaf; rtree->levels[0].cumbits = rtree->levels[0].bits; /* Interior levels. */ for (i = 1; i < height-1; i++) { - rtree->levels[i].subtree = NULL; rtree->levels[i].bits = RTREE_BITS_PER_LEVEL; rtree->levels[i].cumbits = rtree->levels[i-1].cumbits + RTREE_BITS_PER_LEVEL; } /* Leaf level. */ if (height > 1) { - rtree->levels[height-1].subtree = NULL; rtree->levels[height-1].bits = bits_in_leaf; rtree->levels[height-1].cumbits = bits; } - /* Compute lookup table to be used by rtree_[ctx_]start_level(). */ - for (i = 0; i < RTREE_HEIGHT_MAX; i++) { - rtree->start_level[i] = hmin(RTREE_HEIGHT_MAX - 1 - i, height - - 1); - } - rtree->start_level[RTREE_HEIGHT_MAX] = 0; - malloc_mutex_init(&rtree->init_lock, "rtree", WITNESS_RANK_RTREE); return false; @@ -114,13 +101,8 @@ rtree_delete_subtree(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node, void rtree_delete(tsdn_t *tsdn, rtree_t *rtree) { - unsigned i; - - for (i = 0; i < rtree->height; i++) { - rtree_elm_t *subtree = rtree->levels[i].subtree; - if (subtree != NULL) { - rtree_delete_subtree(tsdn, rtree, subtree, i); - } + if (rtree->root_pun != NULL) { + rtree_delete_subtree(tsdn, rtree, rtree->root, 0); } } #endif @@ -146,20 +128,6 @@ rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level, return node; } -static unsigned -rtree_start_level(const rtree_t *rtree, uintptr_t key) { - unsigned start_level; - - if (unlikely(key == 0)) { - return rtree->height - 1; - } - - start_level = rtree->start_level[(lg_floor(key) + 1) >> - LG_RTREE_BITS_PER_LEVEL]; - assert(start_level < rtree->height); - return start_level; -} - static bool rtree_node_valid(rtree_elm_t *node) { return ((uintptr_t)node != (uintptr_t)0); @@ -192,28 +160,21 @@ rtree_child_read(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level, } static rtree_elm_t * -rtree_subtree_tryread(rtree_t *rtree, unsigned level, bool dependent) { - rtree_elm_t *subtree; - +rtree_subtree_tryread(rtree_t *rtree, bool dependent) { /* Double-checked read (first read may be stale). */ - subtree = rtree->levels[level].subtree; + rtree_elm_t *subtree = rtree->root; if (!dependent && unlikely(!rtree_node_valid(subtree))) { - subtree = (rtree_elm_t *)atomic_read_p( - &rtree->levels[level].subtree_pun); + subtree = (rtree_elm_t *)atomic_read_p(&rtree->root_pun); } assert(!dependent || subtree != NULL); return subtree; } static rtree_elm_t * -rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, unsigned level, - bool dependent) { - rtree_elm_t *subtree; - - subtree = rtree_subtree_tryread(rtree, level, dependent); +rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, bool dependent) { + rtree_elm_t *subtree = rtree_subtree_tryread(rtree, dependent); if (!dependent && unlikely(!rtree_node_valid(subtree))) { - subtree = rtree_node_init(tsdn, rtree, level, - &rtree->levels[level].subtree); + subtree = rtree_node_init(tsdn, rtree, 0, &rtree->root); } assert(!dependent || subtree != NULL); return subtree; @@ -222,13 +183,11 @@ rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, unsigned level, rtree_elm_t * rtree_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing) { - unsigned start_level = rtree_start_level(rtree, key); rtree_elm_t *node = init_missing ? rtree_subtree_read(tsdn, rtree, - start_level, dependent) : rtree_subtree_tryread(rtree, start_level, - dependent); + dependent) : rtree_subtree_tryread(rtree, dependent); #define RTREE_GET_BIAS (RTREE_HEIGHT_MAX - rtree->height) - switch (start_level + RTREE_GET_BIAS) { + switch (RTREE_GET_BIAS) { #define RTREE_GET_SUBTREE(level) \ case level: { \ assert(level < (RTREE_HEIGHT_MAX-1)); \ -- GitLab From f5cf9b19c85f88ee91b3caf65e2a6d70f4548f31 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 6 Feb 2017 13:17:12 -0800 Subject: [PATCH 265/544] Determine rtree levels at compile time. Rather than dynamically building a table to aid per level computations, define a constant table at compile time. Omit both high and low insignificant bits. Use one to three tree levels, depending on the number of significant bits. --- configure.ac | 68 +++++ .../internal/jemalloc_internal_defs.h.in | 7 + include/jemalloc/internal/rtree_externs.h | 24 +- include/jemalloc/internal/rtree_inlines.h | 22 +- include/jemalloc/internal/rtree_structs.h | 2 - include/jemalloc/internal/rtree_types.h | 17 +- src/extent.c | 3 +- src/rtree.c | 136 ++-------- test/unit/rtree.c | 241 ++++++++---------- 9 files changed, 248 insertions(+), 272 deletions(-) diff --git a/configure.ac b/configure.ac index 7530eff7..e71edd72 100644 --- a/configure.ac +++ b/configure.ac @@ -406,6 +406,74 @@ case "${host_cpu}" in esac AC_DEFINE_UNQUOTED([CPU_SPINWAIT], [$CPU_SPINWAIT]) +case "${host_cpu}" in + aarch64) + AC_MSG_CHECKING([number of significant virtual address bits]) + LG_VADDR=48 + AC_MSG_RESULT([$LG_VADDR]) + ;; + x86_64) + AC_CACHE_CHECK([number of significant virtual address bits], + [je_cv_lg_vaddr], + AC_RUN_IFELSE([AC_LANG_PROGRAM( +[[ +#include +#ifdef _WIN32 +#include +#include +typedef unsigned __int32 uint32_t; +#else +#include +#endif +]], [[ + uint32_t r[[4]]; + uint32_t eax_in = 0x80000008U; +#ifdef _WIN32 + __cpuid((int *)r, (int)eax_in); +#else + asm volatile ("cpuid" + : "=a" (r[[0]]), "=b" (r[[1]]), "=c" (r[[2]]), "=d" (r[[3]]) + : "a" (eax_in), "c" (0) + ); +#endif + uint32_t eax_out = r[[0]]; + uint32_t vaddr = ((eax_out & 0x0000ff00U) >> 8); + FILE *f = fopen("conftest.out", "w"); + if (f == NULL) { + return 1; + } + fprintf(f, "%u", vaddr); + fclose(f); + return 0; +]])], + [je_cv_lg_vaddr=`cat conftest.out`], + [je_cv_lg_vaddr=error], + [je_cv_lg_vaddr=57])) + if test "x${je_cv_lg_vaddr}" != "x" ; then + LG_VADDR="${je_cv_lg_vaddr}" + fi + if test "x${LG_VADDR}" != "xerror" ; then + AC_DEFINE_UNQUOTED([LG_VADDR], [$LG_VADDR]) + else + AC_MSG_ERROR([cannot determine number of significant virtual address bits]) + fi + ;; + *) + AC_MSG_CHECKING([number of significant virtual address bits]) + if test "x${LG_SIZEOF_PTR}" = "x3" ; then + LG_VADDR=64 + elif test "x${LG_SIZEOF_PTR}" = "x2" ; then + LG_VADDR=32 + elif test "x${LG_SIZEOF_PTR}" = "xLG_SIZEOF_PTR_WIN" ; then + LG_VADDR="(1U << (LG_SIZEOF_PTR_WIN+3))" + else + AC_MSG_ERROR([Unsupported lg(pointer size): ${LG_SIZEOF_PTR}]) + fi + AC_MSG_RESULT([$LG_VADDR]) + ;; +esac +AC_DEFINE_UNQUOTED([LG_VADDR], [$LG_VADDR]) + LD_PRELOAD_VAR="LD_PRELOAD" so="so" importlib="${so}" diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 396a1a27..6c70e167 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -22,6 +22,13 @@ */ #undef CPU_SPINWAIT +/* + * Number of significant bits in virtual addresses. This may be less than the + * total number of bits in a pointer, e.g. on x64, for which the uppermost 16 + * bits are the same as bit 47. + */ +#undef LG_VADDR + /* Defined if C11 atomics are available. */ #undef JEMALLOC_C11ATOMICS diff --git a/include/jemalloc/internal/rtree_externs.h b/include/jemalloc/internal/rtree_externs.h index f4f2feb5..fa53580a 100644 --- a/include/jemalloc/internal/rtree_externs.h +++ b/include/jemalloc/internal/rtree_externs.h @@ -1,7 +1,29 @@ #ifndef JEMALLOC_INTERNAL_RTREE_EXTERNS_H #define JEMALLOC_INTERNAL_RTREE_EXTERNS_H -bool rtree_new(rtree_t *rtree, unsigned bits); +/* + * Split the bits into one to three partitions depending on number of + * significant bits. It the number of bits does not divide evenly into the + * number of levels, place one remainder bit per level starting at the leaf + * level. + */ +static const rtree_level_t rtree_levels[] = { +#if RTREE_NSB <= 10 + {RTREE_NSB, RTREE_NHIB + RTREE_NSB} +#elif RTREE_NSB <= 36 + {RTREE_NSB/2, RTREE_NHIB + RTREE_NSB/2}, + {RTREE_NSB/2 + RTREE_NSB%2, RTREE_NHIB + RTREE_NSB} +#elif RTREE_NSB <= 52 + {RTREE_NSB/3, RTREE_NHIB + RTREE_NSB/3}, + {RTREE_NSB/3 + RTREE_NSB%3/2, + RTREE_NHIB + RTREE_NSB/3*2 + RTREE_NSB%3/2}, + {RTREE_NSB/3 + RTREE_NSB%3 - RTREE_NSB%3/2, RTREE_NHIB + RTREE_NSB} +#else +# error Unsupported number of significant virtual address bits +#endif +}; + +bool rtree_new(rtree_t *rtree); #ifdef JEMALLOC_JET typedef rtree_elm_t *(rtree_node_alloc_t)(tsdn_t *, rtree_t *, size_t); extern rtree_node_alloc_t *rtree_node_alloc; diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 86aa8cd1..4b848541 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -2,8 +2,8 @@ #define JEMALLOC_INTERNAL_RTREE_INLINES_H #ifndef JEMALLOC_ENABLE_INLINE -uintptr_t rtree_leafkey(rtree_t *rtree, uintptr_t key); -uintptr_t rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level); +uintptr_t rtree_leafkey(uintptr_t key); +uintptr_t rtree_subkey(uintptr_t key, unsigned level); extent_t *rtree_elm_read(rtree_elm_t *elm, bool dependent); void rtree_elm_write(rtree_elm_t *elm, const extent_t *extent); rtree_elm_t *rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, @@ -25,21 +25,21 @@ void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_RTREE_C_)) JEMALLOC_ALWAYS_INLINE uintptr_t -rtree_leafkey(rtree_t *rtree, uintptr_t key) { +rtree_leafkey(uintptr_t key) { unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR+3); - unsigned cumbits = (rtree->levels[rtree->height-1].cumbits - - rtree->levels[rtree->height-1].bits); + unsigned cumbits = (rtree_levels[RTREE_HEIGHT-1].cumbits - + rtree_levels[RTREE_HEIGHT-1].bits); unsigned maskbits = ptrbits - cumbits; uintptr_t mask = ~((ZU(1) << maskbits) - 1); return (key & mask); } JEMALLOC_ALWAYS_INLINE uintptr_t -rtree_subkey(rtree_t *rtree, uintptr_t key, unsigned level) { +rtree_subkey(uintptr_t key, unsigned level) { unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR+3); - unsigned cumbits = rtree->levels[level].cumbits; + unsigned cumbits = rtree_levels[level].cumbits; unsigned shiftbits = ptrbits - cumbits; - unsigned maskbits = rtree->levels[level].bits; + unsigned maskbits = rtree_levels[level].bits; unsigned mask = (ZU(1) << maskbits) - 1; return ((key >> shiftbits) & mask); } @@ -82,7 +82,7 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, assert(!dependent || !init_missing); if (likely(key != 0)) { - uintptr_t leafkey = rtree_leafkey(rtree, key); + uintptr_t leafkey = rtree_leafkey(key); #define RTREE_CACHE_CHECK(i) do { \ if (likely(rtree_ctx->cache[i].leafkey == leafkey)) { \ rtree_elm_t *leaf = rtree_ctx->cache[i].leaf; \ @@ -94,8 +94,8 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, rtree_ctx->cache[0].leafkey = leafkey; \ rtree_ctx->cache[0].leaf = leaf; \ \ - uintptr_t subkey = rtree_subkey(rtree, \ - key, rtree->height-1); \ + uintptr_t subkey = rtree_subkey(key, \ + RTREE_HEIGHT-1); \ return &leaf[subkey]; \ } \ } \ diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h index 713d3000..312171e3 100644 --- a/include/jemalloc/internal/rtree_structs.h +++ b/include/jemalloc/internal/rtree_structs.h @@ -41,12 +41,10 @@ struct rtree_ctx_s { }; struct rtree_s { - unsigned height; union { void *root_pun; rtree_elm_t *root; }; - rtree_level_t levels[RTREE_HEIGHT_MAX]; malloc_mutex_t init_lock; }; diff --git a/include/jemalloc/internal/rtree_types.h b/include/jemalloc/internal/rtree_types.h index b4ab018d..a654698b 100644 --- a/include/jemalloc/internal/rtree_types.h +++ b/include/jemalloc/internal/rtree_types.h @@ -16,15 +16,14 @@ typedef struct rtree_ctx_cache_elm_s rtree_ctx_cache_elm_t; typedef struct rtree_ctx_s rtree_ctx_t; typedef struct rtree_s rtree_t; -/* - * RTREE_BITS_PER_LEVEL must be a power of two that is no larger than the - * machine address width. - */ -#define LG_RTREE_BITS_PER_LEVEL 4 -#define RTREE_BITS_PER_LEVEL (1U << LG_RTREE_BITS_PER_LEVEL) -/* Maximum rtree height. */ -#define RTREE_HEIGHT_MAX \ - ((1U << (LG_SIZEOF_PTR+3)) / RTREE_BITS_PER_LEVEL) +/* Number of high insignificant bits. */ +#define RTREE_NHIB ((1U << (LG_SIZEOF_PTR+3)) - LG_VADDR) +/* Number of low insigificant bits. */ +#define RTREE_NLIB LG_PAGE +/* Number of significant bits. */ +#define RTREE_NSB (LG_VADDR - RTREE_NLIB) +/* Number of levels in radix tree. */ +#define RTREE_HEIGHT (sizeof(rtree_levels)/sizeof(rtree_level_t)) /* * Number of leafkey/leaf pairs to cache. Each entry supports an entire leaf, diff --git a/src/extent.c b/src/extent.c index 4a83f694..85c92d0f 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1522,8 +1522,7 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, bool extent_boot(void) { - if (rtree_new(&extents_rtree, (unsigned)((ZU(1) << (LG_SIZEOF_PTR+3)) - - LG_PAGE))) { + if (rtree_new(&extents_rtree)) { return true; } diff --git a/src/rtree.c b/src/rtree.c index fb52cf68..83929ba6 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -6,47 +6,12 @@ * used. */ bool -rtree_new(rtree_t *rtree, unsigned bits) { - unsigned bits_in_leaf, height, i; - - assert(RTREE_HEIGHT_MAX == ((ZU(1) << (LG_SIZEOF_PTR+3)) / - RTREE_BITS_PER_LEVEL)); - assert(bits > 0 && bits <= (sizeof(uintptr_t) << 3)); - - bits_in_leaf = (bits % RTREE_BITS_PER_LEVEL) == 0 ? RTREE_BITS_PER_LEVEL - : (bits % RTREE_BITS_PER_LEVEL); - if (bits > bits_in_leaf) { - height = 1 + (bits - bits_in_leaf) / RTREE_BITS_PER_LEVEL; - if ((height-1) * RTREE_BITS_PER_LEVEL + bits_in_leaf != bits) { - height++; - } - } else { - height = 1; - } - assert((height-1) * RTREE_BITS_PER_LEVEL + bits_in_leaf == bits); - - rtree->height = height; - +rtree_new(rtree_t *rtree) { rtree->root_pun = NULL; - - /* Root level. */ - rtree->levels[0].bits = (height > 1) ? RTREE_BITS_PER_LEVEL : - bits_in_leaf; - rtree->levels[0].cumbits = rtree->levels[0].bits; - /* Interior levels. */ - for (i = 1; i < height-1; i++) { - rtree->levels[i].bits = RTREE_BITS_PER_LEVEL; - rtree->levels[i].cumbits = rtree->levels[i-1].cumbits + - RTREE_BITS_PER_LEVEL; - } - /* Leaf level. */ - if (height > 1) { - rtree->levels[height-1].bits = bits_in_leaf; - rtree->levels[height-1].cumbits = bits; + if (malloc_mutex_init(&rtree->init_lock, "rtree", WITNESS_RANK_RTREE)) { + return true; } - malloc_mutex_init(&rtree->init_lock, "rtree", WITNESS_RANK_RTREE); - return false; } @@ -84,10 +49,10 @@ rtree_node_dalloc_t *rtree_node_dalloc = JEMALLOC_N(rtree_node_dalloc_impl); static void rtree_delete_subtree(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node, unsigned level) { - if (level + 1 < rtree->height) { + if (level + 1 < RTREE_HEIGHT) { size_t nchildren, i; - nchildren = ZU(1) << rtree->levels[level].bits; + nchildren = ZU(1) << rtree_levels[level].bits; for (i = 0; i < nchildren; i++) { rtree_elm_t *child = node[i].child; if (child != NULL) { @@ -116,7 +81,7 @@ rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level, node = atomic_read_p((void**)elmp); if (node == NULL) { node = rtree_node_alloc(tsdn, rtree, ZU(1) << - rtree->levels[level].bits); + rtree_levels[level].bits); if (node == NULL) { malloc_mutex_unlock(tsdn, &rtree->init_lock); return NULL; @@ -186,24 +151,18 @@ rtree_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, rtree_elm_t *node = init_missing ? rtree_subtree_read(tsdn, rtree, dependent) : rtree_subtree_tryread(rtree, dependent); -#define RTREE_GET_BIAS (RTREE_HEIGHT_MAX - rtree->height) - switch (RTREE_GET_BIAS) { -#define RTREE_GET_SUBTREE(level) \ - case level: { \ - assert(level < (RTREE_HEIGHT_MAX-1)); \ +#define RTREE_GET_SUBTREE(level) { \ + assert(level < RTREE_HEIGHT-1); \ if (!dependent && unlikely(!rtree_node_valid(node))) { \ return NULL; \ } \ - uintptr_t subkey = rtree_subkey(rtree, key, level - \ - RTREE_GET_BIAS); \ + uintptr_t subkey = rtree_subkey(key, level); \ node = init_missing ? rtree_child_read(tsdn, rtree, \ - &node[subkey], level - RTREE_GET_BIAS, dependent) : \ + &node[subkey], level, dependent) : \ rtree_child_tryread(&node[subkey], dependent); \ - /* Fall through. */ \ } -#define RTREE_GET_LEAF(level) \ - case level: { \ - assert(level == (RTREE_HEIGHT_MAX-1)); \ +#define RTREE_GET_LEAF(level) { \ + assert(level == RTREE_HEIGHT-1); \ if (!dependent && unlikely(!rtree_node_valid(node))) { \ return NULL; \ } \ @@ -218,68 +177,27 @@ rtree_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, sizeof(rtree_ctx_cache_elm_t) * \ (RTREE_CTX_NCACHE-1)); \ } \ - uintptr_t leafkey = rtree_leafkey(rtree, key); \ + uintptr_t leafkey = rtree_leafkey(key); \ rtree_ctx->cache[0].leafkey = leafkey; \ rtree_ctx->cache[0].leaf = node; \ } \ - uintptr_t subkey = rtree_subkey(rtree, key, level - \ - RTREE_GET_BIAS); \ + uintptr_t subkey = rtree_subkey(key, level); \ return &node[subkey]; \ } -#if RTREE_HEIGHT_MAX > 1 - RTREE_GET_SUBTREE(0) -#endif -#if RTREE_HEIGHT_MAX > 2 - RTREE_GET_SUBTREE(1) -#endif -#if RTREE_HEIGHT_MAX > 3 - RTREE_GET_SUBTREE(2) -#endif -#if RTREE_HEIGHT_MAX > 4 - RTREE_GET_SUBTREE(3) -#endif -#if RTREE_HEIGHT_MAX > 5 - RTREE_GET_SUBTREE(4) -#endif -#if RTREE_HEIGHT_MAX > 6 - RTREE_GET_SUBTREE(5) -#endif -#if RTREE_HEIGHT_MAX > 7 - RTREE_GET_SUBTREE(6) -#endif -#if RTREE_HEIGHT_MAX > 8 - RTREE_GET_SUBTREE(7) -#endif -#if RTREE_HEIGHT_MAX > 9 - RTREE_GET_SUBTREE(8) -#endif -#if RTREE_HEIGHT_MAX > 10 - RTREE_GET_SUBTREE(9) -#endif -#if RTREE_HEIGHT_MAX > 11 - RTREE_GET_SUBTREE(10) -#endif -#if RTREE_HEIGHT_MAX > 12 - RTREE_GET_SUBTREE(11) -#endif -#if RTREE_HEIGHT_MAX > 13 - RTREE_GET_SUBTREE(12) -#endif -#if RTREE_HEIGHT_MAX > 14 - RTREE_GET_SUBTREE(13) -#endif -#if RTREE_HEIGHT_MAX > 15 - RTREE_GET_SUBTREE(14) -#endif -#if RTREE_HEIGHT_MAX > 16 -# error Unsupported RTREE_HEIGHT_MAX -#endif - RTREE_GET_LEAF(RTREE_HEIGHT_MAX-1) + if (RTREE_HEIGHT > 1) { + RTREE_GET_SUBTREE(0) + } + if (RTREE_HEIGHT > 2) { + RTREE_GET_SUBTREE(1) + } + if (RTREE_HEIGHT > 3) { + for (unsigned i = 2; i < RTREE_HEIGHT-1; i++) { + RTREE_GET_SUBTREE(i) + } + } + RTREE_GET_LEAF(RTREE_HEIGHT-1) #undef RTREE_GET_SUBTREE #undef RTREE_GET_LEAF - default: not_reached(); - } -#undef RTREE_GET_BIAS not_reached(); } @@ -351,7 +269,7 @@ rtree_elm_witness_dalloc(tsd_t *tsd, witness_t *witness, witness_init(&rew->witness, "rtree_elm", WITNESS_RANK_RTREE_ELM, rtree_elm_witness_comp, NULL); - return; + return; } } not_reached(); diff --git a/test/unit/rtree.c b/test/unit/rtree.c index d40e6490..2088595b 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -33,31 +33,26 @@ rtree_node_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) { TEST_BEGIN(test_rtree_read_empty) { tsdn_t *tsdn; - unsigned i; tsdn = tsdn_fetch(); - for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) { - rtree_t rtree; - rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; - test_rtree = &rtree; - assert_false(rtree_new(&rtree, i), - "Unexpected rtree_new() failure"); - assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, 0, false), - "rtree_read() should return NULL for empty tree"); - rtree_delete(tsdn, &rtree); - test_rtree = NULL; - } + rtree_t rtree; + rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; + test_rtree = &rtree; + assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure"); + assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, 0, false), + "rtree_read() should return NULL for empty tree"); + rtree_delete(tsdn, &rtree); + test_rtree = NULL; } TEST_END #define NTHREADS 8 -#define MAX_NBITS 18 +#define MAX_NBITS 30 #define NITERS 1000 #define SEED 42 typedef struct { - unsigned nbits; rtree_t rtree; uint32_t seed; } thd_start_arg_t; @@ -77,7 +72,8 @@ thd_start(void *varg) { tsdn = tsdn_fetch(); for (i = 0; i < NITERS; i++) { - uintptr_t key = (uintptr_t)gen_rand64(sfmt); + uintptr_t key = (uintptr_t)(gen_rand64(sfmt) & ((ZU(1) << + MAX_NBITS) - ZU(1))); if (i % 2 == 0) { rtree_elm_t *elm; @@ -110,165 +106,134 @@ TEST_BEGIN(test_rtree_concurrent) { thd_t thds[NTHREADS]; sfmt_t *sfmt; tsdn_t *tsdn; - unsigned i, j; sfmt = init_gen_rand(SEED); tsdn = tsdn_fetch(); - for (i = 1; i < MAX_NBITS; i++) { - arg.nbits = i; - test_rtree = &arg.rtree; - assert_false(rtree_new(&arg.rtree, arg.nbits), - "Unexpected rtree_new() failure"); - arg.seed = gen_rand32(sfmt); - for (j = 0; j < NTHREADS; j++) { - thd_create(&thds[j], thd_start, (void *)&arg); - } - for (j = 0; j < NTHREADS; j++) { - thd_join(thds[j], NULL); - } - rtree_delete(tsdn, &arg.rtree); - test_rtree = NULL; + test_rtree = &arg.rtree; + assert_false(rtree_new(&arg.rtree), "Unexpected rtree_new() failure"); + arg.seed = gen_rand32(sfmt); + for (unsigned i = 0; i < NTHREADS; i++) { + thd_create(&thds[i], thd_start, (void *)&arg); + } + for (unsigned i = 0; i < NTHREADS; i++) { + thd_join(thds[i], NULL); } + rtree_delete(tsdn, &arg.rtree); + test_rtree = NULL; fini_gen_rand(sfmt); } TEST_END #undef NTHREADS -#undef MAX_NBITS #undef NITERS #undef SEED TEST_BEGIN(test_rtree_extrema) { - unsigned i; extent_t extent_a, extent_b; tsdn_t *tsdn; tsdn = tsdn_fetch(); - for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) { - rtree_t rtree; - rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; - test_rtree = &rtree; - assert_false(rtree_new(&rtree, i), - "Unexpected rtree_new() failure"); - - assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, 0, - &extent_a), "Unexpected rtree_write() failure, i=%u", i); - assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, 0, true), - &extent_a, - "rtree_read() should return previously set value, i=%u", i); + rtree_t rtree; + rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; + test_rtree = &rtree; + assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure"); - assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, - ~((uintptr_t)0), &extent_b), - "Unexpected rtree_write() failure, i=%u", i); - assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, - ~((uintptr_t)0), true), &extent_b, - "rtree_read() should return previously set value, i=%u", i); + assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, 0, &extent_a), + "Unexpected rtree_write() failure"); + assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, 0, true), &extent_a, + "rtree_read() should return previously set value"); - rtree_delete(tsdn, &rtree); - test_rtree = NULL; - } + assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, ~((uintptr_t)0), + &extent_b), "Unexpected rtree_write() failure"); + assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, ~((uintptr_t)0), + true), &extent_b, + "rtree_read() should return previously set value"); + + rtree_delete(tsdn, &rtree); + test_rtree = NULL; } TEST_END TEST_BEGIN(test_rtree_bits) { - tsdn_t *tsdn; - unsigned i, j, k; + tsdn_t *tsdn = tsdn_fetch(); - tsdn = tsdn_fetch(); + uintptr_t keys[] = {0, 1, (((uintptr_t)1) << LG_PAGE) - 1}; - for (i = 1; i < (sizeof(uintptr_t) << 3); i++) { - uintptr_t keys[] = {0, 1, - (((uintptr_t)1) << (sizeof(uintptr_t)*8-i)) - 1}; - extent_t extent; - rtree_t rtree; - rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; - - test_rtree = &rtree; - assert_false(rtree_new(&rtree, i), - "Unexpected rtree_new() failure"); - - for (j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) { - assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, - keys[j], &extent), - "Unexpected rtree_write() failure"); - for (k = 0; k < sizeof(keys)/sizeof(uintptr_t); k++) { - assert_ptr_eq(rtree_read(tsdn, &rtree, - &rtree_ctx, keys[k], true), &extent, - "rtree_read() should return previously set " - "value and ignore insignificant key bits; " - "i=%u, j=%u, k=%u, set key=%#"FMTxPTR", " - "get key=%#"FMTxPTR, i, j, k, keys[j], - keys[k]); - } - assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, - (((uintptr_t)1) << (sizeof(uintptr_t)*8-i)), false), - "Only leftmost rtree leaf should be set; " - "i=%u, j=%u", i, j); - rtree_clear(tsdn, &rtree, &rtree_ctx, keys[j]); - } + extent_t extent; + rtree_t rtree; + rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; - rtree_delete(tsdn, &rtree); - test_rtree = NULL; + test_rtree = &rtree; + assert_false(rtree_new(&rtree), + "Unexpected rtree_new() failure"); + + for (unsigned i = 0; i < sizeof(keys)/sizeof(uintptr_t); i++) { + assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, keys[i], + &extent), "Unexpected rtree_write() failure"); + for (unsigned j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) { + assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, + keys[j], true), &extent, + "rtree_read() should return previously set " + "value and ignore insignificant key bits; " + "i=%u, j=%u, set key=%#"FMTxPTR", get " + "key=%#"FMTxPTR, i, j, keys[i], keys[j]); + } + assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, + (((uintptr_t)1) << LG_PAGE), false), + "Only leftmost rtree leaf should be set; i=%u", i); + rtree_clear(tsdn, &rtree, &rtree_ctx, keys[i]); } + + rtree_delete(tsdn, &rtree); + test_rtree = NULL; } TEST_END TEST_BEGIN(test_rtree_random) { - unsigned i; - sfmt_t *sfmt; - tsdn_t *tsdn; #define NSET 16 #define SEED 42 + sfmt_t *sfmt = init_gen_rand(SEED); + tsdn_t *tsdn = tsdn_fetch(); + uintptr_t keys[NSET]; + extent_t extent; + rtree_t rtree; + rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; + rtree_elm_t *elm; + + test_rtree = &rtree; + assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure"); + + for (unsigned i = 0; i < NSET; i++) { + keys[i] = (uintptr_t)gen_rand64(sfmt); + elm = rtree_elm_acquire(tsdn, &rtree, &rtree_ctx, keys[i], + false, true); + assert_ptr_not_null(elm, + "Unexpected rtree_elm_acquire() failure"); + rtree_elm_write_acquired(tsdn, &rtree, elm, &extent); + rtree_elm_release(tsdn, &rtree, elm); + assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, keys[i], + true), &extent, + "rtree_read() should return previously set value"); + } + for (unsigned i = 0; i < NSET; i++) { + assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, keys[i], + true), &extent, + "rtree_read() should return previously set value, i=%u", i); + } - sfmt = init_gen_rand(SEED); - tsdn = tsdn_fetch(); - for (i = 1; i <= (sizeof(uintptr_t) << 3); i++) { - uintptr_t keys[NSET]; - extent_t extent; - unsigned j; - rtree_t rtree; - rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; - rtree_elm_t *elm; - - test_rtree = &rtree; - assert_false(rtree_new(&rtree, i), - "Unexpected rtree_new() failure"); - - for (j = 0; j < NSET; j++) { - keys[j] = (uintptr_t)gen_rand64(sfmt); - elm = rtree_elm_acquire(tsdn, &rtree, &rtree_ctx, - keys[j], false, true); - assert_ptr_not_null(elm, - "Unexpected rtree_elm_acquire() failure"); - rtree_elm_write_acquired(tsdn, &rtree, elm, &extent); - rtree_elm_release(tsdn, &rtree, elm); - assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, - keys[j], true), &extent, - "rtree_read() should return previously set value"); - } - for (j = 0; j < NSET; j++) { - assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, - keys[j], true), &extent, - "rtree_read() should return previously set value, " - "j=%u", j); - } - - for (j = 0; j < NSET; j++) { - rtree_clear(tsdn, &rtree, &rtree_ctx, keys[j]); - assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, - keys[j], true), - "rtree_read() should return previously set value"); - } - for (j = 0; j < NSET; j++) { - assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, - keys[j], true), - "rtree_read() should return previously set value"); - } - - rtree_delete(tsdn, &rtree); - test_rtree = NULL; + for (unsigned i = 0; i < NSET; i++) { + rtree_clear(tsdn, &rtree, &rtree_ctx, keys[i]); + assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, keys[i], + true), "rtree_read() should return previously set value"); } + for (unsigned i = 0; i < NSET; i++) { + assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, keys[i], + true), "rtree_read() should return previously set value"); + } + + rtree_delete(tsdn, &rtree); + test_rtree = NULL; fini_gen_rand(sfmt); #undef NSET #undef SEED -- GitLab From 650c070e102daeedd643dc79b463603a1ea18497 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 5 Feb 2017 02:50:59 -0800 Subject: [PATCH 266/544] Remove rtree support for 0 (NULL) keys. NULL can never actually be inserted in practice, and removing support allows a branch to be removed from the fast path. --- include/jemalloc/internal/rtree_inlines.h | 58 +++++++++++------------ src/rtree.c | 18 ++++--- test/unit/rtree.c | 12 +++-- 3 files changed, 43 insertions(+), 45 deletions(-) diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 4b848541..0d96948b 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -79,43 +79,41 @@ rtree_elm_write(rtree_elm_t *elm, const extent_t *extent) { JEMALLOC_ALWAYS_INLINE rtree_elm_t * rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing) { + assert(key != 0); assert(!dependent || !init_missing); - if (likely(key != 0)) { - uintptr_t leafkey = rtree_leafkey(key); + uintptr_t leafkey = rtree_leafkey(key); #define RTREE_CACHE_CHECK(i) do { \ - if (likely(rtree_ctx->cache[i].leafkey == leafkey)) { \ - rtree_elm_t *leaf = rtree_ctx->cache[i].leaf; \ - if (likely(leaf != NULL)) { \ - /* Reorder. */ \ - memmove(&rtree_ctx->cache[1], \ - &rtree_ctx->cache[0], \ - sizeof(rtree_ctx_cache_elm_t) * i); \ - rtree_ctx->cache[0].leafkey = leafkey; \ - rtree_ctx->cache[0].leaf = leaf; \ + if (likely(rtree_ctx->cache[i].leafkey == leafkey)) { \ + rtree_elm_t *leaf = rtree_ctx->cache[i].leaf; \ + if (likely(leaf != NULL)) { \ + /* Reorder. */ \ + memmove(&rtree_ctx->cache[1], \ + &rtree_ctx->cache[0], \ + sizeof(rtree_ctx_cache_elm_t) * i); \ + rtree_ctx->cache[0].leafkey = leafkey; \ + rtree_ctx->cache[0].leaf = leaf; \ \ - uintptr_t subkey = rtree_subkey(key, \ - RTREE_HEIGHT-1); \ - return &leaf[subkey]; \ - } \ + uintptr_t subkey = rtree_subkey(key, \ + RTREE_HEIGHT-1); \ + return &leaf[subkey]; \ } \ + } \ } while (0) - /* Check the MRU cache entry. */ - RTREE_CACHE_CHECK(0); - /* - * Search the remaining cache elements, and on success move the - * matching element to the front. Unroll the first iteration to - * avoid calling memmove() (the compiler typically optimizes it - * into raw moves). - */ - if (RTREE_CTX_NCACHE > 1) { - RTREE_CACHE_CHECK(1); - } - for (unsigned i = 2; i < RTREE_CTX_NCACHE; i++) { - RTREE_CACHE_CHECK(i); - } -#undef RTREE_CACHE_CHECK + /* Check the MRU cache entry. */ + RTREE_CACHE_CHECK(0); + /* + * Search the remaining cache elements, and on success move the matching + * element to the front. Unroll the first iteration to avoid calling + * memmove() (the compiler typically optimizes it into raw moves). + */ + if (RTREE_CTX_NCACHE > 1) { + RTREE_CACHE_CHECK(1); } + for (unsigned i = 2; i < RTREE_CTX_NCACHE; i++) { + RTREE_CACHE_CHECK(i); + } +#undef RTREE_CACHE_CHECK return rtree_elm_lookup_hard(tsdn, rtree, rtree_ctx, key, dependent, init_missing); diff --git a/src/rtree.c b/src/rtree.c index 83929ba6..a86fa45d 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -170,17 +170,15 @@ rtree_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, * node is a leaf, so it contains values rather than \ * child pointers. \ */ \ - if (likely(key != 0)) { \ - if (RTREE_CTX_NCACHE > 1) { \ - memmove(&rtree_ctx->cache[1], \ - &rtree_ctx->cache[0], \ - sizeof(rtree_ctx_cache_elm_t) * \ - (RTREE_CTX_NCACHE-1)); \ - } \ - uintptr_t leafkey = rtree_leafkey(key); \ - rtree_ctx->cache[0].leafkey = leafkey; \ - rtree_ctx->cache[0].leaf = node; \ + if (RTREE_CTX_NCACHE > 1) { \ + memmove(&rtree_ctx->cache[1], \ + &rtree_ctx->cache[0], \ + sizeof(rtree_ctx_cache_elm_t) * \ + (RTREE_CTX_NCACHE-1)); \ } \ + uintptr_t leafkey = rtree_leafkey(key); \ + rtree_ctx->cache[0].leafkey = leafkey; \ + rtree_ctx->cache[0].leaf = node; \ uintptr_t subkey = rtree_subkey(key, level); \ return &node[subkey]; \ } diff --git a/test/unit/rtree.c b/test/unit/rtree.c index 2088595b..488fd54b 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -40,7 +40,7 @@ TEST_BEGIN(test_rtree_read_empty) { rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; test_rtree = &rtree; assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure"); - assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, 0, false), + assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, PAGE, false), "rtree_read() should return NULL for empty tree"); rtree_delete(tsdn, &rtree); test_rtree = NULL; @@ -139,9 +139,10 @@ TEST_BEGIN(test_rtree_extrema) { test_rtree = &rtree; assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure"); - assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, 0, &extent_a), + assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, PAGE, &extent_a), "Unexpected rtree_write() failure"); - assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, 0, true), &extent_a, + assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, PAGE, true), + &extent_a, "rtree_read() should return previously set value"); assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, ~((uintptr_t)0), @@ -158,7 +159,8 @@ TEST_END TEST_BEGIN(test_rtree_bits) { tsdn_t *tsdn = tsdn_fetch(); - uintptr_t keys[] = {0, 1, (((uintptr_t)1) << LG_PAGE) - 1}; + uintptr_t keys[] = {PAGE, PAGE + 1, + PAGE + (((uintptr_t)1) << LG_PAGE) - 1}; extent_t extent; rtree_t rtree; @@ -180,7 +182,7 @@ TEST_BEGIN(test_rtree_bits) { "key=%#"FMTxPTR, i, j, keys[i], keys[j]); } assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, - (((uintptr_t)1) << LG_PAGE), false), + (((uintptr_t)2) << LG_PAGE), false), "Only leftmost rtree leaf should be set; i=%u", i); rtree_clear(tsdn, &rtree, &rtree_ctx, keys[i]); } -- GitLab From 5f118307543b128e1ad6298ec2ab1acd71140095 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 5 Feb 2017 23:57:16 -0800 Subject: [PATCH 267/544] Replace spin_init() with SPIN_INITIALIZER. --- include/jemalloc/internal/private_symbols.txt | 1 - include/jemalloc/internal/spin_inlines.h | 6 ------ include/jemalloc/internal/spin_types.h | 2 ++ src/extent_dss.c | 3 +-- src/jemalloc.c | 4 +--- 5 files changed, 4 insertions(+), 12 deletions(-) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 3f29d3fe..2c824541 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -445,7 +445,6 @@ size2index_compute size2index_lookup size2index_tab spin_adaptive -spin_init stats_print tcache_alloc_easy tcache_alloc_large diff --git a/include/jemalloc/internal/spin_inlines.h b/include/jemalloc/internal/spin_inlines.h index 1ffc4232..03beeada 100644 --- a/include/jemalloc/internal/spin_inlines.h +++ b/include/jemalloc/internal/spin_inlines.h @@ -2,16 +2,10 @@ #define JEMALLOC_INTERNAL_SPIN_INLINES_H #ifndef JEMALLOC_ENABLE_INLINE -void spin_init(spin_t *spin); void spin_adaptive(spin_t *spin); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_SPIN_C_)) -JEMALLOC_INLINE void -spin_init(spin_t *spin) { - spin->iteration = 0; -} - JEMALLOC_INLINE void spin_adaptive(spin_t *spin) { volatile uint64_t i; diff --git a/include/jemalloc/internal/spin_types.h b/include/jemalloc/internal/spin_types.h index 52ee4cc1..222e0698 100644 --- a/include/jemalloc/internal/spin_types.h +++ b/include/jemalloc/internal/spin_types.h @@ -3,4 +3,6 @@ typedef struct spin_s spin_t; +#define SPIN_INITIALIZER {0U} + #endif /* JEMALLOC_INTERNAL_SPIN_TYPES_H */ diff --git a/src/extent_dss.c b/src/extent_dss.c index a3cfab26..0b4e1fe3 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -62,13 +62,12 @@ extent_dss_prec_set(dss_prec_t dss_prec) { static void * extent_dss_max_update(void *new_addr) { void *max_cur; - spin_t spinner; /* * Get the current end of the DSS as max_cur and assure that dss_max is * up to date. */ - spin_init(&spinner); + spin_t spinner = SPIN_INITIALIZER; while (true) { void *max_prev = atomic_read_p(&dss_max); diff --git a/src/jemalloc.c b/src/jemalloc.c index 48be4a3f..d2c33bbc 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1153,10 +1153,8 @@ malloc_init_hard_needed(void) { } #ifdef JEMALLOC_THREADED_INIT if (malloc_initializer != NO_INITIALIZER && !IS_INITIALIZER) { - spin_t spinner; - /* Busy-wait until the initializing thread completes. */ - spin_init(&spinner); + spin_t spinner = SPIN_INITIALIZER; do { malloc_mutex_unlock(TSDN_NULL, &init_lock); spin_adaptive(&spinner); -- GitLab From de8a68e85304848189643fb48100c18aa9d60e32 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 8 Feb 2017 10:30:44 -0800 Subject: [PATCH 268/544] Enhance spin_adaptive() to yield after several iterations. This avoids worst case behavior if e.g. another thread is preempted while owning the resource the spinning thread is waiting for. --- Makefile.in | 1 + include/jemalloc/internal/spin_inlines.h | 17 +++++++++++------ test/unit/spin.c | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 test/unit/spin.c diff --git a/Makefile.in b/Makefile.in index acd31f73..23056f78 100644 --- a/Makefile.in +++ b/Makefile.in @@ -189,6 +189,7 @@ TESTS_UNIT := \ $(srcroot)test/unit/size_classes.c \ $(srcroot)test/unit/slab.c \ $(srcroot)test/unit/smoothstep.c \ + $(srcroot)test/unit/spin.c \ $(srcroot)test/unit/stats.c \ $(srcroot)test/unit/stats_print.c \ $(srcroot)test/unit/ticker.c \ diff --git a/include/jemalloc/internal/spin_inlines.h b/include/jemalloc/internal/spin_inlines.h index 03beeada..16573261 100644 --- a/include/jemalloc/internal/spin_inlines.h +++ b/include/jemalloc/internal/spin_inlines.h @@ -8,14 +8,19 @@ void spin_adaptive(spin_t *spin); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_SPIN_C_)) JEMALLOC_INLINE void spin_adaptive(spin_t *spin) { - volatile uint64_t i; + volatile uint32_t i; - for (i = 0; i < (KQU(1) << spin->iteration); i++) { - CPU_SPINWAIT; - } - - if (spin->iteration < 63) { + if (spin->iteration < 5) { + for (i = 0; i < (1U << spin->iteration); i++) { + CPU_SPINWAIT; + } spin->iteration++; + } else { +#ifdef _WIN32 + SwitchToThread(); +#else + sched_yield(); +#endif } } diff --git a/test/unit/spin.c b/test/unit/spin.c new file mode 100644 index 00000000..bd368b3d --- /dev/null +++ b/test/unit/spin.c @@ -0,0 +1,16 @@ +#include "test/jemalloc_test.h" + +TEST_BEGIN(test_spin) { + spin_t spinner = SPIN_INITIALIZER; + + for (unsigned i = 0; i < 100; i++) { + spin_adaptive(&spinner); + } +} +TEST_END + +int +main(void) { + return test( + test_spin); +} -- GitLab From db7da563595e49fa56cfd2b94cc77fed3d8ac755 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 5 Feb 2017 23:58:02 -0800 Subject: [PATCH 269/544] Spin adaptively in rtree_elm_acquire(). --- include/jemalloc/internal/rtree_inlines.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 0d96948b..4de04795 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -153,21 +153,22 @@ rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, JEMALLOC_INLINE rtree_elm_t * rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing) { - rtree_elm_t *elm; - - elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, dependent, - init_missing); + rtree_elm_t *elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, + dependent, init_missing); if (!dependent && elm == NULL) { return NULL; } - extent_t *extent; - void *s; - do { - extent = rtree_elm_read(elm, false); + spin_t spinner = SPIN_INITIALIZER; + while (true) { + extent_t *extent = rtree_elm_read(elm, false); /* The least significant bit serves as a lock. */ - s = (void *)((uintptr_t)extent | (uintptr_t)0x1); - } while (atomic_cas_p(&elm->pun, (void *)extent, s)); + void *s = (void *)((uintptr_t)extent | (uintptr_t)0x1); + if (!atomic_cas_p(&elm->pun, (void *)extent, s)) { + break; + } + spin_adaptive(&spinner); + } if (config_debug) { rtree_elm_witness_acquire(tsdn, rtree, key, elm); -- GitLab From 7f55dbef9b2a2b93e021d47fa4e6d69c1a633155 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 9 Feb 2017 09:06:22 -0800 Subject: [PATCH 270/544] Enable mutex witnesses even when !isthreaded. This fixes interactions with witness_assert_depth[_to_rank](), which was added in d0e93ada51e20f4ae394ff4dbdcf96182767c89c (Add witness_assert_depth[_to_rank]().). --- include/jemalloc/internal/mutex_inlines.h | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index 0c6c5dd5..c0c3cfe9 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -11,8 +11,8 @@ void malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) JEMALLOC_INLINE void malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) { + witness_assert_not_owner(tsdn, &mutex->witness); if (isthreaded) { - witness_assert_not_owner(tsdn, &mutex->witness); #ifdef _WIN32 # if _WIN32_WINNT >= 0x0600 AcquireSRWLockExclusive(&mutex->lock); @@ -26,14 +26,14 @@ malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) { #else pthread_mutex_lock(&mutex->lock); #endif - witness_lock(tsdn, &mutex->witness); } + witness_lock(tsdn, &mutex->witness); } JEMALLOC_INLINE void malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) { + witness_unlock(tsdn, &mutex->witness); if (isthreaded) { - witness_unlock(tsdn, &mutex->witness); #ifdef _WIN32 # if _WIN32_WINNT >= 0x0600 ReleaseSRWLockExclusive(&mutex->lock); @@ -52,16 +52,12 @@ malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) { JEMALLOC_INLINE void malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { - if (isthreaded) { - witness_assert_owner(tsdn, &mutex->witness); - } + witness_assert_owner(tsdn, &mutex->witness); } JEMALLOC_INLINE void malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { - if (isthreaded) { - witness_assert_not_owner(tsdn, &mutex->witness); - } + witness_assert_not_owner(tsdn, &mutex->witness); } #endif -- GitLab From 6b8ef771a9de9318964f8b5b7cff5ea3958f0294 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 9 Feb 2017 12:31:11 -0800 Subject: [PATCH 271/544] Fix rtree_subkey() regression. Fix rtree_subkey() to use uintptr_t rather than unsigned for key bitmasking. This regression was introduced by 4a346f55939af4f200121cc4454089592d952f18 (Replace rtree path cache with LRU cache.). --- include/jemalloc/internal/rtree_inlines.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 4de04795..f2efd710 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -40,7 +40,7 @@ rtree_subkey(uintptr_t key, unsigned level) { unsigned cumbits = rtree_levels[level].cumbits; unsigned shiftbits = ptrbits - cumbits; unsigned maskbits = rtree_levels[level].bits; - unsigned mask = (ZU(1) << maskbits) - 1; + uintptr_t mask = (ZU(1) << maskbits) - 1; return ((key >> shiftbits) & mask); } -- GitLab From cd2501efd621b76f799d9f264385b348c6e6678d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 9 Feb 2017 13:00:59 -0800 Subject: [PATCH 272/544] Fix extent_alloc_dss() regression. Fix extent_alloc_dss() to account for bytes that are not a multiple of the page size. This regression was introduced by 577d4572b0821a15e5370f9bf566d884b7cf707c (Make dss operations lockless.), which was first released in 4.3.0. --- src/extent_dss.c | 48 +++++++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/src/extent_dss.c b/src/extent_dss.c index 0b4e1fe3..50825713 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -121,35 +121,45 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, * malloc. */ while (true) { - void *ret, *max_cur, *gap_addr, *dss_next, *dss_prev; - size_t gap_size; - intptr_t incr; - - max_cur = extent_dss_max_update(new_addr); + void *max_cur = extent_dss_max_update(new_addr); if (max_cur == NULL) { goto label_oom; } /* - * Compute how much gap space (if any) is necessary to - * satisfy alignment. This space can be recycled for - * later use. + * Compute how much page-aligned gap space (if any) is + * necessary to satisfy alignment. This space can be + * recycled for later use. */ - gap_addr = (void *)(PAGE_CEILING((uintptr_t)max_cur)); - ret = (void *)ALIGNMENT_CEILING((uintptr_t)gap_addr, - PAGE_CEILING(alignment)); - gap_size = (uintptr_t)ret - (uintptr_t)gap_addr; - if (gap_size != 0) { - extent_init(gap, arena, gap_addr, gap_size, - gap_size, arena_extent_sn_next(arena), + void *gap_addr_page = (void *)(PAGE_CEILING( + (uintptr_t)max_cur)); + void *ret = (void *)ALIGNMENT_CEILING( + (uintptr_t)gap_addr_page, alignment); + size_t gap_size_page = (uintptr_t)ret - + (uintptr_t)gap_addr_page; + if (gap_size_page != 0) { + extent_init(gap, arena, gap_addr_page, + gap_size_page, gap_size_page, + arena_extent_sn_next(arena), extent_state_active, false, true, false); } - dss_next = (void *)((uintptr_t)ret + size); + /* + * Compute the address just past the end of the desired + * allocation space. + */ + void *dss_next = (void *)((uintptr_t)ret + size); if ((uintptr_t)ret < (uintptr_t)max_cur || (uintptr_t)dss_next < (uintptr_t)max_cur) { goto label_oom; /* Wrap-around. */ } - incr = gap_size + size; + /* Compute the increment, including subpage bytes. */ + void *gap_addr_subpage = max_cur; + size_t gap_size_subpage = (uintptr_t)ret - + (uintptr_t)gap_addr_subpage; + intptr_t incr = gap_size_subpage + size; + + assert((uintptr_t)max_cur + incr == (uintptr_t)ret + + size); /* * Optimistically update dss_max, and roll back below if @@ -162,10 +172,10 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, } /* Try to allocate. */ - dss_prev = extent_dss_sbrk(incr); + void *dss_prev = extent_dss_sbrk(incr); if (dss_prev == max_cur) { /* Success. */ - if (gap_size != 0) { + if (gap_size_page != 0) { extent_dalloc_gap(tsdn, arena, gap); } else { extent_dalloc(tsdn, arena, gap); -- GitLab From 0721b895ffac734155956b8d3288c57234093c3a Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 12 Feb 2017 18:28:30 -0800 Subject: [PATCH 273/544] Do not generate unused tsd_*_[gs]et() functions. This avoids a gcc diagnostic note: note: The ABI for passing parameters with 64-byte alignment has changed in GCC 4.6 This note related to the cacheline alignment of rtree_ctx_t, which was introduced by 4a346f55939af4f200121cc4454089592d952f18 (Replace rtree path cache with LRU cache.). --- include/jemalloc/internal/private_symbols.txt | 8 ----- include/jemalloc/internal/tsd_inlines.h | 20 ++++++----- include/jemalloc/internal/tsd_structs.h | 34 ++++++++++--------- src/tsd.c | 2 +- 4 files changed, 31 insertions(+), 33 deletions(-) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 2c824541..ab5a672c 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -485,8 +485,6 @@ ticker_ticks tsd_arena_get tsd_arena_set tsd_arenap_get -tsd_arenas_tdata_bypass_get -tsd_arenas_tdata_bypass_set tsd_arenas_tdata_bypassp_get tsd_arenas_tdata_get tsd_arenas_tdata_set @@ -518,11 +516,7 @@ tsd_nominal tsd_prof_tdata_get tsd_prof_tdata_set tsd_prof_tdatap_get -tsd_rtree_ctx_get -tsd_rtree_ctx_set tsd_rtree_ctxp_get -tsd_rtree_elm_witnesses_get -tsd_rtree_elm_witnesses_set tsd_rtree_elm_witnessesp_get tsd_set tsd_tcache_enabled_get @@ -543,8 +537,6 @@ tsd_tsdn tsd_witness_fork_get tsd_witness_fork_set tsd_witness_forkp_get -tsd_witnesses_get -tsd_witnesses_set tsd_witnessesp_get tsdn_fetch tsdn_null diff --git a/include/jemalloc/internal/tsd_inlines.h b/include/jemalloc/internal/tsd_inlines.h index 3e5860ae..1457c03e 100644 --- a/include/jemalloc/internal/tsd_inlines.h +++ b/include/jemalloc/internal/tsd_inlines.h @@ -8,7 +8,7 @@ tsd_t *tsd_fetch_impl(bool init); tsd_t *tsd_fetch(void); tsdn_t *tsd_tsdn(tsd_t *tsd); bool tsd_nominal(tsd_t *tsd); -#define O(n, t, c) \ +#define O(n, t, gs, c) \ t *tsd_##n##p_get(tsd_t *tsd); \ t tsd_##n##_get(tsd_t *tsd); \ void tsd_##n##_set(tsd_t *tsd, t n); @@ -64,23 +64,27 @@ tsd_nominal(tsd_t *tsd) { return (tsd->state == tsd_state_nominal); } -#define O(n, t, c) \ -JEMALLOC_ALWAYS_INLINE t * \ -tsd_##n##p_get(tsd_t *tsd) { \ - return &tsd->n; \ -} \ - \ +#define MALLOC_TSD_getset_yes(n, t) \ JEMALLOC_ALWAYS_INLINE t \ tsd_##n##_get(tsd_t *tsd) { \ return *tsd_##n##p_get(tsd); \ } \ - \ JEMALLOC_ALWAYS_INLINE void \ tsd_##n##_set(tsd_t *tsd, t n) { \ assert(tsd->state == tsd_state_nominal); \ tsd->n = n; \ } +#define MALLOC_TSD_getset_no(n, t) +#define O(n, t, gs, c) \ +JEMALLOC_ALWAYS_INLINE t * \ +tsd_##n##p_get(tsd_t *tsd) { \ + return &tsd->n; \ +} \ + \ +MALLOC_TSD_getset_##gs(n, t) MALLOC_TSD +#undef MALLOC_TSD_getset_yes +#undef MALLOC_TSD_getset_no #undef O JEMALLOC_ALWAYS_INLINE tsdn_t * diff --git a/include/jemalloc/internal/tsd_structs.h b/include/jemalloc/internal/tsd_structs.h index ca013208..503021e7 100644 --- a/include/jemalloc/internal/tsd_structs.h +++ b/include/jemalloc/internal/tsd_structs.h @@ -15,21 +15,23 @@ struct tsd_init_head_s { #endif #define MALLOC_TSD \ -/* O(name, type, cleanup) */ \ - O(tcache, tcache_t *, yes) \ - O(thread_allocated, uint64_t, no) \ - O(thread_deallocated, uint64_t, no) \ - O(prof_tdata, prof_tdata_t *, yes) \ - O(iarena, arena_t *, yes) \ - O(arena, arena_t *, yes) \ - O(arenas_tdata, arena_tdata_t *, yes) \ - O(narenas_tdata, unsigned, no) \ - O(arenas_tdata_bypass, bool, no) \ - O(tcache_enabled, tcache_enabled_t, no) \ - O(rtree_ctx, rtree_ctx_t, no) \ - O(witnesses, witness_list_t, yes) \ - O(rtree_elm_witnesses, rtree_elm_witness_tsd_t,no) \ - O(witness_fork, bool, no) \ +/* O(name, type, [gs]et, cleanup) */ \ + O(tcache, tcache_t *, yes, yes) \ + O(thread_allocated, uint64_t, yes, no) \ + O(thread_deallocated, uint64_t, yes, no) \ + O(prof_tdata, prof_tdata_t *, yes, yes) \ + O(iarena, arena_t *, yes, yes) \ + O(arena, arena_t *, yes, yes) \ + O(arenas_tdata, arena_tdata_t *,yes, yes) \ + O(narenas_tdata, unsigned, yes, no) \ + O(arenas_tdata_bypass, bool, no, no) \ + O(tcache_enabled, tcache_enabled_t, \ + yes, no) \ + O(rtree_ctx, rtree_ctx_t, no, no) \ + O(witnesses, witness_list_t, no, yes) \ + O(rtree_elm_witnesses, rtree_elm_witness_tsd_t, \ + no, no) \ + O(witness_fork, bool, yes, no) \ #define TSD_INITIALIZER { \ tsd_state_uninitialized, \ @@ -51,7 +53,7 @@ struct tsd_init_head_s { struct tsd_s { tsd_state_t state; -#define O(n, t, c) \ +#define O(n, t, gs, c) \ t n; MALLOC_TSD #undef O diff --git a/src/tsd.c b/src/tsd.c index 7d56e689..9614dd9a 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -72,7 +72,7 @@ tsd_cleanup(void *arg) { #define MALLOC_TSD_cleanup_yes(n, t) \ n##_cleanup(tsd); #define MALLOC_TSD_cleanup_no(n, t) -#define O(n, t, c) \ +#define O(n, t, gs, c) \ MALLOC_TSD_cleanup_##c(n, t) MALLOC_TSD #undef MALLOC_TSD_cleanup_yes -- GitLab From b779522b9b81f8a53a1f147968a890af8664b213 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 12 Feb 2017 16:34:36 -0800 Subject: [PATCH 274/544] Convert arena->dss_prec synchronization to atomics. --- include/jemalloc/internal/arena_externs.h | 4 ++-- include/jemalloc/internal/arena_structs_b.h | 2 +- src/arena.c | 17 +++++------------ src/ctl.c | 4 ++-- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index d0af91bf..d6556dae 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -60,8 +60,8 @@ bool arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t extra, bool zero); void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache); -dss_prec_t arena_dss_prec_get(tsdn_t *tsdn, arena_t *arena); -bool arena_dss_prec_set(tsdn_t *tsdn, arena_t *arena, dss_prec_t dss_prec); +dss_prec_t arena_dss_prec_get(arena_t *arena); +bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec); ssize_t arena_decay_time_default_get(void); bool arena_decay_time_default_set(ssize_t decay_time); void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 8629446d..dde26894 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -156,7 +156,7 @@ struct arena_s { */ size_t extent_sn_next; - /* Synchronization: lock. */ + /* Synchronization: atomic. */ dss_prec_t dss_prec; /* diff --git a/src/arena.c b/src/arena.c index 5905306c..345c57df 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1404,23 +1404,16 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, } dss_prec_t -arena_dss_prec_get(tsdn_t *tsdn, arena_t *arena) { - dss_prec_t ret; - - malloc_mutex_lock(tsdn, &arena->lock); - ret = arena->dss_prec; - malloc_mutex_unlock(tsdn, &arena->lock); - return ret; +arena_dss_prec_get(arena_t *arena) { + return (dss_prec_t)atomic_read_u((unsigned *)&arena->dss_prec); } bool -arena_dss_prec_set(tsdn_t *tsdn, arena_t *arena, dss_prec_t dss_prec) { +arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec) { if (!have_dss) { return (dss_prec != dss_prec_disabled); } - malloc_mutex_lock(tsdn, &arena->lock); - arena->dss_prec = dss_prec; - malloc_mutex_unlock(tsdn, &arena->lock); + atomic_write_u((unsigned *)&arena->dss_prec, dss_prec); return false; } @@ -1442,7 +1435,7 @@ static void arena_basic_stats_merge_locked(arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) { *nthreads += arena_nthreads_get(arena, false); - *dss = dss_prec_names[arena->dss_prec]; + *dss = dss_prec_names[arena_dss_prec_get(arena)]; *decay_time = arena->decay.time; *nactive += atomic_read_zu(&arena->nactive); *ndirty += extents_npages_get(&arena->extents_cached); diff --git a/src/ctl.c b/src/ctl.c index 403bc30c..0bf4258e 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1767,11 +1767,11 @@ arena_i_dss_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, } else { arena_t *arena = arena_get(tsd_tsdn(tsd), arena_ind, false); if (arena == NULL || (dss_prec != dss_prec_limit && - arena_dss_prec_set(tsd_tsdn(tsd), arena, dss_prec))) { + arena_dss_prec_set(arena, dss_prec))) { ret = EFAULT; goto label_return; } - dss_prec_old = arena_dss_prec_get(tsd_tsdn(tsd), arena); + dss_prec_old = arena_dss_prec_get(arena); } dss = dss_prec_names[dss_prec_old]; -- GitLab From fa2d64c94b07ee21a0f6f44b9fe6e3bbefa51c6c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 12 Feb 2017 17:03:46 -0800 Subject: [PATCH 275/544] Convert arena->prof_accumbytes synchronization to atomics. --- include/jemalloc/internal/arena_inlines_a.h | 34 +-------- include/jemalloc/internal/arena_structs_b.h | 3 +- include/jemalloc/internal/atomic_inlines.h | 4 +- include/jemalloc/internal/atomic_types.h | 8 ++ .../jemalloc/internal/jemalloc_internal.h.in | 7 +- include/jemalloc/internal/private_symbols.txt | 5 +- include/jemalloc/internal/prof_externs.h | 1 + include/jemalloc/internal/prof_inlines_a.h | 76 +++++++++++++++++++ .../{prof_inlines.h => prof_inlines_b.h} | 6 +- include/jemalloc/internal/prof_structs.h | 7 ++ include/jemalloc/internal/prof_types.h | 1 + include/jemalloc/internal/witness_types.h | 1 + src/arena.c | 18 +---- src/prof.c | 14 ++++ src/tcache.c | 2 +- 15 files changed, 128 insertions(+), 59 deletions(-) create mode 100644 include/jemalloc/internal/atomic_types.h create mode 100644 include/jemalloc/internal/prof_inlines_a.h rename include/jemalloc/internal/{prof_inlines.h => prof_inlines_b.h} (98%) diff --git a/include/jemalloc/internal/arena_inlines_a.h b/include/jemalloc/internal/arena_inlines_a.h index a81aaf56..ea7e0995 100644 --- a/include/jemalloc/internal/arena_inlines_a.h +++ b/include/jemalloc/internal/arena_inlines_a.h @@ -6,8 +6,6 @@ unsigned arena_ind_get(const arena_t *arena); void arena_internal_add(arena_t *arena, size_t size); void arena_internal_sub(arena_t *arena, size_t size); size_t arena_internal_get(arena_t *arena); -bool arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes); -bool arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes); bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes); #endif /* JEMALLOC_ENABLE_INLINE */ @@ -33,29 +31,6 @@ arena_internal_get(arena_t *arena) { return atomic_read_zu(&arena->stats.internal); } -JEMALLOC_INLINE bool -arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes) { - cassert(config_prof); - assert(prof_interval != 0); - - arena->prof_accumbytes += accumbytes; - if (arena->prof_accumbytes >= prof_interval) { - arena->prof_accumbytes %= prof_interval; - return true; - } - return false; -} - -JEMALLOC_INLINE bool -arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes) { - cassert(config_prof); - - if (likely(prof_interval == 0)) { - return false; - } - return arena_prof_accum_impl(arena, accumbytes); -} - JEMALLOC_INLINE bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) { cassert(config_prof); @@ -64,14 +39,7 @@ arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) { return false; } - { - bool ret; - - malloc_mutex_lock(tsdn, &arena->lock); - ret = arena_prof_accum_impl(arena, accumbytes); - malloc_mutex_unlock(tsdn, &arena->lock); - return ret; - } + return prof_accum_add(tsdn, &arena->prof_accum, accumbytes); } #endif /* (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) */ diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index dde26894..2ee5690e 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -138,7 +138,8 @@ struct arena_s { */ ql_head(tcache_t) tcache_ql; - /* Synchronization: lock. */ + /* Synchronization: internal. */ + prof_accum_t prof_accum; uint64_t prof_accumbytes; /* diff --git a/include/jemalloc/internal/atomic_inlines.h b/include/jemalloc/internal/atomic_inlines.h index 7c1902f8..de66d57d 100644 --- a/include/jemalloc/internal/atomic_inlines.h +++ b/include/jemalloc/internal/atomic_inlines.h @@ -23,7 +23,7 @@ */ #ifndef JEMALLOC_ENABLE_INLINE -# if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) +# ifdef JEMALLOC_ATOMIC_U64 uint64_t atomic_add_u64(uint64_t *p, uint64_t x); uint64_t atomic_sub_u64(uint64_t *p, uint64_t x); bool atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s); @@ -50,7 +50,7 @@ void atomic_write_u(unsigned *p, unsigned x); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ATOMIC_C_)) /******************************************************************************/ /* 64-bit operations. */ -#if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) +#ifdef JEMALLOC_ATOMIC_U64 # if (defined(__amd64__) || defined(__x86_64__)) JEMALLOC_INLINE uint64_t atomic_add_u64(uint64_t *p, uint64_t x) { diff --git a/include/jemalloc/internal/atomic_types.h b/include/jemalloc/internal/atomic_types.h new file mode 100644 index 00000000..0fd5e5b5 --- /dev/null +++ b/include/jemalloc/internal/atomic_types.h @@ -0,0 +1,8 @@ +#ifndef JEMALLOC_INTERNAL_ATOMIC_TYPES_H +#define JEMALLOC_INTERNAL_ATOMIC_TYPES_H + +#if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) +# define JEMALLOC_ATOMIC_U64 +#endif + +#endif /* JEMALLOC_INTERNAL_ATOMIC_TYPES_H */ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index bace9c46..7e9c24b7 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -380,6 +380,7 @@ typedef unsigned szind_t; #include "jemalloc/internal/nstime_types.h" #include "jemalloc/internal/util_types.h" +#include "jemalloc/internal/atomic_types.h" #include "jemalloc/internal/spin_types.h" #include "jemalloc/internal/prng_types.h" #include "jemalloc/internal/ticker_types.h" @@ -419,10 +420,10 @@ typedef unsigned szind_t; #include "jemalloc/internal/extent_structs.h" #include "jemalloc/internal/extent_dss_structs.h" #include "jemalloc/internal/base_structs.h" +#include "jemalloc/internal/prof_structs.h" #include "jemalloc/internal/arena_structs_b.h" #include "jemalloc/internal/rtree_structs.h" #include "jemalloc/internal/tcache_structs.h" -#include "jemalloc/internal/prof_structs.h" #include "jemalloc/internal/tsd_structs.h" @@ -902,6 +903,7 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) { * Include portions of arena code interleaved with tcache code in order to * resolve circular dependencies. */ +#include "jemalloc/internal/prof_inlines_a.h" #include "jemalloc/internal/arena_inlines_a.h" #ifndef JEMALLOC_ENABLE_INLINE @@ -1163,8 +1165,7 @@ ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, } #endif -#include "jemalloc/internal/prof_inlines.h" - +#include "jemalloc/internal/prof_inlines_b.h" #ifdef __cplusplus } diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index ab5a672c..4e799915 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -54,8 +54,6 @@ arena_prefork1 arena_prefork2 arena_prefork3 arena_prof_accum -arena_prof_accum_impl -arena_prof_accum_locked arena_prof_promote arena_prof_tctx_get arena_prof_tctx_reset @@ -364,6 +362,9 @@ prng_range_zu prng_state_next_u32 prng_state_next_u64 prng_state_next_zu +prof_accum_add +prof_accum_cancel +prof_accum_init prof_active prof_active_get prof_active_get_unlocked diff --git a/include/jemalloc/internal/prof_externs.h b/include/jemalloc/internal/prof_externs.h index 76505f82..f3b6f8d3 100644 --- a/include/jemalloc/internal/prof_externs.h +++ b/include/jemalloc/internal/prof_externs.h @@ -55,6 +55,7 @@ extern prof_dump_header_t *prof_dump_header; void prof_cnt_all(uint64_t *curobjs, uint64_t *curbytes, uint64_t *accumobjs, uint64_t *accumbytes); #endif +bool prof_accum_init(tsdn_t *tsdn, prof_accum_t *prof_accum); void prof_idump(tsdn_t *tsdn); bool prof_mdump(tsd_t *tsd, const char *filename); void prof_gdump(tsdn_t *tsdn); diff --git a/include/jemalloc/internal/prof_inlines_a.h b/include/jemalloc/internal/prof_inlines_a.h new file mode 100644 index 00000000..d77635a8 --- /dev/null +++ b/include/jemalloc/internal/prof_inlines_a.h @@ -0,0 +1,76 @@ +#ifndef JEMALLOC_INTERNAL_PROF_INLINES_A_H +#define JEMALLOC_INTERNAL_PROF_INLINES_A_H + +#ifndef JEMALLOC_ENABLE_INLINE +bool prof_accum_add(tsdn_t *tsdn, prof_accum_t *prof_accum, + uint64_t accumbytes); +void prof_accum_cancel(tsdn_t *tsdn, prof_accum_t *prof_accum, size_t usize); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PROF_C_)) +JEMALLOC_INLINE bool +prof_accum_add(tsdn_t *tsdn, prof_accum_t *prof_accum, uint64_t accumbytes) { + cassert(config_prof); + + bool overflow; + uint64_t a0, a1; + + /* + * If the application allocates fast enough (and/or if idump is slow + * enough), extreme overflow here (a1 >= prof_interval * 2) can cause + * idump trigger coalescing. This is an intentional mechanism that + * avoids rate-limiting allocation. + */ +#ifdef JEMALLOC_ATOMIC_U64 + do { + a0 = atomic_read_u64(&prof_accum->accumbytes); + a1 = a0 + accumbytes; + assert(a1 >= a0); + overflow = (a1 >= prof_interval); + if (overflow) { + a1 %= prof_interval; + } + } while (atomic_cas_u64(&prof_accum->accumbytes, a0, a1)); +#else + malloc_mutex_lock(tsdn, &prof_accum->mtx); + a0 = prof_accum->accumbytes; + a1 = a0 + accumbytes; + overflow = (a1 >= prof_interval); + if (overflow) { + a1 %= prof_interval; + } + prof_accum->accumbytes = a1; + malloc_mutex_unlock(tsdn, &prof_accum->mtx); +#endif + return overflow; +} + +JEMALLOC_INLINE void +prof_accum_cancel(tsdn_t *tsdn, prof_accum_t *prof_accum, size_t usize) { + cassert(config_prof); + + /* + * Cancel out as much of the excessive prof_accumbytes increase as + * possible without underflowing. Interval-triggered dumps occur + * slightly more often than intended as a result of incomplete + * canceling. + */ + uint64_t a0, a1; +#ifdef JEMALLOC_ATOMIC_U64 + do { + a0 = atomic_read_u64(&prof_accum->accumbytes); + a1 = (a0 >= LARGE_MINCLASS - usize) ? a0 - (LARGE_MINCLASS - + usize) : 0; + } while (atomic_cas_u64(&prof_accum->accumbytes, a0, a1)); +#else + malloc_mutex_lock(tsdn, &prof_accum->mtx); + a0 = prof_accum->accumbytes; + a1 = (a0 >= LARGE_MINCLASS - usize) ? a0 - (LARGE_MINCLASS - usize) : + 0; + prof_accum->accumbytes = a1; + malloc_mutex_unlock(tsdn, &prof_accum->mtx); +#endif +} +#endif + +#endif /* JEMALLOC_INTERNAL_PROF_INLINES_A_H */ diff --git a/include/jemalloc/internal/prof_inlines.h b/include/jemalloc/internal/prof_inlines_b.h similarity index 98% rename from include/jemalloc/internal/prof_inlines.h rename to include/jemalloc/internal/prof_inlines_b.h index aba2936a..9e969a07 100644 --- a/include/jemalloc/internal/prof_inlines.h +++ b/include/jemalloc/internal/prof_inlines_b.h @@ -1,5 +1,5 @@ -#ifndef JEMALLOC_INTERNAL_PROF_INLINES_H -#define JEMALLOC_INTERNAL_PROF_INLINES_H +#ifndef JEMALLOC_INTERNAL_PROF_INLINES_B_H +#define JEMALLOC_INTERNAL_PROF_INLINES_B_H #ifndef JEMALLOC_ENABLE_INLINE bool prof_active_get_unlocked(void); @@ -237,4 +237,4 @@ prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, size_t usize) { } #endif -#endif /* JEMALLOC_INTERNAL_PROF_INLINES_H */ +#endif /* JEMALLOC_INTERNAL_PROF_INLINES_B_H */ diff --git a/include/jemalloc/internal/prof_structs.h b/include/jemalloc/internal/prof_structs.h index caae1257..afff6aa5 100644 --- a/include/jemalloc/internal/prof_structs.h +++ b/include/jemalloc/internal/prof_structs.h @@ -15,6 +15,13 @@ typedef struct { } prof_unwind_data_t; #endif +struct prof_accum_s { +#ifndef JEMALLOC_ATOMIC_U64 + malloc_mutex_t mtx; +#endif + uint64_t accumbytes; +}; + struct prof_cnt_s { /* Profiling counters. */ uint64_t curobjs; diff --git a/include/jemalloc/internal/prof_types.h b/include/jemalloc/internal/prof_types.h index ff0db65e..1eff995e 100644 --- a/include/jemalloc/internal/prof_types.h +++ b/include/jemalloc/internal/prof_types.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_PROF_TYPES_H typedef struct prof_bt_s prof_bt_t; +typedef struct prof_accum_s prof_accum_t; typedef struct prof_cnt_s prof_cnt_t; typedef struct prof_tctx_s prof_tctx_t; typedef struct prof_gctx_s prof_gctx_t; diff --git a/include/jemalloc/internal/witness_types.h b/include/jemalloc/internal/witness_types.h index 29299168..f919cc5a 100644 --- a/include/jemalloc/internal/witness_types.h +++ b/include/jemalloc/internal/witness_types.h @@ -47,6 +47,7 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *, #define WITNESS_RANK_ARENA_LARGE WITNESS_RANK_LEAF #define WITNESS_RANK_DSS WITNESS_RANK_LEAF #define WITNESS_RANK_PROF_ACTIVE WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_ACCUM WITNESS_RANK_LEAF #define WITNESS_RANK_PROF_DUMP_SEQ WITNESS_RANK_LEAF #define WITNESS_RANK_PROF_GDUMP WITNESS_RANK_LEAF #define WITNESS_RANK_PROF_NEXT_THR_UID WITNESS_RANK_LEAF diff --git a/src/arena.c b/src/arena.c index 345c57df..40db9d1d 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1148,19 +1148,7 @@ arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, extent_usize_set(extent, usize); - /* - * Cancel out as much of the excessive prof_accumbytes increase as - * possible without underflowing. Interval-triggered dumps occur - * slightly more often than intended as a result of incomplete - * canceling. - */ - malloc_mutex_lock(tsdn, &arena->lock); - if (arena->prof_accumbytes >= LARGE_MINCLASS - usize) { - arena->prof_accumbytes -= LARGE_MINCLASS - usize; - } else { - arena->prof_accumbytes = 0; - } - malloc_mutex_unlock(tsdn, &arena->lock); + prof_accum_cancel(tsdn, &arena->prof_accum, usize); assert(isalloc(tsdn, extent, ptr) == usize); } @@ -1574,7 +1562,9 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { } if (config_prof) { - arena->prof_accumbytes = 0; + if (prof_accum_init(tsdn, &arena->prof_accum)) { + goto label_error; + } } if (config_cache_oblivious) { diff --git a/src/prof.c b/src/prof.c index 5aeefb28..13fa20d3 100644 --- a/src/prof.c +++ b/src/prof.c @@ -1753,6 +1753,20 @@ prof_fdump(void) { prof_dump(tsd, false, filename, opt_prof_leak); } +bool +prof_accum_init(tsdn_t *tsdn, prof_accum_t *prof_accum) { + cassert(config_prof); + +#ifndef JEMALLOC_ATOMIC_U64 + if (malloc_mutex_init(&prof_accum->mtx, "prof_accum", + WITNESS_RANK_PROF_ACCUM)) { + return true; + } +#endif + prof_accum->accumbytes = 0; + return false; +} + void prof_idump(tsdn_t *tsdn) { tsd_t *tsd; diff --git a/src/tcache.c b/src/tcache.c index 94c45707..f38c2d5d 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -200,7 +200,7 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, } if ((config_prof || config_stats) && locked_arena == arena) { if (config_prof) { - idump = arena_prof_accum_locked(arena, + idump = arena_prof_accum(tsd_tsdn(tsd), arena, tcache->prof_accumbytes); tcache->prof_accumbytes = 0; } -- GitLab From 6b5cba41916549f1aa37adac45659b60293d9495 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 12 Feb 2017 17:43:33 -0800 Subject: [PATCH 276/544] Convert arena->stats synchronization to atomics. --- include/jemalloc/internal/arena_externs.h | 12 +- include/jemalloc/internal/arena_structs_b.h | 3 +- .../jemalloc/internal/jemalloc_internal.h.in | 4 +- include/jemalloc/internal/private_symbols.txt | 1 + include/jemalloc/internal/stats_structs.h | 6 +- include/jemalloc/internal/witness_types.h | 3 +- src/arena.c | 487 +++++++++++------- src/large.c | 15 +- src/tcache.c | 23 +- 9 files changed, 326 insertions(+), 228 deletions(-) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index d6556dae..2880399b 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -13,6 +13,12 @@ extern ssize_t opt_decay_time; extern const arena_bin_info_t arena_bin_info[NBINS]; +void arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats, + szind_t szind, uint64_t nrequests); +void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, + const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty, + arena_stats_t *astats, malloc_bin_stats_t *bstats, + malloc_large_stats_t *lstats); void arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent); #ifdef JEMALLOC_JET @@ -21,7 +27,7 @@ size_t arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr); extent_t *arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero); void arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena, - extent_t *extent, bool locked); + extent_t *extent); void arena_extent_dalloc_large_finish(tsdn_t *tsdn, arena_t *arena, extent_t *extent); void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, @@ -67,10 +73,6 @@ bool arena_decay_time_default_set(ssize_t decay_time); void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty); -void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty, - arena_stats_t *astats, malloc_bin_stats_t *bstats, - malloc_large_stats_t *lstats); unsigned arena_nthreads_get(arena_t *arena, bool internal); void arena_nthreads_inc(arena_t *arena, bool internal); void arena_nthreads_dec(arena_t *arena, bool internal); diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 2ee5690e..04e859b5 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -127,8 +127,9 @@ struct arena_s { */ malloc_mutex_t lock; - /* Synchronization: lock. */ + /* Synchronization: internal. */ arena_stats_t stats; + /* * List of tcaches for extant threads associated with this arena. * Stats from these are merged incrementally, and at exit if diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 7e9c24b7..0d0440b5 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -411,10 +411,10 @@ typedef unsigned szind_t; #include "jemalloc/internal/spin_structs.h" #include "jemalloc/internal/ticker_structs.h" #include "jemalloc/internal/ckh_structs.h" -#include "jemalloc/internal/stats_structs.h" -#include "jemalloc/internal/ctl_structs.h" #include "jemalloc/internal/witness_structs.h" #include "jemalloc/internal/mutex_structs.h" +#include "jemalloc/internal/stats_structs.h" +#include "jemalloc/internal/ctl_structs.h" #include "jemalloc/internal/bitmap_structs.h" #include "jemalloc/internal/arena_structs_a.h" #include "jemalloc/internal/extent_structs.h" diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 4e799915..ff54a35d 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -66,6 +66,7 @@ arena_salloc arena_sdalloc arena_set arena_slab_regind +arena_stats_init arena_stats_merge arena_tcache_fill_small arena_tdata_get diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index 5cdb0cd9..4f5984ab 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -76,6 +76,10 @@ struct malloc_large_stats_s { * requests. */ struct arena_stats_s { +#ifndef JEMALLOC_ATOMIC_U64 + malloc_mutex_t mtx; +#endif + /* Number of bytes currently mapped, excluding retained memory. */ size_t mapped; /* Derived. */ @@ -97,7 +101,7 @@ struct arena_stats_s { uint64_t purged; size_t base; /* Derived. */ - size_t internal; /* Protected via atomic_*_zu(). */ + size_t internal; size_t resident; /* Derived. */ size_t allocated_large; diff --git a/include/jemalloc/internal/witness_types.h b/include/jemalloc/internal/witness_types.h index f919cc5a..3fd7998a 100644 --- a/include/jemalloc/internal/witness_types.h +++ b/include/jemalloc/internal/witness_types.h @@ -41,10 +41,11 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *, #define WITNESS_RANK_RTREE_ELM 12U #define WITNESS_RANK_RTREE 13U #define WITNESS_RANK_BASE 14U +#define WITNESS_RANK_ARENA_LARGE 15U #define WITNESS_RANK_LEAF 0xffffffffU #define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF -#define WITNESS_RANK_ARENA_LARGE WITNESS_RANK_LEAF +#define WITNESS_RANK_ARENA_STATS WITNESS_RANK_LEAF #define WITNESS_RANK_DSS WITNESS_RANK_LEAF #define WITNESS_RANK_PROF_ACTIVE WITNESS_RANK_LEAF #define WITNESS_RANK_PROF_ACCUM WITNESS_RANK_LEAF diff --git a/src/arena.c b/src/arena.c index 40db9d1d..ac447199 100644 --- a/src/arena.c +++ b/src/arena.c @@ -37,6 +37,212 @@ static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, /******************************************************************************/ +static bool +arena_stats_init(tsdn_t *tsdn, arena_stats_t *arena_stats) { + if (config_debug) { + for (size_t i = 0; i < sizeof(arena_stats_t); i++) { + assert(((char *)arena_stats)[0] == 0); + } + } +#ifndef JEMALLOC_ATOMIC_U64 + if (malloc_mutex_init(&arena_stats->mtx, "arena_stats", + WITNESS_RANK_ARENA_STATS)) { + return true; + } +#endif + /* Memory is zeroed, so there is no need to clear stats. */ + return false; +} + +static void +arena_stats_lock(tsdn_t *tsdn, arena_stats_t *arena_stats) { +#ifndef JEMALLOC_ATOMIC_U64 + malloc_mutex_lock(tsdn, &arena_stats->mtx); +#endif +} + +static void +arena_stats_unlock(tsdn_t *tsdn, arena_stats_t *arena_stats) { +#ifndef JEMALLOC_ATOMIC_U64 + malloc_mutex_unlock(tsdn, &arena_stats->mtx); +#endif +} + +static uint64_t +arena_stats_read_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, uint64_t *p) { +#ifdef JEMALLOC_ATOMIC_U64 + return atomic_read_u64(p); +#else + malloc_mutex_assert_owner(tsdn, &arena_stats->mtx); + return *p; +#endif +} + +static void +arena_stats_add_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, uint64_t *p, + uint64_t x) { +#ifdef JEMALLOC_ATOMIC_U64 + atomic_add_u64(p, x); +#else + malloc_mutex_assert_owner(tsdn, &arena_stats->mtx); + *p += x; +#endif +} + +static void +arena_stats_sub_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, uint64_t *p, + uint64_t x) { +#ifdef JEMALLOC_ATOMIC_U64 + atomic_sub_u64(p, x); +#else + malloc_mutex_assert_owner(tsdn, &arena_stats->mtx); + *p -= x; +#endif +} + +static size_t +arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t *p) { +#ifdef JEMALLOC_ATOMIC_U64 + return atomic_read_zu(p); +#else + malloc_mutex_assert_owner(tsdn, &arena_stats->mtx); + return *p; +#endif +} + +static void +arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t *p, + size_t x) { +#ifdef JEMALLOC_ATOMIC_U64 + atomic_add_zu(p, x); +#else + malloc_mutex_assert_owner(tsdn, &arena_stats->mtx); + *p += x; +#endif +} + +static void +arena_stats_sub_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t *p, + size_t x) { +#ifdef JEMALLOC_ATOMIC_U64 + atomic_sub_zu(p, x); +#else + malloc_mutex_assert_owner(tsdn, &arena_stats->mtx); + *p -= x; +#endif +} + +void +arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats, + szind_t szind, uint64_t nrequests) { + arena_stats_lock(tsdn, arena_stats); + arena_stats_add_u64(tsdn, arena_stats, &arena_stats->nrequests_large, + nrequests); + arena_stats_add_u64(tsdn, arena_stats, &arena_stats->lstats[szind - + NBINS].nrequests, nrequests); + arena_stats_unlock(tsdn, arena_stats); +} + +void +arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, + const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) { + malloc_mutex_lock(tsdn, &arena->lock); + *nthreads += arena_nthreads_get(arena, false); + *dss = dss_prec_names[arena_dss_prec_get(arena)]; + *decay_time = arena->decay.time; + *nactive += atomic_read_zu(&arena->nactive); + *ndirty += extents_npages_get(&arena->extents_cached); + malloc_mutex_unlock(tsdn, &arena->lock); +} + +void +arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, + const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty, + arena_stats_t *astats, malloc_bin_stats_t *bstats, + malloc_large_stats_t *lstats) { + size_t base_allocated, base_resident, base_mapped; + unsigned i; + + cassert(config_stats); + + arena_basic_stats_merge(tsdn, arena, nthreads, dss, decay_time, + nactive, ndirty); + + base_stats_get(tsdn, arena->base, &base_allocated, &base_resident, + &base_mapped); + + arena_stats_lock(tsdn, &arena->stats); + + astats->mapped += base_mapped + arena_stats_read_zu(tsdn, &arena->stats, + &arena->stats.mapped); + astats->retained += (extents_npages_get(&arena->extents_retained) << + LG_PAGE); + astats->npurge += arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.npurge); + astats->nmadvise += arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.nmadvise); + astats->purged += arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.purged); + astats->base += base_allocated; + astats->internal += arena_internal_get(arena); + astats->resident += base_resident + (((atomic_read_zu(&arena->nactive) + + extents_npages_get(&arena->extents_cached)) << LG_PAGE)); + astats->allocated_large += arena_stats_read_zu(tsdn, &arena->stats, + &arena->stats.allocated_large); + astats->nmalloc_large += arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.nmalloc_large); + astats->ndalloc_large += arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.ndalloc_large); + astats->nrequests_large += arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.nrequests_large); + + for (i = 0; i < NSIZES - NBINS; i++) { + lstats[i].nmalloc += arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.lstats[i].nmalloc); + lstats[i].ndalloc += arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.lstats[i].ndalloc); + lstats[i].nrequests += arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.lstats[i].nrequests); + lstats[i].curlextents += arena_stats_read_zu(tsdn, + &arena->stats, &arena->stats.lstats[i].curlextents); + } + + arena_stats_unlock(tsdn, &arena->stats); + + if (config_tcache) { + tcache_bin_t *tbin; + tcache_t *tcache; + + /* tcache_bytes counts currently cached bytes. */ + astats->tcache_bytes = 0; + ql_foreach(tcache, &arena->tcache_ql, link) { + for (i = 0; i < nhbins; i++) { + tbin = &tcache->tbins[i]; + astats->tcache_bytes += tbin->ncached * + index2size(i); + } + } + } + + for (i = 0; i < NBINS; i++) { + arena_bin_t *bin = &arena->bins[i]; + + malloc_mutex_lock(tsdn, &bin->lock); + bstats[i].nmalloc += bin->stats.nmalloc; + bstats[i].ndalloc += bin->stats.ndalloc; + bstats[i].nrequests += bin->stats.nrequests; + bstats[i].curregs += bin->stats.curregs; + if (config_tcache) { + bstats[i].nfills += bin->stats.nfills; + bstats[i].nflushes += bin->stats.nflushes; + } + bstats[i].nslabs += bin->stats.nslabs; + bstats[i].reslabs += bin->stats.reslabs; + bstats[i].curslabs += bin->stats.curslabs; + malloc_mutex_unlock(tsdn, &bin->lock); + } +} + void arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { @@ -128,26 +334,7 @@ arena_nactive_sub(arena_t *arena, size_t sub_pages) { } static void -arena_large_malloc_stats_update(arena_t *arena, size_t usize) { - szind_t index, hindex; - - cassert(config_stats); - - if (usize < LARGE_MINCLASS) { - usize = LARGE_MINCLASS; - } - index = size2index(usize); - hindex = (index >= NBINS) ? index - NBINS : 0; - - arena->stats.nmalloc_large++; - arena->stats.allocated_large += usize; - arena->stats.lstats[hindex].nmalloc++; - arena->stats.lstats[hindex].nrequests++; - arena->stats.lstats[hindex].curlextents++; -} - -static void -arena_large_malloc_stats_update_undo(arena_t *arena, size_t usize) { +arena_large_malloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t usize) { szind_t index, hindex; cassert(config_stats); @@ -158,15 +345,20 @@ arena_large_malloc_stats_update_undo(arena_t *arena, size_t usize) { index = size2index(usize); hindex = (index >= NBINS) ? index - NBINS : 0; - arena->stats.nmalloc_large--; - arena->stats.allocated_large -= usize; - arena->stats.lstats[hindex].nmalloc--; - arena->stats.lstats[hindex].nrequests--; - arena->stats.lstats[hindex].curlextents--; + arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.nmalloc_large, + 1); + arena_stats_add_zu(tsdn, &arena->stats, &arena->stats.allocated_large, + usize); + arena_stats_add_u64(tsdn, &arena->stats, + &arena->stats.lstats[hindex].nmalloc, 1); + arena_stats_add_u64(tsdn, &arena->stats, + &arena->stats.lstats[hindex].nrequests, 1); + arena_stats_add_zu(tsdn, &arena->stats, + &arena->stats.lstats[hindex].curlextents, 1); } static void -arena_large_dalloc_stats_update(arena_t *arena, size_t usize) { +arena_large_dalloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t usize) { szind_t index, hindex; cassert(config_stats); @@ -177,52 +369,36 @@ arena_large_dalloc_stats_update(arena_t *arena, size_t usize) { index = size2index(usize); hindex = (index >= NBINS) ? index - NBINS : 0; - arena->stats.ndalloc_large++; - arena->stats.allocated_large -= usize; - arena->stats.lstats[hindex].ndalloc++; - arena->stats.lstats[hindex].curlextents--; + arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.ndalloc_large, + 1); + arena_stats_sub_zu(tsdn, &arena->stats, &arena->stats.allocated_large, + usize); + arena_stats_add_u64(tsdn, &arena->stats, + &arena->stats.lstats[hindex].ndalloc, 1); + arena_stats_sub_zu(tsdn, &arena->stats, + &arena->stats.lstats[hindex].curlextents, 1); } static void -arena_large_reset_stats_cancel(arena_t *arena, size_t usize) { +arena_large_reset_stats_cancel(tsdn_t *tsdn, arena_t *arena, size_t usize) { szind_t index = size2index(usize); szind_t hindex = (index >= NBINS) ? index - NBINS : 0; cassert(config_stats); - arena->stats.ndalloc_large--; - arena->stats.lstats[hindex].ndalloc--; + arena_stats_lock(tsdn, &arena->stats); + arena_stats_sub_u64(tsdn, &arena->stats, &arena->stats.ndalloc_large, + 1); + arena_stats_sub_u64(tsdn, &arena->stats, + &arena->stats.lstats[hindex].ndalloc, 1); + arena_stats_unlock(tsdn, &arena->stats); } static void -arena_large_ralloc_stats_update(arena_t *arena, size_t oldusize, size_t usize) { - arena_large_dalloc_stats_update(arena, oldusize); - arena_large_malloc_stats_update(arena, usize); -} - -static extent_t * -arena_extent_alloc_large_hard(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, size_t usize, size_t alignment, - bool *zero) { - extent_t *extent; - bool commit = true; - - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - - extent = extent_alloc_wrapper(tsdn, arena, r_extent_hooks, NULL, usize, - large_pad, alignment, zero, &commit, false); - if (extent == NULL) { - /* Revert optimistic stats updates. */ - malloc_mutex_lock(tsdn, &arena->lock); - if (config_stats) { - arena_large_malloc_stats_update_undo(arena, usize); - arena->stats.mapped -= usize; - } - arena_nactive_sub(arena, (usize + large_pad) >> LG_PAGE); - malloc_mutex_unlock(tsdn, &arena->lock); - } - - return extent; +arena_large_ralloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t oldusize, + size_t usize) { + arena_large_dalloc_stats_update(tsdn, arena, oldusize); + arena_large_malloc_stats_update(tsdn, arena, usize); } extent_t * @@ -233,43 +409,35 @@ arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - malloc_mutex_lock(tsdn, &arena->lock); - - /* Optimistically update stats. */ - if (config_stats) { - arena_large_malloc_stats_update(arena, usize); - arena->stats.mapped += usize; - } - arena_nactive_add(arena, (usize + large_pad) >> LG_PAGE); - - malloc_mutex_unlock(tsdn, &arena->lock); - bool commit = true; extent = extent_alloc_cache(tsdn, arena, &extent_hooks, NULL, usize, large_pad, alignment, zero, &commit, false); if (extent == NULL) { - extent = arena_extent_alloc_large_hard(tsdn, arena, - &extent_hooks, usize, alignment, zero); + extent = extent_alloc_wrapper(tsdn, arena, &extent_hooks, NULL, + usize, large_pad, alignment, zero, &commit, false); + } + + if (config_stats && extent != NULL) { + arena_stats_lock(tsdn, &arena->stats); + arena_large_malloc_stats_update(tsdn, arena, usize); + arena_stats_add_zu(tsdn, &arena->stats, &arena->stats.mapped, + usize); + arena_stats_unlock(tsdn, &arena->stats); } + arena_nactive_add(arena, (usize + large_pad) >> LG_PAGE); return extent; } void -arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - bool locked) { - if (!locked) { - malloc_mutex_lock(tsdn, &arena->lock); - } else { - malloc_mutex_assert_owner(tsdn, &arena->lock); - } +arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { if (config_stats) { - arena_large_dalloc_stats_update(arena, + arena_stats_lock(tsdn, &arena->stats); + arena_large_dalloc_stats_update(tsdn, arena, extent_usize_get(extent)); - arena->stats.mapped -= extent_size_get(extent); - } - if (!locked) { - malloc_mutex_unlock(tsdn, &arena->lock); + arena_stats_sub_zu(tsdn, &arena->stats, &arena->stats.mapped, + extent_size_get(extent)); + arena_stats_unlock(tsdn, &arena->stats); } arena_nactive_sub(arena, extent_size_get(extent) >> LG_PAGE); } @@ -287,13 +455,14 @@ arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize = extent_usize_get(extent); size_t udiff = oldusize - usize; - malloc_mutex_lock(tsdn, &arena->lock); if (config_stats) { - arena_large_ralloc_stats_update(arena, oldusize, usize); - arena->stats.mapped -= udiff; + arena_stats_lock(tsdn, &arena->stats); + arena_large_ralloc_stats_update(tsdn, arena, oldusize, usize); + arena_stats_sub_zu(tsdn, &arena->stats, &arena->stats.mapped, + udiff); + arena_stats_unlock(tsdn, &arena->stats); } arena_nactive_sub(arena, udiff >> LG_PAGE); - malloc_mutex_unlock(tsdn, &arena->lock); } void @@ -302,13 +471,14 @@ arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize = extent_usize_get(extent); size_t udiff = usize - oldusize; - malloc_mutex_lock(tsdn, &arena->lock); if (config_stats) { - arena_large_ralloc_stats_update(arena, oldusize, usize); - arena->stats.mapped += udiff; + arena_stats_lock(tsdn, &arena->stats); + arena_large_ralloc_stats_update(tsdn, arena, oldusize, usize); + arena_stats_add_zu(tsdn, &arena->stats, &arena->stats.mapped, + udiff); + arena_stats_unlock(tsdn, &arena->stats); } arena_nactive_add(arena, udiff >> LG_PAGE); - malloc_mutex_unlock(tsdn, &arena->lock); } static void @@ -575,8 +745,12 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, } if (config_stats) { - arena->stats.nmadvise += nmadvise; - arena->stats.purged += npurged; + arena_stats_lock(tsdn, &arena->stats); + arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.nmadvise, + nmadvise); + arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.purged, + npurged); + arena_stats_unlock(tsdn, &arena->stats); } return npurged; @@ -616,7 +790,10 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) { malloc_mutex_lock(tsdn, &arena->lock); if (config_stats) { - arena->stats.npurge++; + arena_stats_lock(tsdn, &arena->stats); + arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.npurge, + 1); + arena_stats_unlock(tsdn, &arena->stats); } label_return: @@ -717,7 +894,8 @@ arena_reset(tsd_t *tsd, arena_t *arena) { malloc_mutex_lock(tsd_tsdn(tsd), &arena->large_mtx); /* Cancel out unwanted effects on stats. */ if (config_stats) { - arena_large_reset_stats_cancel(arena, usize); + arena_large_reset_stats_cancel(tsd_tsdn(tsd), arena, + usize); } } malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx); @@ -849,8 +1027,6 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, } assert(extent_slab_get(slab)); - malloc_mutex_lock(tsdn, &arena->lock); - arena_nactive_add(arena, extent_size_get(slab) >> LG_PAGE); /* Initialize slab internals. */ @@ -860,9 +1036,11 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, bitmap_init(slab_data->bitmap, &bin_info->bitmap_info); if (config_stats) { - arena->stats.mapped += extent_size_get(slab); + arena_stats_lock(tsdn, &arena->stats); + arena_stats_add_zu(tsdn, &arena->stats, &arena->stats.mapped, + extent_size_get(slab)); + arena_stats_unlock(tsdn, &arena->stats); } - malloc_mutex_unlock(tsdn, &arena->lock); return slab; } @@ -1419,99 +1597,6 @@ arena_decay_time_default_set(ssize_t decay_time) { return false; } -static void -arena_basic_stats_merge_locked(arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) { - *nthreads += arena_nthreads_get(arena, false); - *dss = dss_prec_names[arena_dss_prec_get(arena)]; - *decay_time = arena->decay.time; - *nactive += atomic_read_zu(&arena->nactive); - *ndirty += extents_npages_get(&arena->extents_cached); -} - -void -arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) { - malloc_mutex_lock(tsdn, &arena->lock); - arena_basic_stats_merge_locked(arena, nthreads, dss, decay_time, - nactive, ndirty); - malloc_mutex_unlock(tsdn, &arena->lock); -} - -void -arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty, - arena_stats_t *astats, malloc_bin_stats_t *bstats, - malloc_large_stats_t *lstats) { - size_t base_allocated, base_resident, base_mapped; - unsigned i; - - cassert(config_stats); - - malloc_mutex_lock(tsdn, &arena->lock); - arena_basic_stats_merge_locked(arena, nthreads, dss, decay_time, - nactive, ndirty); - - base_stats_get(tsdn, arena->base, &base_allocated, &base_resident, - &base_mapped); - - astats->mapped += base_mapped + arena->stats.mapped; - astats->retained += (extents_npages_get(&arena->extents_retained) << - LG_PAGE); - astats->npurge += arena->stats.npurge; - astats->nmadvise += arena->stats.nmadvise; - astats->purged += arena->stats.purged; - astats->base += base_allocated; - astats->internal += arena_internal_get(arena); - astats->resident += base_resident + (((atomic_read_zu(&arena->nactive) + - extents_npages_get(&arena->extents_cached)) << LG_PAGE)); - astats->allocated_large += arena->stats.allocated_large; - astats->nmalloc_large += arena->stats.nmalloc_large; - astats->ndalloc_large += arena->stats.ndalloc_large; - astats->nrequests_large += arena->stats.nrequests_large; - - for (i = 0; i < NSIZES - NBINS; i++) { - lstats[i].nmalloc += arena->stats.lstats[i].nmalloc; - lstats[i].ndalloc += arena->stats.lstats[i].ndalloc; - lstats[i].nrequests += arena->stats.lstats[i].nrequests; - lstats[i].curlextents += arena->stats.lstats[i].curlextents; - } - - if (config_tcache) { - tcache_bin_t *tbin; - tcache_t *tcache; - - /* tcache_bytes counts currently cached bytes. */ - astats->tcache_bytes = 0; - ql_foreach(tcache, &arena->tcache_ql, link) { - for (i = 0; i < nhbins; i++) { - tbin = &tcache->tbins[i]; - astats->tcache_bytes += tbin->ncached * - index2size(i); - } - } - } - malloc_mutex_unlock(tsdn, &arena->lock); - - for (i = 0; i < NBINS; i++) { - arena_bin_t *bin = &arena->bins[i]; - - malloc_mutex_lock(tsdn, &bin->lock); - bstats[i].nmalloc += bin->stats.nmalloc; - bstats[i].ndalloc += bin->stats.ndalloc; - bstats[i].nrequests += bin->stats.nrequests; - bstats[i].curregs += bin->stats.curregs; - if (config_tcache) { - bstats[i].nfills += bin->stats.nfills; - bstats[i].nflushes += bin->stats.nflushes; - } - bstats[i].nslabs += bin->stats.nslabs; - bstats[i].reslabs += bin->stats.reslabs; - bstats[i].curslabs += bin->stats.curslabs; - malloc_mutex_unlock(tsdn, &bin->lock); - } -} - unsigned arena_nthreads_get(arena_t *arena, bool internal) { return atomic_read_u(&arena->nthreads[internal]); @@ -1557,6 +1642,12 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { goto label_error; } + if (config_stats) { + if (arena_stats_init(tsdn, &arena->stats)) { + goto label_error; + } + } + if (config_stats && config_tcache) { ql_new(&arena->tcache_ql); } @@ -1663,20 +1754,20 @@ arena_prefork3(tsdn_t *tsdn, arena_t *arena) { unsigned i; base_prefork(tsdn, arena->base); + malloc_mutex_prefork(tsdn, &arena->large_mtx); for (i = 0; i < NBINS; i++) { malloc_mutex_prefork(tsdn, &arena->bins[i].lock); } - malloc_mutex_prefork(tsdn, &arena->large_mtx); } void arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) { unsigned i; - malloc_mutex_postfork_parent(tsdn, &arena->large_mtx); for (i = 0; i < NBINS; i++) { malloc_mutex_postfork_parent(tsdn, &arena->bins[i].lock); } + malloc_mutex_postfork_parent(tsdn, &arena->large_mtx); base_postfork_parent(tsdn, arena->base); malloc_mutex_postfork_parent(tsdn, &arena->extent_freelist_mtx); extents_postfork_parent(tsdn, &arena->extents_cached); @@ -1688,10 +1779,10 @@ void arena_postfork_child(tsdn_t *tsdn, arena_t *arena) { unsigned i; - malloc_mutex_postfork_child(tsdn, &arena->large_mtx); for (i = 0; i < NBINS; i++) { malloc_mutex_postfork_child(tsdn, &arena->bins[i].lock); } + malloc_mutex_postfork_child(tsdn, &arena->large_mtx); base_postfork_child(tsdn, arena->base); malloc_mutex_postfork_child(tsdn, &arena->extent_freelist_mtx); extents_postfork_child(tsdn, &arena->extents_cached); diff --git a/src/large.c b/src/large.c index bfe2f714..55e0737e 100644 --- a/src/large.c +++ b/src/large.c @@ -286,20 +286,23 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, /* * junked_locked indicates whether the extent's data have been junk-filled, and - * whether the arena's lock is currently held. The arena's large_mtx is - * independent of these considerations. + * whether the arena's large_mtx is currently held. */ static void large_dalloc_prep_impl(tsdn_t *tsdn, arena_t *arena, extent_t *extent, bool junked_locked) { - malloc_mutex_lock(tsdn, &arena->large_mtx); - extent_list_remove(&arena->large, extent); - malloc_mutex_unlock(tsdn, &arena->large_mtx); + if (!junked_locked) { + malloc_mutex_lock(tsdn, &arena->large_mtx); + extent_list_remove(&arena->large, extent); + malloc_mutex_unlock(tsdn, &arena->large_mtx); large_dalloc_maybe_junk(extent_addr_get(extent), extent_usize_get(extent)); + } else { + malloc_mutex_assert_owner(tsdn, &arena->large_mtx); + extent_list_remove(&arena->large, extent); } - arena_extent_dalloc_large_prep(tsdn, arena, extent, junked_locked); + arena_extent_dalloc_large_prep(tsdn, arena, extent); } static void diff --git a/src/tcache.c b/src/tcache.c index f38c2d5d..075f3481 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -188,7 +188,7 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, idump = false; } - malloc_mutex_lock(tsd_tsdn(tsd), &locked_arena->lock); + malloc_mutex_lock(tsd_tsdn(tsd), &locked_arena->large_mtx); for (unsigned i = 0; i < nflush; i++) { void *ptr = *(tbin->avail - 1 - i); assert(ptr != NULL); @@ -206,14 +206,13 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, } if (config_stats) { merged_stats = true; - arena->stats.nrequests_large += - tbin->tstats.nrequests; - arena->stats.lstats[binind - NBINS].nrequests += - tbin->tstats.nrequests; + arena_stats_large_nrequests_add(tsd_tsdn(tsd), + &arena->stats, binind, + tbin->tstats.nrequests); tbin->tstats.nrequests = 0; } } - malloc_mutex_unlock(tsd_tsdn(tsd), &locked_arena->lock); + malloc_mutex_unlock(tsd_tsdn(tsd), &locked_arena->large_mtx); unsigned ndeferred = 0; for (unsigned i = 0; i < nflush; i++) { @@ -245,12 +244,9 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, * The flush loop didn't happen to flush to this thread's * arena, so the stats didn't get merged. Manually do so now. */ - malloc_mutex_lock(tsd_tsdn(tsd), &arena->lock); - arena->stats.nrequests_large += tbin->tstats.nrequests; - arena->stats.lstats[binind - NBINS].nrequests += - tbin->tstats.nrequests; + arena_stats_large_nrequests_add(tsd_tsdn(tsd), &arena->stats, + binind, tbin->tstats.nrequests); tbin->tstats.nrequests = 0; - malloc_mutex_unlock(tsd_tsdn(tsd), &arena->lock); } memmove(tbin->avail - rem, tbin->avail - tbin->ncached, rem * @@ -426,10 +422,9 @@ tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { } for (; i < nhbins; i++) { - malloc_large_stats_t *lstats = &arena->stats.lstats[i - NBINS]; tcache_bin_t *tbin = &tcache->tbins[i]; - arena->stats.nrequests_large += tbin->tstats.nrequests; - lstats->nrequests += tbin->tstats.nrequests; + arena_stats_large_nrequests_add(tsdn, &arena->stats, i, + tbin->tstats.nrequests); tbin->tstats.nrequests = 0; } } -- GitLab From ab25d3c987ddb32846760cc08af8db22a6389c02 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 12 Feb 2017 18:50:53 -0800 Subject: [PATCH 277/544] Synchronize arena->tcache_ql with arena->tcache_ql_mtx. This replaces arena->lock synchronization. --- include/jemalloc/internal/arena_structs_b.h | 3 ++- include/jemalloc/internal/witness_types.h | 15 ++++++++------- src/arena.c | 15 +++++++++++++++ src/jemalloc.c | 11 +++-------- src/tcache.c | 10 ++++------ 5 files changed, 32 insertions(+), 22 deletions(-) diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 04e859b5..132a328b 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -135,9 +135,10 @@ struct arena_s { * Stats from these are merged incrementally, and at exit if * opt_stats_print is enabled. * - * Synchronization: lock. + * Synchronization: tcache_ql_mtx. */ ql_head(tcache_t) tcache_ql; + malloc_mutex_t tcache_ql_mtx; /* Synchronization: internal. */ prof_accum_t prof_accum; diff --git a/include/jemalloc/internal/witness_types.h b/include/jemalloc/internal/witness_types.h index 3fd7998a..7957b410 100644 --- a/include/jemalloc/internal/witness_types.h +++ b/include/jemalloc/internal/witness_types.h @@ -35,13 +35,14 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *, #define WITNESS_RANK_CORE 9U #define WITNESS_RANK_ARENA 9U -#define WITNESS_RANK_EXTENTS 10U -#define WITNESS_RANK_EXTENT_FREELIST 11U - -#define WITNESS_RANK_RTREE_ELM 12U -#define WITNESS_RANK_RTREE 13U -#define WITNESS_RANK_BASE 14U -#define WITNESS_RANK_ARENA_LARGE 15U +#define WITNESS_RANK_TCACHE_QL 10U +#define WITNESS_RANK_EXTENTS 11U +#define WITNESS_RANK_EXTENT_FREELIST 12U + +#define WITNESS_RANK_RTREE_ELM 13U +#define WITNESS_RANK_RTREE 14U +#define WITNESS_RANK_BASE 15U +#define WITNESS_RANK_ARENA_LARGE 16U #define WITNESS_RANK_LEAF 0xffffffffU #define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF diff --git a/src/arena.c b/src/arena.c index ac447199..f4e051ca 100644 --- a/src/arena.c +++ b/src/arena.c @@ -215,6 +215,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, /* tcache_bytes counts currently cached bytes. */ astats->tcache_bytes = 0; + malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx); ql_foreach(tcache, &arena->tcache_ql, link) { for (i = 0; i < nhbins; i++) { tbin = &tcache->tbins[i]; @@ -222,6 +223,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, index2size(i); } } + malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx); } for (i = 0; i < NBINS; i++) { @@ -1650,6 +1652,10 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { if (config_stats && config_tcache) { ql_new(&arena->tcache_ql); + if (malloc_mutex_init(&arena->tcache_ql_mtx, "tcache_ql", + WITNESS_RANK_TCACHE_QL)) { + goto label_error; + } } if (config_prof) { @@ -1736,6 +1742,9 @@ arena_boot(void) { void arena_prefork0(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_prefork(tsdn, &arena->lock); + if (config_stats && config_tcache) { + malloc_mutex_prefork(tsdn, &arena->tcache_ql_mtx); + } } void @@ -1773,6 +1782,9 @@ arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) { extents_postfork_parent(tsdn, &arena->extents_cached); extents_postfork_parent(tsdn, &arena->extents_retained); malloc_mutex_postfork_parent(tsdn, &arena->lock); + if (config_stats && config_tcache) { + malloc_mutex_postfork_parent(tsdn, &arena->tcache_ql_mtx); + } } void @@ -1788,4 +1800,7 @@ arena_postfork_child(tsdn_t *tsdn, arena_t *arena) { extents_postfork_child(tsdn, &arena->extents_cached); extents_postfork_child(tsdn, &arena->extents_retained); malloc_mutex_postfork_child(tsdn, &arena->lock); + if (config_stats && config_tcache) { + malloc_mutex_postfork_child(tsdn, &arena->tcache_ql_mtx); + } } diff --git a/src/jemalloc.c b/src/jemalloc.c index d2c33bbc..197f9bdc 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -684,17 +684,12 @@ stats_print_atexit(void) { if (arena != NULL) { tcache_t *tcache; - /* - * tcache_stats_merge() locks bins, so if any - * code is introduced that acquires both arena - * and bin locks in the opposite order, - * deadlocks may result. - */ - malloc_mutex_lock(tsdn, &arena->lock); + malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx); ql_foreach(tcache, &arena->tcache_ql, link) { tcache_stats_merge(tsdn, tcache, arena); } - malloc_mutex_unlock(tsdn, &arena->lock); + malloc_mutex_unlock(tsdn, + &arena->tcache_ql_mtx); } } } diff --git a/src/tcache.c b/src/tcache.c index 075f3481..dff31d19 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -261,10 +261,10 @@ static void tcache_arena_associate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { if (config_stats) { /* Link into list of extant tcaches. */ - malloc_mutex_lock(tsdn, &arena->lock); + malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx); ql_elm_new(tcache, link); ql_tail_insert(&arena->tcache_ql, tcache, link); - malloc_mutex_unlock(tsdn, &arena->lock); + malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx); } } @@ -272,7 +272,7 @@ static void tcache_arena_dissociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { if (config_stats) { /* Unlink from list of extant tcaches. */ - malloc_mutex_lock(tsdn, &arena->lock); + malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx); if (config_debug) { bool in_ql = false; tcache_t *iter; @@ -286,7 +286,7 @@ tcache_arena_dissociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { } ql_remove(&arena->tcache_ql, tcache, link); tcache_stats_merge(tsdn, tcache, arena); - malloc_mutex_unlock(tsdn, &arena->lock); + malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx); } } @@ -409,8 +409,6 @@ tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { cassert(config_stats); - malloc_mutex_assert_owner(tsdn, &arena->lock); - /* Merge and reset tcache stats. */ for (i = 0; i < NBINS; i++) { arena_bin_t *bin = &arena->bins[i]; -- GitLab From d433471f581ca50583c7a99f9802f7388f81aa36 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 13 Feb 2017 09:44:46 -0800 Subject: [PATCH 278/544] Derive {allocated,nmalloc,ndalloc,nrequests}_large stats. This mildly reduces stats update overhead during normal operation. --- include/jemalloc/internal/stats_structs.h | 8 ++-- src/arena.c | 45 ++++++++++++----------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index 4f5984ab..1571ef4f 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -104,10 +104,10 @@ struct arena_stats_s { size_t internal; size_t resident; /* Derived. */ - size_t allocated_large; - uint64_t nmalloc_large; - uint64_t ndalloc_large; - uint64_t nrequests_large; + size_t allocated_large; /* Derived. */ + uint64_t nmalloc_large; /* Derived. */ + uint64_t ndalloc_large; /* Derived. */ + uint64_t nrequests_large; /* Derived. */ /* Number of bytes cached in tcache associated with this arena. */ size_t tcache_bytes; /* Derived. */ diff --git a/src/arena.c b/src/arena.c index f4e051ca..8a658b99 100644 --- a/src/arena.c +++ b/src/arena.c @@ -136,8 +136,6 @@ void arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats, szind_t szind, uint64_t nrequests) { arena_stats_lock(tsdn, arena_stats); - arena_stats_add_u64(tsdn, arena_stats, &arena_stats->nrequests_large, - nrequests); arena_stats_add_u64(tsdn, arena_stats, &arena_stats->lstats[szind - NBINS].nrequests, nrequests); arena_stats_unlock(tsdn, arena_stats); @@ -160,14 +158,12 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty, arena_stats_t *astats, malloc_bin_stats_t *bstats, malloc_large_stats_t *lstats) { - size_t base_allocated, base_resident, base_mapped; - unsigned i; - cassert(config_stats); arena_basic_stats_merge(tsdn, arena, nthreads, dss, decay_time, nactive, ndirty); + size_t base_allocated, base_resident, base_mapped; base_stats_get(tsdn, arena->base, &base_allocated, &base_resident, &base_mapped); @@ -196,15 +192,30 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, astats->nrequests_large += arena_stats_read_u64(tsdn, &arena->stats, &arena->stats.nrequests_large); - for (i = 0; i < NSIZES - NBINS; i++) { - lstats[i].nmalloc += arena_stats_read_u64(tsdn, &arena->stats, + astats->allocated_large = 0; + astats->nmalloc_large = 0; + astats->ndalloc_large = 0; + astats->nrequests_large = 0; + for (szind_t i = 0; i < NSIZES - NBINS; i++) { + uint64_t nmalloc = arena_stats_read_u64(tsdn, &arena->stats, &arena->stats.lstats[i].nmalloc); - lstats[i].ndalloc += arena_stats_read_u64(tsdn, &arena->stats, + lstats[i].nmalloc += nmalloc; + astats->nmalloc_large += nmalloc; + + uint64_t ndalloc = arena_stats_read_u64(tsdn, &arena->stats, &arena->stats.lstats[i].ndalloc); - lstats[i].nrequests += arena_stats_read_u64(tsdn, &arena->stats, + lstats[i].ndalloc += ndalloc; + astats->ndalloc_large += ndalloc; + + uint64_t nrequests = arena_stats_read_u64(tsdn, &arena->stats, &arena->stats.lstats[i].nrequests); - lstats[i].curlextents += arena_stats_read_zu(tsdn, + lstats[i].nrequests += nrequests; + astats->nrequests_large += nrequests; + + size_t curlextents = arena_stats_read_zu(tsdn, &arena->stats, &arena->stats.lstats[i].curlextents); + lstats[i].curlextents += curlextents; + astats->allocated_large += curlextents * index2size(i); } arena_stats_unlock(tsdn, &arena->stats); @@ -217,7 +228,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, astats->tcache_bytes = 0; malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx); ql_foreach(tcache, &arena->tcache_ql, link) { - for (i = 0; i < nhbins; i++) { + for (szind_t i = 0; i < nhbins; i++) { tbin = &tcache->tbins[i]; astats->tcache_bytes += tbin->ncached * index2size(i); @@ -226,7 +237,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx); } - for (i = 0; i < NBINS; i++) { + for (szind_t i = 0; i < NBINS; i++) { arena_bin_t *bin = &arena->bins[i]; malloc_mutex_lock(tsdn, &bin->lock); @@ -347,10 +358,6 @@ arena_large_malloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t usize) { index = size2index(usize); hindex = (index >= NBINS) ? index - NBINS : 0; - arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.nmalloc_large, - 1); - arena_stats_add_zu(tsdn, &arena->stats, &arena->stats.allocated_large, - usize); arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.lstats[hindex].nmalloc, 1); arena_stats_add_u64(tsdn, &arena->stats, @@ -371,10 +378,6 @@ arena_large_dalloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t usize) { index = size2index(usize); hindex = (index >= NBINS) ? index - NBINS : 0; - arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.ndalloc_large, - 1); - arena_stats_sub_zu(tsdn, &arena->stats, &arena->stats.allocated_large, - usize); arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.lstats[hindex].ndalloc, 1); arena_stats_sub_zu(tsdn, &arena->stats, @@ -389,8 +392,6 @@ arena_large_reset_stats_cancel(tsdn_t *tsdn, arena_t *arena, size_t usize) { cassert(config_stats); arena_stats_lock(tsdn, &arena->stats); - arena_stats_sub_u64(tsdn, &arena->stats, &arena->stats.ndalloc_large, - 1); arena_stats_sub_u64(tsdn, &arena->stats, &arena->stats.lstats[hindex].ndalloc, 1); arena_stats_unlock(tsdn, &arena->stats); -- GitLab From f8fee6908d554aaa4f356bfcf7642bc7707eb6df Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 13 Feb 2017 11:02:32 -0800 Subject: [PATCH 279/544] Synchronize arena->decay with arena->decay.mtx. This removes the last use of arena->lock. --- include/jemalloc/internal/arena_inlines_b.h | 2 +- include/jemalloc/internal/arena_structs_b.h | 8 +-- include/jemalloc/internal/witness_types.h | 2 +- src/arena.c | 56 ++++++++++++--------- 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index a180322b..275866a4 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -81,7 +81,7 @@ arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) { JEMALLOC_ALWAYS_INLINE void arena_decay_tick(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_assert_not_owner(tsdn, &arena->lock); + malloc_mutex_assert_not_owner(tsdn, &arena->decay.mtx); arena_decay_ticks(tsdn, arena, 1); } diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 132a328b..92f1e41f 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -37,6 +37,8 @@ struct arena_bin_info_s { }; struct arena_decay_s { + /* Synchronizes all fields. */ + malloc_mutex_t mtx; /* * Approximate time in seconds from the creation of a set of unused * dirty pages until an equivalent set of unused dirty pages is purged @@ -121,12 +123,6 @@ struct arena_s { */ unsigned nthreads[2]; - /* - * Synchronizes various arena operations, as indicated in field-specific - * comments. - */ - malloc_mutex_t lock; - /* Synchronization: internal. */ arena_stats_t stats; diff --git a/include/jemalloc/internal/witness_types.h b/include/jemalloc/internal/witness_types.h index 7957b410..0678b082 100644 --- a/include/jemalloc/internal/witness_types.h +++ b/include/jemalloc/internal/witness_types.h @@ -34,7 +34,7 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *, */ #define WITNESS_RANK_CORE 9U -#define WITNESS_RANK_ARENA 9U +#define WITNESS_RANK_DECAY 9U #define WITNESS_RANK_TCACHE_QL 10U #define WITNESS_RANK_EXTENTS 11U #define WITNESS_RANK_EXTENT_FREELIST 12U diff --git a/src/arena.c b/src/arena.c index 8a658b99..98004ecb 100644 --- a/src/arena.c +++ b/src/arena.c @@ -144,13 +144,11 @@ arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats, void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) { - malloc_mutex_lock(tsdn, &arena->lock); *nthreads += arena_nthreads_get(arena, false); *dss = dss_prec_names[arena_dss_prec_get(arena)]; - *decay_time = arena->decay.time; + *decay_time = arena_decay_time_get(tsdn, arena); *nactive += atomic_read_zu(&arena->nactive); *ndirty += extents_npages_get(&arena->extents_cached); - malloc_mutex_unlock(tsdn, &arena->lock); } void @@ -607,7 +605,7 @@ arena_decay_epoch_advance(tsdn_t *tsdn, arena_t *arena, const nstime_t *time) { } static void -arena_decay_init(arena_t *arena, ssize_t decay_time) { +arena_decay_reinit(arena_t *arena, ssize_t decay_time) { arena->decay.time = decay_time; if (decay_time > 0) { nstime_init2(&arena->decay.interval, decay_time, 0); @@ -622,6 +620,15 @@ arena_decay_init(arena_t *arena, ssize_t decay_time) { memset(arena->decay.backlog, 0, SMOOTHSTEP_NSTEPS * sizeof(size_t)); } +static bool +arena_decay_init(arena_t *arena, ssize_t decay_time) { + if (malloc_mutex_init(&arena->decay.mtx, "decay", WITNESS_RANK_DECAY)) { + return true; + } + arena_decay_reinit(arena, decay_time); + return false; +} + static bool arena_decay_time_valid(ssize_t decay_time) { if (decay_time < -1) { @@ -637,9 +644,9 @@ ssize_t arena_decay_time_get(tsdn_t *tsdn, arena_t *arena) { ssize_t decay_time; - malloc_mutex_lock(tsdn, &arena->lock); + malloc_mutex_lock(tsdn, &arena->decay.mtx); decay_time = arena->decay.time; - malloc_mutex_unlock(tsdn, &arena->lock); + malloc_mutex_unlock(tsdn, &arena->decay.mtx); return decay_time; } @@ -650,7 +657,7 @@ arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { return true; } - malloc_mutex_lock(tsdn, &arena->lock); + malloc_mutex_lock(tsdn, &arena->decay.mtx); /* * Restart decay backlog from scratch, which may cause many dirty pages * to be immediately purged. It would conceptually be possible to map @@ -659,16 +666,16 @@ arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { * infrequent, either between the {-1, 0, >0} states, or a one-time * arbitrary change during initial arena configuration. */ - arena_decay_init(arena, decay_time); + arena_decay_reinit(arena, decay_time); arena_maybe_purge(tsdn, arena); - malloc_mutex_unlock(tsdn, &arena->lock); + malloc_mutex_unlock(tsdn, &arena->decay.mtx); return false; } void arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_assert_owner(tsdn, &arena->lock); + malloc_mutex_assert_owner(tsdn, &arena->decay.mtx); /* Purge all or nothing if the option is disabled. */ if (arena->decay.time <= 0) { @@ -766,7 +773,7 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, static void arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 1); - malloc_mutex_assert_owner(tsdn, &arena->lock); + malloc_mutex_assert_owner(tsdn, &arena->decay.mtx); if (atomic_cas_u(&arena->purging, 0, 1)) { return; @@ -778,19 +785,19 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) { extent_list_init(&purge_extents); - malloc_mutex_unlock(tsdn, &arena->lock); + malloc_mutex_unlock(tsdn, &arena->decay.mtx); npurge = arena_stash_dirty(tsdn, arena, &extent_hooks, ndirty_limit, &purge_extents); if (npurge == 0) { - malloc_mutex_lock(tsdn, &arena->lock); + malloc_mutex_lock(tsdn, &arena->decay.mtx); goto label_return; } npurged = arena_purge_stashed(tsdn, arena, &extent_hooks, &purge_extents); assert(npurged == npurge); - malloc_mutex_lock(tsdn, &arena->lock); + malloc_mutex_lock(tsdn, &arena->decay.mtx); if (config_stats) { arena_stats_lock(tsdn, &arena->stats); @@ -805,13 +812,13 @@ label_return: void arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) { - malloc_mutex_lock(tsdn, &arena->lock); + malloc_mutex_lock(tsdn, &arena->decay.mtx); if (all) { arena_purge_to_limit(tsdn, arena, 0); } else { arena_maybe_purge(tsdn, arena); } - malloc_mutex_unlock(tsdn, &arena->lock); + malloc_mutex_unlock(tsdn, &arena->decay.mtx); } static void @@ -822,9 +829,9 @@ arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) { extent_dalloc_cache(tsdn, arena, &extent_hooks, slab); arena_nactive_sub(arena, npages); - malloc_mutex_lock(tsdn, &arena->lock); + malloc_mutex_lock(tsdn, &arena->decay.mtx); arena_maybe_purge(tsdn, arena); - malloc_mutex_unlock(tsdn, &arena->lock); + malloc_mutex_unlock(tsdn, &arena->decay.mtx); } static void @@ -1641,9 +1648,6 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { } arena->nthreads[0] = arena->nthreads[1] = 0; - if (malloc_mutex_init(&arena->lock, "arena", WITNESS_RANK_ARENA)) { - goto label_error; - } if (config_stats) { if (arena_stats_init(tsdn, &arena->stats)) { @@ -1684,7 +1688,9 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { atomic_write_u(&arena->purging, 0); atomic_write_zu(&arena->nactive, 0); - arena_decay_init(arena, arena_decay_time_default_get()); + if (arena_decay_init(arena, arena_decay_time_default_get())) { + goto label_error; + } extent_list_init(&arena->large); if (malloc_mutex_init(&arena->large_mtx, "arena_large", @@ -1742,7 +1748,7 @@ arena_boot(void) { void arena_prefork0(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_prefork(tsdn, &arena->lock); + malloc_mutex_prefork(tsdn, &arena->decay.mtx); if (config_stats && config_tcache) { malloc_mutex_prefork(tsdn, &arena->tcache_ql_mtx); } @@ -1782,7 +1788,7 @@ arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_postfork_parent(tsdn, &arena->extent_freelist_mtx); extents_postfork_parent(tsdn, &arena->extents_cached); extents_postfork_parent(tsdn, &arena->extents_retained); - malloc_mutex_postfork_parent(tsdn, &arena->lock); + malloc_mutex_postfork_parent(tsdn, &arena->decay.mtx); if (config_stats && config_tcache) { malloc_mutex_postfork_parent(tsdn, &arena->tcache_ql_mtx); } @@ -1800,7 +1806,7 @@ arena_postfork_child(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_postfork_child(tsdn, &arena->extent_freelist_mtx); extents_postfork_child(tsdn, &arena->extents_cached); extents_postfork_child(tsdn, &arena->extents_retained); - malloc_mutex_postfork_child(tsdn, &arena->lock); + malloc_mutex_postfork_child(tsdn, &arena->decay.mtx); if (config_stats && config_tcache) { malloc_mutex_postfork_child(tsdn, &arena->tcache_ql_mtx); } -- GitLab From b0654b95ed784be609c5212bd34f8141bdf5caca Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 13 Feb 2017 10:35:41 -0800 Subject: [PATCH 280/544] Fix arena->stats.mapped accounting. Mapped memory increases when extent_alloc_wrapper() succeeds, and decreases when extent_dalloc_wrapper() is called (during purging). --- include/jemalloc/internal/arena_externs.h | 2 + include/jemalloc/internal/private_symbols.txt | 1 + src/arena.c | 72 ++++++++++++------- src/large.c | 12 ++++ 4 files changed, 61 insertions(+), 26 deletions(-) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 2880399b..72cbf5fe 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -15,6 +15,8 @@ extern const arena_bin_info_t arena_bin_info[NBINS]; void arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats, szind_t szind, uint64_t nrequests); +void arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, + size_t size); void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty, arena_stats_t *astats, malloc_bin_stats_t *bstats, diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index ff54a35d..15d0449c 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -67,6 +67,7 @@ arena_sdalloc arena_set arena_slab_regind arena_stats_init +arena_stats_mapped_add arena_stats_merge arena_tcache_fill_small arena_tdata_get diff --git a/src/arena.c b/src/arena.c index 98004ecb..80843693 100644 --- a/src/arena.c +++ b/src/arena.c @@ -93,10 +93,12 @@ static void arena_stats_sub_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, uint64_t *p, uint64_t x) { #ifdef JEMALLOC_ATOMIC_U64 - atomic_sub_u64(p, x); + UNUSED uint64_t r = atomic_sub_u64(p, x); + assert(r + x >= r); #else malloc_mutex_assert_owner(tsdn, &arena_stats->mtx); *p -= x; + assert(*p + x >= *p); #endif } @@ -125,10 +127,12 @@ static void arena_stats_sub_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t *p, size_t x) { #ifdef JEMALLOC_ATOMIC_U64 - atomic_sub_zu(p, x); + UNUSED size_t r = atomic_sub_zu(p, x); + assert(r + x >= r); #else malloc_mutex_assert_owner(tsdn, &arena_stats->mtx); *p -= x; + assert(*p + x >= *p); #endif } @@ -141,6 +145,13 @@ arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats, arena_stats_unlock(tsdn, arena_stats); } +void +arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t size) { + arena_stats_lock(tsdn, arena_stats); + arena_stats_add_zu(tsdn, arena_stats, &arena_stats->mapped, size); + arena_stats_unlock(tsdn, arena_stats); +} + void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) { @@ -410,22 +421,38 @@ arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + size_t mapped_add; bool commit = true; extent = extent_alloc_cache(tsdn, arena, &extent_hooks, NULL, usize, large_pad, alignment, zero, &commit, false); + size_t size = usize + large_pad; if (extent == NULL) { extent = extent_alloc_wrapper(tsdn, arena, &extent_hooks, NULL, usize, large_pad, alignment, zero, &commit, false); + if (config_stats) { + /* + * extent may be NULL on OOM, but in that case + * mapped_add isn't used below, so there's no need to + * conditionlly set it to 0 here. + */ + mapped_add = size; + } + } else if (config_stats) { + mapped_add = 0; } - if (config_stats && extent != NULL) { - arena_stats_lock(tsdn, &arena->stats); - arena_large_malloc_stats_update(tsdn, arena, usize); - arena_stats_add_zu(tsdn, &arena->stats, &arena->stats.mapped, - usize); - arena_stats_unlock(tsdn, &arena->stats); + if (extent != NULL) { + if (config_stats) { + arena_stats_lock(tsdn, &arena->stats); + arena_large_malloc_stats_update(tsdn, arena, usize); + if (mapped_add != 0) { + arena_stats_add_zu(tsdn, &arena->stats, + &arena->stats.mapped, mapped_add); + } + arena_stats_unlock(tsdn, &arena->stats); + } + arena_nactive_add(arena, size >> LG_PAGE); } - arena_nactive_add(arena, (usize + large_pad) >> LG_PAGE); return extent; } @@ -436,8 +463,6 @@ arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { arena_stats_lock(tsdn, &arena->stats); arena_large_dalloc_stats_update(tsdn, arena, extent_usize_get(extent)); - arena_stats_sub_zu(tsdn, &arena->stats, &arena->stats.mapped, - extent_size_get(extent)); arena_stats_unlock(tsdn, &arena->stats); } arena_nactive_sub(arena, extent_size_get(extent) >> LG_PAGE); @@ -459,8 +484,6 @@ arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, if (config_stats) { arena_stats_lock(tsdn, &arena->stats); arena_large_ralloc_stats_update(tsdn, arena, oldusize, usize); - arena_stats_sub_zu(tsdn, &arena->stats, &arena->stats.mapped, - udiff); arena_stats_unlock(tsdn, &arena->stats); } arena_nactive_sub(arena, udiff >> LG_PAGE); @@ -475,8 +498,6 @@ arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, if (config_stats) { arena_stats_lock(tsdn, &arena->stats); arena_large_ralloc_stats_update(tsdn, arena, oldusize, usize); - arena_stats_add_zu(tsdn, &arena->stats, &arena->stats.mapped, - udiff); arena_stats_unlock(tsdn, &arena->stats); } arena_nactive_add(arena, udiff >> LG_PAGE); @@ -760,6 +781,8 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, nmadvise); arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.purged, npurged); + arena_stats_sub_zu(tsdn, &arena->stats, &arena->stats.mapped, + npurged << LG_PAGE); arena_stats_unlock(tsdn, &arena->stats); } @@ -823,12 +846,11 @@ arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) { static void arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) { - extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; - size_t npages = extent_size_get(slab) >> LG_PAGE; + arena_nactive_sub(arena, extent_size_get(slab) >> LG_PAGE); + extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; extent_dalloc_cache(tsdn, arena, &extent_hooks, slab); - arena_nactive_sub(arena, npages); malloc_mutex_lock(tsdn, &arena->decay.mtx); arena_maybe_purge(tsdn, arena); malloc_mutex_unlock(tsdn, &arena->decay.mtx); @@ -1015,6 +1037,11 @@ arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, slab = extent_alloc_wrapper(tsdn, arena, r_extent_hooks, NULL, bin_info->slab_size, 0, PAGE, &zero, &commit, true); + if (config_stats && slab != NULL) { + arena_stats_mapped_add(tsdn, &arena->stats, + bin_info->slab_size); + } + return slab; } @@ -1037,20 +1064,13 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, } assert(extent_slab_get(slab)); - arena_nactive_add(arena, extent_size_get(slab) >> LG_PAGE); - /* Initialize slab internals. */ arena_slab_data_t *slab_data = extent_slab_data_get(slab); slab_data->binind = binind; slab_data->nfree = bin_info->nregs; bitmap_init(slab_data->bitmap, &bin_info->bitmap_info); - if (config_stats) { - arena_stats_lock(tsdn, &arena->stats); - arena_stats_add_zu(tsdn, &arena->stats, &arena->stats.mapped, - extent_size_get(slab)); - arena_stats_unlock(tsdn, &arena->stats); - } + arena_nactive_add(arena, extent_size_get(slab) >> LG_PAGE); return slab; } diff --git a/src/large.c b/src/large.c index 55e0737e..bb638499 100644 --- a/src/large.c +++ b/src/large.c @@ -147,6 +147,7 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, bool is_zeroed_trail = false; bool commit = true; extent_t *trail; + bool new_mapping; if ((trail = extent_alloc_cache(tsdn, arena, &extent_hooks, extent_past_get(extent), trailsize, 0, CACHELINE, &is_zeroed_trail, &commit, false)) == NULL) { @@ -155,6 +156,13 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, &is_zeroed_trail, &commit, false)) == NULL) { return true; } + if (config_stats) { + new_mapping = true; + } + } else { + if (config_stats) { + new_mapping = false; + } } if (extent_merge_wrapper(tsdn, arena, &extent_hooks, extent, trail)) { @@ -162,6 +170,10 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, return true; } + if (config_stats && new_mapping) { + arena_stats_mapped_add(tsdn, &arena->stats, trailsize); + } + if (zero || (config_fill && unlikely(opt_zero))) { if (config_cache_oblivious) { /* -- GitLab From c1ebfaa673f769eff399fc5806591b3a4782a9c5 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 12 Feb 2017 23:00:19 -0800 Subject: [PATCH 281/544] Optimize extent coalescing. Refactor extent_can_coalesce(), extent_coalesce(), and extent_record() to avoid needlessly repeating extent [de]activation operations. --- src/extent.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/extent.c b/src/extent.c index 85c92d0f..cf502ca3 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1020,14 +1020,19 @@ extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, } static bool -extent_can_coalesce(const extent_t *a, const extent_t *b) { - if (extent_arena_get(a) != extent_arena_get(b)) { +extent_can_coalesce(arena_t *arena, extents_t *extents, const extent_t *inner, + const extent_t *outer) { + assert(extent_arena_get(inner) == arena); + if (extent_arena_get(outer) != arena) { return false; } - if (extent_state_get(a) != extent_state_get(b)) { + + assert(extent_state_get(inner) == extent_state_active); + if (extent_state_get(outer) != extents->state) { return false; } - if (extent_committed_get(a) != extent_committed_get(b)) { + + if (extent_committed_get(inner) != extent_committed_get(outer)) { return false; } @@ -1036,24 +1041,21 @@ extent_can_coalesce(const extent_t *a, const extent_t *b) { static bool extent_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extent_t *a, extent_t *b, extents_t *extents) { - assert(extent_can_coalesce(a, b)); - assert(extent_arena_get(a) == arena); - assert(extent_arena_get(b) == arena); + extents_t *extents, extent_t *inner, extent_t *outer, bool forward) { + assert(extent_can_coalesce(arena, extents, inner, outer)); - extent_activate_locked(tsdn, arena, extents, a); - extent_activate_locked(tsdn, arena, extents, b); + extent_activate_locked(tsdn, arena, extents, outer); malloc_mutex_unlock(tsdn, &extents->mtx); - bool err = extent_merge_wrapper(tsdn, arena, r_extent_hooks, a, b); + bool err = extent_merge_wrapper(tsdn, arena, r_extent_hooks, + forward ? inner : outer, forward ? outer : inner); malloc_mutex_lock(tsdn, &extents->mtx); - extent_deactivate_locked(tsdn, arena, extents, a); + if (err) { - extent_deactivate_locked(tsdn, arena, extents, b); - return true; + extent_deactivate_locked(tsdn, arena, extents, outer); } - return false; + return err; } static void @@ -1075,7 +1077,6 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, } assert(extent_lookup(tsdn, extent_base_get(extent), true) == extent); - extent_deactivate_locked(tsdn, arena, extents, extent); /* * Continue attempting to coalesce until failure, to protect against @@ -1098,10 +1099,10 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, * before releasing the next_elm lock. */ bool can_coalesce = (next != NULL && - extent_can_coalesce(extent, next)); + extent_can_coalesce(arena, extents, extent, next)); rtree_elm_release(tsdn, &extents_rtree, next_elm); if (can_coalesce && !extent_coalesce(tsdn, arena, - r_extent_hooks, extent, next, extents)) { + r_extent_hooks, extents, extent, next, true)) { coalesced = true; } } @@ -1114,16 +1115,18 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *prev = rtree_elm_read_acquired(tsdn, &extents_rtree, prev_elm); bool can_coalesce = (prev != NULL && - extent_can_coalesce(prev, extent)); + extent_can_coalesce(arena, extents, extent, prev)); rtree_elm_release(tsdn, &extents_rtree, prev_elm); if (can_coalesce && !extent_coalesce(tsdn, arena, - r_extent_hooks, prev, extent, extents)) { + r_extent_hooks, extents, extent, prev, false)) { extent = prev; coalesced = true; } } } while (coalesced); + extent_deactivate_locked(tsdn, arena, extents, extent); + malloc_mutex_unlock(tsdn, &extents->mtx); } -- GitLab From 2dfc5b5aac983f8f192c63c604a59fed8b39e937 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 12 Feb 2017 23:18:57 -0800 Subject: [PATCH 282/544] Disable coalescing of cached extents. Extent splitting and coalescing is a major component of large allocation overhead, and disabling coalescing of cached extents provides a simple and effective hysteresis mechanism. Once two-phase purging is implemented, it will probably make sense to leave coalescing disabled for the first phase, but coalesce during the second phase. --- include/jemalloc/internal/extent_externs.h | 3 +- include/jemalloc/internal/extent_structs.h | 3 ++ src/arena.c | 5 +- src/extent.c | 56 ++++++++++++++-------- 4 files changed, 43 insertions(+), 24 deletions(-) diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index a3556118..d971ec3a 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -21,7 +21,8 @@ size_t extent_size_quantize_ceil(size_t size); ph_proto(, extent_heap_, extent_heap_t, extent_t) -bool extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state); +bool extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state, + bool try_coalesce); extent_state_t extents_state_get(const extents_t *extents); size_t extents_npages_get(extents_t *extents); extent_t *extents_evict(tsdn_t *tsdn, extents_t *extents, size_t npages_min); diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 33ca4ac7..008b6352 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -115,6 +115,9 @@ struct extents_s { /* All stored extents must be in the same state. */ extent_state_t state; + + /* If true, try to coalesce during extent deallocation. */ + bool try_coalesce; }; #endif /* JEMALLOC_INTERNAL_EXTENT_STRUCTS_H */ diff --git a/src/arena.c b/src/arena.c index 80843693..e0fa3a8b 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1718,11 +1718,12 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { goto label_error; } - if (extents_init(tsdn, &arena->extents_cached, extent_state_dirty)) { + if (extents_init(tsdn, &arena->extents_cached, extent_state_dirty, + false)) { goto label_error; } if (extents_init(tsdn, &arena->extents_retained, - extent_state_retained)) { + extent_state_retained, true)) { goto label_error; } diff --git a/src/extent.c b/src/extent.c index cf502ca3..afc60061 100644 --- a/src/extent.c +++ b/src/extent.c @@ -191,7 +191,8 @@ extent_size_quantize_t *extent_size_quantize_ceil = ph_gen(, extent_heap_, extent_heap_t, extent_t, ph_link, extent_snad_comp) bool -extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state) { +extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state, + bool try_coalesce) { if (malloc_mutex_init(&extents->mtx, "extents", WITNESS_RANK_EXTENTS)) { return true; } @@ -201,6 +202,7 @@ extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state) { extent_list_init(&extents->lru); extents->npages = 0; extents->state = state; + extents->try_coalesce = try_coalesce; return false; } @@ -1058,26 +1060,10 @@ extent_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, return err; } -static void -extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extents_t *extents, extent_t *extent) { - rtree_ctx_t rtree_ctx_fallback; - rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - - assert(extents_state_get(extents) != extent_state_dirty || - !extent_zeroed_get(extent)); - - malloc_mutex_lock(tsdn, &extents->mtx); - extent_hooks_assure_initialized(arena, r_extent_hooks); - - extent_usize_set(extent, 0); - if (extent_slab_get(extent)) { - extent_interior_deregister(tsdn, rtree_ctx, extent); - extent_slab_set(extent, false); - } - - assert(extent_lookup(tsdn, extent_base_get(extent), true) == extent); - +static extent_t * +extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, + extent_t *extent) { /* * Continue attempting to coalesce until failure, to protect against * races with other threads that are thwarted by this one. @@ -1125,6 +1111,34 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, } } while (coalesced); + return extent; +} + +static void +extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, + extents_t *extents, extent_t *extent) { + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + + assert(extents_state_get(extents) != extent_state_dirty || + !extent_zeroed_get(extent)); + + malloc_mutex_lock(tsdn, &extents->mtx); + extent_hooks_assure_initialized(arena, r_extent_hooks); + + extent_usize_set(extent, 0); + if (extent_slab_get(extent)) { + extent_interior_deregister(tsdn, rtree_ctx, extent); + extent_slab_set(extent, false); + } + + assert(extent_lookup(tsdn, extent_base_get(extent), true) == extent); + + if (extents->try_coalesce) { + extent = extent_try_coalesce(tsdn, arena, r_extent_hooks, + rtree_ctx, extents, extent); + } + extent_deactivate_locked(tsdn, arena, extents, extent); malloc_mutex_unlock(tsdn, &extents->mtx); -- GitLab From 003ca8717fed0cf4d6eb28486bf7fa2c00643f39 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 19 Feb 2017 14:05:05 -0800 Subject: [PATCH 283/544] Move arena_basic_stats_merge() prototype (hygienic cleanup). --- include/jemalloc/internal/arena_externs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 72cbf5fe..d97b6a7d 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -17,6 +17,9 @@ void arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats, szind_t szind, uint64_t nrequests); void arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t size); +void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, + unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, + size_t *ndirty); void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty, arena_stats_t *astats, malloc_bin_stats_t *bstats, @@ -72,9 +75,6 @@ dss_prec_t arena_dss_prec_get(arena_t *arena); bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec); ssize_t arena_decay_time_default_get(void); bool arena_decay_time_default_set(ssize_t decay_time); -void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, - unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, - size_t *ndirty); unsigned arena_nthreads_get(arena_t *arena, bool internal); void arena_nthreads_inc(arena_t *arena, bool internal); void arena_nthreads_dec(arena_t *arena, bool internal); -- GitLab From 54269dc0ed3e4d04b2539016431de3cfe8330719 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 16 Feb 2017 22:02:42 -0800 Subject: [PATCH 284/544] Remove obsolete arena_maybe_purge() call. Remove a call to arena_maybe_purge() that was necessary for ratio-based purging, but is obsolete in the context of decay-based purging. --- src/arena.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/arena.c b/src/arena.c index e0fa3a8b..a914abda 100644 --- a/src/arena.c +++ b/src/arena.c @@ -850,10 +850,6 @@ arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) { extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; extent_dalloc_cache(tsdn, arena, &extent_hooks, slab); - - malloc_mutex_lock(tsdn, &arena->decay.mtx); - arena_maybe_purge(tsdn, arena); - malloc_mutex_unlock(tsdn, &arena->decay.mtx); } static void -- GitLab From 664ef652d970e14a4c941bf650cb50dbb4128b05 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 18 Feb 2017 00:02:23 -0800 Subject: [PATCH 285/544] Avoid -lgcc for heap profiling if unwind.h is missing. This removes an unneeded library dependency when falling back to intrinsics-based backtracing (or failing to enable heap profiling at all). --- configure.ac | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index e71edd72..1627a3d9 100644 --- a/configure.ac +++ b/configure.ac @@ -1082,7 +1082,9 @@ fi if test "x$backtrace_method" = "x" -a "x$enable_prof_libgcc" = "x1" \ -a "x$GCC" = "xyes" ; then AC_CHECK_HEADERS([unwind.h], , [enable_prof_libgcc="0"]) - AC_CHECK_LIB([gcc], [_Unwind_Backtrace], [JE_APPEND_VS(LIBS, -lgcc)], [enable_prof_libgcc="0"]) + if test "x${enable_prof_libgcc}" = "x1" ; then + AC_CHECK_LIB([gcc], [_Unwind_Backtrace], [JE_APPEND_VS(LIBS, -lgcc)], [enable_prof_libgcc="0"]) + fi if test "x${enable_prof_libgcc}" = "x1" ; then backtrace_method="libgcc" AC_DEFINE([JEMALLOC_PROF_LIBGCC], [ ]) -- GitLab From 8ac7937eb5ce011945188ef3553dbc2bcc294a25 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 21 Feb 2017 19:38:12 -0800 Subject: [PATCH 286/544] Remove remainder of mb (memory barrier). This complements 94c5d22a4da7844d0bdc5b370e47b1ba14268af2 (Remove mb.h, which is unused). --- Makefile.in | 1 - include/jemalloc/internal/private_symbols.txt | 1 - src/mb.c | 2 -- 3 files changed, 4 deletions(-) delete mode 100644 src/mb.c diff --git a/Makefile.in b/Makefile.in index 23056f78..76a73b76 100644 --- a/Makefile.in +++ b/Makefile.in @@ -100,7 +100,6 @@ C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/extent_mmap.c \ $(srcroot)src/hash.c \ $(srcroot)src/large.c \ - $(srcroot)src/mb.c \ $(srcroot)src/mutex.c \ $(srcroot)src/nstime.c \ $(srcroot)src/pages.c \ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 15d0449c..be56e1a2 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -296,7 +296,6 @@ malloc_tsd_no_cleanup malloc_vcprintf malloc_vsnprintf malloc_write -mb_write narenas_auto narenas_total_get ncpus diff --git a/src/mb.c b/src/mb.c deleted file mode 100644 index 94f3c724..00000000 --- a/src/mb.c +++ /dev/null @@ -1,2 +0,0 @@ -#define JEMALLOC_MB_C_ -#include "jemalloc/internal/jemalloc_internal.h" -- GitLab From de49674fbde4d124a0a7e7e97f5656e190980759 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 21 Feb 2017 23:40:06 -0800 Subject: [PATCH 287/544] Use MALLOC_CONF rather than malloc_conf for tests. malloc_conf does not reliably work with MSVC, which complains of "inconsistent dll linkage", i.e. its inability to support the application overriding malloc_conf when dynamically linking/loading. Work around this limitation by adding test harness support for per test shell script sourcing, and converting all tests to use MALLOC_CONF instead of malloc_conf. --- test/integration/extent.c | 4 ---- test/integration/extent.sh | 5 +++++ test/integration/mallocx.c | 4 ---- test/integration/mallocx.sh | 5 +++++ test/integration/xallocx.c | 4 ---- test/integration/xallocx.sh | 5 +++++ test/test.sh.in | 29 ++++++++++++++++++++++++++++- test/unit/arena_reset_prof.c | 1 - test/unit/arena_reset_prof.sh | 3 +++ test/unit/decay.c | 6 ------ test/unit/decay.sh | 6 ++++++ test/unit/junk.c | 8 -------- test/unit/junk.sh | 5 +++++ test/unit/junk_alloc.c | 2 -- test/unit/junk_alloc.sh | 5 +++++ test/unit/junk_free.c | 2 -- test/unit/junk_free.sh | 5 +++++ test/unit/pack.c | 3 --- test/unit/pack.sh | 4 ++++ test/unit/prof_accum.c | 5 ----- test/unit/prof_accum.sh | 5 +++++ test/unit/prof_active.c | 5 ----- test/unit/prof_active.sh | 5 +++++ test/unit/prof_gdump.c | 4 ---- test/unit/prof_gdump.sh | 6 ++++++ test/unit/prof_idump.c | 13 ------------- test/unit/prof_idump.sh | 12 ++++++++++++ test/unit/prof_reset.c | 5 ----- test/unit/prof_reset.sh | 5 +++++ test/unit/prof_tctx.c | 4 ---- test/unit/prof_tctx.sh | 5 +++++ test/unit/prof_thread_name.c | 4 ---- test/unit/prof_thread_name.sh | 5 +++++ test/unit/zero.c | 5 ----- test/unit/zero.sh | 5 +++++ 35 files changed, 119 insertions(+), 80 deletions(-) create mode 100644 test/integration/extent.sh create mode 100644 test/integration/mallocx.sh create mode 100644 test/integration/xallocx.sh create mode 100644 test/unit/arena_reset_prof.sh create mode 100644 test/unit/decay.sh create mode 100644 test/unit/junk.sh create mode 100644 test/unit/junk_alloc.sh create mode 100644 test/unit/junk_free.sh create mode 100644 test/unit/pack.sh create mode 100644 test/unit/prof_accum.sh create mode 100644 test/unit/prof_active.sh create mode 100644 test/unit/prof_gdump.sh create mode 100644 test/unit/prof_idump.sh create mode 100644 test/unit/prof_reset.sh create mode 100644 test/unit/prof_tctx.sh create mode 100644 test/unit/prof_thread_name.sh create mode 100644 test/unit/zero.sh diff --git a/test/integration/extent.c b/test/integration/extent.c index 08792df3..32432af9 100644 --- a/test/integration/extent.c +++ b/test/integration/extent.c @@ -1,9 +1,5 @@ #include "test/jemalloc_test.h" -#ifdef JEMALLOC_FILL -const char *malloc_conf = "junk:false"; -#endif - #include "test/extent_hooks.h" static void diff --git a/test/integration/extent.sh b/test/integration/extent.sh new file mode 100644 index 00000000..0cc21873 --- /dev/null +++ b/test/integration/extent.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ "x${enable_fill}" = "x1" ] ; then + export MALLOC_CONF="junk:false" +fi diff --git a/test/integration/mallocx.c b/test/integration/mallocx.c index b60e27b6..b0b5cdac 100644 --- a/test/integration/mallocx.c +++ b/test/integration/mallocx.c @@ -1,9 +1,5 @@ #include "test/jemalloc_test.h" -#ifdef JEMALLOC_FILL -const char *malloc_conf = "junk:false"; -#endif - static unsigned get_nsizes_impl(const char *cmd) { unsigned ret; diff --git a/test/integration/mallocx.sh b/test/integration/mallocx.sh new file mode 100644 index 00000000..0cc21873 --- /dev/null +++ b/test/integration/mallocx.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ "x${enable_fill}" = "x1" ] ; then + export MALLOC_CONF="junk:false" +fi diff --git a/test/integration/xallocx.c b/test/integration/xallocx.c index c95fbf18..cd0ca048 100644 --- a/test/integration/xallocx.c +++ b/test/integration/xallocx.c @@ -1,9 +1,5 @@ #include "test/jemalloc_test.h" -#ifdef JEMALLOC_FILL -const char *malloc_conf = "junk:false"; -#endif - /* * Use a separate arena for xallocx() extension/contraction tests so that * internal allocation e.g. by heap profiling can't interpose allocations where diff --git a/test/integration/xallocx.sh b/test/integration/xallocx.sh new file mode 100644 index 00000000..0cc21873 --- /dev/null +++ b/test/integration/xallocx.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ "x${enable_fill}" = "x1" ] ; then + export MALLOC_CONF="junk:false" +fi diff --git a/test/test.sh.in b/test/test.sh.in index a39f99f6..f0f0f979 100644 --- a/test/test.sh.in +++ b/test/test.sh.in @@ -11,6 +11,18 @@ case @abi@ in ;; esac +# Make a copy of the @JEMALLOC_CPREFIX@MALLOC_CONF passed in to this script, so +# it can be repeatedly concatenated with per test settings. +export MALLOC_CONF_ALL=${@JEMALLOC_CPREFIX@MALLOC_CONF} +# Concatenate the individual test's MALLOC_CONF and MALLOC_CONF_ALL. +export_malloc_conf() { + if [ "x${MALLOC_CONF}" != "x" -a "x${MALLOC_CONF_ALL}" != "x" ] ; then + export @JEMALLOC_CPREFIX@MALLOC_CONF="${MALLOC_CONF},${MALLOC_CONF_ALL}" + else + export @JEMALLOC_CPREFIX@MALLOC_CONF="${MALLOC_CONF}${MALLOC_CONF_ALL}" + fi +} + # Corresponds to test_status_t. pass_code=0 skip_code=1 @@ -24,7 +36,22 @@ for t in $@; do echo fi echo "=== ${t} ===" - ${t}@exe@ @abs_srcroot@ @abs_objroot@ + if [ -e "@srcroot@${t}.sh" ] ; then + # Source the shell script corresponding to the test in a subshell and + # execute the test. This allows the shell script to set MALLOC_CONF, which + # is then used to set @JEMALLOC_CPREFIX@MALLOC_CONF (thus allowing the + # per test shell script to ignore the @JEMALLOC_CPREFIX@ detail). + $(enable_fill=@enable_fill@ \ + enable_prof=@enable_prof@ \ + enable_tcache=@enable_tcache@ \ + . @srcroot@${t}.sh && \ + export_malloc_conf && \ + ${t}@exe@ @abs_srcroot@ @abs_objroot@) + else + $(export MALLOC_CONF= && \ + export_malloc_conf && + ${t}@exe@ @abs_srcroot@ @abs_objroot@) + fi result_code=$? case ${result_code} in ${pass_code}) diff --git a/test/unit/arena_reset_prof.c b/test/unit/arena_reset_prof.c index 6d83c843..38d80124 100644 --- a/test/unit/arena_reset_prof.c +++ b/test/unit/arena_reset_prof.c @@ -1,5 +1,4 @@ #include "test/jemalloc_test.h" #define ARENA_RESET_PROF_C_ -const char *malloc_conf = "prof:true,lg_prof_sample:0"; #include "arena_reset.c" diff --git a/test/unit/arena_reset_prof.sh b/test/unit/arena_reset_prof.sh new file mode 100644 index 00000000..041dc1c3 --- /dev/null +++ b/test/unit/arena_reset_prof.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +export MALLOC_CONF="prof:true,lg_prof_sample:0" diff --git a/test/unit/decay.c b/test/unit/decay.c index fc8fabcf..98453221 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -1,11 +1,5 @@ #include "test/jemalloc_test.h" -const char *malloc_conf = "decay_time:1" -#ifdef JEMALLOC_TCACHE - ",lg_tcache_max:0" -#endif - ; - static nstime_monotonic_t *nstime_monotonic_orig; static nstime_update_t *nstime_update_orig; diff --git a/test/unit/decay.sh b/test/unit/decay.sh new file mode 100644 index 00000000..284af815 --- /dev/null +++ b/test/unit/decay.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +export MALLOC_CONF="decay_time:1" +if [ "x${enable_tcache}" = "x1" ] ; then + export MALLOC_CONF="${MALLOC_CONF},lg_tcache_max:0" +fi diff --git a/test/unit/junk.c b/test/unit/junk.c index 86c51089..cfa8d0f2 100644 --- a/test/unit/junk.c +++ b/test/unit/junk.c @@ -1,13 +1,5 @@ #include "test/jemalloc_test.h" -#ifdef JEMALLOC_FILL -# ifndef JEMALLOC_TEST_JUNK_OPT -# define JEMALLOC_TEST_JUNK_OPT "junk:true" -# endif -const char *malloc_conf = - "abort:false,zero:false," JEMALLOC_TEST_JUNK_OPT; -#endif - static arena_dalloc_junk_small_t *arena_dalloc_junk_small_orig; static large_dalloc_junk_t *large_dalloc_junk_orig; static large_dalloc_maybe_junk_t *large_dalloc_maybe_junk_orig; diff --git a/test/unit/junk.sh b/test/unit/junk.sh new file mode 100644 index 00000000..97cd8ca5 --- /dev/null +++ b/test/unit/junk.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ "x${enable_fill}" = "x1" ] ; then + export MALLOC_CONF="abort:false,zero:false,junk:true" +fi diff --git a/test/unit/junk_alloc.c b/test/unit/junk_alloc.c index 8db3331d..a442a0ca 100644 --- a/test/unit/junk_alloc.c +++ b/test/unit/junk_alloc.c @@ -1,3 +1 @@ -#define JEMALLOC_TEST_JUNK_OPT "junk:alloc" #include "junk.c" -#undef JEMALLOC_TEST_JUNK_OPT diff --git a/test/unit/junk_alloc.sh b/test/unit/junk_alloc.sh new file mode 100644 index 00000000..e1008c2e --- /dev/null +++ b/test/unit/junk_alloc.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ "x${enable_fill}" = "x1" ] ; then + export MALLOC_CONF="abort:false,zero:false,junk:alloc" +fi diff --git a/test/unit/junk_free.c b/test/unit/junk_free.c index 482a61d0..a442a0ca 100644 --- a/test/unit/junk_free.c +++ b/test/unit/junk_free.c @@ -1,3 +1 @@ -#define JEMALLOC_TEST_JUNK_OPT "junk:free" #include "junk.c" -#undef JEMALLOC_TEST_JUNK_OPT diff --git a/test/unit/junk_free.sh b/test/unit/junk_free.sh new file mode 100644 index 00000000..402196ca --- /dev/null +++ b/test/unit/junk_free.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ "x${enable_fill}" = "x1" ] ; then + export MALLOC_CONF="abort:false,zero:false,junk:free" +fi diff --git a/test/unit/pack.c b/test/unit/pack.c index d35ac5ea..5da4ae12 100644 --- a/test/unit/pack.c +++ b/test/unit/pack.c @@ -1,8 +1,5 @@ #include "test/jemalloc_test.h" -/* Immediately purge to minimize fragmentation. */ -const char *malloc_conf = "decay_time:-1"; - /* * Size class that is a divisor of the page size, ideally 4+ regions per run. */ diff --git a/test/unit/pack.sh b/test/unit/pack.sh new file mode 100644 index 00000000..de12e553 --- /dev/null +++ b/test/unit/pack.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +# Immediately purge to minimize fragmentation. +export MALLOC_CONF="decay_time:-1" diff --git a/test/unit/prof_accum.c b/test/unit/prof_accum.c index bcd1d881..6ccab82b 100644 --- a/test/unit/prof_accum.c +++ b/test/unit/prof_accum.c @@ -5,11 +5,6 @@ #define DUMP_INTERVAL 1 #define BT_COUNT_CHECK_INTERVAL 5 -#ifdef JEMALLOC_PROF -const char *malloc_conf = - "prof:true,prof_accum:true,prof_active:false,lg_prof_sample:0"; -#endif - static int prof_dump_open_intercept(bool propagate_err, const char *filename) { int fd; diff --git a/test/unit/prof_accum.sh b/test/unit/prof_accum.sh new file mode 100644 index 00000000..b3e13fc5 --- /dev/null +++ b/test/unit/prof_accum.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ "x${enable_prof}" = "x1" ] ; then + export MALLOC_CONF="prof:true,prof_accum:true,prof_active:false,lg_prof_sample:0" +fi diff --git a/test/unit/prof_active.c b/test/unit/prof_active.c index c0e085a8..275aac89 100644 --- a/test/unit/prof_active.c +++ b/test/unit/prof_active.c @@ -1,10 +1,5 @@ #include "test/jemalloc_test.h" -#ifdef JEMALLOC_PROF -const char *malloc_conf = - "prof:true,prof_thread_active_init:false,lg_prof_sample:0"; -#endif - static void mallctl_bool_get(const char *name, bool expected, const char *func, int line) { bool old; diff --git a/test/unit/prof_active.sh b/test/unit/prof_active.sh new file mode 100644 index 00000000..0167cb10 --- /dev/null +++ b/test/unit/prof_active.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ "x${enable_prof}" = "x1" ] ; then + export MALLOC_CONF="prof:true,prof_thread_active_init:false,lg_prof_sample:0" +fi diff --git a/test/unit/prof_gdump.c b/test/unit/prof_gdump.c index 30320b7a..97ade68c 100644 --- a/test/unit/prof_gdump.c +++ b/test/unit/prof_gdump.c @@ -1,9 +1,5 @@ #include "test/jemalloc_test.h" -#ifdef JEMALLOC_PROF -const char *malloc_conf = "prof:true,prof_active:false,prof_gdump:true"; -#endif - static bool did_prof_dump_open; static int diff --git a/test/unit/prof_gdump.sh b/test/unit/prof_gdump.sh new file mode 100644 index 00000000..3f600d20 --- /dev/null +++ b/test/unit/prof_gdump.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +if [ "x${enable_prof}" = "x1" ] ; then + export MALLOC_CONF="prof:true,prof_active:false,prof_gdump:true" +fi + diff --git a/test/unit/prof_idump.c b/test/unit/prof_idump.c index 1fed7b37..1cc6c98c 100644 --- a/test/unit/prof_idump.c +++ b/test/unit/prof_idump.c @@ -1,18 +1,5 @@ #include "test/jemalloc_test.h" -const char *malloc_conf = "" -#ifdef JEMALLOC_PROF - "prof:true,prof_accum:true,prof_active:false,lg_prof_sample:0" - ",lg_prof_interval:0" -# ifdef JEMALLOC_TCACHE - "," -# endif -#endif -#ifdef JEMALLOC_TCACHE - "tcache:false" -#endif - ; - static bool did_prof_dump_open; static int diff --git a/test/unit/prof_idump.sh b/test/unit/prof_idump.sh new file mode 100644 index 00000000..fdb5813f --- /dev/null +++ b/test/unit/prof_idump.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +if [ "x${enable_prof}" = "x1" ] ; then + export MALLOC_CONF="prof:true,prof_accum:true,prof_active:false,lg_prof_sample:0,lg_prof_interval:0" + if [ "x${enable_tcache}" = "x1" ] ; then + export MALLOC_CONF="${MALLOC_CONF},tcache:false" + fi +elif [ "x${enable_tcache}" = "x1" ] ; then + export MALLOC_CONF="tcache:false" +fi + + diff --git a/test/unit/prof_reset.c b/test/unit/prof_reset.c index fc954f9f..6120714e 100644 --- a/test/unit/prof_reset.c +++ b/test/unit/prof_reset.c @@ -1,10 +1,5 @@ #include "test/jemalloc_test.h" -#ifdef JEMALLOC_PROF -const char *malloc_conf = - "prof:true,prof_active:false,lg_prof_sample:0"; -#endif - static int prof_dump_open_intercept(bool propagate_err, const char *filename) { int fd; diff --git a/test/unit/prof_reset.sh b/test/unit/prof_reset.sh new file mode 100644 index 00000000..43c516a0 --- /dev/null +++ b/test/unit/prof_reset.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ "x${enable_prof}" = "x1" ] ; then + export MALLOC_CONF="prof:true,prof_active:false,lg_prof_sample:0" +fi diff --git a/test/unit/prof_tctx.c b/test/unit/prof_tctx.c index 2e35b7ec..14510c65 100644 --- a/test/unit/prof_tctx.c +++ b/test/unit/prof_tctx.c @@ -1,9 +1,5 @@ #include "test/jemalloc_test.h" -#ifdef JEMALLOC_PROF -const char *malloc_conf = "prof:true,lg_prof_sample:0"; -#endif - TEST_BEGIN(test_prof_realloc) { tsdn_t *tsdn; int flags; diff --git a/test/unit/prof_tctx.sh b/test/unit/prof_tctx.sh new file mode 100644 index 00000000..8fcc7d8a --- /dev/null +++ b/test/unit/prof_tctx.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ "x${enable_prof}" = "x1" ] ; then + export MALLOC_CONF="prof:true,lg_prof_sample:0" +fi diff --git a/test/unit/prof_thread_name.c b/test/unit/prof_thread_name.c index a094a1c0..c9c2a2b7 100644 --- a/test/unit/prof_thread_name.c +++ b/test/unit/prof_thread_name.c @@ -1,9 +1,5 @@ #include "test/jemalloc_test.h" -#ifdef JEMALLOC_PROF -const char *malloc_conf = "prof:true,prof_active:false"; -#endif - static void mallctl_thread_name_get_impl(const char *thread_name_expected, const char *func, int line) { diff --git a/test/unit/prof_thread_name.sh b/test/unit/prof_thread_name.sh new file mode 100644 index 00000000..298c1058 --- /dev/null +++ b/test/unit/prof_thread_name.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ "x${enable_prof}" = "x1" ] ; then + export MALLOC_CONF="prof:true,prof_active:false" +fi diff --git a/test/unit/zero.c b/test/unit/zero.c index d5b03f8d..553692ba 100644 --- a/test/unit/zero.c +++ b/test/unit/zero.c @@ -1,10 +1,5 @@ #include "test/jemalloc_test.h" -#ifdef JEMALLOC_FILL -const char *malloc_conf = - "abort:false,junk:false,zero:true"; -#endif - static void test_zero(size_t sz_min, size_t sz_max) { uint8_t *s; diff --git a/test/unit/zero.sh b/test/unit/zero.sh new file mode 100644 index 00000000..b4540b27 --- /dev/null +++ b/test/unit/zero.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +if [ "x${enable_fill}" = "x1" ] ; then + export MALLOC_CONF="abort:false,junk:false,zero:true" +fi -- GitLab From c2323e13a5eec70f554e532336a912a9cd78317a Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Thu, 23 Feb 2017 14:42:52 -0800 Subject: [PATCH 288/544] Get rid of witness in malloc_mutex_t when !(configured w/ debug). We don't touch witness at all when config_debug == false. Let's only pay the memory cost in malloc_mutex_s when needed. Note that when !config_debug, we keep the field in a union so that we don't have to do #ifdefs in multiple places. --- include/jemalloc/internal/mutex_structs.h | 30 +++++++++++++++++------ include/jemalloc/internal/mutex_types.h | 12 ++++----- include/jemalloc/internal/witness_types.h | 6 ++++- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/include/jemalloc/internal/mutex_structs.h b/include/jemalloc/internal/mutex_structs.h index 4a18a075..c34c1d47 100644 --- a/include/jemalloc/internal/mutex_structs.h +++ b/include/jemalloc/internal/mutex_structs.h @@ -2,23 +2,39 @@ #define JEMALLOC_INTERNAL_MUTEX_STRUCTS_H struct malloc_mutex_s { + union { + struct { #ifdef _WIN32 # if _WIN32_WINNT >= 0x0600 - SRWLOCK lock; + SRWLOCK lock; # else - CRITICAL_SECTION lock; + CRITICAL_SECTION lock; # endif #elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) - os_unfair_lock lock; + os_unfair_lock lock; #elif (defined(JEMALLOC_OSSPIN)) - OSSpinLock lock; + OSSpinLock lock; #elif (defined(JEMALLOC_MUTEX_INIT_CB)) - pthread_mutex_t lock; - malloc_mutex_t *postponed_next; + pthread_mutex_t lock; + malloc_mutex_t *postponed_next; #else - pthread_mutex_t lock; + pthread_mutex_t lock; #endif + }; + /* + * We only touch witness when configured w/ debug. However we + * keep the field in a union when !debug so that we don't have + * to pollute the code base with #ifdefs, while avoid paying the + * memory cost. + */ +#if !defined(JEMALLOC_DEBUG) + witness_t witness; +#endif + }; + +#if defined(JEMALLOC_DEBUG) witness_t witness; +#endif }; #endif /* JEMALLOC_INTERNAL_MUTEX_STRUCTS_H */ diff --git a/include/jemalloc/internal/mutex_types.h b/include/jemalloc/internal/mutex_types.h index 8c9f249d..b7e3a7a1 100644 --- a/include/jemalloc/internal/mutex_types.h +++ b/include/jemalloc/internal/mutex_types.h @@ -7,25 +7,25 @@ typedef struct malloc_mutex_s malloc_mutex_t; # define MALLOC_MUTEX_INITIALIZER #elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) # define MALLOC_MUTEX_INITIALIZER \ - {OS_UNFAIR_LOCK_INIT, WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} + {{{OS_UNFAIR_LOCK_INIT}}, WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} #elif (defined(JEMALLOC_OSSPIN)) # define MALLOC_MUTEX_INITIALIZER \ - {0, WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} + {{{0}}, WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} #elif (defined(JEMALLOC_MUTEX_INIT_CB)) # define MALLOC_MUTEX_INITIALIZER \ - {PTHREAD_MUTEX_INITIALIZER, NULL, \ - WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} + {{{PTHREAD_MUTEX_INITIALIZER, NULL}}, \ + WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} #else # if (defined(JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP) && \ defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP)) # define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_ADAPTIVE_NP # define MALLOC_MUTEX_INITIALIZER \ - {PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP, \ + {{{PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP}}, \ WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} # else # define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT # define MALLOC_MUTEX_INITIALIZER \ - {PTHREAD_MUTEX_INITIALIZER, \ + {{{PTHREAD_MUTEX_INITIALIZER}}, \ WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} # endif #endif diff --git a/include/jemalloc/internal/witness_types.h b/include/jemalloc/internal/witness_types.h index 0678b082..3efaad7e 100644 --- a/include/jemalloc/internal/witness_types.h +++ b/include/jemalloc/internal/witness_types.h @@ -55,6 +55,10 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *, #define WITNESS_RANK_PROF_NEXT_THR_UID WITNESS_RANK_LEAF #define WITNESS_RANK_PROF_THREAD_ACTIVE_INIT WITNESS_RANK_LEAF -#define WITNESS_INITIALIZER(name, rank) {name, rank, NULL, NULL, {NULL, NULL}} +#if defined(JEMALLOC_DEBUG) +# define WITNESS_INITIALIZER(name, rank) {name, rank, NULL, NULL, {NULL, NULL}} +#else +# define WITNESS_INITIALIZER(name, rank) +#endif #endif /* JEMALLOC_INTERNAL_WITNESS_TYPES_H */ -- GitLab From d727596bcbd3f2d6b2af1e21cf19210ac236f8df Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 24 Feb 2017 08:59:34 -0800 Subject: [PATCH 289/544] Update a comment. --- include/jemalloc/internal/witness_types.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/jemalloc/internal/witness_types.h b/include/jemalloc/internal/witness_types.h index 3efaad7e..95fc296c 100644 --- a/include/jemalloc/internal/witness_types.h +++ b/include/jemalloc/internal/witness_types.h @@ -27,10 +27,10 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *, #define WITNESS_RANK_PROF_GCTX 8U /* - * Used as an argument to witness_depth_to_rank() in order to validate depth - * excluding non-core locks with lower ranks. Since the rank argument to - * witness_depth_to_rank() is inclusive rather than exclusive, this definition - * can have the same value as the minimally ranked core lock. + * Used as an argument to witness_assert_depth_to_rank() in order to validate + * depth excluding non-core locks with lower ranks. Since the rank argument to + * witness_assert_depth_to_rank() is inclusive rather than exclusive, this + * definition can have the same value as the minimally ranked core lock. */ #define WITNESS_RANK_CORE 9U -- GitLab From 079b8bee37ddd35e25c0cf7ac9241520290fa66c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 26 Feb 2017 12:48:43 -0800 Subject: [PATCH 290/544] Tidy up extent quantization. Remove obsolete unit test scaffolding for extent quantization. Remove redundant assertions. Add an assertion to extents_first_best_fit_locked() that should help prevent aligned allocation regressions. --- include/jemalloc/internal/extent_externs.h | 4 ---- src/extent.c | 26 +++++----------------- 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index d971ec3a..f5efed06 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -11,10 +11,6 @@ extent_hooks_t *extent_hooks_get(arena_t *arena); extent_hooks_t *extent_hooks_set(arena_t *arena, extent_hooks_t *extent_hooks); #ifdef JEMALLOC_JET -typedef size_t (extent_size_quantize_t)(size_t); -extern extent_size_quantize_t *extent_size_quantize_floor; -extern extent_size_quantize_t *extent_size_quantize_ceil; -#else size_t extent_size_quantize_floor(size_t size); size_t extent_size_quantize_ceil(size_t size); #endif diff --git a/src/extent.c b/src/extent.c index afc60061..09990aae 100644 --- a/src/extent.c +++ b/src/extent.c @@ -118,9 +118,8 @@ extent_hooks_assure_initialized(arena_t *arena, } } -#ifdef JEMALLOC_JET -#undef extent_size_quantize_floor -#define extent_size_quantize_floor JEMALLOC_N(n_extent_size_quantize_floor) +#ifndef JEMALLOC_JET +static #endif size_t extent_size_quantize_floor(size_t size) { @@ -130,9 +129,6 @@ extent_size_quantize_floor(size_t size) { assert(size > 0); assert((size & PAGE_MASK) == 0); - assert(size != 0); - assert(size == PAGE_CEILING(size)); - pind = psz2ind(size - large_pad + 1); if (pind == 0) { /* @@ -147,16 +143,9 @@ extent_size_quantize_floor(size_t size) { assert(ret <= size); return ret; } -#ifdef JEMALLOC_JET -#undef extent_size_quantize_floor -#define extent_size_quantize_floor JEMALLOC_N(extent_size_quantize_floor) -extent_size_quantize_t *extent_size_quantize_floor = - JEMALLOC_N(n_extent_size_quantize_floor); -#endif -#ifdef JEMALLOC_JET -#undef extent_size_quantize_ceil -#define extent_size_quantize_ceil JEMALLOC_N(n_extent_size_quantize_ceil) +#ifndef JEMALLOC_JET +static #endif size_t extent_size_quantize_ceil(size_t size) { @@ -180,12 +169,6 @@ extent_size_quantize_ceil(size_t size) { } return ret; } -#ifdef JEMALLOC_JET -#undef extent_size_quantize_ceil -#define extent_size_quantize_ceil JEMALLOC_N(extent_size_quantize_ceil) -extent_size_quantize_t *extent_size_quantize_ceil = - JEMALLOC_N(n_extent_size_quantize_ceil); -#endif /* Generate pairing heap functions. */ ph_gen(, extent_heap_, extent_heap_t, extent_t, ph_link, extent_snad_comp) @@ -258,6 +241,7 @@ extents_first_best_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, for (pszind_t i = pind; i < NPSIZES+1; i++) { extent_t *extent = extent_heap_first(&extents->heaps[i]); if (extent != NULL) { + assert(extent_size_get(extent) >= size); return extent; } } -- GitLab From 472fef2e125489e236afbbccad78946fc9f1d73f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 25 Feb 2017 14:10:05 -0800 Subject: [PATCH 291/544] Fix {allocated,nmalloc,ndalloc,nrequests}_large stats regression. This fixes a regression introduced by d433471f581ca50583c7a99f9802f7388f81aa36 (Derive {allocated,nmalloc,ndalloc,nrequests}_large stats.). --- include/jemalloc/internal/stats_structs.h | 2 +- src/arena.c | 16 ++-------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index 1571ef4f..354f93ee 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -81,7 +81,7 @@ struct arena_stats_s { #endif /* Number of bytes currently mapped, excluding retained memory. */ - size_t mapped; /* Derived. */ + size_t mapped; /* Partially derived. */ /* * Number of bytes currently retained as a side effect of munmap() being diff --git a/src/arena.c b/src/arena.c index a914abda..18b49312 100644 --- a/src/arena.c +++ b/src/arena.c @@ -192,19 +192,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, astats->internal += arena_internal_get(arena); astats->resident += base_resident + (((atomic_read_zu(&arena->nactive) + extents_npages_get(&arena->extents_cached)) << LG_PAGE)); - astats->allocated_large += arena_stats_read_zu(tsdn, &arena->stats, - &arena->stats.allocated_large); - astats->nmalloc_large += arena_stats_read_u64(tsdn, &arena->stats, - &arena->stats.nmalloc_large); - astats->ndalloc_large += arena_stats_read_u64(tsdn, &arena->stats, - &arena->stats.ndalloc_large); - astats->nrequests_large += arena_stats_read_u64(tsdn, &arena->stats, - &arena->stats.nrequests_large); - - astats->allocated_large = 0; - astats->nmalloc_large = 0; - astats->ndalloc_large = 0; - astats->nrequests_large = 0; + for (szind_t i = 0; i < NSIZES - NBINS; i++) { uint64_t nmalloc = arena_stats_read_u64(tsdn, &arena->stats, &arena->stats.lstats[i].nmalloc); @@ -224,7 +212,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, size_t curlextents = arena_stats_read_zu(tsdn, &arena->stats, &arena->stats.lstats[i].curlextents); lstats[i].curlextents += curlextents; - astats->allocated_large += curlextents * index2size(i); + astats->allocated_large += curlextents * index2size(NBINS + i); } arena_stats_unlock(tsdn, &arena->stats); -- GitLab From 4a068644c7b60ed91c08ade8c71c2077fec4687b Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 27 Feb 2017 17:35:19 -0800 Subject: [PATCH 292/544] Put -D_REENTRANT in CPPFLAGS rather than CFLAGS. This regression was introduced by 194d6f9de8ff92841b67f38a2a6a06818e3240dd (Restructure *CFLAGS/*CXXFLAGS configuration.). --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 1627a3d9..5e655471 100644 --- a/configure.ac +++ b/configure.ac @@ -1503,7 +1503,7 @@ if test "x$abi" != "xpecoff" ; then fi fi -JE_APPEND_VS(CFLAGS, -D_REENTRANT) +JE_APPEND_VS(CPPFLAGS, -D_REENTRANT) dnl Check whether clock_gettime(2) is in libc or librt. AC_SEARCH_LIBS([clock_gettime], [rt]) -- GitLab From 25d50a943a46e2f435002fcfdacfa93f6974ac11 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 27 Feb 2017 18:11:58 -0800 Subject: [PATCH 293/544] Dodge 32-bit-clang-specific backtracing failure. This disables run_tests.sh configurations that use the combination of 32-bit clang and heap profiling. --- scripts/gen_run_tests.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/gen_run_tests.py b/scripts/gen_run_tests.py index 694685cb..729ecb1a 100755 --- a/scripts/gen_run_tests.py +++ b/scripts/gen_run_tests.py @@ -28,6 +28,10 @@ print 'unamestr=`uname`' for cc, cxx in possible_compilers: for compiler_opts in powerset(possible_compiler_opts): for config_opts in powerset(possible_config_opts): + if cc is 'clang' \ + and '-m32' in possible_compiler_opts \ + and '--enable-prof' in config_opts: + continue config_line = ( './configure ' + 'CC="{} {}" '.format(cc, " ".join(compiler_opts)) -- GitLab From cbb6720861e67b9e4e965614422e22d9bfa95244 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 28 Feb 2017 12:59:22 -0800 Subject: [PATCH 294/544] Update ChangeLog for 4.5.0. --- ChangeLog | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/ChangeLog b/ChangeLog index f75edd93..a9406853 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,41 @@ brevity. Much more detail can be found in the git revision history: https://github.com/jemalloc/jemalloc +* 4.5.0 (February 28, 2017) + + This is the first release to benefit from much broader continuous integration + testing, thanks to @davidtgoldblatt. Had we had this testing infrastructure + in place for prior releases, it would have caught all of the most serious + regressions fixed by this release. + + New features: + - Add --disable-thp and the opt.thp to provide opt-out mechanisms for + transparent huge page integration. (@jasone) + - Update zone allocator integration to work with macOS 10.12. (@glandium) + - Restructure *CFLAGS configuration, so that CFLAGS behaves typically, and + EXTRA_CFLAGS provides a way to specify e.g. -Werror during building, but not + during configuration. (@jasone, @ronawho) + + Bug fixes: + - Fix DSS (sbrk(2)-based) allocation. This regression was first released in + 4.3.0. (@jasone) + - Handle race in per size class utilization computation. This functionality + was first released in 4.0.0. (@interwq) + - Fix lock order reversal during gdump. (@jasone) + - Fix-refactor tcache synchronization. This regression was first released in + 4.0.0. (@jasone) + - Fix various JSON-formatted malloc_stats_print() bugs. This functionality + was first released in 4.3.0. (@jasone) + - Fix huge-aligned allocation. This regression was first released in 4.4.0. + (@jasone) + - When transparent huge page integration is enabled, detect what state pages + start in according to the kernel's current operating mode, and only convert + arena chunks to non-huge during purging if that is not their initial state. + This functionality was first released in 4.4.0. (@jasone) + - Fix lg_chunk clamping for the --enable-cache-oblivious --disable-fill case. + This regression was first released in 4.0.0. (@jasone, @428desmo) + - Properly detect sparc64 when building for Linux. (@glaubitz) + * 4.4.0 (December 3, 2016) New features: -- GitLab From 379dd44c572111ea5505d33d808e659e8a8b4592 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 28 Feb 2017 14:54:07 -0800 Subject: [PATCH 295/544] Add casts to CONF_HANDLE_T_U(). This avoids signed/unsigned comparison warnings when specifying integer constants as inputs. --- src/jemalloc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index 197f9bdc..7e652802 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -962,20 +962,20 @@ malloc_conf_init(void) { k, klen, v, vlen); \ } else if (clip) { \ if (CONF_MIN_##check_min(um, \ - (min))) { \ + (t)(min))) { \ o = (t)(min); \ } else if ( \ CONF_MAX_##check_max(um, \ - (max))) { \ + (t)(max))) { \ o = (t)(max); \ } else { \ o = (t)um; \ } \ } else { \ if (CONF_MIN_##check_min(um, \ - (min)) || \ + (t)(min)) || \ CONF_MAX_##check_max(um, \ - (max))) { \ + (t)(max))) { \ malloc_conf_error( \ "Out-of-range " \ "conf value", \ -- GitLab From a8c9e9c651671b09f1055882b4a9e59955e303f7 Mon Sep 17 00:00:00 2001 From: charsyam Date: Wed, 1 Mar 2017 20:58:38 +0900 Subject: [PATCH 296/544] fix typo sytem -> system --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5e655471..1653fe7f 100644 --- a/configure.ac +++ b/configure.ac @@ -1388,7 +1388,7 @@ fi AC_ARG_WITH([lg_hugepage], [AS_HELP_STRING([--with-lg-hugepage=], - [Base 2 log of sytem huge page size])], + [Base 2 log of system huge page size])], [je_cv_lg_hugepage="${with_lg_hugepage}"], [je_cv_lg_hugepage=""]) if test "x${je_cv_lg_hugepage}" = "x" ; then -- GitLab From aa1de06e3ab439e69a20fdd555a8253b0e31fc04 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 1 Mar 2017 14:43:35 -0800 Subject: [PATCH 297/544] Small style fix in ctl.c --- src/ctl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ctl.c b/src/ctl.c index 0bf4258e..7ec8ff2a 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -943,8 +943,7 @@ ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp, node = ctl_named_node(nodes[depth-1]); if (node != NULL && node->ctl) { ret = node->ctl(tsd, mib, depth, oldp, oldlenp, newp, newlen); - } - else { + } else { /* The name refers to a partial path through the ctl tree. */ ret = ENOENT; } -- GitLab From ff55f07eb6cc775755ffbea406d8967ec5e13d6e Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 28 Feb 2017 19:24:08 -0800 Subject: [PATCH 298/544] Fix typos. --- ChangeLog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index a9406853..e630595b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,7 +12,7 @@ brevity. Much more detail can be found in the git revision history: regressions fixed by this release. New features: - - Add --disable-thp and the opt.thp to provide opt-out mechanisms for + - Add --disable-thp and the opt.thp mallctl to provide opt-out mechanisms for transparent huge page integration. (@jasone) - Update zone allocator integration to work with macOS 10.12. (@glandium) - Restructure *CFLAGS configuration, so that CFLAGS behaves typically, and @@ -25,7 +25,7 @@ brevity. Much more detail can be found in the git revision history: - Handle race in per size class utilization computation. This functionality was first released in 4.0.0. (@interwq) - Fix lock order reversal during gdump. (@jasone) - - Fix-refactor tcache synchronization. This regression was first released in + - Fix/refactor tcache synchronization. This regression was first released in 4.0.0. (@jasone) - Fix various JSON-formatted malloc_stats_print() bugs. This functionality was first released in 4.3.0. (@jasone) -- GitLab From d61a5f76b2e3bcd866e19ab90a59081c5fc917fa Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Mar 2017 11:21:18 -0800 Subject: [PATCH 299/544] Convert arena_decay_t's time to be atomically synchronized. --- include/jemalloc/internal/arena_externs.h | 2 +- include/jemalloc/internal/arena_structs_b.h | 11 +++++-- src/arena.c | 35 +++++++++++++-------- src/ctl.c | 2 +- 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index d97b6a7d..7b16d229 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -39,7 +39,7 @@ void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); -ssize_t arena_decay_time_get(tsdn_t *tsdn, arena_t *arena); +ssize_t arena_decay_time_get(arena_t *arena); bool arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time); void arena_purge(tsdn_t *tsdn, arena_t *arena, bool all); void arena_maybe_purge(tsdn_t *tsdn, arena_t *arena); diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 92f1e41f..49fdd17d 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -36,15 +36,22 @@ struct arena_bin_info_s { bitmap_info_t bitmap_info; }; +typedef union { + size_t u; /* Used for atomic operations. */ + ssize_t s; /* Time may be negative (means "never"). */ +} arena_decay_time_t; + struct arena_decay_s { - /* Synchronizes all fields. */ + /* Synchronizes all non-atomic fields. */ malloc_mutex_t mtx; /* * Approximate time in seconds from the creation of a set of unused * dirty pages until an equivalent set of unused dirty pages is purged * and/or reused. + * + * Synchronization: atomic. */ - ssize_t time; + arena_decay_time_t time; /* time / SMOOTHSTEP_NSTEPS. */ nstime_t interval; /* diff --git a/src/arena.c b/src/arena.c index 18b49312..9f395769 100644 --- a/src/arena.c +++ b/src/arena.c @@ -157,7 +157,7 @@ arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) { *nthreads += arena_nthreads_get(arena, false); *dss = dss_prec_names[arena_dss_prec_get(arena)]; - *decay_time = arena_decay_time_get(tsdn, arena); + *decay_time = arena_decay_time_get(arena); *nactive += atomic_read_zu(&arena->nactive); *ndirty += extents_npages_get(&arena->extents_cached); } @@ -491,6 +491,20 @@ arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, arena_nactive_add(arena, udiff >> LG_PAGE); } +static ssize_t +arena_decay_time_read(arena_t *arena) { + arena_decay_time_t dt; + dt.u = atomic_read_zu(&arena->decay.time.u); + return dt.s; +} + +static void +arena_decay_time_write(arena_t *arena, ssize_t decay_time) { + arena_decay_time_t dt; + dt.s = decay_time; + atomic_write_zu(&arena->decay.time.u, dt.u); +} + static void arena_decay_deadline_init(arena_t *arena) { /* @@ -499,7 +513,7 @@ arena_decay_deadline_init(arena_t *arena) { */ nstime_copy(&arena->decay.deadline, &arena->decay.epoch); nstime_add(&arena->decay.deadline, &arena->decay.interval); - if (arena->decay.time > 0) { + if (arena_decay_time_read(arena) > 0) { nstime_t jitter; nstime_init(&jitter, prng_range_u64(&arena->decay.jitter_state, @@ -615,7 +629,7 @@ arena_decay_epoch_advance(tsdn_t *tsdn, arena_t *arena, const nstime_t *time) { static void arena_decay_reinit(arena_t *arena, ssize_t decay_time) { - arena->decay.time = decay_time; + arena_decay_time_write(arena, decay_time); if (decay_time > 0) { nstime_init2(&arena->decay.interval, decay_time, 0); nstime_idivide(&arena->decay.interval, SMOOTHSTEP_NSTEPS); @@ -650,14 +664,8 @@ arena_decay_time_valid(ssize_t decay_time) { } ssize_t -arena_decay_time_get(tsdn_t *tsdn, arena_t *arena) { - ssize_t decay_time; - - malloc_mutex_lock(tsdn, &arena->decay.mtx); - decay_time = arena->decay.time; - malloc_mutex_unlock(tsdn, &arena->decay.mtx); - - return decay_time; +arena_decay_time_get(arena_t *arena) { + return arena_decay_time_read(arena); } bool @@ -687,8 +695,9 @@ arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_assert_owner(tsdn, &arena->decay.mtx); /* Purge all or nothing if the option is disabled. */ - if (arena->decay.time <= 0) { - if (arena->decay.time == 0) { + ssize_t decay_time = arena_decay_time_read(arena); + if (decay_time <= 0) { + if (decay_time == 0) { arena_purge_to_limit(tsdn, arena, 0); } return; diff --git a/src/ctl.c b/src/ctl.c index 7ec8ff2a..83e9e93e 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1797,7 +1797,7 @@ arena_i_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, } if (oldp != NULL && oldlenp != NULL) { - size_t oldval = arena_decay_time_get(tsd_tsdn(tsd), arena); + size_t oldval = arena_decay_time_get(arena); READ(oldval, ssize_t); } if (newp != NULL) { -- GitLab From fd058f572baf0955091ed0dd66cca78105fdb539 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 1 Mar 2017 15:25:48 -0800 Subject: [PATCH 300/544] Immediately purge cached extents if decay_time is 0. This fixes a regression caused by 54269dc0ed3e4d04b2539016431de3cfe8330719 (Remove obsolete arena_maybe_purge() call.), as well as providing a general fix. This resolves #665. --- include/jemalloc/internal/arena_externs.h | 3 - include/jemalloc/internal/private_symbols.txt | 2 - src/arena.c | 69 ++++++------ src/large.c | 3 +- test/unit/decay.c | 105 +++++++++++++++++- 5 files changed, 138 insertions(+), 44 deletions(-) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 7b16d229..36d91869 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -33,8 +33,6 @@ extent_t *arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero); void arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena, extent_t *extent); -void arena_extent_dalloc_large_finish(tsdn_t *tsdn, arena_t *arena, - extent_t *extent); void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, @@ -42,7 +40,6 @@ void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, ssize_t arena_decay_time_get(arena_t *arena); bool arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time); void arena_purge(tsdn_t *tsdn, arena_t *arena, bool all); -void arena_maybe_purge(tsdn_t *tsdn, arena_t *arena); void arena_reset(tsd_t *tsd, arena_t *arena); void arena_destroy(tsd_t *tsd, arena_t *arena); void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index be56e1a2..0234181e 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -26,7 +26,6 @@ arena_dss_prec_get arena_dss_prec_set arena_extent_alloc_large arena_extent_cache_dalloc -arena_extent_dalloc_large_finish arena_extent_dalloc_large_prep arena_extent_ralloc_large_expand arena_extent_ralloc_large_shrink @@ -40,7 +39,6 @@ arena_internal_get arena_internal_sub arena_malloc arena_malloc_hard -arena_maybe_purge arena_migrate arena_new arena_nthreads_dec diff --git a/src/arena.c b/src/arena.c index 9f395769..ecb5cd42 100644 --- a/src/arena.c +++ b/src/arena.c @@ -259,7 +259,9 @@ arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); extent_dalloc_cache(tsdn, arena, r_extent_hooks, extent); - arena_purge(tsdn, arena, false); + if (arena_decay_time_get(arena) == 0) { + arena_purge(tsdn, arena, true); + } } JEMALLOC_INLINE_C void * @@ -456,13 +458,6 @@ arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { arena_nactive_sub(arena, extent_size_get(extent) >> LG_PAGE); } -void -arena_extent_dalloc_large_finish(tsdn_t *tsdn, arena_t *arena, - extent_t *extent) { - extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; - extent_dalloc_cache(tsdn, arena, &extent_hooks, extent); -} - void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldusize) { @@ -663,34 +658,7 @@ arena_decay_time_valid(ssize_t decay_time) { return false; } -ssize_t -arena_decay_time_get(arena_t *arena) { - return arena_decay_time_read(arena); -} - -bool -arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { - if (!arena_decay_time_valid(decay_time)) { - return true; - } - - malloc_mutex_lock(tsdn, &arena->decay.mtx); - /* - * Restart decay backlog from scratch, which may cause many dirty pages - * to be immediately purged. It would conceptually be possible to map - * the old backlog onto the new backlog, but there is no justification - * for such complexity since decay_time changes are intended to be - * infrequent, either between the {-1, 0, >0} states, or a one-time - * arbitrary change during initial arena configuration. - */ - arena_decay_reinit(arena, decay_time); - arena_maybe_purge(tsdn, arena); - malloc_mutex_unlock(tsdn, &arena->decay.mtx); - - return false; -} - -void +static void arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_assert_owner(tsdn, &arena->decay.mtx); @@ -735,6 +703,33 @@ arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) { } } +ssize_t +arena_decay_time_get(arena_t *arena) { + return arena_decay_time_read(arena); +} + +bool +arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { + if (!arena_decay_time_valid(decay_time)) { + return true; + } + + malloc_mutex_lock(tsdn, &arena->decay.mtx); + /* + * Restart decay backlog from scratch, which may cause many dirty pages + * to be immediately purged. It would conceptually be possible to map + * the old backlog onto the new backlog, but there is no justification + * for such complexity since decay_time changes are intended to be + * infrequent, either between the {-1, 0, >0} states, or a one-time + * arbitrary change during initial arena configuration. + */ + arena_decay_reinit(arena, decay_time); + arena_maybe_purge(tsdn, arena); + malloc_mutex_unlock(tsdn, &arena->decay.mtx); + + return false; +} + static size_t arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, size_t ndirty_limit, extent_list_t *purge_extents) { @@ -846,7 +841,7 @@ arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) { arena_nactive_sub(arena, extent_size_get(slab) >> LG_PAGE); extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; - extent_dalloc_cache(tsdn, arena, &extent_hooks, slab); + arena_extent_cache_dalloc(tsdn, arena, &extent_hooks, slab); } static void diff --git a/src/large.c b/src/large.c index bb638499..e9536bca 100644 --- a/src/large.c +++ b/src/large.c @@ -319,7 +319,8 @@ large_dalloc_prep_impl(tsdn_t *tsdn, arena_t *arena, extent_t *extent, static void large_dalloc_finish_impl(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { - arena_extent_dalloc_large_finish(tsdn, arena, extent); + extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; + arena_extent_cache_dalloc(tsdn, arena, &extent_hooks, extent); } void diff --git a/test/unit/decay.c b/test/unit/decay.c index 98453221..2513dbd4 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -348,10 +348,113 @@ TEST_BEGIN(test_decay_nonmonotonic) { } TEST_END +static unsigned +do_arena_create(ssize_t decay_time) { + unsigned arena_ind; + size_t sz = sizeof(unsigned); + assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), + 0, "Unexpected mallctl() failure"); + size_t mib[3]; + size_t miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("arena.0.decay_time", mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + mib[1] = (size_t)arena_ind; + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&decay_time, + sizeof(decay_time)), 0, "Unexpected mallctlbymib() failure"); + return arena_ind; +} + +static void +do_arena_destroy(unsigned arena_ind) { + size_t mib[3]; + size_t miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("arena.0.destroy", mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + mib[1] = (size_t)arena_ind; + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, + "Unexpected mallctlbymib() failure"); +} + +void +do_epoch(void) { + uint64_t epoch = 1; + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), + 0, "Unexpected mallctl() failure"); +} + +static size_t +get_arena_pdirty(unsigned arena_ind) { + do_epoch(); + size_t mib[4]; + size_t miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("stats.arenas.0.pdirty", mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + mib[2] = (size_t)arena_ind; + size_t pdirty; + size_t sz = sizeof(pdirty); + assert_d_eq(mallctlbymib(mib, miblen, (void *)&pdirty, &sz, NULL, 0), 0, + "Unexpected mallctlbymib() failure"); + return pdirty; +} + +static void * +do_mallocx(size_t size, int flags) { + void *p = mallocx(size, flags); + assert_ptr_not_null(p, "Unexpected mallocx() failure"); + return p; +} + +static void +generate_dirty(unsigned arena_ind, size_t size) { + int flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; + void *p = do_mallocx(size, flags); + dallocx(p, flags); +} + +TEST_BEGIN(test_decay_now) { + unsigned arena_ind = do_arena_create(0); + assert_zu_eq(get_arena_pdirty(arena_ind), 0, "Unexpected dirty pages"); + size_t sizes[] = {16, PAGE<<2, HUGEPAGE<<2}; + /* Verify that dirty pages never linger after deallocation. */ + for (unsigned i = 0; i < sizeof(sizes)/sizeof(size_t); i++) { + size_t size = sizes[i]; + generate_dirty(arena_ind, size); + assert_zu_eq(get_arena_pdirty(arena_ind), 0, + "Unexpected dirty pages"); + } + do_arena_destroy(arena_ind); +} +TEST_END + +TEST_BEGIN(test_decay_never) { + unsigned arena_ind = do_arena_create(-1); + int flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; + assert_zu_eq(get_arena_pdirty(arena_ind), 0, "Unexpected dirty pages"); + size_t sizes[] = {16, PAGE<<2, HUGEPAGE<<2}; + void *ptrs[sizeof(sizes)/sizeof(size_t)]; + for (unsigned i = 0; i < sizeof(sizes)/sizeof(size_t); i++) { + ptrs[i] = do_mallocx(sizes[i], flags); + } + /* Verify that each deallocation generates additional dirty pages. */ + size_t pdirty_prev = get_arena_pdirty(arena_ind); + assert_zu_eq(pdirty_prev, 0, "Unexpected dirty pages"); + for (unsigned i = 0; i < sizeof(sizes)/sizeof(size_t); i++) { + dallocx(ptrs[i], flags); + size_t pdirty = get_arena_pdirty(arena_ind); + assert_zu_gt(pdirty, pdirty_prev, + "Expected dirty pages to increase."); + pdirty_prev = pdirty; + } + do_arena_destroy(arena_ind); +} +TEST_END + int main(void) { return test( test_decay_ticks, test_decay_ticker, - test_decay_nonmonotonic); + test_decay_nonmonotonic, + test_decay_now, + test_decay_never); } -- GitLab From 957b8c5f2171f54f66689875144830e682be8e64 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 27 Feb 2017 17:33:38 -0800 Subject: [PATCH 301/544] Stop #define-ining away 'inline' In the long term, we'll transition to C99-style inline semantics. In the short-term, this will allow both styles to coexist without breaking one another. --- include/jemalloc/internal/jemalloc_internal_macros.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/jemalloc/internal/jemalloc_internal_macros.h b/include/jemalloc/internal/jemalloc_internal_macros.h index b70d08a2..35a7a104 100644 --- a/include/jemalloc/internal/jemalloc_internal_macros.h +++ b/include/jemalloc/internal/jemalloc_internal_macros.h @@ -16,7 +16,6 @@ # define JEMALLOC_ALWAYS_INLINE_C static # define JEMALLOC_INLINE # define JEMALLOC_INLINE_C static -# define inline #else # define JEMALLOC_ENABLE_INLINE # ifdef JEMALLOC_HAVE_ATTR -- GitLab From d4ac7582f32f506d5203bea2f0115076202add38 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 25 Jan 2017 09:54:27 -0800 Subject: [PATCH 302/544] Introduce a backport of C11 atomics This introduces a backport of C11 atomics. It has four implementations; ranked in order of preference, they are: - GCC/Clang __atomic builtins - GCC/Clang __sync builtins - MSVC _Interlocked builtins - C11 atomics, from The primary advantages are: - Close adherence to the standard API gives us a defined memory model. - Type safety: atomic objects are now separate types from non-atomic ones, so that it's impossible to mix up atomic and non-atomic updates (which is undefined behavior that compilers are starting to take advantage of). - Efficiency: we can specify ordering for operations, avoiding fences and atomic operations on strongly ordered architectures (example: `atomic_write_u32(ptr, val);` involves a CAS loop, whereas `atomic_store(ptr, val, ATOMIC_RELEASE);` is a plain store. This diff leaves in the current atomics API (implementing them in terms of the backport). This lets us transition uses over piecemeal. Testing: This is by nature hard to test. I've manually tested the first three options on Linux on gcc by futzing with the #defines manually, on freebsd with gcc and clang, on MSVC, and on OS X with clang. All of these were x86 machines though, and we don't have any test infrastructure set up for non-x86 platforms. --- Makefile.in | 1 - configure.ac | 52 +- include/jemalloc/internal/atomic.h | 111 ++++ include/jemalloc/internal/atomic_c11.h | 97 ++++ include/jemalloc/internal/atomic_externs.h | 12 - include/jemalloc/internal/atomic_gcc_atomic.h | 125 +++++ include/jemalloc/internal/atomic_gcc_sync.h | 191 +++++++ include/jemalloc/internal/atomic_inlines.h | 525 ------------------ include/jemalloc/internal/atomic_msvc.h | 158 ++++++ include/jemalloc/internal/atomic_types.h | 8 - .../jemalloc/internal/jemalloc_internal.h.in | 22 +- .../internal/jemalloc_internal_defs.h.in | 13 +- include/jemalloc/internal/private_symbols.txt | 20 - src/atomic.c | 2 - test/unit/atomic.c | 298 +++++++--- 15 files changed, 955 insertions(+), 680 deletions(-) create mode 100644 include/jemalloc/internal/atomic.h create mode 100644 include/jemalloc/internal/atomic_c11.h delete mode 100644 include/jemalloc/internal/atomic_externs.h create mode 100644 include/jemalloc/internal/atomic_gcc_atomic.h create mode 100644 include/jemalloc/internal/atomic_gcc_sync.h delete mode 100644 include/jemalloc/internal/atomic_inlines.h create mode 100644 include/jemalloc/internal/atomic_msvc.h delete mode 100644 include/jemalloc/internal/atomic_types.h delete mode 100644 src/atomic.c diff --git a/Makefile.in b/Makefile.in index 76a73b76..53ebe32e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -90,7 +90,6 @@ BINS := $(objroot)bin/jemalloc-config $(objroot)bin/jemalloc.sh $(objroot)bin/je C_HDRS := $(objroot)include/jemalloc/jemalloc$(install_suffix).h C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/arena.c \ - $(srcroot)src/atomic.c \ $(srcroot)src/base.c \ $(srcroot)src/bitmap.c \ $(srcroot)src/ckh.c \ diff --git a/configure.ac b/configure.ac index 1653fe7f..0095caf1 100644 --- a/configure.ac +++ b/configure.ac @@ -550,7 +550,7 @@ case "${host}" in AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) - AC_DEFINE([JEMALLOC_C11ATOMICS]) + AC_DEFINE([JEMALLOC_C11_ATOMICS]) force_tls="0" default_munmap="0" ;; @@ -1730,36 +1730,44 @@ JE_COMPILABLE([C11 atomics], [ volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; uint64_t r = atomic_fetch_add(a, x) + x; return r == 0; -], [je_cv_c11atomics]) -if test "x${je_cv_c11atomics}" = "xyes" ; then - AC_DEFINE([JEMALLOC_C11ATOMICS]) +], [je_cv_c11_atomics]) +if test "x${je_cv_c11_atomics}" = "xyes" ; then + AC_DEFINE([JEMALLOC_C11_ATOMICS]) fi dnl ============================================================================ -dnl Check for atomic(9) operations as provided on FreeBSD. +dnl Check for GCC-style __atomic atomics. -JE_COMPILABLE([atomic(9)], [ -#include -#include -#include +JE_COMPILABLE([GCC __atomic atomics], [ ], [ - { - uint32_t x32 = 0; - volatile uint32_t *x32p = &x32; - atomic_fetchadd_32(x32p, 1); - } - { - unsigned long xlong = 0; - volatile unsigned long *xlongp = &xlong; - atomic_fetchadd_long(xlongp, 1); - } -], [je_cv_atomic9]) -if test "x${je_cv_atomic9}" = "xyes" ; then - AC_DEFINE([JEMALLOC_ATOMIC9]) + int x = 0; + int val = 1; + int y = __atomic_fetch_add(&x, val, __ATOMIC_RELAXED); + int after_add = x; + return after_add == 1; +], [je_cv_gcc_atomic_atomics]) +if test "x${je_cv_gcc_atomic_atomics}" = "xyes" ; then + AC_DEFINE([JEMALLOC_GCC_ATOMIC_ATOMICS]) +fi + +dnl ============================================================================ +dnl Check for GCC-style __sync atomics. + +JE_COMPILABLE([GCC __sync atomics], [ +], [ + int x = 0; + int before_add = __sync_fetch_and_add(&x, 1); + int after_add = x; + return (before_add == 0) && (after_add == 1); +], [je_cv_gcc_sync_atomics]) +if test "x${je_cv_gcc_sync_atomics}" = "xyes" ; then + AC_DEFINE([JEMALLOC_GCC_SYNC_ATOMICS]) fi dnl ============================================================================ dnl Check for atomic(3) operations as provided on Darwin. +dnl We need this not for the atomic operations (which are provided above), but +dnl rather for the OSSpinLock type it exposes. JE_COMPILABLE([Darwin OSAtomic*()], [ #include diff --git a/include/jemalloc/internal/atomic.h b/include/jemalloc/internal/atomic.h new file mode 100644 index 00000000..84fbbdfb --- /dev/null +++ b/include/jemalloc/internal/atomic.h @@ -0,0 +1,111 @@ +#ifndef JEMALLOC_INTERNAL_ATOMIC_H +#define JEMALLOC_INTERNAL_ATOMIC_H + +#define ATOMIC_INLINE static inline + +#if defined(JEMALLOC_GCC_ATOMIC_ATOMICS) +# include "jemalloc/internal/atomic_gcc_atomic.h" +#elif defined(JEMALLOC_GCC_SYNC_ATOMICS) +# include "jemalloc/internal/atomic_gcc_sync.h" +#elif defined(_MSC_VER) +# include "jemalloc/internal/atomic_msvc.h" +#elif defined(JEMALLOC_C11_ATOMICS) +# include "jemalloc/internal/atomic_c11.h" +#else +# error "Don't have atomics implemented on this platform." +#endif + +/* + * This header gives more or less a backport of C11 atomics. The user can write + * JEMALLOC_GENERATE_ATOMICS(type, short_type, lg_sizeof_type); to generate + * counterparts of the C11 atomic functions for type, as so: + * JEMALLOC_GENERATE_ATOMICS(int *, pi, 3); + * and then write things like: + * int *some_ptr; + * atomic_pi_t atomic_ptr_to_int; + * atomic_store_pi(&atomic_ptr_to_int, some_ptr, ATOMIC_RELAXED); + * int *prev_value = atomic_exchange_pi(&ptr_to_int, NULL, ATOMIC_ACQ_REL); + * assert(some_ptr == prev_value); + * and expect things to work in the obvious way. + * + * Also included (with naming differences to avoid conflicts with the standard + * library): + * atomic_fence(atomic_memory_order_t) (mimics C11's atomic_thread_fence). + * ATOMIC_INIT (mimics C11's ATOMIC_VAR_INIT). + */ + +/* + * Pure convenience, so that we don't have to type "atomic_memory_order_" + * quite so often. + */ +#define ATOMIC_RELAXED atomic_memory_order_relaxed +#define ATOMIC_ACQUIRE atomic_memory_order_acquire, +#define ATOMIC_RELEASE atomic_memory_order_release, +#define ATOMIC_ACQ_REL atomic_memory_order_acq_rel, +#define ATOMIC_SEQ_CST atomic_memory_order_seq_cst + +/* + * In order to let us transition atomics usage piecemeal (and reason locally + * about memory orders), we'll support the previous API for a while. + */ +#define JEMALLOC_GENERATE_COMPATABILITY_ATOMICS(type, short_type) \ +ATOMIC_INLINE type \ +atomic_read_##short_type(type *p) { \ + return atomic_load_##short_type ((atomic_##short_type##_t *)p, \ + ATOMIC_SEQ_CST); \ +} \ + \ +ATOMIC_INLINE void \ +atomic_write_##short_type(type *p, const type val) { \ + atomic_store_##short_type((atomic_##short_type##_t *)p, \ + (type)val, ATOMIC_SEQ_CST); \ +} \ +ATOMIC_INLINE bool \ +atomic_cas_##short_type(type *p, type c, type s) { \ + /* Note the '!' -- atomic_cas inverts the usual semantics. */ \ + return !atomic_compare_exchange_strong_##short_type( \ + (atomic_##short_type##_t *)p, &c, s, ATOMIC_SEQ_CST, \ + ATOMIC_SEQ_CST); \ +} + +#define JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(type, short_type) \ +JEMALLOC_GENERATE_COMPATABILITY_ATOMICS(type, short_type) \ + \ +ATOMIC_INLINE type \ +atomic_add_##short_type(type *p, type x) { \ + return atomic_fetch_add_##short_type( \ + (atomic_##short_type##_t *)p, x, ATOMIC_SEQ_CST) + x; \ +} \ +ATOMIC_INLINE type \ +atomic_sub_##short_type(type *p, type x) { \ + return atomic_fetch_sub_##short_type( \ + (atomic_##short_type##_t *)p, x, ATOMIC_SEQ_CST) - x; \ +} + +JEMALLOC_GENERATE_ATOMICS(void *, p, LG_SIZEOF_PTR) +JEMALLOC_GENERATE_COMPATABILITY_ATOMICS(void *, p) + +/* + * There's no actual guarantee that sizeof(bool) == 1, but it's true on the only + * platform that actually needs to know the size, MSVC. + */ +JEMALLOC_GENERATE_ATOMICS(bool, b, 0) +JEMALLOC_GENERATE_COMPATABILITY_ATOMICS(bool, b) + +JEMALLOC_GENERATE_INT_ATOMICS(unsigned, u, LG_SIZEOF_INT) +JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(unsigned, u) + +JEMALLOC_GENERATE_INT_ATOMICS(size_t, zu, LG_SIZEOF_PTR) +JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(size_t, zu) + +JEMALLOC_GENERATE_INT_ATOMICS(uint32_t, u32, 2) +JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(uint32_t, u32) + +# if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) +JEMALLOC_GENERATE_INT_ATOMICS(uint64_t, u64, 3) +JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(uint64_t, u64) +# endif + +#undef ATOMIC_INLINE + +#endif /* JEMALLOC_INTERNAL_ATOMIC_H */ diff --git a/include/jemalloc/internal/atomic_c11.h b/include/jemalloc/internal/atomic_c11.h new file mode 100644 index 00000000..a5f9313a --- /dev/null +++ b/include/jemalloc/internal/atomic_c11.h @@ -0,0 +1,97 @@ +#ifndef JEMALLOC_INTERNAL_ATOMIC_C11_H +#define JEMALLOC_INTERNAL_ATOMIC_C11_H + +#include + +#define ATOMIC_INIT(...) ATOMIC_VAR_INIT(__VA_ARGS__) + +#define atomic_memory_order_t memory_order +#define atomic_memory_order_relaxed memory_order_relaxed +#define atomic_memory_order_acquire memory_order_acquire +#define atomic_memory_order_release memory_order_release +#define atomic_memory_order_acq_rel memory_order_acq_rel +#define atomic_memory_order_seq_cst memory_order_seq_cst + +#define atomic_fence atomic_thread_fence + +#define JEMALLOC_GENERATE_ATOMICS(type, short_type, \ + /* unused */ lg_size) \ +typedef _Atomic(type) atomic_##short_type##_t; \ + \ +ATOMIC_INLINE type \ +atomic_load_##short_type(const atomic_##short_type##_t *a, \ + atomic_memory_order_t mo) { \ + /* \ + * A strict interpretation of the C standard prevents \ + * atomic_load from taking a const argument, but it's \ + * convenient for our purposes. This cast is a workaround. \ + */ \ + atomic_##short_type##_t* a_nonconst = \ + (atomic_##short_type##_t*)a; \ + return atomic_load_explicit(a_nonconst, mo); \ +} \ + \ +ATOMIC_INLINE void \ +atomic_store_##short_type(atomic_##short_type##_t *a, \ + type val, atomic_memory_order_t mo) { \ + atomic_store_explicit(a, val, mo); \ +} \ + \ +ATOMIC_INLINE type \ +atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + return atomic_exchange_explicit(a, val, mo); \ +} \ + \ +ATOMIC_INLINE bool \ +atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \ + type *expected, type desired, atomic_memory_order_t success_mo, \ + atomic_memory_order_t failure_mo) { \ + return atomic_compare_exchange_weak_explicit(a, expected, \ + desired, success_mo, failure_mo); \ +} \ + \ +ATOMIC_INLINE bool \ +atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \ + type *expected, type desired, atomic_memory_order_t success_mo, \ + atomic_memory_order_t failure_mo) { \ + return atomic_compare_exchange_strong_explicit(a, expected, \ + desired, success_mo, failure_mo); \ +} + +/* + * Integral types have some special operations available that non-integral ones + * lack. + */ +#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, \ + /* unused */ lg_size) \ +JEMALLOC_GENERATE_ATOMICS(type, short_type, /* unused */ lg_size) \ + \ +ATOMIC_INLINE type \ +atomic_fetch_add_##short_type(atomic_##short_type##_t *a, \ + type val, atomic_memory_order_t mo) { \ + return atomic_fetch_add_explicit(a, val, mo); \ +} \ + \ +ATOMIC_INLINE type \ +atomic_fetch_sub_##short_type(atomic_##short_type##_t *a, \ + type val, atomic_memory_order_t mo) { \ + return atomic_fetch_sub_explicit(a, val, mo); \ +} \ +ATOMIC_INLINE type \ +atomic_fetch_and_##short_type(atomic_##short_type##_t *a, \ + type val, atomic_memory_order_t mo) { \ + return atomic_fetch_and_explicit(a, val, mo); \ +} \ +ATOMIC_INLINE type \ +atomic_fetch_or_##short_type(atomic_##short_type##_t *a, \ + type val, atomic_memory_order_t mo) { \ + return atomic_fetch_or_explicit(a, val, mo); \ +} \ +ATOMIC_INLINE type \ +atomic_fetch_xor_##short_type(atomic_##short_type##_t *a, \ + type val, atomic_memory_order_t mo) { \ + return atomic_fetch_xor_explicit(a, val, mo); \ +} + +#endif /* JEMALLOC_INTERNAL_ATOMIC_C11_H */ diff --git a/include/jemalloc/internal/atomic_externs.h b/include/jemalloc/internal/atomic_externs.h deleted file mode 100644 index 09f06408..00000000 --- a/include/jemalloc/internal/atomic_externs.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_ATOMIC_EXTERNS_H -#define JEMALLOC_INTERNAL_ATOMIC_EXTERNS_H - -#if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) -#define atomic_read_u64(p) atomic_add_u64(p, 0) -#endif -#define atomic_read_u32(p) atomic_add_u32(p, 0) -#define atomic_read_p(p) atomic_add_p(p, NULL) -#define atomic_read_zu(p) atomic_add_zu(p, 0) -#define atomic_read_u(p) atomic_add_u(p, 0) - -#endif /* JEMALLOC_INTERNAL_ATOMIC_EXTERNS_H */ diff --git a/include/jemalloc/internal/atomic_gcc_atomic.h b/include/jemalloc/internal/atomic_gcc_atomic.h new file mode 100644 index 00000000..3d13b4a6 --- /dev/null +++ b/include/jemalloc/internal/atomic_gcc_atomic.h @@ -0,0 +1,125 @@ +#ifndef JEMALLOC_INTERNAL_ATOMIC_GCC_ATOMIC_H +#define JEMALLOC_INTERNAL_ATOMIC_GCC_ATOMIC_H + +#define ATOMIC_INIT(...) {__VA_ARGS__} + +typedef enum { + atomic_memory_order_relaxed, + atomic_memory_order_acquire, + atomic_memory_order_release, + atomic_memory_order_acq_rel, + atomic_memory_order_seq_cst +} atomic_memory_order_t; + +ATOMIC_INLINE int +atomic_enum_to_builtin(atomic_memory_order_t mo) { + switch (mo) { + case atomic_memory_order_relaxed: + return __ATOMIC_RELAXED; + case atomic_memory_order_acquire: + return __ATOMIC_ACQUIRE; + case atomic_memory_order_release: + return __ATOMIC_RELEASE; + case atomic_memory_order_acq_rel: + return __ATOMIC_ACQ_REL; + case atomic_memory_order_seq_cst: + return __ATOMIC_SEQ_CST; + } + /* Can't actually happen; the switch is exhaustive. */ + return __ATOMIC_SEQ_CST; +} + +ATOMIC_INLINE void +atomic_fence(atomic_memory_order_t mo) { + __atomic_thread_fence(atomic_enum_to_builtin(mo)); +} + +#define JEMALLOC_GENERATE_ATOMICS(type, short_type, \ + /* unused */ lg_size) \ +typedef struct { \ + type repr; \ +} atomic_##short_type##_t; \ + \ +ATOMIC_INLINE type \ +atomic_load_##short_type(const atomic_##short_type##_t *a, \ + atomic_memory_order_t mo) { \ + type result; \ + __atomic_load(&a->repr, &result, atomic_enum_to_builtin(mo)); \ + return result; \ +} \ + \ +ATOMIC_INLINE void \ +atomic_store_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + __atomic_store(&a->repr, &val, atomic_enum_to_builtin(mo)); \ +} \ + \ +ATOMIC_INLINE type \ +atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + type result; \ + __atomic_exchange(&a->repr, &val, &result, \ + atomic_enum_to_builtin(mo)); \ + return result; \ +} \ + \ +ATOMIC_INLINE bool \ +atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \ + type *expected, type desired, atomic_memory_order_t success_mo, \ + atomic_memory_order_t failure_mo) { \ + return __atomic_compare_exchange(&a->repr, expected, &desired, \ + true, atomic_enum_to_builtin(success_mo), \ + atomic_enum_to_builtin(failure_mo)); \ +} \ + \ +ATOMIC_INLINE bool \ +atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \ + type *expected, type desired, atomic_memory_order_t success_mo, \ + atomic_memory_order_t failure_mo) { \ + return __atomic_compare_exchange(&a->repr, expected, &desired, \ + false, \ + atomic_enum_to_builtin(success_mo), \ + atomic_enum_to_builtin(failure_mo)); \ +} + + +#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, \ + /* unused */ lg_size) \ +JEMALLOC_GENERATE_ATOMICS(type, short_type, /* unused */ lg_size) \ + \ +ATOMIC_INLINE type \ +atomic_fetch_add_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + return __atomic_fetch_add(&a->repr, val, \ + atomic_enum_to_builtin(mo)); \ +} \ + \ +ATOMIC_INLINE type \ +atomic_fetch_sub_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + return __atomic_fetch_sub(&a->repr, val, \ + atomic_enum_to_builtin(mo)); \ +} \ + \ +ATOMIC_INLINE type \ +atomic_fetch_and_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + return __atomic_fetch_and(&a->repr, val, \ + atomic_enum_to_builtin(mo)); \ +} \ + \ +ATOMIC_INLINE type \ +atomic_fetch_or_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + return __atomic_fetch_or(&a->repr, val, \ + atomic_enum_to_builtin(mo)); \ +} \ + \ +ATOMIC_INLINE type \ +atomic_fetch_xor_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + return __atomic_fetch_xor(&a->repr, val, \ + atomic_enum_to_builtin(mo)); \ +} + +#endif /* JEMALLOC_INTERNAL_ATOMIC_GCC_ATOMIC_H */ diff --git a/include/jemalloc/internal/atomic_gcc_sync.h b/include/jemalloc/internal/atomic_gcc_sync.h new file mode 100644 index 00000000..30846e4d --- /dev/null +++ b/include/jemalloc/internal/atomic_gcc_sync.h @@ -0,0 +1,191 @@ +#ifndef JEMALLOC_INTERNAL_ATOMIC_GCC_SYNC_H +#define JEMALLOC_INTERNAL_ATOMIC_GCC_SYNC_H + +#define ATOMIC_INIT(...) {__VA_ARGS__} + +typedef enum { + atomic_memory_order_relaxed, + atomic_memory_order_acquire, + atomic_memory_order_release, + atomic_memory_order_acq_rel, + atomic_memory_order_seq_cst +} atomic_memory_order_t; + +ATOMIC_INLINE void +atomic_fence(atomic_memory_order_t mo) { + /* Easy cases first: no barrier, and full barrier. */ + if (mo == atomic_memory_order_relaxed) { + asm volatile("" ::: "memory"); + return; + } + if (mo == atomic_memory_order_seq_cst) { + asm volatile("" ::: "memory"); + __sync_synchronize(); + asm volatile("" ::: "memory"); + return; + } + asm volatile("" ::: "memory"); +# if defined(__i386__) || defined(__x86_64__) + /* This is implicit on x86. */ +# elif defined(__ppc__) + asm volatile("lwsync"); +# elif defined(__sparc__) && defined(__arch64__) + if (mo == atomic_memory_order_acquire) { + asm volatile("membar #LoadLoad | #LoadStore"); + } else if (mo == atomic_memory_order_release) { + asm volatile("membar #LoadStore | #StoreStore"); + } else { + asm volatile("membar #LoadLoad | #LoadStore | #StoreStore"); + } +# else + __sync_synchronize(); +# endif + asm volatile("" ::: "memory"); +} + +/* + * A correct implementation of seq_cst loads and stores on weakly ordered + * architectures could do either of the following: + * 1. store() is weak-fence -> store -> strong fence, load() is load -> + * strong-fence. + * 2. store() is strong-fence -> store, load() is strong-fence -> load -> + * weak-fence. + * The tricky thing is, load() and store() above can be the load or store + * portions of a gcc __sync builtin, so we have to follow GCC's lead, which + * means going with strategy 2. + * On strongly ordered architectures, the natural strategy is to stick a strong + * fence after seq_cst stores, and have naked loads. So we want the strong + * fences in different places on different architectures. + * atomic_pre_sc_load_fence and atomic_post_sc_store_fence allow us to + * accomplish this. + */ + +ATOMIC_INLINE void +atomic_pre_sc_load_fence() { +# if defined(__i386__) || defined(__x86_64__) || \ + (defined(__sparc__) && defined(__arch64__)) + atomic_fence(atomic_memory_order_relaxed); +# else + atomic_fence(atomic_memory_order_seq_cst); +# endif +} + +ATOMIC_INLINE void +atomic_post_sc_store_fence() { +# if defined(__i386__) || defined(__x86_64__) || \ + (defined(__sparc__) && defined(__arch64__)) + atomic_fence(atomic_memory_order_seq_cst); +# else + atomic_fence(atomic_memory_order_relaxed); +# endif + +} + +#define JEMALLOC_GENERATE_ATOMICS(type, short_type, \ + /* unused */ lg_size) \ +typedef struct { \ + type volatile repr; \ +} atomic_##short_type##_t; \ + \ +ATOMIC_INLINE type \ +atomic_load_##short_type(const atomic_##short_type##_t *a, \ + atomic_memory_order_t mo) { \ + if (mo == atomic_memory_order_seq_cst) { \ + atomic_pre_sc_load_fence(); \ + } \ + type result = a->repr; \ + if (mo != atomic_memory_order_relaxed) { \ + atomic_fence(atomic_memory_order_acquire); \ + } \ + return result; \ +} \ + \ +ATOMIC_INLINE void \ +atomic_store_##short_type(atomic_##short_type##_t *a, \ + type val, atomic_memory_order_t mo) { \ + if (mo != atomic_memory_order_relaxed) { \ + atomic_fence(atomic_memory_order_release); \ + } \ + a->repr = val; \ + if (mo == atomic_memory_order_seq_cst) { \ + atomic_post_sc_store_fence(); \ + } \ +} \ + \ +ATOMIC_INLINE type \ +atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + /* \ + * Because of FreeBSD, we care about gcc 4.2, which doesn't have\ + * an atomic exchange builtin. We fake it with a CAS loop. \ + */ \ + while (true) { \ + type old = a->repr; \ + if (__sync_bool_compare_and_swap(&a->repr, old, val)) { \ + return old; \ + } \ + } \ +} \ + \ +ATOMIC_INLINE bool \ +atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \ + type *expected, type desired, atomic_memory_order_t success_mo, \ + atomic_memory_order_t failure_mo) { \ + type prev = __sync_val_compare_and_swap(&a->repr, *expected, \ + desired); \ + if (prev == *expected) { \ + return true; \ + } else { \ + *expected = prev; \ + return false; \ + } \ +} \ +ATOMIC_INLINE bool \ +atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \ + type *expected, type desired, atomic_memory_order_t success_mo, \ + atomic_memory_order_t failure_mo) { \ + type prev = __sync_val_compare_and_swap(&a->repr, *expected, \ + desired); \ + if (prev == *expected) { \ + return true; \ + } else { \ + *expected = prev; \ + return false; \ + } \ +} + +#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, \ + /* unused */ lg_size) \ +JEMALLOC_GENERATE_ATOMICS(type, short_type, /* unused */ lg_size) \ + \ +ATOMIC_INLINE type \ +atomic_fetch_add_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + return __sync_fetch_and_add(&a->repr, val); \ +} \ + \ +ATOMIC_INLINE type \ +atomic_fetch_sub_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + return __sync_fetch_and_sub(&a->repr, val); \ +} \ + \ +ATOMIC_INLINE type \ +atomic_fetch_and_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + return __sync_fetch_and_and(&a->repr, val); \ +} \ + \ +ATOMIC_INLINE type \ +atomic_fetch_or_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + return __sync_fetch_and_or(&a->repr, val); \ +} \ + \ +ATOMIC_INLINE type \ +atomic_fetch_xor_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + return __sync_fetch_and_xor(&a->repr, val); \ +} + +#endif /* JEMALLOC_INTERNAL_ATOMIC_GCC_SYNC_H */ diff --git a/include/jemalloc/internal/atomic_inlines.h b/include/jemalloc/internal/atomic_inlines.h deleted file mode 100644 index de66d57d..00000000 --- a/include/jemalloc/internal/atomic_inlines.h +++ /dev/null @@ -1,525 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_ATOMIC_INLINES_H -#define JEMALLOC_INTERNAL_ATOMIC_INLINES_H - -/* - * All arithmetic functions return the arithmetic result of the atomic - * operation. Some atomic operation APIs return the value prior to mutation, in - * which case the following functions must redundantly compute the result so - * that it can be returned. These functions are normally inlined, so the extra - * operations can be optimized away if the return values aren't used by the - * callers. - * - * atomic_read_( *p) { return *p; } - * atomic_add_( *p, x) { return *p += x; } - * atomic_sub_( *p, x) { return *p -= x; } - * bool atomic_cas_( *p, c, s) - * { - * if (*p != c) - * return true; - * *p = s; - * return false; - * } - * void atomic_write_( *p, x) { *p = x; } - */ - -#ifndef JEMALLOC_ENABLE_INLINE -# ifdef JEMALLOC_ATOMIC_U64 -uint64_t atomic_add_u64(uint64_t *p, uint64_t x); -uint64_t atomic_sub_u64(uint64_t *p, uint64_t x); -bool atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s); -void atomic_write_u64(uint64_t *p, uint64_t x); -# endif -uint32_t atomic_add_u32(uint32_t *p, uint32_t x); -uint32_t atomic_sub_u32(uint32_t *p, uint32_t x); -bool atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s); -void atomic_write_u32(uint32_t *p, uint32_t x); -void *atomic_add_p(void **p, void *x); -void *atomic_sub_p(void **p, void *x); -bool atomic_cas_p(void **p, void *c, void *s); -void atomic_write_p(void **p, const void *x); -size_t atomic_add_zu(size_t *p, size_t x); -size_t atomic_sub_zu(size_t *p, size_t x); -bool atomic_cas_zu(size_t *p, size_t c, size_t s); -void atomic_write_zu(size_t *p, size_t x); -unsigned atomic_add_u(unsigned *p, unsigned x); -unsigned atomic_sub_u(unsigned *p, unsigned x); -bool atomic_cas_u(unsigned *p, unsigned c, unsigned s); -void atomic_write_u(unsigned *p, unsigned x); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ATOMIC_C_)) -/******************************************************************************/ -/* 64-bit operations. */ -#ifdef JEMALLOC_ATOMIC_U64 -# if (defined(__amd64__) || defined(__x86_64__)) -JEMALLOC_INLINE uint64_t -atomic_add_u64(uint64_t *p, uint64_t x) { - uint64_t t = x; - - asm volatile ( - "lock; xaddq %0, %1;" - : "+r" (t), "=m" (*p) /* Outputs. */ - : "m" (*p) /* Inputs. */ - ); - - return t + x; -} - -JEMALLOC_INLINE uint64_t -atomic_sub_u64(uint64_t *p, uint64_t x) { - uint64_t t; - - x = (uint64_t)(-(int64_t)x); - t = x; - asm volatile ( - "lock; xaddq %0, %1;" - : "+r" (t), "=m" (*p) /* Outputs. */ - : "m" (*p) /* Inputs. */ - ); - - return t + x; -} - -JEMALLOC_INLINE bool -atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { - uint8_t success; - - asm volatile ( - "lock; cmpxchgq %4, %0;" - "sete %1;" - : "=m" (*p), "=a" (success) /* Outputs. */ - : "m" (*p), "a" (c), "r" (s) /* Inputs. */ - : "memory" /* Clobbers. */ - ); - - return !(bool)success; -} - -JEMALLOC_INLINE void -atomic_write_u64(uint64_t *p, uint64_t x) { - asm volatile ( - "xchgq %1, %0;" /* Lock is implied by xchgq. */ - : "=m" (*p), "+r" (x) /* Outputs. */ - : "m" (*p) /* Inputs. */ - : "memory" /* Clobbers. */ - ); -} -# elif (defined(JEMALLOC_C11ATOMICS)) -JEMALLOC_INLINE uint64_t -atomic_add_u64(uint64_t *p, uint64_t x) { - volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; - return atomic_fetch_add(a, x) + x; -} - -JEMALLOC_INLINE uint64_t -atomic_sub_u64(uint64_t *p, uint64_t x) { - volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; - return atomic_fetch_sub(a, x) - x; -} - -JEMALLOC_INLINE bool -atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { - volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; - return !atomic_compare_exchange_strong(a, &c, s); -} - -JEMALLOC_INLINE void -atomic_write_u64(uint64_t *p, uint64_t x) { - volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p; - atomic_store(a, x); -} -# elif (defined(JEMALLOC_ATOMIC9)) -JEMALLOC_INLINE uint64_t -atomic_add_u64(uint64_t *p, uint64_t x) { - /* - * atomic_fetchadd_64() doesn't exist, but we only ever use this - * function on LP64 systems, so atomic_fetchadd_long() will do. - */ - assert(sizeof(uint64_t) == sizeof(unsigned long)); - - return atomic_fetchadd_long(p, (unsigned long)x) + x; -} - -JEMALLOC_INLINE uint64_t -atomic_sub_u64(uint64_t *p, uint64_t x) { - assert(sizeof(uint64_t) == sizeof(unsigned long)); - - return atomic_fetchadd_long(p, (unsigned long)(-(long)x)) - x; -} - -JEMALLOC_INLINE bool -atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { - assert(sizeof(uint64_t) == sizeof(unsigned long)); - - return !atomic_cmpset_long(p, (unsigned long)c, (unsigned long)s); -} - -JEMALLOC_INLINE void -atomic_write_u64(uint64_t *p, uint64_t x) { - assert(sizeof(uint64_t) == sizeof(unsigned long)); - - atomic_store_rel_long(p, x); -} -# elif (defined(JEMALLOC_OSATOMIC)) -JEMALLOC_INLINE uint64_t -atomic_add_u64(uint64_t *p, uint64_t x) { - return OSAtomicAdd64((int64_t)x, (int64_t *)p); -} - -JEMALLOC_INLINE uint64_t -atomic_sub_u64(uint64_t *p, uint64_t x) { - return OSAtomicAdd64(-((int64_t)x), (int64_t *)p); -} - -JEMALLOC_INLINE bool -atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { - return !OSAtomicCompareAndSwap64(c, s, (int64_t *)p); -} - -JEMALLOC_INLINE void -atomic_write_u64(uint64_t *p, uint64_t x) { - uint64_t o; - - /*The documented OSAtomic*() API does not expose an atomic exchange. */ - do { - o = atomic_read_u64(p); - } while (atomic_cas_u64(p, o, x)); -} -# elif (defined(_MSC_VER)) -JEMALLOC_INLINE uint64_t -atomic_add_u64(uint64_t *p, uint64_t x) { - return InterlockedExchangeAdd64(p, x) + x; -} - -JEMALLOC_INLINE uint64_t -atomic_sub_u64(uint64_t *p, uint64_t x) { - return InterlockedExchangeAdd64(p, -((int64_t)x)) - x; -} - -JEMALLOC_INLINE bool -atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { - uint64_t o; - - o = InterlockedCompareExchange64(p, s, c); - return o != c; -} - -JEMALLOC_INLINE void -atomic_write_u64(uint64_t *p, uint64_t x) { - InterlockedExchange64(p, x); -} -# elif (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || \ - defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8)) -JEMALLOC_INLINE uint64_t -atomic_add_u64(uint64_t *p, uint64_t x) { - return __sync_add_and_fetch(p, x); -} - -JEMALLOC_INLINE uint64_t -atomic_sub_u64(uint64_t *p, uint64_t x) { - return __sync_sub_and_fetch(p, x); -} - -JEMALLOC_INLINE bool -atomic_cas_u64(uint64_t *p, uint64_t c, uint64_t s) { - return !__sync_bool_compare_and_swap(p, c, s); -} - -JEMALLOC_INLINE void -atomic_write_u64(uint64_t *p, uint64_t x) { - __sync_lock_test_and_set(p, x); -} -# else -# error "Missing implementation for 64-bit atomic operations" -# endif -#endif - -/******************************************************************************/ -/* 32-bit operations. */ -#if (defined(__i386__) || defined(__amd64__) || defined(__x86_64__)) -JEMALLOC_INLINE uint32_t -atomic_add_u32(uint32_t *p, uint32_t x) { - uint32_t t = x; - - asm volatile ( - "lock; xaddl %0, %1;" - : "+r" (t), "=m" (*p) /* Outputs. */ - : "m" (*p) /* Inputs. */ - ); - - return t + x; -} - -JEMALLOC_INLINE uint32_t -atomic_sub_u32(uint32_t *p, uint32_t x) { - uint32_t t; - - x = (uint32_t)(-(int32_t)x); - t = x; - asm volatile ( - "lock; xaddl %0, %1;" - : "+r" (t), "=m" (*p) /* Outputs. */ - : "m" (*p) /* Inputs. */ - ); - - return t + x; -} - -JEMALLOC_INLINE bool -atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { - uint8_t success; - - asm volatile ( - "lock; cmpxchgl %4, %0;" - "sete %1;" - : "=m" (*p), "=a" (success) /* Outputs. */ - : "m" (*p), "a" (c), "r" (s) /* Inputs. */ - : "memory" - ); - - return !(bool)success; -} - -JEMALLOC_INLINE void -atomic_write_u32(uint32_t *p, uint32_t x) { - asm volatile ( - "xchgl %1, %0;" /* Lock is implied by xchgl. */ - : "=m" (*p), "+r" (x) /* Outputs. */ - : "m" (*p) /* Inputs. */ - : "memory" /* Clobbers. */ - ); -} -# elif (defined(JEMALLOC_C11ATOMICS)) -JEMALLOC_INLINE uint32_t -atomic_add_u32(uint32_t *p, uint32_t x) { - volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; - return atomic_fetch_add(a, x) + x; -} - -JEMALLOC_INLINE uint32_t -atomic_sub_u32(uint32_t *p, uint32_t x) { - volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; - return atomic_fetch_sub(a, x) - x; -} - -JEMALLOC_INLINE bool -atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { - volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; - return !atomic_compare_exchange_strong(a, &c, s); -} - -JEMALLOC_INLINE void -atomic_write_u32(uint32_t *p, uint32_t x) { - volatile atomic_uint_least32_t *a = (volatile atomic_uint_least32_t *)p; - atomic_store(a, x); -} -#elif (defined(JEMALLOC_ATOMIC9)) -JEMALLOC_INLINE uint32_t -atomic_add_u32(uint32_t *p, uint32_t x) { - return atomic_fetchadd_32(p, x) + x; -} - -JEMALLOC_INLINE uint32_t -atomic_sub_u32(uint32_t *p, uint32_t x) { - return atomic_fetchadd_32(p, (uint32_t)(-(int32_t)x)) - x; -} - -JEMALLOC_INLINE bool -atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { - return !atomic_cmpset_32(p, c, s); -} - -JEMALLOC_INLINE void -atomic_write_u32(uint32_t *p, uint32_t x) { - atomic_store_rel_32(p, x); -} -#elif (defined(JEMALLOC_OSATOMIC)) -JEMALLOC_INLINE uint32_t -atomic_add_u32(uint32_t *p, uint32_t x) { - return OSAtomicAdd32((int32_t)x, (int32_t *)p); -} - -JEMALLOC_INLINE uint32_t -atomic_sub_u32(uint32_t *p, uint32_t x) { - return OSAtomicAdd32(-((int32_t)x), (int32_t *)p); -} - -JEMALLOC_INLINE bool -atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { - return !OSAtomicCompareAndSwap32(c, s, (int32_t *)p); -} - -JEMALLOC_INLINE void -atomic_write_u32(uint32_t *p, uint32_t x) { - uint32_t o; - - /*The documented OSAtomic*() API does not expose an atomic exchange. */ - do { - o = atomic_read_u32(p); - } while (atomic_cas_u32(p, o, x)); -} -#elif (defined(_MSC_VER)) -JEMALLOC_INLINE uint32_t -atomic_add_u32(uint32_t *p, uint32_t x) { - return InterlockedExchangeAdd(p, x) + x; -} - -JEMALLOC_INLINE uint32_t -atomic_sub_u32(uint32_t *p, uint32_t x) { - return InterlockedExchangeAdd(p, -((int32_t)x)) - x; -} - -JEMALLOC_INLINE bool -atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { - uint32_t o; - - o = InterlockedCompareExchange(p, s, c); - return o != c; -} - -JEMALLOC_INLINE void -atomic_write_u32(uint32_t *p, uint32_t x) { - InterlockedExchange(p, x); -} -#elif (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || \ - defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4)) -JEMALLOC_INLINE uint32_t -atomic_add_u32(uint32_t *p, uint32_t x) { - return __sync_add_and_fetch(p, x); -} - -JEMALLOC_INLINE uint32_t -atomic_sub_u32(uint32_t *p, uint32_t x) { - return __sync_sub_and_fetch(p, x); -} - -JEMALLOC_INLINE bool -atomic_cas_u32(uint32_t *p, uint32_t c, uint32_t s) { - return !__sync_bool_compare_and_swap(p, c, s); -} - -JEMALLOC_INLINE void -atomic_write_u32(uint32_t *p, uint32_t x) { - __sync_lock_test_and_set(p, x); -} -#else -# error "Missing implementation for 32-bit atomic operations" -#endif - -/******************************************************************************/ -/* Pointer operations. */ -JEMALLOC_INLINE void * -atomic_add_p(void **p, void *x) { -#if (LG_SIZEOF_PTR == 3) - return (void *)atomic_add_u64((uint64_t *)p, (uint64_t)x); -#elif (LG_SIZEOF_PTR == 2) - return (void *)atomic_add_u32((uint32_t *)p, (uint32_t)x); -#endif -} - -JEMALLOC_INLINE void * -atomic_sub_p(void **p, void *x) { -#if (LG_SIZEOF_PTR == 3) - return (void *)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x)); -#elif (LG_SIZEOF_PTR == 2) - return (void *)atomic_add_u32((uint32_t *)p, (uint32_t)-((int32_t)x)); -#endif -} - -JEMALLOC_INLINE bool -atomic_cas_p(void **p, void *c, void *s) { -#if (LG_SIZEOF_PTR == 3) - return atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s); -#elif (LG_SIZEOF_PTR == 2) - return atomic_cas_u32((uint32_t *)p, (uint32_t)c, (uint32_t)s); -#endif -} - -JEMALLOC_INLINE void -atomic_write_p(void **p, const void *x) { -#if (LG_SIZEOF_PTR == 3) - atomic_write_u64((uint64_t *)p, (uint64_t)x); -#elif (LG_SIZEOF_PTR == 2) - atomic_write_u32((uint32_t *)p, (uint32_t)x); -#endif -} - -/******************************************************************************/ -/* size_t operations. */ -JEMALLOC_INLINE size_t -atomic_add_zu(size_t *p, size_t x) { -#if (LG_SIZEOF_PTR == 3) - return (size_t)atomic_add_u64((uint64_t *)p, (uint64_t)x); -#elif (LG_SIZEOF_PTR == 2) - return (size_t)atomic_add_u32((uint32_t *)p, (uint32_t)x); -#endif -} - -JEMALLOC_INLINE size_t -atomic_sub_zu(size_t *p, size_t x) { -#if (LG_SIZEOF_PTR == 3) - return (size_t)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x)); -#elif (LG_SIZEOF_PTR == 2) - return (size_t)atomic_add_u32((uint32_t *)p, (uint32_t)-((int32_t)x)); -#endif -} - -JEMALLOC_INLINE bool -atomic_cas_zu(size_t *p, size_t c, size_t s) { -#if (LG_SIZEOF_PTR == 3) - return atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s); -#elif (LG_SIZEOF_PTR == 2) - return atomic_cas_u32((uint32_t *)p, (uint32_t)c, (uint32_t)s); -#endif -} - -JEMALLOC_INLINE void -atomic_write_zu(size_t *p, size_t x) { -#if (LG_SIZEOF_PTR == 3) - atomic_write_u64((uint64_t *)p, (uint64_t)x); -#elif (LG_SIZEOF_PTR == 2) - atomic_write_u32((uint32_t *)p, (uint32_t)x); -#endif -} - -/******************************************************************************/ -/* unsigned operations. */ -JEMALLOC_INLINE unsigned -atomic_add_u(unsigned *p, unsigned x) { -#if (LG_SIZEOF_INT == 3) - return (unsigned)atomic_add_u64((uint64_t *)p, (uint64_t)x); -#elif (LG_SIZEOF_INT == 2) - return (unsigned)atomic_add_u32((uint32_t *)p, (uint32_t)x); -#endif -} - -JEMALLOC_INLINE unsigned -atomic_sub_u(unsigned *p, unsigned x) { -#if (LG_SIZEOF_INT == 3) - return (unsigned)atomic_add_u64((uint64_t *)p, (uint64_t)-((int64_t)x)); -#elif (LG_SIZEOF_INT == 2) - return (unsigned)atomic_add_u32((uint32_t *)p, (uint32_t)-((int32_t)x)); -#endif -} - -JEMALLOC_INLINE bool -atomic_cas_u(unsigned *p, unsigned c, unsigned s) { -#if (LG_SIZEOF_INT == 3) - return atomic_cas_u64((uint64_t *)p, (uint64_t)c, (uint64_t)s); -#elif (LG_SIZEOF_INT == 2) - return atomic_cas_u32((uint32_t *)p, (uint32_t)c, (uint32_t)s); -#endif -} - -JEMALLOC_INLINE void -atomic_write_u(unsigned *p, unsigned x) { -#if (LG_SIZEOF_INT == 3) - atomic_write_u64((uint64_t *)p, (uint64_t)x); -#elif (LG_SIZEOF_INT == 2) - atomic_write_u32((uint32_t *)p, (uint32_t)x); -#endif -} - -/******************************************************************************/ -#endif -#endif /* JEMALLOC_INTERNAL_ATOMIC_INLINES_H */ diff --git a/include/jemalloc/internal/atomic_msvc.h b/include/jemalloc/internal/atomic_msvc.h new file mode 100644 index 00000000..67057ce5 --- /dev/null +++ b/include/jemalloc/internal/atomic_msvc.h @@ -0,0 +1,158 @@ +#ifndef JEMALLOC_INTERNAL_ATOMIC_MSVC_H +#define JEMALLOC_INTERNAL_ATOMIC_MSVC_H + +#define ATOMIC_INIT(...) {__VA_ARGS__} + +typedef enum { + atomic_memory_order_relaxed, + atomic_memory_order_acquire, + atomic_memory_order_release, + atomic_memory_order_acq_rel, + atomic_memory_order_seq_cst +} atomic_memory_order_t; + +typedef char atomic_repr_0_t; +typedef short atomic_repr_1_t; +typedef long atomic_repr_2_t; +typedef __int64 atomic_repr_3_t; + +ATOMIC_INLINE void +atomic_fence(atomic_memory_order_t mo) { + _ReadWriteBarrier(); +# if defined(_M_ARM) || defined(_M_ARM64) + /* ARM needs a barrier for everything but relaxed. */ + if (mo != atomic_memory_order_relaxed) { + MemoryBarrier(); + } +# elif defined(_M_IX86) || defined (_M_X64) + /* x86 needs a barrier only for seq_cst. */ + if (mo == atomic_memory_order_seq_cst) { + MemoryBarrier(); + } +# else +# error "Don't know how to create atomics for this platform for MSVC." +# endif + _ReadWriteBarrier(); +} + +#define ATOMIC_INTERLOCKED_REPR(lg_size) atomic_repr_ ## lg_size ## _t + +#define ATOMIC_CONCAT(a, b) ATOMIC_RAW_CONCAT(a, b) +#define ATOMIC_RAW_CONCAT(a, b) a ## b + +#define ATOMIC_INTERLOCKED_NAME(base_name, lg_size) ATOMIC_CONCAT( \ + base_name, ATOMIC_INTERLOCKED_SUFFIX(lg_size)) + +#define ATOMIC_INTERLOCKED_SUFFIX(lg_size) \ + ATOMIC_CONCAT(ATOMIC_INTERLOCKED_SUFFIX_, lg_size) + +#define ATOMIC_INTERLOCKED_SUFFIX_0 8 +#define ATOMIC_INTERLOCKED_SUFFIX_1 16 +#define ATOMIC_INTERLOCKED_SUFFIX_2 +#define ATOMIC_INTERLOCKED_SUFFIX_3 64 + +#define JEMALLOC_GENERATE_ATOMICS(type, short_type, lg_size) \ +typedef struct { \ + ATOMIC_INTERLOCKED_REPR(lg_size) repr; \ +} atomic_##short_type##_t; \ + \ +ATOMIC_INLINE type \ +atomic_load_##short_type(const atomic_##short_type##_t *a, \ + atomic_memory_order_t mo) { \ + ATOMIC_INTERLOCKED_REPR(lg_size) ret = a->repr; \ + if (mo != atomic_memory_order_relaxed) { \ + atomic_fence(atomic_memory_order_acquire); \ + } \ + return (type) ret; \ +} \ + \ +ATOMIC_INLINE void \ +atomic_store_##short_type(atomic_##short_type##_t *a, \ + type val, atomic_memory_order_t mo) { \ + if (mo != atomic_memory_order_relaxed) { \ + atomic_fence(atomic_memory_order_release); \ + } \ + a->repr = (ATOMIC_INTERLOCKED_REPR(lg_size)) val; \ + if (mo == atomic_memory_order_seq_cst) { \ + atomic_fence(atomic_memory_order_seq_cst); \ + } \ +} \ + \ +ATOMIC_INLINE type \ +atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \ + atomic_memory_order_t mo) { \ + return (type)ATOMIC_INTERLOCKED_NAME(_InterlockedExchange, \ + lg_size)(&a->repr, (ATOMIC_INTERLOCKED_REPR(lg_size))val); \ +} \ + \ +ATOMIC_INLINE bool \ +atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \ + type *expected, type desired, atomic_memory_order_t success_mo, \ + atomic_memory_order_t failure_mo) { \ + ATOMIC_INTERLOCKED_REPR(lg_size) e = \ + (ATOMIC_INTERLOCKED_REPR(lg_size))*expected; \ + ATOMIC_INTERLOCKED_REPR(lg_size) d = \ + (ATOMIC_INTERLOCKED_REPR(lg_size))desired; \ + ATOMIC_INTERLOCKED_REPR(lg_size) old = \ + ATOMIC_INTERLOCKED_NAME(_InterlockedCompareExchange, \ + lg_size)(&a->repr, d, e); \ + if (old == e) { \ + return true; \ + } else { \ + *expected = (type)old; \ + return false; \ + } \ +} \ + \ +ATOMIC_INLINE bool \ +atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \ + type *expected, type desired, atomic_memory_order_t success_mo, \ + atomic_memory_order_t failure_mo) { \ + /* We implement the weak version with strong semantics. */ \ + return atomic_compare_exchange_weak_##short_type(a, expected, \ + desired, success_mo, failure_mo); \ +} + + +#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, lg_size) \ +JEMALLOC_GENERATE_ATOMICS(type, short_type, lg_size) \ + \ +ATOMIC_INLINE type \ +atomic_fetch_add_##short_type(atomic_##short_type##_t *a, \ + type val, atomic_memory_order_t mo) { \ + return (type)ATOMIC_INTERLOCKED_NAME(_InterlockedExchangeAdd, \ + lg_size)(&a->repr, (ATOMIC_INTERLOCKED_REPR(lg_size))val); \ +} \ + \ +ATOMIC_INLINE type \ +atomic_fetch_sub_##short_type(atomic_##short_type##_t *a, \ + type val, atomic_memory_order_t mo) { \ + /* \ + * MSVC warns on negation of unsigned operands, but for us it \ + * gives exactly the right semantics (MAX_TYPE + 1 - operand). \ + */ \ + __pragma(warning(push)) \ + __pragma(warning(disable: 4146)) \ + return atomic_fetch_add_##short_type(a, -val, mo); \ + __pragma(warning(pop)) \ +} \ +ATOMIC_INLINE type \ +atomic_fetch_and_##short_type(atomic_##short_type##_t *a, \ + type val, atomic_memory_order_t mo) { \ + return (type)ATOMIC_INTERLOCKED_NAME(_InterlockedAnd, lg_size)( \ + &a->repr, (ATOMIC_INTERLOCKED_REPR(lg_size))val); \ +} \ +ATOMIC_INLINE type \ +atomic_fetch_or_##short_type(atomic_##short_type##_t *a, \ + type val, atomic_memory_order_t mo) { \ + return (type)ATOMIC_INTERLOCKED_NAME(_InterlockedOr, lg_size)( \ + &a->repr, (ATOMIC_INTERLOCKED_REPR(lg_size))val); \ +} \ +ATOMIC_INLINE type \ +atomic_fetch_xor_##short_type(atomic_##short_type##_t *a, \ + type val, atomic_memory_order_t mo) { \ + return (type)ATOMIC_INTERLOCKED_NAME(_InterlockedXor, lg_size)( \ + &a->repr, (ATOMIC_INTERLOCKED_REPR(lg_size))val); \ +} + +#endif /* JEMALLOC_INTERNAL_ATOMIC_MSVC_H */ diff --git a/include/jemalloc/internal/atomic_types.h b/include/jemalloc/internal/atomic_types.h deleted file mode 100644 index 0fd5e5b5..00000000 --- a/include/jemalloc/internal/atomic_types.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_ATOMIC_TYPES_H -#define JEMALLOC_INTERNAL_ATOMIC_TYPES_H - -#if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) -# define JEMALLOC_ATOMIC_U64 -#endif - -#endif /* JEMALLOC_INTERNAL_ATOMIC_TYPES_H */ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 0d0440b5..f18acabb 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -146,14 +146,6 @@ static const bool have_thp = #endif ; -#if defined(JEMALLOC_C11ATOMICS) && !defined(__cplusplus) -#include -#endif - -#ifdef JEMALLOC_ATOMIC9 -#include -#endif - #if (defined(JEMALLOC_OSATOMIC) || defined(JEMALLOC_OSSPIN)) #include #endif @@ -199,10 +191,21 @@ static const bool have_thp = * its translation unit). Each component is now broken up into multiple header * files, corresponding to the sections above (e.g. instead of "tsd.h", we now * have "tsd_types.h", "tsd_structs.h", "tsd_externs.h", "tsd_inlines.h"). + * + * Those files which have been converted to explicitly include their + * inter-component dependencies are now in the initial HERMETIC HEADERS + * section. These headers may still rely on this file for system headers and + * global jemalloc headers, however. */ #include "jemalloc/internal/jemalloc_internal_macros.h" +/******************************************************************************/ +/* HERMETIC HEADERS */ +/******************************************************************************/ + +#include "jemalloc/internal/atomic.h" + /******************************************************************************/ /* TYPES */ /******************************************************************************/ @@ -380,7 +383,6 @@ typedef unsigned szind_t; #include "jemalloc/internal/nstime_types.h" #include "jemalloc/internal/util_types.h" -#include "jemalloc/internal/atomic_types.h" #include "jemalloc/internal/spin_types.h" #include "jemalloc/internal/prng_types.h" #include "jemalloc/internal/ticker_types.h" @@ -489,7 +491,6 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/nstime_externs.h" #include "jemalloc/internal/util_externs.h" -#include "jemalloc/internal/atomic_externs.h" #include "jemalloc/internal/ckh_externs.h" #include "jemalloc/internal/stats_externs.h" #include "jemalloc/internal/ctl_externs.h" @@ -513,7 +514,6 @@ void jemalloc_postfork_child(void); /******************************************************************************/ #include "jemalloc/internal/util_inlines.h" -#include "jemalloc/internal/atomic_inlines.h" #include "jemalloc/internal/spin_inlines.h" #include "jemalloc/internal/prng_inlines.h" #include "jemalloc/internal/ticker_inlines.h" diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 6c70e167..b2e0077e 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -30,16 +30,13 @@ #undef LG_VADDR /* Defined if C11 atomics are available. */ -#undef JEMALLOC_C11ATOMICS +#undef JEMALLOC_C11_ATOMICS -/* Defined if the equivalent of FreeBSD's atomic(9) functions are available. */ -#undef JEMALLOC_ATOMIC9 +/* Defined if GCC __atomic atomics are available. */ +#undef JEMALLOC_GCC_ATOMIC_ATOMICS -/* - * Defined if OSAtomic*() functions are available, as provided by Darwin, and - * documented in the atomic(3) manual page. - */ -#undef JEMALLOC_OSATOMIC +/* Defined if GCC __sync atomics are available. */ +#undef JEMALLOC_GCC_SYNC_ATOMICS /* * Defined if __sync_add_and_fetch(uint32_t *, uint32_t) and diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 0234181e..b122dae6 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -72,26 +72,6 @@ arena_tdata_get arena_tdata_get_hard arenas arenas_tdata_cleanup -atomic_add_p -atomic_add_u -atomic_add_u32 -atomic_add_u64 -atomic_add_zu -atomic_cas_p -atomic_cas_u -atomic_cas_u32 -atomic_cas_u64 -atomic_cas_zu -atomic_sub_p -atomic_sub_u -atomic_sub_u32 -atomic_sub_u64 -atomic_sub_zu -atomic_write_p -atomic_write_u -atomic_write_u32 -atomic_write_u64 -atomic_write_zu b0get base_alloc base_boot diff --git a/src/atomic.c b/src/atomic.c deleted file mode 100644 index 9871390d..00000000 --- a/src/atomic.c +++ /dev/null @@ -1,2 +0,0 @@ -#define JEMALLOC_ATOMIC_C_ -#include "jemalloc/internal/jemalloc_internal.h" diff --git a/test/unit/atomic.c b/test/unit/atomic.c index 78661597..237c7474 100644 --- a/test/unit/atomic.c +++ b/test/unit/atomic.c @@ -1,101 +1,257 @@ #include "test/jemalloc_test.h" -#define TEST_STRUCT(p, t) \ -struct p##_test_s { \ - t accum0; \ - t x; \ - t s; \ -}; \ -typedef struct p##_test_s p##_test_t; +/* + * We *almost* have consistent short names (e.g. "u32" for uint32_t, "b" for + * bool, etc. The one exception is that the short name for void * is "p" in + * some places and "ptr" in others. In the long run it would be nice to unify + * these, but in the short run we'll use this shim. + */ +#define assert_p_eq assert_ptr_eq -#define TEST_BODY(p, t, tc, ta, FMT) do { \ - const p##_test_t tests[] = { \ - {(t)-1, (t)-1, (t)-2}, \ - {(t)-1, (t) 0, (t)-2}, \ - {(t)-1, (t) 1, (t)-2}, \ - \ - {(t) 0, (t)-1, (t)-2}, \ - {(t) 0, (t) 0, (t)-2}, \ - {(t) 0, (t) 1, (t)-2}, \ - \ - {(t) 1, (t)-1, (t)-2}, \ - {(t) 1, (t) 0, (t)-2}, \ - {(t) 1, (t) 1, (t)-2}, \ - \ - {(t)0, (t)-(1 << 22), (t)-2}, \ - {(t)0, (t)(1 << 22), (t)-2}, \ - {(t)(1 << 22), (t)-(1 << 22), (t)-2}, \ - {(t)(1 << 22), (t)(1 << 22), (t)-2} \ - }; \ - unsigned i; \ - \ - for (i = 0; i < sizeof(tests)/sizeof(p##_test_t); i++) { \ - bool err; \ - t accum = tests[i].accum0; \ - assert_##ta##_eq(atomic_read_##p(&accum), \ - tests[i].accum0, \ - "Erroneous read, i=%u", i); \ - \ - assert_##ta##_eq(atomic_add_##p(&accum, tests[i].x), \ - (t)((tc)tests[i].accum0 + (tc)tests[i].x), \ - "i=%u, accum=%"FMT", x=%"FMT, \ - i, tests[i].accum0, tests[i].x); \ - assert_##ta##_eq(atomic_read_##p(&accum), accum, \ - "Erroneous add, i=%u", i); \ - \ - accum = tests[i].accum0; \ - assert_##ta##_eq(atomic_sub_##p(&accum, tests[i].x), \ - (t)((tc)tests[i].accum0 - (tc)tests[i].x), \ - "i=%u, accum=%"FMT", x=%"FMT, \ - i, tests[i].accum0, tests[i].x); \ - assert_##ta##_eq(atomic_read_##p(&accum), accum, \ - "Erroneous sub, i=%u", i); \ - \ - accum = tests[i].accum0; \ - err = atomic_cas_##p(&accum, tests[i].x, tests[i].s); \ - assert_b_eq(err, tests[i].accum0 != tests[i].x, \ - "Erroneous cas success/failure result"); \ - assert_##ta##_eq(accum, err ? tests[i].accum0 : \ - tests[i].s, "Erroneous cas effect, i=%u", i); \ - \ - accum = tests[i].accum0; \ - atomic_write_##p(&accum, tests[i].s); \ - assert_##ta##_eq(accum, tests[i].s, \ - "Erroneous write, i=%u", i); \ +/* + * t: the non-atomic type, like "uint32_t". + * ta: the short name for the type, like "u32". + * val[1,2,3]: Values of the given type. The CAS tests use val2 for expected, + * and val3 for desired. + */ + +#define DO_TESTS(t, ta, val1, val2, val3) do { \ + t val; \ + t raw_atomic; \ + t expected; \ + bool success; \ + /* This (along with the load below) also tests ATOMIC_LOAD. */ \ + atomic_##ta##_t atom = ATOMIC_INIT(val1); \ + \ + /* ATOMIC_INIT and load. */ \ + val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \ + assert_##ta##_eq(val1, val, "Load or init failed"); \ + \ + /* Store. */ \ + atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \ + atomic_store_##ta(&atom, val2, ATOMIC_RELAXED); \ + val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \ + assert_##ta##_eq(val2, val, "Store failed"); \ + \ + /* Exchange. */ \ + atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \ + val = atomic_exchange_##ta(&atom, val2, ATOMIC_RELAXED); \ + assert_##ta##_eq(val1, val, "Exchange returned invalid value"); \ + val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \ + assert_##ta##_eq(val2, val, "Exchange store invalid value"); \ + \ + /* \ + * Weak CAS. Spurious failures are allowed, so we loop a few \ + * times. \ + */ \ + atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \ + success = false; \ + for (int i = 0; i < 10 && !success; i++) { \ + expected = val2; \ + success = atomic_compare_exchange_weak_##ta(&atom, \ + &expected, val3, ATOMIC_RELAXED, ATOMIC_RELAXED); \ + assert_##ta##_eq(val1, expected, \ + "CAS should update expected"); \ + } \ + assert_b_eq(val1 == val2, success, \ + "Weak CAS did the wrong state update"); \ + val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \ + if (success) { \ + assert_##ta##_eq(val3, val, \ + "Successful CAS should update atomic"); \ + } else { \ + assert_##ta##_eq(val1, val, \ + "Unsuccessful CAS should not update atomic"); \ + } \ + \ + /* Strong CAS. */ \ + atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \ + expected = val2; \ + success = atomic_compare_exchange_strong_##ta(&atom, &expected, \ + val3, ATOMIC_RELAXED, ATOMIC_RELAXED); \ + assert_b_eq(val1 == val2, success, \ + "Strong CAS did the wrong state update"); \ + val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \ + if (success) { \ + assert_##ta##_eq(val3, val, \ + "Successful CAS should update atomic"); \ + } else { \ + assert_##ta##_eq(val1, val, \ + "Unsuccessful CAS should not update atomic"); \ + } \ + \ + \ + /* Previous atomics API. */ \ + \ + /* Read. */ \ + raw_atomic = val1; \ + val = atomic_read_##ta(&raw_atomic); \ + assert_##ta##_eq(val1, val, "Read failed"); \ + \ + /* Write. */ \ + raw_atomic = val1; \ + atomic_write_##ta(&raw_atomic, val2); \ + assert_##ta##_eq(val2, raw_atomic, "Write failed"); \ + \ + /* CAS. */ \ + raw_atomic = val1; \ + success = !atomic_cas_##ta(&raw_atomic, val2, val3); \ + assert_b_eq(val1 == val2, success, \ + "CAS did the wrong state update"); \ + val = raw_atomic; \ + if (success) { \ + assert_##ta##_eq(val3, val, \ + "Successful CAS should update atomic"); \ + } else { \ + assert_##ta##_eq(val1, val, \ + "Unsuccessful CAS should not update atomic"); \ } \ } while (0) -TEST_STRUCT(u64, uint64_t) +#define DO_INTEGER_TESTS(t, ta, val1, val2) do { \ + atomic_##ta##_t atom; \ + t val; \ + t raw_atomic; \ + \ + /* Fetch-add. */ \ + atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \ + val = atomic_fetch_add_##ta(&atom, val2, ATOMIC_RELAXED); \ + assert_##ta##_eq(val1, val, \ + "Fetch-add should return previous value"); \ + val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \ + assert_##ta##_eq(val1 + val2, val, \ + "Fetch-add should update atomic"); \ + \ + /* Fetch-sub. */ \ + atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \ + val = atomic_fetch_sub_##ta(&atom, val2, ATOMIC_RELAXED); \ + assert_##ta##_eq(val1, val, \ + "Fetch-sub should return previous value"); \ + val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \ + assert_##ta##_eq(val1 - val2, val, \ + "Fetch-sub should update atomic"); \ + \ + /* Fetch-and. */ \ + atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \ + val = atomic_fetch_and_##ta(&atom, val2, ATOMIC_RELAXED); \ + assert_##ta##_eq(val1, val, \ + "Fetch-and should return previous value"); \ + val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \ + assert_##ta##_eq(val1 & val2, val, \ + "Fetch-and should update atomic"); \ + \ + /* Fetch-or. */ \ + atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \ + val = atomic_fetch_or_##ta(&atom, val2, ATOMIC_RELAXED); \ + assert_##ta##_eq(val1, val, \ + "Fetch-or should return previous value"); \ + val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \ + assert_##ta##_eq(val1 | val2, val, \ + "Fetch-or should update atomic"); \ + \ + /* Fetch-xor. */ \ + atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \ + val = atomic_fetch_xor_##ta(&atom, val2, ATOMIC_RELAXED); \ + assert_##ta##_eq(val1, val, \ + "Fetch-xor should return previous value"); \ + val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \ + assert_##ta##_eq(val1 ^ val2, val, \ + "Fetch-xor should update atomic"); \ + \ + /* Previous atomics API. */ \ + \ + /* Add. */ \ + raw_atomic = val1; \ + val = atomic_add_##ta(&raw_atomic, val2); \ + assert_##ta##_eq(val1 + val2, val, \ + "atomic_add should return new value"); \ + assert_##ta##_eq(val1 + val2, raw_atomic, \ + "atomic_add should update atomic"); \ + \ + /* Sub. */ \ + raw_atomic = val1; \ + val = atomic_sub_##ta(&raw_atomic, val2); \ + assert_##ta##_eq(val1 - val2, val, \ + "atomic_sub should return new value"); \ + assert_##ta##_eq(val1 - val2, raw_atomic, \ + "atomic_add should update atomic"); \ +} while (0) + +#define TEST_STRUCT(t, ta) \ +typedef struct { \ + t val1; \ + t val2; \ + t val3; \ +} ta##_test_t; + +#define TEST_CASES(t) { \ + {(t)-1, (t)-1, (t)-2}, \ + {(t)-1, (t) 0, (t)-2}, \ + {(t)-1, (t) 1, (t)-2}, \ + \ + {(t) 0, (t)-1, (t)-2}, \ + {(t) 0, (t) 0, (t)-2}, \ + {(t) 0, (t) 1, (t)-2}, \ + \ + {(t) 1, (t)-1, (t)-2}, \ + {(t) 1, (t) 0, (t)-2}, \ + {(t) 1, (t) 1, (t)-2}, \ + \ + {(t)0, (t)-(1 << 22), (t)-2}, \ + {(t)0, (t)(1 << 22), (t)-2}, \ + {(t)(1 << 22), (t)-(1 << 22), (t)-2}, \ + {(t)(1 << 22), (t)(1 << 22), (t)-2} \ +} + +#define TEST_BODY(t, ta) do { \ + const ta##_test_t tests[] = TEST_CASES(t); \ + for (unsigned i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { \ + ta##_test_t test = tests[i]; \ + DO_TESTS(t, ta, test.val1, test.val2, test.val3); \ + } \ +} while (0) + +#define INTEGER_TEST_BODY(t, ta) do { \ + const ta##_test_t tests[] = TEST_CASES(t); \ + for (unsigned i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { \ + ta##_test_t test = tests[i]; \ + DO_TESTS(t, ta, test.val1, test.val2, test.val3); \ + DO_INTEGER_TESTS(t, ta, test.val1, test.val2); \ + } \ +} while (0) + +TEST_STRUCT(uint64_t, u64); TEST_BEGIN(test_atomic_u64) { #if !(LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) test_skip("64-bit atomic operations not supported"); #else - TEST_BODY(u64, uint64_t, uint64_t, u64, FMTx64); + INTEGER_TEST_BODY(uint64_t, u64); #endif } TEST_END -TEST_STRUCT(u32, uint32_t) + +TEST_STRUCT(uint32_t, u32); TEST_BEGIN(test_atomic_u32) { - TEST_BODY(u32, uint32_t, uint32_t, u32, "#"FMTx32); + INTEGER_TEST_BODY(uint32_t, u32); } TEST_END -TEST_STRUCT(p, void *) +TEST_STRUCT(void *, p); TEST_BEGIN(test_atomic_p) { - TEST_BODY(p, void *, uintptr_t, ptr, "p"); + TEST_BODY(void *, p); } TEST_END -TEST_STRUCT(zu, size_t) +TEST_STRUCT(size_t, zu); TEST_BEGIN(test_atomic_zu) { - TEST_BODY(zu, size_t, size_t, zu, "#zx"); + INTEGER_TEST_BODY(size_t, zu); } TEST_END -TEST_STRUCT(u, unsigned) +TEST_STRUCT(unsigned, u); TEST_BEGIN(test_atomic_u) { - TEST_BODY(u, unsigned, unsigned, u, "#x"); + INTEGER_TEST_BODY(unsigned, u); } TEST_END -- GitLab From 04d8fcb74563a305bdaa8d3ee3ba6ba49d09dfb8 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 3 Mar 2017 20:44:39 -0800 Subject: [PATCH 303/544] Optimize malloc_large_stats_t maintenance. Convert the nrequests field to be partially derived, and the curlextents to be fully derived, in order to reduce the number of stats updates needed during common operations. This change affects ndalloc stats during arena reset, because it is no longer possible to cancel out ndalloc effects (curlextents would become negative). --- include/jemalloc/internal/stats_structs.h | 4 +-- src/arena.c | 35 ++++------------------- 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index 354f93ee..06ba95fc 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -64,10 +64,10 @@ struct malloc_large_stats_s { * This includes requests served by tcache, though tcache only * periodically merges into this counter. */ - uint64_t nrequests; + uint64_t nrequests; /* Partially derived. */ /* Current number of allocations of this size class. */ - size_t curlextents; + size_t curlextents; /* Derived. */ }; /* diff --git a/src/arena.c b/src/arena.c index ecb5cd42..f4450f34 100644 --- a/src/arena.c +++ b/src/arena.c @@ -89,7 +89,7 @@ arena_stats_add_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, uint64_t *p, #endif } -static void +UNUSED static void arena_stats_sub_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, uint64_t *p, uint64_t x) { #ifdef JEMALLOC_ATOMIC_U64 @@ -206,11 +206,12 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, uint64_t nrequests = arena_stats_read_u64(tsdn, &arena->stats, &arena->stats.lstats[i].nrequests); - lstats[i].nrequests += nrequests; - astats->nrequests_large += nrequests; + lstats[i].nrequests += nmalloc + nrequests; + astats->nrequests_large += nmalloc + nrequests; - size_t curlextents = arena_stats_read_zu(tsdn, - &arena->stats, &arena->stats.lstats[i].curlextents); + assert(nmalloc >= ndalloc); + assert(nmalloc - ndalloc <= SIZE_T_MAX); + size_t curlextents = (size_t)(nmalloc - ndalloc); lstats[i].curlextents += curlextents; astats->allocated_large += curlextents * index2size(NBINS + i); } @@ -359,10 +360,6 @@ arena_large_malloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t usize) { arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.lstats[hindex].nmalloc, 1); - arena_stats_add_u64(tsdn, &arena->stats, - &arena->stats.lstats[hindex].nrequests, 1); - arena_stats_add_zu(tsdn, &arena->stats, - &arena->stats.lstats[hindex].curlextents, 1); } static void @@ -379,21 +376,6 @@ arena_large_dalloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t usize) { arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.lstats[hindex].ndalloc, 1); - arena_stats_sub_zu(tsdn, &arena->stats, - &arena->stats.lstats[hindex].curlextents, 1); -} - -static void -arena_large_reset_stats_cancel(tsdn_t *tsdn, arena_t *arena, size_t usize) { - szind_t index = size2index(usize); - szind_t hindex = (index >= NBINS) ? index - NBINS : 0; - - cassert(config_stats); - - arena_stats_lock(tsdn, &arena->stats); - arena_stats_sub_u64(tsdn, &arena->stats, - &arena->stats.lstats[hindex].ndalloc, 1); - arena_stats_unlock(tsdn, &arena->stats); } static void @@ -912,11 +894,6 @@ arena_reset(tsd_t *tsd, arena_t *arena) { } large_dalloc(tsd_tsdn(tsd), extent); malloc_mutex_lock(tsd_tsdn(tsd), &arena->large_mtx); - /* Cancel out unwanted effects on stats. */ - if (config_stats) { - arena_large_reset_stats_cancel(tsd_tsdn(tsd), arena, - usize); - } } malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx); -- GitLab From e9852b577643433a2ecfef1026f1f9498e723654 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Fri, 3 Mar 2017 10:10:08 -0800 Subject: [PATCH 304/544] Disentangle assert and util This is the first header refactoring diff, #533. It splits the assert and util components into separate, hermetic, header files. In the process, it splits out two of the large sub-components of util (the stdio.h replacement, and bit manipulation routines) into their own components (malloc_io.h and bit_util.h). This is mostly to break up cyclic dependencies, but it also breaks off a good chunk of the catch-all-ness of util, which is nice. --- Makefile.in | 8 +- include/jemalloc/internal/assert.h | 12 ++- .../internal/{util_inlines.h => bit_util.h} | 74 ++++----------- .../jemalloc/internal/jemalloc_internal.h.in | 7 +- include/jemalloc/internal/malloc_io.h | 63 ++++++++++++ include/jemalloc/internal/util.h | 71 ++++++++++++++ include/jemalloc/internal/util_externs.h | 23 ----- include/jemalloc/internal/util_types.h | 95 ------------------- src/{util.c => malloc_io.c} | 42 +++++--- test/include/test/jemalloc_test.h.in | 9 +- test/unit/bit_util.c | 55 +++++++++++ test/unit/{util.c => malloc_io.c} | 49 ---------- 12 files changed, 266 insertions(+), 242 deletions(-) rename include/jemalloc/internal/{util_inlines.h => bit_util.h} (67%) create mode 100644 include/jemalloc/internal/malloc_io.h create mode 100644 include/jemalloc/internal/util.h delete mode 100644 include/jemalloc/internal/util_externs.h delete mode 100644 include/jemalloc/internal/util_types.h rename src/{util.c => malloc_io.c} (94%) create mode 100644 test/unit/bit_util.c rename test/unit/{util.c => malloc_io.c} (86%) diff --git a/Makefile.in b/Makefile.in index 53ebe32e..04ce288a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -99,6 +99,7 @@ C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/extent_mmap.c \ $(srcroot)src/hash.c \ $(srcroot)src/large.c \ + $(srcroot)src/malloc_io.c \ $(srcroot)src/mutex.c \ $(srcroot)src/nstime.c \ $(srcroot)src/pages.c \ @@ -110,7 +111,6 @@ C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/tcache.c \ $(srcroot)src/ticker.c \ $(srcroot)src/tsd.c \ - $(srcroot)src/util.c \ $(srcroot)src/witness.c ifeq ($(enable_zone_allocator), 1) C_SRCS += $(srcroot)src/zone.c @@ -147,8 +147,8 @@ ifeq (1, $(link_whole_archive)) C_UTIL_INTEGRATION_SRCS := C_UTIL_CPP_SRCS := else -C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/util.c -C_UTIL_CPP_SRCS := $(srcroot)src/nstime.c $(srcroot)src/util.c +C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/malloc_io.c +C_UTIL_CPP_SRCS := $(srcroot)src/nstime.c $(srcroot)src/malloc_io.c endif TESTS_UNIT := \ $(srcroot)test/unit/a0.c \ @@ -165,6 +165,7 @@ TESTS_UNIT := \ $(srcroot)test/unit/junk_alloc.c \ $(srcroot)test/unit/junk_free.c \ $(srcroot)test/unit/mallctl.c \ + $(srcroot)test/unit/malloc_io.c \ $(srcroot)test/unit/math.c \ $(srcroot)test/unit/mq.c \ $(srcroot)test/unit/mtx.c \ @@ -193,7 +194,6 @@ TESTS_UNIT := \ $(srcroot)test/unit/ticker.c \ $(srcroot)test/unit/nstime.c \ $(srcroot)test/unit/tsd.c \ - $(srcroot)test/unit/util.c \ $(srcroot)test/unit/witness.c \ $(srcroot)test/unit/zero.c ifeq (@enable_prof@, 1) diff --git a/include/jemalloc/internal/assert.h b/include/jemalloc/internal/assert.h index b9ab813e..be4d45b3 100644 --- a/include/jemalloc/internal/assert.h +++ b/include/jemalloc/internal/assert.h @@ -1,3 +1,6 @@ +#include "jemalloc/internal/malloc_io.h" +#include "jemalloc/internal/util.h" + /* * Define a custom assert() in order to reduce the chances of deadlock during * assertion failure. @@ -43,4 +46,11 @@ } while (0) #endif - +/* Use to assert a particular configuration, e.g., cassert(config_debug). */ +#ifndef cassert +#define cassert(c) do { \ + if (unlikely(!(c))) { \ + not_reached(); \ + } \ +} while (0) +#endif diff --git a/include/jemalloc/internal/util_inlines.h b/include/jemalloc/internal/bit_util.h similarity index 67% rename from include/jemalloc/internal/util_inlines.h rename to include/jemalloc/internal/bit_util.h index c09bd6da..8d078a8a 100644 --- a/include/jemalloc/internal/util_inlines.h +++ b/include/jemalloc/internal/bit_util.h @@ -1,22 +1,9 @@ -#ifndef JEMALLOC_INTERNAL_UTIL_INLINES_H -#define JEMALLOC_INTERNAL_UTIL_INLINES_H - -#ifndef JEMALLOC_ENABLE_INLINE -unsigned ffs_llu(unsigned long long bitmap); -unsigned ffs_lu(unsigned long bitmap); -unsigned ffs_u(unsigned bitmap); -unsigned ffs_zu(size_t bitmap); -unsigned ffs_u64(uint64_t bitmap); -unsigned ffs_u32(uint32_t bitmap); -uint64_t pow2_ceil_u64(uint64_t x); -uint32_t pow2_ceil_u32(uint32_t x); -size_t pow2_ceil_zu(size_t x); -unsigned lg_floor(size_t x); -void set_errno(int errnum); -int get_errno(void); -#endif +#ifndef JEMALLOC_INTERNAL_BIT_UTIL_H +#define JEMALLOC_INTERNAL_BIT_UTIL_H + +#include "jemalloc/internal/assert.h" -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_UTIL_C_)) +#define BIT_UTIL_INLINE static inline /* Sanity check. */ #if !defined(JEMALLOC_INTERNAL_FFSLL) || !defined(JEMALLOC_INTERNAL_FFSL) \ @@ -24,22 +11,23 @@ int get_errno(void); # error JEMALLOC_INTERNAL_FFS{,L,LL} should have been defined by configure #endif -JEMALLOC_ALWAYS_INLINE unsigned + +BIT_UTIL_INLINE unsigned ffs_llu(unsigned long long bitmap) { return JEMALLOC_INTERNAL_FFSLL(bitmap); } -JEMALLOC_ALWAYS_INLINE unsigned +BIT_UTIL_INLINE unsigned ffs_lu(unsigned long bitmap) { return JEMALLOC_INTERNAL_FFSL(bitmap); } -JEMALLOC_ALWAYS_INLINE unsigned +BIT_UTIL_INLINE unsigned ffs_u(unsigned bitmap) { return JEMALLOC_INTERNAL_FFS(bitmap); } -JEMALLOC_ALWAYS_INLINE unsigned +BIT_UTIL_INLINE unsigned ffs_zu(size_t bitmap) { #if LG_SIZEOF_PTR == LG_SIZEOF_INT return ffs_u(bitmap); @@ -52,7 +40,7 @@ ffs_zu(size_t bitmap) { #endif } -JEMALLOC_ALWAYS_INLINE unsigned +BIT_UTIL_INLINE unsigned ffs_u64(uint64_t bitmap) { #if LG_SIZEOF_LONG == 3 return ffs_lu(bitmap); @@ -63,7 +51,7 @@ ffs_u64(uint64_t bitmap) { #endif } -JEMALLOC_ALWAYS_INLINE unsigned +BIT_UTIL_INLINE unsigned ffs_u32(uint32_t bitmap) { #if LG_SIZEOF_INT == 2 return ffs_u(bitmap); @@ -73,7 +61,7 @@ ffs_u32(uint32_t bitmap) { return ffs_u(bitmap); } -JEMALLOC_INLINE uint64_t +BIT_UTIL_INLINE uint64_t pow2_ceil_u64(uint64_t x) { x--; x |= x >> 1; @@ -86,7 +74,7 @@ pow2_ceil_u64(uint64_t x) { return x; } -JEMALLOC_INLINE uint32_t +BIT_UTIL_INLINE uint32_t pow2_ceil_u32(uint32_t x) { x--; x |= x >> 1; @@ -99,7 +87,7 @@ pow2_ceil_u32(uint32_t x) { } /* Compute the smallest power of 2 that is >= x. */ -JEMALLOC_INLINE size_t +BIT_UTIL_INLINE size_t pow2_ceil_zu(size_t x) { #if (LG_SIZEOF_PTR == 3) return pow2_ceil_u64(x); @@ -109,10 +97,9 @@ pow2_ceil_zu(size_t x) { } #if (defined(__i386__) || defined(__amd64__) || defined(__x86_64__)) -JEMALLOC_INLINE unsigned +BIT_UTIL_INLINE unsigned lg_floor(size_t x) { size_t ret; - assert(x != 0); asm ("bsr %1, %0" @@ -123,7 +110,7 @@ lg_floor(size_t x) { return (unsigned)ret; } #elif (defined(_MSC_VER)) -JEMALLOC_INLINE unsigned +BIT_UTIL_INLINE unsigned lg_floor(size_t x) { unsigned long ret; @@ -140,7 +127,7 @@ lg_floor(size_t x) { return (unsigned)ret; } #elif (defined(JEMALLOC_HAVE_BUILTIN_CLZ)) -JEMALLOC_INLINE unsigned +BIT_UTIL_INLINE unsigned lg_floor(size_t x) { assert(x != 0); @@ -153,7 +140,7 @@ lg_floor(size_t x) { #endif } #else -JEMALLOC_INLINE unsigned +BIT_UTIL_INLINE unsigned lg_floor(size_t x) { assert(x != 0); @@ -173,25 +160,6 @@ lg_floor(size_t x) { } #endif -/* Set error code. */ -JEMALLOC_INLINE void -set_errno(int errnum) { -#ifdef _WIN32 - SetLastError(errnum); -#else - errno = errnum; -#endif -} - -/* Get last error code. */ -JEMALLOC_INLINE int -get_errno(void) { -#ifdef _WIN32 - return GetLastError(); -#else - return errno; -#endif -} -#endif +#undef BIT_UTIL_INLINE -#endif /* JEMALLOC_INTERNAL_UTIL_INLINES_H */ +#endif /* JEMALLOC_INTERNAL_BIT_UTIL_H */ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index f18acabb..09eda5ec 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -204,7 +204,11 @@ static const bool have_thp = /* HERMETIC HEADERS */ /******************************************************************************/ +#include "jemalloc/internal/assert.h" #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/bit_util.h" +#include "jemalloc/internal/malloc_io.h" +#include "jemalloc/internal/util.h" /******************************************************************************/ /* TYPES */ @@ -382,7 +386,6 @@ typedef unsigned szind_t; #endif #include "jemalloc/internal/nstime_types.h" -#include "jemalloc/internal/util_types.h" #include "jemalloc/internal/spin_types.h" #include "jemalloc/internal/prng_types.h" #include "jemalloc/internal/ticker_types.h" @@ -490,7 +493,6 @@ void jemalloc_postfork_parent(void); void jemalloc_postfork_child(void); #include "jemalloc/internal/nstime_externs.h" -#include "jemalloc/internal/util_externs.h" #include "jemalloc/internal/ckh_externs.h" #include "jemalloc/internal/stats_externs.h" #include "jemalloc/internal/ctl_externs.h" @@ -513,7 +515,6 @@ void jemalloc_postfork_child(void); /* INLINES */ /******************************************************************************/ -#include "jemalloc/internal/util_inlines.h" #include "jemalloc/internal/spin_inlines.h" #include "jemalloc/internal/prng_inlines.h" #include "jemalloc/internal/ticker_inlines.h" diff --git a/include/jemalloc/internal/malloc_io.h b/include/jemalloc/internal/malloc_io.h new file mode 100644 index 00000000..7ff3d5b1 --- /dev/null +++ b/include/jemalloc/internal/malloc_io.h @@ -0,0 +1,63 @@ +#ifndef JEMALLOC_INTERNAL_MALLOC_IO_H +#define JEMALLOC_INTERNAL_MALLOC_IO_H + +#ifdef _WIN32 +# ifdef _WIN64 +# define FMT64_PREFIX "ll" +# define FMTPTR_PREFIX "ll" +# else +# define FMT64_PREFIX "ll" +# define FMTPTR_PREFIX "" +# endif +# define FMTd32 "d" +# define FMTu32 "u" +# define FMTx32 "x" +# define FMTd64 FMT64_PREFIX "d" +# define FMTu64 FMT64_PREFIX "u" +# define FMTx64 FMT64_PREFIX "x" +# define FMTdPTR FMTPTR_PREFIX "d" +# define FMTuPTR FMTPTR_PREFIX "u" +# define FMTxPTR FMTPTR_PREFIX "x" +#else +# include +# define FMTd32 PRId32 +# define FMTu32 PRIu32 +# define FMTx32 PRIx32 +# define FMTd64 PRId64 +# define FMTu64 PRIu64 +# define FMTx64 PRIx64 +# define FMTdPTR PRIdPTR +# define FMTuPTR PRIuPTR +# define FMTxPTR PRIxPTR +#endif + +/* Size of stack-allocated buffer passed to buferror(). */ +#define BUFERROR_BUF 64 + +/* + * Size of stack-allocated buffer used by malloc_{,v,vc}printf(). This must be + * large enough for all possible uses within jemalloc. + */ +#define MALLOC_PRINTF_BUFSIZE 4096 + + +int buferror(int err, char *buf, size_t buflen); +uintmax_t malloc_strtoumax(const char *restrict nptr, char **restrict endptr, + int base); +void malloc_write(const char *s); + +/* + * malloc_vsnprintf() supports a subset of snprintf(3) that avoids floating + * point math. + */ +size_t malloc_vsnprintf(char *str, size_t size, const char *format, + va_list ap); +size_t malloc_snprintf(char *str, size_t size, const char *format, ...) + JEMALLOC_FORMAT_PRINTF(3, 4); +void malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque, + const char *format, va_list ap); +void malloc_cprintf(void (*write)(void *, const char *), void *cbopaque, + const char *format, ...) JEMALLOC_FORMAT_PRINTF(3, 4); +void malloc_printf(const char *format, ...) JEMALLOC_FORMAT_PRINTF(1, 2); + +#endif /* JEMALLOC_INTERNAL_MALLOC_IO_H */ diff --git a/include/jemalloc/internal/util.h b/include/jemalloc/internal/util.h new file mode 100644 index 00000000..88662e89 --- /dev/null +++ b/include/jemalloc/internal/util.h @@ -0,0 +1,71 @@ +#ifndef JEMALLOC_INTERNAL_UTIL_H +#define JEMALLOC_INTERNAL_UTIL_H + +#define UTIL_INLINE static inline + +/* Junk fill patterns. */ +#ifndef JEMALLOC_ALLOC_JUNK +# define JEMALLOC_ALLOC_JUNK ((uint8_t)0xa5) +#endif +#ifndef JEMALLOC_FREE_JUNK +# define JEMALLOC_FREE_JUNK ((uint8_t)0x5a) +#endif + +/* + * Wrap a cpp argument that contains commas such that it isn't broken up into + * multiple arguments. + */ +#define JEMALLOC_ARG_CONCAT(...) __VA_ARGS__ + +/* cpp macro definition stringification. */ +#define STRINGIFY_HELPER(x) #x +#define STRINGIFY(x) STRINGIFY_HELPER(x) + +/* + * Silence compiler warnings due to uninitialized values. This is used + * wherever the compiler fails to recognize that the variable is never used + * uninitialized. + */ +#ifdef JEMALLOC_CC_SILENCE +# define JEMALLOC_CC_SILENCE_INIT(v) = v +#else +# define JEMALLOC_CC_SILENCE_INIT(v) +#endif + +#ifdef __GNUC__ +# define likely(x) __builtin_expect(!!(x), 1) +# define unlikely(x) __builtin_expect(!!(x), 0) +#else +# define likely(x) !!(x) +# define unlikely(x) !!(x) +#endif + +#if !defined(JEMALLOC_INTERNAL_UNREACHABLE) +# error JEMALLOC_INTERNAL_UNREACHABLE should have been defined by configure +#endif + +#define unreachable() JEMALLOC_INTERNAL_UNREACHABLE() + +/* Set error code. */ +UTIL_INLINE void +set_errno(int errnum) { +#ifdef _WIN32 + SetLastError(errnum); +#else + errno = errnum; +#endif +} + +/* Get last error code. */ +UTIL_INLINE int +get_errno(void) { +#ifdef _WIN32 + return GetLastError(); +#else + return errno; +#endif +} + +#undef UTIL_INLINE + +#endif /* JEMALLOC_INTERNAL_UTIL_H */ diff --git a/include/jemalloc/internal/util_externs.h b/include/jemalloc/internal/util_externs.h deleted file mode 100644 index b203b773..00000000 --- a/include/jemalloc/internal/util_externs.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_UTIL_EXTERNS_H -#define JEMALLOC_INTERNAL_UTIL_EXTERNS_H - -int buferror(int err, char *buf, size_t buflen); -uintmax_t malloc_strtoumax(const char *restrict nptr, - char **restrict endptr, int base); -void malloc_write(const char *s); - -/* - * malloc_vsnprintf() supports a subset of snprintf(3) that avoids floating - * point math. - */ -size_t malloc_vsnprintf(char *str, size_t size, const char *format, - va_list ap); -size_t malloc_snprintf(char *str, size_t size, const char *format, ...) - JEMALLOC_FORMAT_PRINTF(3, 4); -void malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque, - const char *format, va_list ap); -void malloc_cprintf(void (*write)(void *, const char *), void *cbopaque, - const char *format, ...) JEMALLOC_FORMAT_PRINTF(3, 4); -void malloc_printf(const char *format, ...) JEMALLOC_FORMAT_PRINTF(1, 2); - -#endif /* JEMALLOC_INTERNAL_UTIL_EXTERNS_H */ diff --git a/include/jemalloc/internal/util_types.h b/include/jemalloc/internal/util_types.h deleted file mode 100644 index e0f79aad..00000000 --- a/include/jemalloc/internal/util_types.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_UTIL_TYPES_H -#define JEMALLOC_INTERNAL_UTIL_TYPES_H - -#ifdef _WIN32 -# ifdef _WIN64 -# define FMT64_PREFIX "ll" -# define FMTPTR_PREFIX "ll" -# else -# define FMT64_PREFIX "ll" -# define FMTPTR_PREFIX "" -# endif -# define FMTd32 "d" -# define FMTu32 "u" -# define FMTx32 "x" -# define FMTd64 FMT64_PREFIX "d" -# define FMTu64 FMT64_PREFIX "u" -# define FMTx64 FMT64_PREFIX "x" -# define FMTdPTR FMTPTR_PREFIX "d" -# define FMTuPTR FMTPTR_PREFIX "u" -# define FMTxPTR FMTPTR_PREFIX "x" -#else -# include -# define FMTd32 PRId32 -# define FMTu32 PRIu32 -# define FMTx32 PRIx32 -# define FMTd64 PRId64 -# define FMTu64 PRIu64 -# define FMTx64 PRIx64 -# define FMTdPTR PRIdPTR -# define FMTuPTR PRIuPTR -# define FMTxPTR PRIxPTR -#endif - -/* Size of stack-allocated buffer passed to buferror(). */ -#define BUFERROR_BUF 64 - -/* - * Size of stack-allocated buffer used by malloc_{,v,vc}printf(). This must be - * large enough for all possible uses within jemalloc. - */ -#define MALLOC_PRINTF_BUFSIZE 4096 - -/* Junk fill patterns. */ -#ifndef JEMALLOC_ALLOC_JUNK -# define JEMALLOC_ALLOC_JUNK ((uint8_t)0xa5) -#endif -#ifndef JEMALLOC_FREE_JUNK -# define JEMALLOC_FREE_JUNK ((uint8_t)0x5a) -#endif - -/* - * Wrap a cpp argument that contains commas such that it isn't broken up into - * multiple arguments. - */ -#define JEMALLOC_ARG_CONCAT(...) __VA_ARGS__ - -/* cpp macro definition stringification. */ -#define STRINGIFY_HELPER(x) #x -#define STRINGIFY(x) STRINGIFY_HELPER(x) - -/* - * Silence compiler warnings due to uninitialized values. This is used - * wherever the compiler fails to recognize that the variable is never used - * uninitialized. - */ -#ifdef JEMALLOC_CC_SILENCE -# define JEMALLOC_CC_SILENCE_INIT(v) = v -#else -# define JEMALLOC_CC_SILENCE_INIT(v) -#endif - -#ifdef __GNUC__ -# define likely(x) __builtin_expect(!!(x), 1) -# define unlikely(x) __builtin_expect(!!(x), 0) -#else -# define likely(x) !!(x) -# define unlikely(x) !!(x) -#endif - -#if !defined(JEMALLOC_INTERNAL_UNREACHABLE) -# error JEMALLOC_INTERNAL_UNREACHABLE should have been defined by configure -#endif - -#define unreachable() JEMALLOC_INTERNAL_UNREACHABLE() - -#include "jemalloc/internal/assert.h" - -/* Use to assert a particular configuration, e.g., cassert(config_debug). */ -#define cassert(c) do { \ - if (unlikely(!(c))) { \ - not_reached(); \ - } \ -} while (0) - -#endif /* JEMALLOC_INTERNAL_UTIL_TYPES_H */ diff --git a/src/util.c b/src/malloc_io.c similarity index 94% rename from src/util.c rename to src/malloc_io.c index ee5fa47e..fd6ff0f0 100644 --- a/src/util.c +++ b/src/malloc_io.c @@ -1,3 +1,19 @@ +#define JEMALLOC_MALLOC_IO_C_ +#include "jemalloc/internal/jemalloc_internal.h" + +#ifdef assert +# undef assert +#endif +#ifdef not_reached +# undef not_reached +#endif +#ifdef not_implemented +# undef not_implemented +#endif +#ifdef assert_not_implemented +# undef assert_not_implemented +#endif + /* * Define simple versions of assertion macros that won't recurse in case * of assertion failures in malloc_*printf(). @@ -24,22 +40,25 @@ } \ } while (0) -#define JEMALLOC_UTIL_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#define assert_not_implemented(e) do { \ + if (unlikely(config_debug && !(e))) { \ + not_implemented(); \ + } \ +} while (0) /******************************************************************************/ /* Function prototypes for non-inline static functions. */ -static void wrtmessage(void *cbopaque, const char *s); -#define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1) -static char *u2s(uintmax_t x, unsigned base, bool uppercase, char *s, +static void wrtmessage(void *cbopaque, const char *s); +#define U2S_BUFSIZE ((1U << (LG_SIZEOF_INTMAX_T + 3)) + 1) +static char *u2s(uintmax_t x, unsigned base, bool uppercase, char *s, size_t *slen_p); -#define D2S_BUFSIZE (1 + U2S_BUFSIZE) -static char *d2s(intmax_t x, char sign, char *s, size_t *slen_p); -#define O2S_BUFSIZE (1 + U2S_BUFSIZE) -static char *o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p); -#define X2S_BUFSIZE (2 + U2S_BUFSIZE) -static char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, +#define D2S_BUFSIZE (1 + U2S_BUFSIZE) +static char *d2s(intmax_t x, char sign, char *s, size_t *slen_p); +#define O2S_BUFSIZE (1 + U2S_BUFSIZE) +static char *o2s(uintmax_t x, bool alt_form, char *s, size_t *slen_p); +#define X2S_BUFSIZE (2 + U2S_BUFSIZE) +static char *x2s(uintmax_t x, bool alt_form, bool uppercase, char *s, size_t *slen_p); /******************************************************************************/ @@ -662,4 +681,5 @@ malloc_printf(const char *format, ...) { #undef assert #undef not_reached #undef not_implemented +#undef assert_not_implemented #include "jemalloc/internal/assert.h" diff --git a/test/include/test/jemalloc_test.h.in b/test/include/test/jemalloc_test.h.in index 36d59cff..0770d020 100644 --- a/test/include/test/jemalloc_test.h.in +++ b/test/include/test/jemalloc_test.h.in @@ -69,12 +69,15 @@ static const bool config_debug = # define JEMALLOC_N(n) @private_namespace@##n # include "jemalloc/internal/private_namespace.h" +/* Hermetic headers. */ +# include "jemalloc/internal/assert.h" +# include "jemalloc/internal/malloc_io.h" +# include "jemalloc/internal/util.h" + +/* Non-hermetic headers. */ # include "jemalloc/internal/nstime_types.h" # include "jemalloc/internal/nstime_structs.h" # include "jemalloc/internal/nstime_externs.h" -# include "jemalloc/internal/util_types.h" -# include "jemalloc/internal/util_externs.h" -# include "jemalloc/internal/util_inlines.h" # include "jemalloc/internal/qr.h" # include "jemalloc/internal/ql.h" diff --git a/test/unit/bit_util.c b/test/unit/bit_util.c new file mode 100644 index 00000000..fe5c4473 --- /dev/null +++ b/test/unit/bit_util.c @@ -0,0 +1,55 @@ +#include "test/jemalloc_test.h" + +#define TEST_POW2_CEIL(t, suf, pri) do { \ + unsigned i, pow2; \ + t x; \ + \ + assert_##suf##_eq(pow2_ceil_##suf(0), 0, "Unexpected result"); \ + \ + for (i = 0; i < sizeof(t) * 8; i++) { \ + assert_##suf##_eq(pow2_ceil_##suf(((t)1) << i), ((t)1) \ + << i, "Unexpected result"); \ + } \ + \ + for (i = 2; i < sizeof(t) * 8; i++) { \ + assert_##suf##_eq(pow2_ceil_##suf((((t)1) << i) - 1), \ + ((t)1) << i, "Unexpected result"); \ + } \ + \ + for (i = 0; i < sizeof(t) * 8 - 1; i++) { \ + assert_##suf##_eq(pow2_ceil_##suf((((t)1) << i) + 1), \ + ((t)1) << (i+1), "Unexpected result"); \ + } \ + \ + for (pow2 = 1; pow2 < 25; pow2++) { \ + for (x = (((t)1) << (pow2-1)) + 1; x <= ((t)1) << pow2; \ + x++) { \ + assert_##suf##_eq(pow2_ceil_##suf(x), \ + ((t)1) << pow2, \ + "Unexpected result, x=%"pri, x); \ + } \ + } \ +} while (0) + +TEST_BEGIN(test_pow2_ceil_u64) { + TEST_POW2_CEIL(uint64_t, u64, FMTu64); +} +TEST_END + +TEST_BEGIN(test_pow2_ceil_u32) { + TEST_POW2_CEIL(uint32_t, u32, FMTu32); +} +TEST_END + +TEST_BEGIN(test_pow2_ceil_zu) { + TEST_POW2_CEIL(size_t, zu, "zu"); +} +TEST_END + +int +main(void) { + return test( + test_pow2_ceil_u64, + test_pow2_ceil_u32, + test_pow2_ceil_zu); +} diff --git a/test/unit/util.c b/test/unit/malloc_io.c similarity index 86% rename from test/unit/util.c rename to test/unit/malloc_io.c index 5760966f..79ba7fc5 100644 --- a/test/unit/util.c +++ b/test/unit/malloc_io.c @@ -1,51 +1,5 @@ #include "test/jemalloc_test.h" -#define TEST_POW2_CEIL(t, suf, pri) do { \ - unsigned i, pow2; \ - t x; \ - \ - assert_##suf##_eq(pow2_ceil_##suf(0), 0, "Unexpected result"); \ - \ - for (i = 0; i < sizeof(t) * 8; i++) { \ - assert_##suf##_eq(pow2_ceil_##suf(((t)1) << i), ((t)1) \ - << i, "Unexpected result"); \ - } \ - \ - for (i = 2; i < sizeof(t) * 8; i++) { \ - assert_##suf##_eq(pow2_ceil_##suf((((t)1) << i) - 1), \ - ((t)1) << i, "Unexpected result"); \ - } \ - \ - for (i = 0; i < sizeof(t) * 8 - 1; i++) { \ - assert_##suf##_eq(pow2_ceil_##suf((((t)1) << i) + 1), \ - ((t)1) << (i+1), "Unexpected result"); \ - } \ - \ - for (pow2 = 1; pow2 < 25; pow2++) { \ - for (x = (((t)1) << (pow2-1)) + 1; x <= ((t)1) << pow2; \ - x++) { \ - assert_##suf##_eq(pow2_ceil_##suf(x), \ - ((t)1) << pow2, \ - "Unexpected result, x=%"pri, x); \ - } \ - } \ -} while (0) - -TEST_BEGIN(test_pow2_ceil_u64) { - TEST_POW2_CEIL(uint64_t, u64, FMTu64); -} -TEST_END - -TEST_BEGIN(test_pow2_ceil_u32) { - TEST_POW2_CEIL(uint32_t, u32, FMTu32); -} -TEST_END - -TEST_BEGIN(test_pow2_ceil_zu) { - TEST_POW2_CEIL(size_t, zu, "zu"); -} -TEST_END - TEST_BEGIN(test_malloc_strtoumax_no_endptr) { int err; @@ -297,9 +251,6 @@ TEST_END int main(void) { return test( - test_pow2_ceil_u64, - test_pow2_ceil_u32, - test_pow2_ceil_zu, test_malloc_strtoumax_no_endptr, test_malloc_strtoumax, test_malloc_snprintf_truncated, -- GitLab From 84326c566af7d20662ee927c2daef0f63ccd3841 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Fri, 3 Mar 2017 16:43:47 -0800 Subject: [PATCH 305/544] Insert not_reached after an exhaustive switch In the C11 atomics backport, we couldn't use not_reached() in atomic_enum_to_builtin (in atomic_gcc_atomic.h), since atomic.h was hermetic and assert.h wasn't; there was a dependency issue. assert.h is hermetic now, so we can include it. --- include/jemalloc/internal/atomic_gcc_atomic.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/jemalloc/internal/atomic_gcc_atomic.h b/include/jemalloc/internal/atomic_gcc_atomic.h index 3d13b4a6..6b73a14f 100644 --- a/include/jemalloc/internal/atomic_gcc_atomic.h +++ b/include/jemalloc/internal/atomic_gcc_atomic.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_ATOMIC_GCC_ATOMIC_H #define JEMALLOC_INTERNAL_ATOMIC_GCC_ATOMIC_H +#include "jemalloc/internal/assert.h" + #define ATOMIC_INIT(...) {__VA_ARGS__} typedef enum { @@ -25,8 +27,8 @@ atomic_enum_to_builtin(atomic_memory_order_t mo) { case atomic_memory_order_seq_cst: return __ATOMIC_SEQ_CST; } - /* Can't actually happen; the switch is exhaustive. */ - return __ATOMIC_SEQ_CST; + /* Can't happen; the switch is exhaustive. */ + not_reached(); } ATOMIC_INLINE void -- GitLab From 424e3428b16eef4614bf6786611e35e30983d23f Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 6 Mar 2017 11:40:29 -0800 Subject: [PATCH 306/544] Make type abbreviations consistent: ssize_t is zd everywhere --- include/jemalloc/internal/jemalloc_internal.h.in | 4 ++-- include/jemalloc/internal/jemalloc_internal_macros.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 09eda5ec..8d2ec7dd 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -565,7 +565,7 @@ psz2ind(size_t psz) { pszind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1; - size_t delta_inverse_mask = ZI(-1) << lg_delta; + size_t delta_inverse_mask = ZD(-1) << lg_delta; pszind_t mod = ((((psz-1) & delta_inverse_mask) >> lg_delta)) & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); @@ -646,7 +646,7 @@ size2index_compute(size_t size) { szind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; - size_t delta_inverse_mask = ZI(-1) << lg_delta; + size_t delta_inverse_mask = ZD(-1) << lg_delta; szind_t mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); diff --git a/include/jemalloc/internal/jemalloc_internal_macros.h b/include/jemalloc/internal/jemalloc_internal_macros.h index 35a7a104..c5dd9b39 100644 --- a/include/jemalloc/internal/jemalloc_internal_macros.h +++ b/include/jemalloc/internal/jemalloc_internal_macros.h @@ -41,14 +41,14 @@ #endif #define ZU(z) ((size_t)z) -#define ZI(z) ((ssize_t)z) +#define ZD(z) ((ssize_t)z) #define QU(q) ((uint64_t)q) -#define QI(q) ((int64_t)q) +#define QD(q) ((int64_t)q) #define KZU(z) ZU(z##ULL) -#define KZI(z) ZI(z##LL) +#define KZD(z) ZD(z##LL) #define KQU(q) QU(q##ULL) -#define KQI(q) QI(q##LL) +#define KQD(q) QI(q##LL) #ifndef __DECONST # define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) -- GitLab From 438efede7838a04af041ae97d34208b71033fd32 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 6 Mar 2017 11:40:58 -0800 Subject: [PATCH 307/544] Add atomic types for ssize_t --- include/jemalloc/internal/atomic.h | 3 +++ test/unit/atomic.c | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/include/jemalloc/internal/atomic.h b/include/jemalloc/internal/atomic.h index 84fbbdfb..866adff0 100644 --- a/include/jemalloc/internal/atomic.h +++ b/include/jemalloc/internal/atomic.h @@ -98,6 +98,9 @@ JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(unsigned, u) JEMALLOC_GENERATE_INT_ATOMICS(size_t, zu, LG_SIZEOF_PTR) JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(size_t, zu) +JEMALLOC_GENERATE_INT_ATOMICS(ssize_t, zd, LG_SIZEOF_PTR) +JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(ssize_t, zd) + JEMALLOC_GENERATE_INT_ATOMICS(uint32_t, u32, 2) JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(uint32_t, u32) diff --git a/test/unit/atomic.c b/test/unit/atomic.c index 237c7474..fa24415a 100644 --- a/test/unit/atomic.c +++ b/test/unit/atomic.c @@ -249,6 +249,13 @@ TEST_BEGIN(test_atomic_zu) { } TEST_END +TEST_STRUCT(ssize_t, zd); +TEST_BEGIN(test_atomic_zd) { + INTEGER_TEST_BODY(ssize_t, zd); +} +TEST_END + + TEST_STRUCT(unsigned, u); TEST_BEGIN(test_atomic_u) { INTEGER_TEST_BODY(unsigned, u); @@ -262,5 +269,6 @@ main(void) { test_atomic_u32, test_atomic_p, test_atomic_zu, + test_atomic_zd, test_atomic_u); } -- GitLab From 4f1e94658a7efd748f10bdb9de778c835e74e539 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 6 Mar 2017 11:41:29 -0800 Subject: [PATCH 308/544] Change arena to use the atomic functions for ssize_t instead of the union strategy --- include/jemalloc/internal/arena_structs_b.h | 7 +------ src/arena.c | 8 ++------ 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 49fdd17d..ebcdbc4d 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -36,11 +36,6 @@ struct arena_bin_info_s { bitmap_info_t bitmap_info; }; -typedef union { - size_t u; /* Used for atomic operations. */ - ssize_t s; /* Time may be negative (means "never"). */ -} arena_decay_time_t; - struct arena_decay_s { /* Synchronizes all non-atomic fields. */ malloc_mutex_t mtx; @@ -51,7 +46,7 @@ struct arena_decay_s { * * Synchronization: atomic. */ - arena_decay_time_t time; + ssize_t time; /* time / SMOOTHSTEP_NSTEPS. */ nstime_t interval; /* diff --git a/src/arena.c b/src/arena.c index f4450f34..56ab362d 100644 --- a/src/arena.c +++ b/src/arena.c @@ -470,16 +470,12 @@ arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, static ssize_t arena_decay_time_read(arena_t *arena) { - arena_decay_time_t dt; - dt.u = atomic_read_zu(&arena->decay.time.u); - return dt.s; + return atomic_read_zd(&arena->decay.time); } static void arena_decay_time_write(arena_t *arena, ssize_t decay_time) { - arena_decay_time_t dt; - dt.s = decay_time; - atomic_write_zu(&arena->decay.time.u, dt.u); + atomic_write_zd(&arena->decay.time, decay_time); } static void -- GitLab From 8547ee11c38738f12cf9437e773edeb4c533fddc Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 2 Mar 2017 23:32:42 -0800 Subject: [PATCH 309/544] Fix flakiness in test_decay_ticker. Fix the test_decay_ticker test to carefully control slab creation/destruction such that the decay backlog reliably reaches zero. Use an isolated arena so that no extraneous allocation can confuse the situation. Speed up time during the latter part of the test so that the entire decay time can expire in a reasonable amount of wall time. --- test/unit/decay.c | 254 +++++++++++++++++++++++++++------------------- 1 file changed, 148 insertions(+), 106 deletions(-) diff --git a/test/unit/decay.c b/test/unit/decay.c index 2513dbd4..df910aac 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -21,6 +21,106 @@ nstime_update_mock(nstime_t *time) { return !monotonic_mock; } +static unsigned +do_arena_create(ssize_t decay_time) { + unsigned arena_ind; + size_t sz = sizeof(unsigned); + assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), + 0, "Unexpected mallctl() failure"); + size_t mib[3]; + size_t miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("arena.0.decay_time", mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + mib[1] = (size_t)arena_ind; + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&decay_time, + sizeof(decay_time)), 0, "Unexpected mallctlbymib() failure"); + return arena_ind; +} + +static void +do_arena_destroy(unsigned arena_ind) { + size_t mib[3]; + size_t miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("arena.0.destroy", mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + mib[1] = (size_t)arena_ind; + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, + "Unexpected mallctlbymib() failure"); +} + +void +do_epoch(void) { + uint64_t epoch = 1; + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), + 0, "Unexpected mallctl() failure"); +} + +void +do_purge(unsigned arena_ind) { + size_t mib[3]; + size_t miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("arena.0.purge", mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + mib[1] = (size_t)arena_ind; + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, + "Unexpected mallctlbymib() failure"); +} + +void +do_decay(unsigned arena_ind) { + size_t mib[3]; + size_t miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("arena.0.decay", mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + mib[1] = (size_t)arena_ind; + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, + "Unexpected mallctlbymib() failure"); +} + +static uint64_t +get_arena_npurge(unsigned arena_ind) { + do_epoch(); + size_t mib[4]; + size_t miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("stats.arenas.0.npurge", mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + mib[2] = (size_t)arena_ind; + uint64_t npurge = 0; + size_t sz = sizeof(npurge); + assert_d_eq(mallctlbymib(mib, miblen, (void *)&npurge, &sz, NULL, 0), + config_stats ? 0 : ENOENT, "Unexpected mallctlbymib() failure"); + return npurge; +} + +static size_t +get_arena_pdirty(unsigned arena_ind) { + do_epoch(); + size_t mib[4]; + size_t miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("stats.arenas.0.pdirty", mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + mib[2] = (size_t)arena_ind; + size_t pdirty; + size_t sz = sizeof(pdirty); + assert_d_eq(mallctlbymib(mib, miblen, (void *)&pdirty, &sz, NULL, 0), 0, + "Unexpected mallctlbymib() failure"); + return pdirty; +} + +static void * +do_mallocx(size_t size, int flags) { + void *p = mallocx(size, flags); + assert_ptr_not_null(p, "Unexpected mallocx() failure"); + return p; +} + +static void +generate_dirty(unsigned arena_ind, size_t size) { + int flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; + void *p = do_mallocx(size, flags); + dallocx(p, flags); +} + TEST_BEGIN(test_decay_ticks) { ticker_t *decay_ticker; unsigned tick0, tick1; @@ -195,45 +295,37 @@ TEST_END TEST_BEGIN(test_decay_ticker) { #define NPS 1024 - int flags = (MALLOCX_ARENA(0) | MALLOCX_TCACHE_NONE); +#define NINTERVALS 101 + ssize_t dt = opt_decay_time; + unsigned arena_ind = do_arena_create(dt); + int flags = (MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE); void *ps[NPS]; - uint64_t epoch; - uint64_t npurge0 = 0; - uint64_t npurge1 = 0; - size_t sz, large; - unsigned i, nupdates0; - nstime_t time, decay_time, deadline; + size_t large; /* * Allocate a bunch of large objects, pause the clock, deallocate the - * objects, restore the clock, then [md]allocx() in a tight loop to - * verify the ticker triggers purging. + * objects, restore the clock, then [md]allocx() in a tight loop while + * advancing time rapidly to verify the ticker triggers purging. */ if (config_tcache) { size_t tcache_max; - sz = sizeof(size_t); + size_t sz = sizeof(size_t); assert_d_eq(mallctl("arenas.tcache_max", (void *)&tcache_max, &sz, NULL, 0), 0, "Unexpected mallctl failure"); large = nallocx(tcache_max + 1, flags); } else { - sz = sizeof(size_t); + size_t sz = sizeof(size_t); assert_d_eq(mallctl("arenas.lextent.0.size", &large, &sz, NULL, 0), 0, "Unexpected mallctl failure"); } - assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, - "Unexpected mallctl failure"); - assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, - sizeof(uint64_t)), 0, "Unexpected mallctl failure"); - sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge0, &sz, - NULL, 0), config_stats ? 0 : ENOENT, "Unexpected mallctl result"); + do_purge(arena_ind); + uint64_t npurge0 = get_arena_npurge(arena_ind); - for (i = 0; i < NPS; i++) { - ps[i] = mallocx(large, flags); - assert_ptr_not_null(ps[i], "Unexpected mallocx() failure"); + for (unsigned i = 0; i < NPS; i++) { + ps[i] = do_mallocx(large, flags); } nupdates_mock = 0; @@ -246,43 +338,59 @@ TEST_BEGIN(test_decay_ticker) { nstime_monotonic = nstime_monotonic_mock; nstime_update = nstime_update_mock; - for (i = 0; i < NPS; i++) { + for (unsigned i = 0; i < NPS; i++) { dallocx(ps[i], flags); - nupdates0 = nupdates_mock; - assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0, - "Unexpected arena.0.decay failure"); + unsigned nupdates0 = nupdates_mock; + do_decay(arena_ind); assert_u_gt(nupdates_mock, nupdates0, "Expected nstime_update() to be called"); } - nstime_monotonic = nstime_monotonic_orig; - nstime_update = nstime_update_orig; + nstime_t time, update_interval, decay_time, deadline; nstime_init(&time, 0); nstime_update(&time); - nstime_init2(&decay_time, opt_decay_time, 0); + + nstime_init2(&decay_time, dt, 0); + nstime_copy(&deadline, &time); + nstime_add(&deadline, &decay_time); + + nstime_init2(&update_interval, dt, 0); + nstime_idivide(&update_interval, NINTERVALS); + + nstime_init2(&decay_time, dt, 0); nstime_copy(&deadline, &time); nstime_add(&deadline, &decay_time); + + /* + * Keep q's slab from being deallocated during the looping below. If + * a cached slab were to repeatedly come and go during looping, it could + * prevent the decay backlog ever becoming empty. + */ + void *p = do_mallocx(1, flags); + uint64_t npurge1; do { - for (i = 0; i < DECAY_NTICKS_PER_UPDATE / 2; i++) { - void *p = mallocx(1, flags); - assert_ptr_not_null(p, "Unexpected mallocx() failure"); - dallocx(p, flags); + for (unsigned i = 0; i < DECAY_NTICKS_PER_UPDATE / 2; i++) { + void *q = do_mallocx(1, flags); + dallocx(q, flags); } - assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, - sizeof(uint64_t)), 0, "Unexpected mallctl failure"); - sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge1, - &sz, NULL, 0), config_stats ? 0 : ENOENT, - "Unexpected mallctl result"); + npurge1 = get_arena_npurge(arena_ind); + nstime_add(&time_mock, &update_interval); nstime_update(&time); } while (nstime_compare(&time, &deadline) <= 0 && npurge1 == npurge0); + dallocx(p, flags); + + nstime_monotonic = nstime_monotonic_orig; + nstime_update = nstime_update_orig; if (config_stats) { assert_u64_gt(npurge1, npurge0, "Expected purging to occur"); } + + do_arena_destroy(arena_ind); #undef NPS +#undef NINTERVALS } TEST_END @@ -290,7 +398,6 @@ TEST_BEGIN(test_decay_nonmonotonic) { #define NPS (SMOOTHSTEP_NSTEPS + 1) int flags = (MALLOCX_ARENA(0) | MALLOCX_TCACHE_NONE); void *ps[NPS]; - uint64_t epoch; uint64_t npurge0 = 0; uint64_t npurge1 = 0; size_t sz, large0; @@ -302,8 +409,7 @@ TEST_BEGIN(test_decay_nonmonotonic) { assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl failure"); - assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, - sizeof(uint64_t)), 0, "Unexpected mallctl failure"); + do_epoch(); sz = sizeof(uint64_t); assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge0, &sz, NULL, 0), config_stats ? 0 : ENOENT, "Unexpected mallctl result"); @@ -332,8 +438,7 @@ TEST_BEGIN(test_decay_nonmonotonic) { "Expected nstime_update() to be called"); } - assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, - sizeof(uint64_t)), 0, "Unexpected mallctl failure"); + do_epoch(); sz = sizeof(uint64_t); assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge1, &sz, NULL, 0), config_stats ? 0 : ENOENT, "Unexpected mallctl result"); @@ -348,69 +453,6 @@ TEST_BEGIN(test_decay_nonmonotonic) { } TEST_END -static unsigned -do_arena_create(ssize_t decay_time) { - unsigned arena_ind; - size_t sz = sizeof(unsigned); - assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), - 0, "Unexpected mallctl() failure"); - size_t mib[3]; - size_t miblen = sizeof(mib)/sizeof(size_t); - assert_d_eq(mallctlnametomib("arena.0.decay_time", mib, &miblen), 0, - "Unexpected mallctlnametomib() failure"); - mib[1] = (size_t)arena_ind; - assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&decay_time, - sizeof(decay_time)), 0, "Unexpected mallctlbymib() failure"); - return arena_ind; -} - -static void -do_arena_destroy(unsigned arena_ind) { - size_t mib[3]; - size_t miblen = sizeof(mib)/sizeof(size_t); - assert_d_eq(mallctlnametomib("arena.0.destroy", mib, &miblen), 0, - "Unexpected mallctlnametomib() failure"); - mib[1] = (size_t)arena_ind; - assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, - "Unexpected mallctlbymib() failure"); -} - -void -do_epoch(void) { - uint64_t epoch = 1; - assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), - 0, "Unexpected mallctl() failure"); -} - -static size_t -get_arena_pdirty(unsigned arena_ind) { - do_epoch(); - size_t mib[4]; - size_t miblen = sizeof(mib)/sizeof(size_t); - assert_d_eq(mallctlnametomib("stats.arenas.0.pdirty", mib, &miblen), 0, - "Unexpected mallctlnametomib() failure"); - mib[2] = (size_t)arena_ind; - size_t pdirty; - size_t sz = sizeof(pdirty); - assert_d_eq(mallctlbymib(mib, miblen, (void *)&pdirty, &sz, NULL, 0), 0, - "Unexpected mallctlbymib() failure"); - return pdirty; -} - -static void * -do_mallocx(size_t size, int flags) { - void *p = mallocx(size, flags); - assert_ptr_not_null(p, "Unexpected mallocx() failure"); - return p; -} - -static void -generate_dirty(unsigned arena_ind, size_t size) { - int flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; - void *p = do_mallocx(size, flags); - dallocx(p, flags); -} - TEST_BEGIN(test_decay_now) { unsigned arena_ind = do_arena_create(0); assert_zu_eq(get_arena_pdirty(arena_ind), 0, "Unexpected dirty pages"); -- GitLab From e201e24904d53897409b1dda451d40c5d2e0dc29 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 2 Mar 2017 18:04:35 -0800 Subject: [PATCH 310/544] Perform delayed coalescing prior to purging. Rather than purging uncoalesced extents, perform just enough incremental coalescing to purge only fully coalesced extents. In the absence of cached extent reuse, the immediate versus delayed incremental purging algorithms result in the same purge order. This resolves #655. --- include/jemalloc/internal/extent_externs.h | 5 +- include/jemalloc/internal/extent_inlines.h | 9 ++ include/jemalloc/internal/extent_structs.h | 7 +- include/jemalloc/internal/private_symbols.txt | 2 + src/arena.c | 28 +++- src/extent.c | 151 +++++++++++++----- 6 files changed, 152 insertions(+), 50 deletions(-) diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index f5efed06..ef2467e1 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -18,10 +18,11 @@ size_t extent_size_quantize_ceil(size_t size); ph_proto(, extent_heap_, extent_heap_t, extent_t) bool extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state, - bool try_coalesce); + bool delay_coalesce); extent_state_t extents_state_get(const extents_t *extents); size_t extents_npages_get(extents_t *extents); -extent_t *extents_evict(tsdn_t *tsdn, extents_t *extents, size_t npages_min); +extent_t *extents_evict(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extents_t *extents, size_t npages_min); void extents_prefork(tsdn_t *tsdn, extents_t *extents); void extents_postfork_parent(tsdn_t *tsdn, extents_t *extents); void extents_postfork_child(tsdn_t *tsdn, extents_t *extents); diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index 473aad71..989c0d19 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -37,6 +37,8 @@ void extent_list_init(extent_list_t *list); extent_t *extent_list_first(const extent_list_t *list); extent_t *extent_list_last(const extent_list_t *list); void extent_list_append(extent_list_t *list, extent_t *extent); +void extent_list_replace(extent_list_t *list, extent_t *to_remove, + extent_t *to_insert); void extent_list_remove(extent_list_t *list, extent_t *extent); int extent_sn_comp(const extent_t *a, const extent_t *b); int extent_ad_comp(const extent_t *a, const extent_t *b); @@ -253,6 +255,13 @@ extent_list_append(extent_list_t *list, extent_t *extent) { ql_tail_insert(list, extent, ql_link); } +JEMALLOC_INLINE void +extent_list_replace(extent_list_t *list, extent_t *to_remove, + extent_t *to_insert) { + ql_after_insert(to_remove, to_insert, ql_link); + ql_remove(list, to_remove, ql_link); +} + JEMALLOC_INLINE void extent_list_remove(extent_list_t *list, extent_t *extent) { ql_remove(list, extent, ql_link); diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 008b6352..9ea69728 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -116,8 +116,11 @@ struct extents_s { /* All stored extents must be in the same state. */ extent_state_t state; - /* If true, try to coalesce during extent deallocation. */ - bool try_coalesce; + /* + * If true, delay coalescing until eviction; otherwise coalesce during + * deallocation. + */ + bool delay_coalesce; }; #endif /* JEMALLOC_INTERNAL_EXTENT_STRUCTS_H */ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index b122dae6..30cd3958 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -159,8 +159,10 @@ extent_init extent_last_get extent_list_append extent_list_first +extent_list_init extent_list_last extent_list_remove +extent_list_replace extent_lookup extent_merge_wrapper extent_past_get diff --git a/src/arena.c b/src/arena.c index 56ab362d..cef61cc3 100644 --- a/src/arena.c +++ b/src/arena.c @@ -715,9 +715,9 @@ arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, /* Stash extents according to ndirty_limit. */ size_t nstashed = 0; - for (extent_t *extent = extents_evict(tsdn, &arena->extents_cached, - ndirty_limit); extent != NULL; extent = extents_evict(tsdn, - &arena->extents_cached, ndirty_limit)) { + extent_t *extent; + while ((extent = extents_evict(tsdn, arena, r_extent_hooks, + &arena->extents_cached, ndirty_limit)) != NULL) { extent_list_append(purge_extents, extent); nstashed += extent_size_get(extent) >> LG_PAGE; } @@ -943,9 +943,9 @@ arena_destroy_retained(tsdn_t *tsdn, arena_t *arena) { * either unmap retained extents or track them for later use. */ extent_hooks_t *extent_hooks = extent_hooks_get(arena); - for (extent_t *extent = extents_evict(tsdn, &arena->extents_retained, - 0); extent != NULL; extent = extents_evict(tsdn, - &arena->extents_retained, 0)) { + extent_t *extent; + while ((extent = extents_evict(tsdn, arena, &extent_hooks, + &arena->extents_retained, 0)) != NULL) { extent_dalloc_wrapper_try(tsdn, arena, &extent_hooks, extent); } } @@ -1679,12 +1679,24 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { goto label_error; } + /* + * Delay coalescing for cached extents despite the disruptive effect on + * memory layout for best-fit extent allocation, since cached extents + * are likely to be reused soon after deallocation, and the cost of + * merging/splitting extents is non-trivial. + */ if (extents_init(tsdn, &arena->extents_cached, extent_state_dirty, - false)) { + true)) { goto label_error; } + /* + * Coalesce retained extents immediately, in part because they will + * never be evicted (and therefore there's no opportunity for delayed + * coalescing), but also because operations on retained extents are not + * in the critical path. + */ if (extents_init(tsdn, &arena->extents_retained, - extent_state_retained, true)) { + extent_state_retained, false)) { goto label_error; } diff --git a/src/extent.c b/src/extent.c index 09990aae..368c9741 100644 --- a/src/extent.c +++ b/src/extent.c @@ -69,6 +69,9 @@ static size_t highpages; */ static void extent_deregister(tsdn_t *tsdn, extent_t *extent); +static extent_t *extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, + extent_t *extent, bool *coalesced); static void extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extents_t *extents, extent_t *extent); @@ -175,7 +178,7 @@ ph_gen(, extent_heap_, extent_heap_t, extent_t, ph_link, extent_snad_comp) bool extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state, - bool try_coalesce) { + bool delay_coalesce) { if (malloc_mutex_init(&extents->mtx, "extents", WITNESS_RANK_EXTENTS)) { return true; } @@ -185,7 +188,7 @@ extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state, extent_list_init(&extents->lru); extents->npages = 0; extents->state = state; - extents->try_coalesce = try_coalesce; + extents->delay_coalesce = delay_coalesce; return false; } @@ -200,7 +203,8 @@ extents_npages_get(extents_t *extents) { } static void -extents_insert_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent) { +extents_insert_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent, + bool preserve_lru) { malloc_mutex_assert_owner(tsdn, &extents->mtx); assert(extent_state_get(extent) == extents->state); @@ -208,13 +212,16 @@ extents_insert_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent) { size_t psz = extent_size_quantize_floor(size); pszind_t pind = psz2ind(psz); extent_heap_insert(&extents->heaps[pind], extent); - extent_list_append(&extents->lru, extent); + if (!preserve_lru) { + extent_list_append(&extents->lru, extent); + } size_t npages = size >> LG_PAGE; atomic_add_zu(&extents->npages, npages); } static void -extents_remove_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent) { +extents_remove_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent, + bool preserve_lru) { malloc_mutex_assert_owner(tsdn, &extents->mtx); assert(extent_state_get(extent) == extents->state); @@ -222,7 +229,9 @@ extents_remove_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent) { size_t psz = extent_size_quantize_floor(size); pszind_t pind = psz2ind(psz); extent_heap_remove(&extents->heaps[pind], extent); - extent_list_remove(&extents->lru, extent); + if (!preserve_lru) { + extent_list_remove(&extents->lru, extent); + } size_t npages = size >> LG_PAGE; assert(atomic_read_zu(&extents->npages) >= npages); atomic_sub_zu(&extents->npages, size >> LG_PAGE); @@ -249,22 +258,62 @@ extents_first_best_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, return NULL; } +static bool +extent_try_delayed_coalesce(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, + extent_t *extent) { + extent_state_set(extent, extent_state_active); + bool coalesced; + extent = extent_try_coalesce(tsdn, arena, r_extent_hooks, rtree_ctx, + extents, extent, &coalesced); + extent_state_set(extent, extents_state_get(extents)); + + if (!coalesced) { + return true; + } + extents_insert_locked(tsdn, extents, extent, true); + return false; +} + extent_t * -extents_evict(tsdn_t *tsdn, extents_t *extents, size_t npages_min) { +extents_evict(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, + extents_t *extents, size_t npages_min) { + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + malloc_mutex_lock(tsdn, &extents->mtx); - /* Get the LRU extent, if any. */ - extent_t *extent = extent_list_first(&extents->lru); - if (extent == NULL) { - goto label_return; - } - /* Check the eviction limit. */ - size_t npages = extent_size_get(extent) >> LG_PAGE; - if (atomic_read_zu(&extents->npages) - npages < npages_min) { - extent = NULL; - goto label_return; + /* + * Get the LRU coalesced extent, if any. If coalescing was delayed, + * the loop will iterate until the LRU extent is fully coalesced. + */ + extent_t *extent; + while (true) { + /* Get the LRU extent, if any. */ + extent = extent_list_first(&extents->lru); + if (extent == NULL) { + goto label_return; + } + /* Check the eviction limit. */ + size_t npages = extent_size_get(extent) >> LG_PAGE; + if (atomic_read_zu(&extents->npages) - npages < npages_min) { + extent = NULL; + goto label_return; + } + extents_remove_locked(tsdn, extents, extent, false); + if (!extents->delay_coalesce) { + break; + } + /* Try to coalesce. */ + if (extent_try_delayed_coalesce(tsdn, arena, r_extent_hooks, + rtree_ctx, extents, extent)) { + break; + } + /* + * The LRU extent was just coalesced and the result placed in + * the LRU at its neighbor's position. Start over. + */ } - extents_remove_locked(tsdn, extents, extent); /* * Either mark the extent active or deregister it to protect against @@ -320,29 +369,29 @@ extents_postfork_child(tsdn_t *tsdn, extents_t *extents) { static void extent_deactivate_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, - extent_t *extent) { + extent_t *extent, bool preserve_lru) { assert(extent_arena_get(extent) == arena); assert(extent_state_get(extent) == extent_state_active); extent_state_set(extent, extents_state_get(extents)); - extents_insert_locked(tsdn, extents, extent); + extents_insert_locked(tsdn, extents, extent, preserve_lru); } static void extent_deactivate(tsdn_t *tsdn, arena_t *arena, extents_t *extents, - extent_t *extent) { + extent_t *extent, bool preserve_lru) { malloc_mutex_lock(tsdn, &extents->mtx); - extent_deactivate_locked(tsdn, arena, extents, extent); + extent_deactivate_locked(tsdn, arena, extents, extent, preserve_lru); malloc_mutex_unlock(tsdn, &extents->mtx); } static void extent_activate_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, - extent_t *extent) { + extent_t *extent, bool preserve_lru) { assert(extent_arena_get(extent) == arena); assert(extent_state_get(extent) == extents_state_get(extents)); - extents_remove_locked(tsdn, extents, extent); + extents_remove_locked(tsdn, extents, extent, preserve_lru); extent_state_set(extent, extent_state_active); } @@ -581,7 +630,7 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, return NULL; } - extent_activate_locked(tsdn, arena, extents, extent); + extent_activate_locked(tsdn, arena, extents, extent, false); if (!locked) { malloc_mutex_unlock(tsdn, &extents->mtx); } @@ -620,7 +669,7 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena, lead); return NULL; } - extent_deactivate(tsdn, arena, extents, lead); + extent_deactivate(tsdn, arena, extents, lead, false); } /* Split the trail. */ @@ -633,7 +682,7 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena, extent); return NULL; } - extent_deactivate(tsdn, arena, extents, trail); + extent_deactivate(tsdn, arena, extents, trail, false); } else if (leadsize == 0) { /* * Splitting causes usize to be set as a side effect, but no @@ -1030,7 +1079,16 @@ extent_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extents_t *extents, extent_t *inner, extent_t *outer, bool forward) { assert(extent_can_coalesce(arena, extents, inner, outer)); - extent_activate_locked(tsdn, arena, extents, outer); + if (forward && extents->delay_coalesce) { + /* + * The extent that remains after coalescing must occupy the + * outer extent's position in the LRU. For forward coalescing, + * swap the inner extent into the LRU. + */ + extent_list_replace(&extents->lru, outer, inner); + } + extent_activate_locked(tsdn, arena, extents, outer, + extents->delay_coalesce); malloc_mutex_unlock(tsdn, &extents->mtx); bool err = extent_merge_wrapper(tsdn, arena, r_extent_hooks, @@ -1038,7 +1096,11 @@ extent_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, malloc_mutex_lock(tsdn, &extents->mtx); if (err) { - extent_deactivate_locked(tsdn, arena, extents, outer); + if (forward && extents->delay_coalesce) { + extent_list_replace(&extents->lru, inner, outer); + } + extent_deactivate_locked(tsdn, arena, extents, outer, + extents->delay_coalesce); } return err; @@ -1047,14 +1109,14 @@ extent_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, static extent_t * extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, - extent_t *extent) { + extent_t *extent, bool *coalesced) { /* * Continue attempting to coalesce until failure, to protect against * races with other threads that are thwarted by this one. */ - bool coalesced; + bool again; do { - coalesced = false; + again = false; /* Try to coalesce forward. */ rtree_elm_t *next_elm = rtree_elm_acquire(tsdn, &extents_rtree, @@ -1073,7 +1135,12 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, rtree_elm_release(tsdn, &extents_rtree, next_elm); if (can_coalesce && !extent_coalesce(tsdn, arena, r_extent_hooks, extents, extent, next, true)) { - coalesced = true; + if (extents->delay_coalesce) { + /* Do minimal coalescing. */ + *coalesced = true; + return extent; + } + again = true; } } @@ -1090,11 +1157,19 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, if (can_coalesce && !extent_coalesce(tsdn, arena, r_extent_hooks, extents, extent, prev, false)) { extent = prev; - coalesced = true; + if (extents->delay_coalesce) { + /* Do minimal coalescing. */ + *coalesced = true; + return extent; + } + again = true; } } - } while (coalesced); + } while (again); + if (extents->delay_coalesce) { + *coalesced = false; + } return extent; } @@ -1118,12 +1193,12 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, assert(extent_lookup(tsdn, extent_base_get(extent), true) == extent); - if (extents->try_coalesce) { + if (!extents->delay_coalesce) { extent = extent_try_coalesce(tsdn, arena, r_extent_hooks, - rtree_ctx, extents, extent); + rtree_ctx, extents, extent, NULL); } - extent_deactivate_locked(tsdn, arena, extents, extent); + extent_deactivate_locked(tsdn, arena, extents, extent, false); malloc_mutex_unlock(tsdn, &extents->mtx); } -- GitLab From cc75c35db58f4ce4a27455fe5fe46fe9347d2c45 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 3 Mar 2017 22:51:21 -0800 Subject: [PATCH 311/544] Add any() and remove_any() to ph. These functions select the easiest-to-remove element in the heap, which is either the most recently inserted aux list element or the root. If no calls are made to first() or remove_first(), the behavior (and time complexity) is the same as for a LIFO queue. --- include/jemalloc/internal/ph.h | 58 +++++++++++++++++++++++++++++++--- test/unit/ph.c | 31 +++++++++++++++++- 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/include/jemalloc/internal/ph.h b/include/jemalloc/internal/ph.h index 7e1920cb..84d6778a 100644 --- a/include/jemalloc/internal/ph.h +++ b/include/jemalloc/internal/ph.h @@ -198,8 +198,10 @@ struct { \ a_attr void a_prefix##new(a_ph_type *ph); \ a_attr bool a_prefix##empty(a_ph_type *ph); \ a_attr a_type *a_prefix##first(a_ph_type *ph); \ +a_attr a_type *a_prefix##any(a_ph_type *ph); \ a_attr void a_prefix##insert(a_ph_type *ph, a_type *phn); \ a_attr a_type *a_prefix##remove_first(a_ph_type *ph); \ +a_attr a_type *a_prefix##remove_any(a_ph_type *ph); \ a_attr void a_prefix##remove(a_ph_type *ph, a_type *phn); /* @@ -223,6 +225,17 @@ a_prefix##first(a_ph_type *ph) { \ ph_merge_aux(a_type, a_field, ph, a_cmp); \ return ph->ph_root; \ } \ +a_attr a_type * \ +a_prefix##any(a_ph_type *ph) { \ + if (ph->ph_root == NULL) { \ + return NULL; \ + } \ + a_type *aux = phn_next_get(a_type, a_field, ph->ph_root); \ + if (aux != NULL) { \ + return aux; \ + } \ + return ph->ph_root; \ +} \ a_attr void \ a_prefix##insert(a_ph_type *ph, a_type *phn) { \ memset(&phn->a_field, 0, sizeof(phn(a_type))); \ @@ -266,15 +279,52 @@ a_prefix##remove_first(a_ph_type *ph) { \ \ return ret; \ } \ +a_attr a_type * \ +a_prefix##remove_any(a_ph_type *ph) { \ + /* \ + * Remove the most recently inserted aux list element, or the \ + * root if the aux list is empty. This has the effect of \ + * behaving as a LIFO (and insertion/removal is therefore \ + * constant-time) if a_prefix##[remove_]first() are never \ + * called. \ + */ \ + if (ph->ph_root == NULL) { \ + return NULL; \ + } \ + a_type *ret = phn_next_get(a_type, a_field, ph->ph_root); \ + if (ret != NULL) { \ + a_type *aux = phn_next_get(a_type, a_field, ret); \ + phn_next_set(a_type, a_field, ph->ph_root, aux); \ + if (aux != NULL) { \ + phn_prev_set(a_type, a_field, aux, \ + ph->ph_root); \ + } \ + return ret; \ + } \ + ret = ph->ph_root; \ + ph_merge_children(a_type, a_field, ph->ph_root, a_cmp, \ + ph->ph_root); \ + return ret; \ +} \ a_attr void \ a_prefix##remove(a_ph_type *ph, a_type *phn) { \ a_type *replace, *parent; \ \ - /* \ - * We can delete from aux list without merging it, but we need \ - * to merge if we are dealing with the root node. \ - */ \ if (ph->ph_root == phn) { \ + /* \ + * We can delete from aux list without merging it, but \ + * we need to merge if we are dealing with the root \ + * node and it has children. \ + */ \ + if (phn_lchild_get(a_type, a_field, phn) == NULL) { \ + ph->ph_root = phn_next_get(a_type, a_field, \ + phn); \ + if (ph->ph_root != NULL) { \ + phn_prev_set(a_type, a_field, \ + ph->ph_root, NULL); \ + } \ + return; \ + } \ ph_merge_aux(a_type, a_field, ph, a_cmp); \ if (ph->ph_root == phn) { \ ph_merge_children(a_type, a_field, ph->ph_root, \ diff --git a/test/unit/ph.c b/test/unit/ph.c index 91516fae..01df340c 100644 --- a/test/unit/ph.c +++ b/test/unit/ph.c @@ -142,6 +142,7 @@ TEST_BEGIN(test_ph_empty) { heap_new(&heap); assert_true(heap_empty(&heap), "Heap should be empty"); assert_ptr_null(heap_first(&heap), "Unexpected node"); + assert_ptr_null(heap_any(&heap), "Unexpected node"); } TEST_END @@ -159,6 +160,13 @@ node_remove_first(heap_t *heap) { return node; } +static node_t * +node_remove_any(heap_t *heap) { + node_t *node = heap_remove_any(heap); + node->magic = 0; + return node; +} + TEST_BEGIN(test_ph_random) { #define NNODES 25 #define NBAGS 250 @@ -204,6 +212,8 @@ TEST_BEGIN(test_ph_random) { for (k = 0; k < j; k++) { heap_insert(&heap, &nodes[k]); if (i % 13 == 12) { + assert_ptr_not_null(heap_any(&heap), + "Heap should not be empty"); /* Trigger merging. */ assert_ptr_not_null(heap_first(&heap), "Heap should not be empty"); @@ -216,7 +226,7 @@ TEST_BEGIN(test_ph_random) { "Heap should not be empty"); /* Remove nodes. */ - switch (i % 4) { + switch (i % 6) { case 0: for (k = 0; k < j; k++) { assert_u_eq(heap_validate(&heap), j - k, @@ -264,12 +274,31 @@ TEST_BEGIN(test_ph_random) { prev = node; } break; + } case 4: { + for (k = 0; k < j; k++) { + node_remove_any(&heap); + assert_u_eq(heap_validate(&heap), j - k + - 1, "Incorrect node count"); + } + break; + } case 5: { + for (k = 0; k < j; k++) { + node_t *node = heap_any(&heap); + assert_u_eq(heap_validate(&heap), j - k, + "Incorrect node count"); + node_remove(&heap, node); + assert_u_eq(heap_validate(&heap), j - k + - 1, "Incorrect node count"); + } + break; } default: not_reached(); } assert_ptr_null(heap_first(&heap), "Heap should be empty"); + assert_ptr_null(heap_any(&heap), + "Heap should be empty"); assert_true(heap_empty(&heap), "Heap should be empty"); } } -- GitLab From cdce93e4a3045bcf0d30409666d2d4c29818aec7 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 3 Mar 2017 22:55:28 -0800 Subject: [PATCH 312/544] Use any-best-fit for cached extent allocation. This simplifies what would be pairing heap operations to the equivalent of LIFO queue operations. This is a complementary optimization in the context of delayed coalescing for cached extents. --- src/extent.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/extent.c b/src/extent.c index 368c9741..60e385ee 100644 --- a/src/extent.c +++ b/src/extent.c @@ -238,17 +238,20 @@ extents_remove_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent, } /* - * Do first-best-fit extent selection, i.e. select the oldest/lowest extent that - * best fits. + * Do {first,any}-best-fit extent selection, i.e. select the oldest/lowest or + * any extent that best fits, where {first,any} corresponds to + * extents->delay_coalesce={false,true}. */ static extent_t * -extents_first_best_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, +extents_best_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, size_t size) { malloc_mutex_assert_owner(tsdn, &extents->mtx); pszind_t pind = psz2ind(extent_size_quantize_ceil(size)); for (pszind_t i = pind; i < NPSIZES+1; i++) { - extent_t *extent = extent_heap_first(&extents->heaps[i]); + extent_t *extent = extents->delay_coalesce ? + extent_heap_any(&extents->heaps[i]) : + extent_heap_first(&extents->heaps[i]); if (extent != NULL) { assert(extent_size_get(extent) >= size); return extent; @@ -620,7 +623,7 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, extent = NULL; } } else { - extent = extents_first_best_fit_locked(tsdn, arena, extents, + extent = extents_best_fit_locked(tsdn, arena, extents, alloc_size); } if (extent == NULL) { -- GitLab From 01f47f11a67d1a2505cc1f21851c466651eba431 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 6 Mar 2017 12:51:41 -0800 Subject: [PATCH 313/544] Store associated arena in tcache. This fixes tcache_flush for manual tcaches, which wasn't able to find the correct arena it associated with. Also changed the decay test to cover this case (by using manually created arenas). --- include/jemalloc/internal/tcache_externs.h | 2 +- include/jemalloc/internal/tcache_structs.h | 1 + src/ctl.c | 2 +- src/jemalloc.c | 1 + src/tcache.c | 17 ++++----- test/unit/decay.c | 40 +++++++++++++++++----- 6 files changed, 45 insertions(+), 18 deletions(-) diff --git a/include/jemalloc/internal/tcache_externs.h b/include/jemalloc/internal/tcache_externs.h index 3e4a7511..83643033 100644 --- a/include/jemalloc/internal/tcache_externs.h +++ b/include/jemalloc/internal/tcache_externs.h @@ -34,7 +34,7 @@ void tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, void tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, unsigned rem, tcache_t *tcache); void tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, - arena_t *oldarena, arena_t *newarena); + arena_t *arena); tcache_t *tcache_get_hard(tsd_t *tsd); tcache_t *tcache_create(tsdn_t *tsdn, arena_t *arena); void tcache_cleanup(tsd_t *tsd); diff --git a/include/jemalloc/internal/tcache_structs.h b/include/jemalloc/internal/tcache_structs.h index a2b28afd..a9b70312 100644 --- a/include/jemalloc/internal/tcache_structs.h +++ b/include/jemalloc/internal/tcache_structs.h @@ -35,6 +35,7 @@ struct tcache_s { uint64_t prof_accumbytes;/* Cleared after arena_prof_accum(). */ ticker_t gc_ticker; /* Drives incremental GC. */ szind_t next_gc_bin; /* Next bin to GC. */ + arena_t *arena; /* Associated arena. */ tcache_bin_t tbins[1]; /* Dynamically sized. */ /* * The pointer stacks associated with tbins follow as a contiguous diff --git a/src/ctl.c b/src/ctl.c index 83e9e93e..831877b0 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1342,7 +1342,7 @@ thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, tcache_t *tcache = tsd_tcache_get(tsd); if (tcache != NULL) { tcache_arena_reassociate(tsd_tsdn(tsd), tcache, - oldarena, newarena); + newarena); } } } diff --git a/src/jemalloc.c b/src/jemalloc.c index 7e652802..b5379cc4 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -446,6 +446,7 @@ arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind) { arena_nthreads_dec(oldarena, false); arena_nthreads_inc(newarena, false); tsd_arena_set(tsd, newarena); + tsd_iarena_set(tsd, newarena); } static void diff --git a/src/tcache.c b/src/tcache.c index dff31d19..78570663 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -99,7 +99,7 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, assert(binind < NBINS); assert(rem <= tbin->ncached); - arena = arena_choose(tsd, NULL); + arena = tcache->arena; assert(arena != NULL); for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) { /* Lock the arena bin associated with the first object. */ @@ -175,7 +175,7 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, assert(binind < nhbins); assert(rem <= tbin->ncached); - arena_t *arena = arena_choose(tsd, NULL); + arena_t *arena = tcache->arena; assert(arena != NULL); unsigned nflush = tbin->ncached - rem; while (nflush > 0) { @@ -259,6 +259,7 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, static void tcache_arena_associate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { + tcache->arena = arena; if (config_stats) { /* Link into list of extant tcaches. */ malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx); @@ -269,7 +270,8 @@ tcache_arena_associate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { } static void -tcache_arena_dissociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { +tcache_arena_dissociate(tsdn_t *tsdn, tcache_t *tcache) { + arena_t *arena = tcache->arena; if (config_stats) { /* Unlink from list of extant tcaches. */ malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx); @@ -291,10 +293,9 @@ tcache_arena_dissociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { } void -tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *oldarena, - arena_t *newarena) { - tcache_arena_dissociate(tsdn, tcache, oldarena); - tcache_arena_associate(tsdn, tcache, newarena); +tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { + tcache_arena_dissociate(tsdn, tcache); + tcache_arena_associate(tsdn, tcache, arena); } tcache_t * @@ -360,7 +361,7 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache) { unsigned i; arena = arena_choose(tsd, NULL); - tcache_arena_dissociate(tsd_tsdn(tsd), tcache, arena); + tcache_arena_dissociate(tsd_tsdn(tsd), tcache); for (i = 0; i < NBINS; i++) { tcache_bin_t *tbin = &tcache->tbins[i]; diff --git a/test/unit/decay.c b/test/unit/decay.c index df910aac..eb4df9d7 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -123,18 +123,28 @@ generate_dirty(unsigned arena_ind, size_t size) { TEST_BEGIN(test_decay_ticks) { ticker_t *decay_ticker; - unsigned tick0, tick1; + unsigned tick0, tick1, arena_ind; size_t sz, large0; void *p; - decay_ticker = decay_ticker_get(tsd_fetch(), 0); - assert_ptr_not_null(decay_ticker, - "Unexpected failure getting decay ticker"); - sz = sizeof(size_t); assert_d_eq(mallctl("arenas.lextent.0.size", (void *)&large0, &sz, NULL, 0), 0, "Unexpected mallctl failure"); + int err; + /* Set up a manually managed arena for test. */ + arena_ind = do_arena_create(0); + + /* Migrate to the new arena, and get the ticker. */ + unsigned old_arena_ind; + size_t sz_arena_ind = sizeof(old_arena_ind); + err = mallctl("thread.arena", (void *)&old_arena_ind, &sz_arena_ind, + (void *)&arena_ind, sizeof(arena_ind)); + assert_d_eq(err, 0, "Unexpected mallctl() failure"); + decay_ticker = decay_ticker_get(tsd_fetch(), arena_ind); + assert_ptr_not_null(decay_ticker, + "Unexpected failure getting decay ticker"); + /* * Test the standard APIs using a large size class, since we can't * control tcache interactions for small size classes (except by @@ -263,6 +273,12 @@ TEST_BEGIN(test_decay_ticks) { tcache_sizes[0] = large0; tcache_sizes[1] = 1; + size_t tcache_max, sz_tcache_max; + sz_tcache_max = sizeof(tcache_max); + err = mallctl("arenas.tcache_max", (void *)&tcache_max, + &sz_tcache_max, NULL, 0); + assert_d_eq(err, 0, "Unexpected mallctl() failure"); + sz = sizeof(unsigned); assert_d_eq(mallctl("tcache.create", (void *)&tcache_ind, &sz, NULL, 0), 0, "Unexpected mallctl failure"); @@ -285,9 +301,17 @@ TEST_BEGIN(test_decay_ticks) { (void *)&tcache_ind, sizeof(unsigned)), 0, "Unexpected mallctl failure"); tick1 = ticker_read(decay_ticker); - assert_u32_ne(tick1, tick0, - "Expected ticker to tick during tcache flush " - "(sz=%zu)", sz); + + /* Will only tick if it's in tcache. */ + if (sz <= tcache_max) { + assert_u32_ne(tick1, tick0, + "Expected ticker to tick during tcache " + "flush (sz=%zu)", sz); + } else { + assert_u32_eq(tick1, tick0, + "Unexpected ticker tick during tcache " + "flush (sz=%zu)", sz); + } } } } -- GitLab From dafadce62205bddac7da1c595c956a69367810ec Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 8 Mar 2017 12:13:59 -0800 Subject: [PATCH 314/544] Reintroduce JEMALLOC_ATOMIC_U64 The C11 atomics backport removed this #define, which degraded atomic 64-bit reads to require a lock even on platforms that support them. This commit fixes that. --- include/jemalloc/internal/atomic.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/jemalloc/internal/atomic.h b/include/jemalloc/internal/atomic.h index 866adff0..acbb6216 100644 --- a/include/jemalloc/internal/atomic.h +++ b/include/jemalloc/internal/atomic.h @@ -44,6 +44,14 @@ #define ATOMIC_ACQ_REL atomic_memory_order_acq_rel, #define ATOMIC_SEQ_CST atomic_memory_order_seq_cst +/* + * Not all platforms have 64-bit atomics. If we do, this #define exposes that + * fact. + */ +#if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) +# define JEMALLOC_ATOMIC_U64 +#endif + /* * In order to let us transition atomics usage piecemeal (and reason locally * about memory orders), we'll support the previous API for a while. @@ -104,10 +112,10 @@ JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(ssize_t, zd) JEMALLOC_GENERATE_INT_ATOMICS(uint32_t, u32, 2) JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(uint32_t, u32) -# if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3) +#ifdef JEMALLOC_ATOMIC_U64 JEMALLOC_GENERATE_INT_ATOMICS(uint64_t, u64, 3) JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(uint64_t, u64) -# endif +#endif #undef ATOMIC_INLINE -- GitLab From 8adab269721b0271399027d45a8aa6b425e53fd9 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 7 Mar 2017 17:57:48 -0800 Subject: [PATCH 315/544] Convert extents_t's npages field to use C11-style atomics In the process, we can do some strength reduction, changing the fetch-adds and fetch-subs to be simple loads followed by stores, since the modifications all occur while holding the mutex. --- include/jemalloc/internal/extent_structs.h | 7 ++++-- src/extent.c | 29 +++++++++++++++++----- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 9ea69728..c14aef86 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -109,9 +109,12 @@ struct extents_s { /* * Page sum for all extents in heaps. * - * Synchronization: atomic. + * The synchronization here is a little tricky. Modifications to npages + * must hold mtx, but reads need not (though, a reader who sees npages + * without holding the mutex can't assume anything about the rest of the + * state of the extents_t). */ - size_t npages; + atomic_zu_t npages; /* All stored extents must be in the same state. */ extent_state_t state; diff --git a/src/extent.c b/src/extent.c index 60e385ee..33589394 100644 --- a/src/extent.c +++ b/src/extent.c @@ -186,7 +186,7 @@ extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state, extent_heap_new(&extents->heaps[i]); } extent_list_init(&extents->lru); - extents->npages = 0; + atomic_store_zu(&extents->npages, 0, ATOMIC_RELAXED); extents->state = state; extents->delay_coalesce = delay_coalesce; return false; @@ -199,7 +199,7 @@ extents_state_get(const extents_t *extents) { size_t extents_npages_get(extents_t *extents) { - return atomic_read_zu(&extents->npages); + return atomic_load_zu(&extents->npages, ATOMIC_RELAXED); } static void @@ -216,7 +216,15 @@ extents_insert_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent, extent_list_append(&extents->lru, extent); } size_t npages = size >> LG_PAGE; - atomic_add_zu(&extents->npages, npages); + /* + * All modifications to npages hold the mutex (as asserted above), so we + * don't need an atomic fetch-add; we can get by with a load followed by + * a store. + */ + size_t cur_extents_npages = + atomic_load_zu(&extents->npages, ATOMIC_RELAXED); + atomic_store_zu(&extents->npages, cur_extents_npages + npages, + ATOMIC_RELAXED); } static void @@ -233,8 +241,15 @@ extents_remove_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent, extent_list_remove(&extents->lru, extent); } size_t npages = size >> LG_PAGE; - assert(atomic_read_zu(&extents->npages) >= npages); - atomic_sub_zu(&extents->npages, size >> LG_PAGE); + /* + * As in extents_insert_locked, we hold extents->mtx and so don't need + * atomic operations for updating extents->npages. + */ + size_t cur_extents_npages = + atomic_load_zu(&extents->npages, ATOMIC_RELAXED); + assert(cur_extents_npages >= npages); + atomic_store_zu(&extents->npages, + cur_extents_npages - (size >> LG_PAGE), ATOMIC_RELAXED); } /* @@ -299,7 +314,9 @@ extents_evict(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, } /* Check the eviction limit. */ size_t npages = extent_size_get(extent) >> LG_PAGE; - if (atomic_read_zu(&extents->npages) - npages < npages_min) { + size_t extents_npages = atomic_load_zu(&extents->npages, + ATOMIC_RELAXED); + if (extents_npages - npages < npages_min) { extent = NULL; goto label_return; } -- GitLab From 8721e19c0414dce0f47a627ff948130d4294b4d7 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 8 Mar 2017 13:00:42 -0800 Subject: [PATCH 316/544] Fix arena_prefork lock rank order for witness. When witness is enabled, lock rank order needs to be preserved during prefork, not only for each arena, but also across arenas. This change breaks arena_prefork into further stages to ensure valid rank order across arenas. Also changed test/unit/fork to use a manual arena to catch this case. --- include/jemalloc/internal/arena_externs.h | 3 +++ include/jemalloc/internal/private_symbols.txt | 3 +++ src/arena.c | 22 ++++++++++++++----- src/jemalloc.c | 20 ++++++++++++----- test/unit/fork.c | 13 +++++++++++ 5 files changed, 49 insertions(+), 12 deletions(-) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 36d91869..2df55184 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -82,6 +82,9 @@ void arena_prefork0(tsdn_t *tsdn, arena_t *arena); void arena_prefork1(tsdn_t *tsdn, arena_t *arena); void arena_prefork2(tsdn_t *tsdn, arena_t *arena); void arena_prefork3(tsdn_t *tsdn, arena_t *arena); +void arena_prefork4(tsdn_t *tsdn, arena_t *arena); +void arena_prefork5(tsdn_t *tsdn, arena_t *arena); +void arena_prefork6(tsdn_t *tsdn, arena_t *arena); void arena_postfork_parent(tsdn_t *tsdn, arena_t *arena); void arena_postfork_child(tsdn_t *tsdn, arena_t *arena); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 30cd3958..64bea334 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -51,6 +51,9 @@ arena_prefork0 arena_prefork1 arena_prefork2 arena_prefork3 +arena_prefork4 +arena_prefork5 +arena_prefork6 arena_prof_accum arena_prof_promote arena_prof_tctx_get diff --git a/src/arena.c b/src/arena.c index cef61cc3..43bad81c 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1743,29 +1743,39 @@ arena_boot(void) { void arena_prefork0(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_prefork(tsdn, &arena->decay.mtx); +} + +void +arena_prefork1(tsdn_t *tsdn, arena_t *arena) { if (config_stats && config_tcache) { malloc_mutex_prefork(tsdn, &arena->tcache_ql_mtx); } } void -arena_prefork1(tsdn_t *tsdn, arena_t *arena) { +arena_prefork2(tsdn_t *tsdn, arena_t *arena) { extents_prefork(tsdn, &arena->extents_cached); extents_prefork(tsdn, &arena->extents_retained); } void -arena_prefork2(tsdn_t *tsdn, arena_t *arena) { +arena_prefork3(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_prefork(tsdn, &arena->extent_freelist_mtx); } void -arena_prefork3(tsdn_t *tsdn, arena_t *arena) { - unsigned i; - +arena_prefork4(tsdn_t *tsdn, arena_t *arena) { base_prefork(tsdn, arena->base); +} + +void +arena_prefork5(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_prefork(tsdn, &arena->large_mtx); - for (i = 0; i < NBINS; i++) { +} + +void +arena_prefork6(tsdn_t *tsdn, arena_t *arena) { + for (unsigned i = 0; i < NBINS; i++) { malloc_mutex_prefork(tsdn, &arena->bins[i].lock); } } diff --git a/src/jemalloc.c b/src/jemalloc.c index b5379cc4..ecfecf9c 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -2773,7 +2773,8 @@ _malloc_prefork(void) tcache_prefork(tsd_tsdn(tsd)); malloc_mutex_prefork(tsd_tsdn(tsd), &arenas_lock); prof_prefork0(tsd_tsdn(tsd)); - for (i = 0; i < 3; i++) { + /* Break arena prefork into stages to preserve lock order. */ + for (i = 0; i < 7; i++) { for (j = 0; j < narenas; j++) { if ((arena = arena_get(tsd_tsdn(tsd), j, false)) != NULL) { @@ -2787,16 +2788,23 @@ _malloc_prefork(void) case 2: arena_prefork2(tsd_tsdn(tsd), arena); break; + case 3: + arena_prefork3(tsd_tsdn(tsd), arena); + break; + case 4: + arena_prefork4(tsd_tsdn(tsd), arena); + break; + case 5: + arena_prefork5(tsd_tsdn(tsd), arena); + break; + case 6: + arena_prefork6(tsd_tsdn(tsd), arena); + break; default: not_reached(); } } } } - for (i = 0; i < narenas; i++) { - if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) { - arena_prefork3(tsd_tsdn(tsd), arena); - } - } prof_prefork1(tsd_tsdn(tsd)); } diff --git a/test/unit/fork.c b/test/unit/fork.c index 96b1c5a0..afe22141 100644 --- a/test/unit/fork.c +++ b/test/unit/fork.c @@ -9,6 +9,19 @@ TEST_BEGIN(test_fork) { void *p; pid_t pid; + /* Set up a manually managed arena for test. */ + unsigned arena_ind; + size_t sz = sizeof(unsigned); + assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), + 0, "Unexpected mallctl() failure"); + + /* Migrate to the new arena. */ + unsigned old_arena_ind; + sz = sizeof(old_arena_ind); + assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz, + (void *)&arena_ind, sizeof(arena_ind)), 0, + "Unexpected mallctl() failure"); + p = malloc(1); assert_ptr_not_null(p, "Unexpected malloc() failure"); -- GitLab From ec532e2c5c0b25fb7ab09383fe5a274583a90def Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Thu, 2 Feb 2017 17:02:05 -0800 Subject: [PATCH 317/544] Implement per-CPU arena. The new feature, opt.percpu_arena, determines thread-arena association dynamically based CPU id. Three modes are supported: "percpu", "phycpu" and disabled. "percpu" uses the current core id (with help from sched_getcpu()) directly as the arena index, while "phycpu" will assign threads on the same physical CPU to the same arena. In other words, "percpu" means # of arenas == # of CPUs, while "phycpu" has # of arenas == 1/2 * (# of CPUs). Note that no runtime check on whether hyper threading is enabled is added yet. When enabled, threads will be migrated between arenas when a CPU change is detected. In the current design, to reduce overhead from reading CPU id, each arena tracks the thread accessed most recently. When a new thread comes in, we will read CPU id and update arena if necessary. --- configure.ac | 9 ++ include/jemalloc/internal/arena_externs.h | 4 + include/jemalloc/internal/arena_inlines_a.h | 25 ++++ include/jemalloc/internal/arena_structs_b.h | 7 + include/jemalloc/internal/arena_types.h | 16 ++ .../jemalloc/internal/jemalloc_internal.h.in | 123 +++++++++++++--- .../internal/jemalloc_internal_defs.h.in | 3 + include/jemalloc/internal/private_symbols.txt | 4 + src/arena.c | 10 ++ src/ctl.c | 18 ++- src/jemalloc.c | 139 +++++++++++++++--- src/stats.c | 1 + src/tcache.c | 11 +- test/integration/thread_arena.c | 25 +++- test/unit/mallctl.c | 39 +++-- test/unit/stats.c | 98 ++++++------ 16 files changed, 414 insertions(+), 118 deletions(-) diff --git a/configure.ac b/configure.ac index 0095caf1..96b105f3 100644 --- a/configure.ac +++ b/configure.ac @@ -1598,6 +1598,15 @@ if test "x$have_secure_getenv" = "x1" ; then AC_DEFINE([JEMALLOC_HAVE_SECURE_GETENV], [ ]) fi +dnl Check if the GNU-specific sched_getcpu function exists. +AC_CHECK_FUNC([sched_getcpu], + [have_sched_getcpu="1"], + [have_sched_getcpu="0"] + ) +if test "x$have_sched_getcpu" = "x1" ; then + AC_DEFINE([JEMALLOC_HAVE_SCHED_GETCPU], [ ]) +fi + dnl Check if the Solaris/BSD issetugid function exists. AC_CHECK_FUNC([issetugid], [have_issetugid="1"], diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 2df55184..349bae99 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -13,6 +13,10 @@ extern ssize_t opt_decay_time; extern const arena_bin_info_t arena_bin_info[NBINS]; +extern percpu_arena_mode_t percpu_arena_mode; +extern const char *opt_percpu_arena; +extern const char *percpu_arena_mode_names[]; + void arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats, szind_t szind, uint64_t nrequests); void arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, diff --git a/include/jemalloc/internal/arena_inlines_a.h b/include/jemalloc/internal/arena_inlines_a.h index ea7e0995..9dd5304c 100644 --- a/include/jemalloc/internal/arena_inlines_a.h +++ b/include/jemalloc/internal/arena_inlines_a.h @@ -7,6 +7,7 @@ void arena_internal_add(arena_t *arena, size_t size); void arena_internal_sub(arena_t *arena, size_t size); size_t arena_internal_get(arena_t *arena); bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes); +void percpu_arena_update(tsd_t *tsd, unsigned cpu); #endif /* JEMALLOC_ENABLE_INLINE */ #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) @@ -42,6 +43,30 @@ arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) { return prof_accum_add(tsdn, &arena->prof_accum, accumbytes); } +JEMALLOC_INLINE void +percpu_arena_update(tsd_t *tsd, unsigned cpu) { + assert(have_percpu_arena); + arena_t *oldarena = tsd_arena_get(tsd); + assert(oldarena != NULL); + unsigned oldind = arena_ind_get(oldarena); + + if (oldind != cpu) { + unsigned newind = cpu; + arena_t *newarena = arena_get(tsd_tsdn(tsd), newind, true); + assert(newarena != NULL); + + /* Set new arena/tcache associations. */ + arena_migrate(tsd, oldind, newind); + if (config_tcache) { + tcache_t *tcache = tsd_tcache_get(tsd); + if (tcache) { + tcache_arena_reassociate(tsd_tsdn(tsd), tcache, + newarena); + } + } + } +} + #endif /* (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) */ #endif /* JEMALLOC_INTERNAL_ARENA_INLINES_A_H */ diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index ebcdbc4d..ba8bb8ad 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -125,6 +125,13 @@ struct arena_s { */ unsigned nthreads[2]; + /* + * When percpu_arena is enabled, to amortize the cost of reading / + * updating the current CPU id, track the most recent thread accessing + * this arena, and only read CPU if there is a mismatch. + */ + tsdn_t *last_thd; + /* Synchronization: internal. */ arena_stats_t stats; diff --git a/include/jemalloc/internal/arena_types.h b/include/jemalloc/internal/arena_types.h index d821be45..067c9ee9 100644 --- a/include/jemalloc/internal/arena_types.h +++ b/include/jemalloc/internal/arena_types.h @@ -19,4 +19,20 @@ typedef struct arena_bin_s arena_bin_t; typedef struct arena_s arena_t; typedef struct arena_tdata_s arena_tdata_t; +typedef enum { + percpu_arena_disabled = 0, + percpu_arena = 1, + per_phycpu_arena = 2, /* i.e. hyper threads share arena. */ + + percpu_arena_mode_limit = 3 +} percpu_arena_mode_t; + +#ifdef JEMALLOC_PERCPU_ARENA +#define PERCPU_ARENA_MODE_DEFAULT percpu_arena +#define OPT_PERCPU_ARENA_DEFAULT "percpu" +#else +#define PERCPU_ARENA_MODE_DEFAULT percpu_arena_disabled +#define OPT_PERCPU_ARENA_DEFAULT "disabled" +#endif + #endif /* JEMALLOC_INTERNAL_ARENA_TYPES_H */ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 8d2ec7dd..97b41bb0 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -145,6 +145,17 @@ static const bool have_thp = false #endif ; +#ifdef JEMALLOC_HAVE_SCHED_GETCPU +/* Currently percpu_arena depends on sched_getcpu. */ +#define JEMALLOC_PERCPU_ARENA +#endif +static const bool have_percpu_arena = +#ifdef JEMALLOC_PERCPU_ARENA + true +#else + false +#endif + ; #if (defined(JEMALLOC_OSATOMIC) || defined(JEMALLOC_OSSPIN)) #include @@ -220,6 +231,9 @@ typedef unsigned pszind_t; /* Size class index type. */ typedef unsigned szind_t; +/* Processor / core id type. */ +typedef int malloc_cpuid_t; + /* * Flags bits: * @@ -455,7 +469,7 @@ extern unsigned narenas_auto; * Arenas that are used to service external requests. Not all elements of the * arenas array are necessarily used; arenas are created lazily as needed. */ -extern arena_t **arenas; +extern arena_t *arenas[]; /* * pind2sz_tab encodes the same information as could be computed by @@ -548,6 +562,10 @@ arena_tdata_t *arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing); arena_t *arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing); ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind); +malloc_cpuid_t malloc_getcpu(void); +unsigned percpu_arena_choose(void); +unsigned percpu_arena_ind_limit(void); + #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) @@ -818,32 +836,53 @@ sa2u(size_t size, size_t alignment) { return usize; } -/* Choose an arena based on a per-thread value. */ -JEMALLOC_INLINE arena_t * -arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { - arena_t *ret; - - if (arena != NULL) { - return arena; - } +JEMALLOC_ALWAYS_INLINE malloc_cpuid_t +malloc_getcpu(void) { + assert(have_percpu_arena); +#if defined(JEMALLOC_HAVE_SCHED_GETCPU) + return (malloc_cpuid_t)sched_getcpu(); +#else + not_reached(); + return -1; +#endif +} - ret = internal ? tsd_iarena_get(tsd) : tsd_arena_get(tsd); - if (unlikely(ret == NULL)) { - ret = arena_choose_hard(tsd, internal); +/* Return the chosen arena index based on current cpu. */ +JEMALLOC_ALWAYS_INLINE unsigned +percpu_arena_choose(void) { + unsigned arena_ind; + assert(have_percpu_arena && (percpu_arena_mode != percpu_arena_disabled)); + + malloc_cpuid_t cpuid = malloc_getcpu(); + assert(cpuid >= 0); + if ((percpu_arena_mode == percpu_arena) || + ((unsigned)cpuid < ncpus / 2)) { + arena_ind = cpuid; + } else { + assert(percpu_arena_mode == per_phycpu_arena); + /* Hyper threads on the same physical CPU share arena. */ + arena_ind = cpuid - ncpus / 2; } - return ret; + return arena_ind; } -JEMALLOC_INLINE arena_t * -arena_choose(tsd_t *tsd, arena_t *arena) { - return arena_choose_impl(tsd, arena, false); +/* Return the limit of percpu auto arena range, i.e. arenas[0...ind_limit). */ +JEMALLOC_ALWAYS_INLINE unsigned +percpu_arena_ind_limit(void) { + assert(have_percpu_arena && (percpu_arena_mode != percpu_arena_disabled)); + if (percpu_arena_mode == per_phycpu_arena && ncpus > 1) { + if (ncpus % 2) { + /* This likely means a misconfig. */ + return ncpus / 2 + 1; + } + return ncpus / 2; + } else { + return ncpus; + } } -JEMALLOC_INLINE arena_t * -arena_ichoose(tsd_t *tsd, arena_t *arena) { - return arena_choose_impl(tsd, arena, true); -} + JEMALLOC_INLINE arena_tdata_t * arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing) { @@ -912,6 +951,50 @@ extent_t *iealloc(tsdn_t *tsdn, const void *ptr); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) +/* Choose an arena based on a per-thread value. */ +JEMALLOC_INLINE arena_t * +arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { + arena_t *ret; + + if (arena != NULL) { + return arena; + } + + ret = internal ? tsd_iarena_get(tsd) : tsd_arena_get(tsd); + if (unlikely(ret == NULL)) { + ret = arena_choose_hard(tsd, internal); + } + + assert(ret != NULL); + /* + * Note that for percpu arena, if the current arena is outside of the + * auto percpu arena range, (i.e. thread is assigned to a manually + * managed arena), then percpu arena is skipped. + */ + if (have_percpu_arena && (percpu_arena_mode != percpu_arena_disabled) && + (arena_ind_get(ret) < percpu_arena_ind_limit()) && + (ret->last_thd != tsd_tsdn(tsd))) { + unsigned ind = percpu_arena_choose(); + if (arena_ind_get(ret) != ind) { + percpu_arena_update(tsd, ind); + ret = tsd_arena_get(tsd); + } + ret->last_thd = tsd_tsdn(tsd); + } + + return ret; +} + +JEMALLOC_INLINE arena_t * +arena_choose(tsd_t *tsd, arena_t *arena) { + return arena_choose_impl(tsd, arena, false); +} + +JEMALLOC_INLINE arena_t * +arena_ichoose(tsd_t *tsd, arena_t *arena) { + return arena_choose_impl(tsd, arena, true); +} + JEMALLOC_ALWAYS_INLINE extent_t * iealloc(tsdn_t *tsdn, const void *ptr) { return extent_lookup(tsdn, ptr, true); diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index b2e0077e..500f4274 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -308,6 +308,9 @@ /* Adaptive mutex support in pthreads. */ #undef JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP +/* GNU specific sched_getcpu support */ +#undef JEMALLOC_HAVE_SCHED_GETCPU + /* * If defined, jemalloc symbols are not exported (doesn't work when * JEMALLOC_PREFIX is not defined). diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 64bea334..c0211e58 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -258,6 +258,7 @@ large_salloc lg_floor lg_prof_sample malloc_cprintf +malloc_getcpu malloc_mutex_assert_not_owner malloc_mutex_assert_owner malloc_mutex_boot @@ -330,6 +331,9 @@ pages_purge_forced pages_purge_lazy pages_trim pages_unmap +percpu_arena_choose +percpu_arena_ind_limit +percpu_arena_update pind2sz pind2sz_compute pind2sz_lookup diff --git a/src/arena.c b/src/arena.c index 43bad81c..a3a1fdd7 100644 --- a/src/arena.c +++ b/src/arena.c @@ -4,6 +4,15 @@ /******************************************************************************/ /* Data. */ +const char *percpu_arena_mode_names[] = { + "disabled", + "percpu", + "phycpu" +}; + +const char *opt_percpu_arena = OPT_PERCPU_ARENA_DEFAULT; +percpu_arena_mode_t percpu_arena_mode = PERCPU_ARENA_MODE_DEFAULT; + ssize_t opt_decay_time = DECAY_TIME_DEFAULT; static ssize_t decay_time_default; @@ -1629,6 +1638,7 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { } arena->nthreads[0] = arena->nthreads[1] = 0; + arena->last_thd = NULL; if (config_stats) { if (arena_stats_init(tsdn, &arena->stats)) { diff --git a/src/ctl.c b/src/ctl.c index 831877b0..d4ab699f 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -72,6 +72,7 @@ CTL_PROTO(config_xmalloc) CTL_PROTO(opt_abort) CTL_PROTO(opt_dss) CTL_PROTO(opt_narenas) +CTL_PROTO(opt_percpu_arena) CTL_PROTO(opt_decay_time) CTL_PROTO(opt_stats_print) CTL_PROTO(opt_junk) @@ -229,6 +230,7 @@ static const ctl_named_node_t opt_node[] = { {NAME("abort"), CTL(opt_abort)}, {NAME("dss"), CTL(opt_dss)}, {NAME("narenas"), CTL(opt_narenas)}, + {NAME("percpu_arena"), CTL(opt_percpu_arena)}, {NAME("decay_time"), CTL(opt_decay_time)}, {NAME("stats_print"), CTL(opt_stats_print)}, {NAME("junk"), CTL(opt_junk)}, @@ -1284,6 +1286,7 @@ CTL_RO_CONFIG_GEN(config_xmalloc, bool) CTL_RO_NL_GEN(opt_abort, opt_abort, bool) CTL_RO_NL_GEN(opt_dss, opt_dss, const char *) CTL_RO_NL_GEN(opt_narenas, opt_narenas, unsigned) +CTL_RO_NL_GEN(opt_percpu_arena, opt_percpu_arena, const char *) CTL_RO_NL_GEN(opt_decay_time, opt_decay_time, ssize_t) CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool) CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *) @@ -1317,10 +1320,10 @@ thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, if (oldarena == NULL) { return EAGAIN; } - newind = oldind = arena_ind_get(oldarena); WRITE(newind, unsigned); READ(oldind, unsigned); + if (newind != oldind) { arena_t *newarena; @@ -1330,6 +1333,19 @@ thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, goto label_return; } + if (have_percpu_arena && + (percpu_arena_mode != percpu_arena_disabled)) { + if (newind < percpu_arena_ind_limit()) { + /* + * If perCPU arena is enabled, thread_arena + * control is not allowed for the auto arena + * range. + */ + ret = EPERM; + goto label_return; + } + } + /* Initialize arena if necessary. */ newarena = arena_get(tsd_tsdn(tsd), newind, true); if (newarena == NULL) { diff --git a/src/jemalloc.c b/src/jemalloc.c index ecfecf9c..ce84b3cf 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -56,7 +56,8 @@ static malloc_mutex_t arenas_lock; * arenas. arenas[narenas_auto..narenas_total) are only used if the application * takes some action to create them and allocate from them. */ -arena_t **arenas; +JEMALLOC_ALIGNED(CACHELINE) +arena_t *arenas[MALLOCX_ARENA_MAX + 1]; static unsigned narenas_total; /* Use narenas_total_*(). */ static arena_t *a0; /* arenas[0]; read-only after initialization. */ unsigned narenas_auto; /* Read-only after initialization. */ @@ -543,6 +544,16 @@ arena_t * arena_choose_hard(tsd_t *tsd, bool internal) { arena_t *ret JEMALLOC_CC_SILENCE_INIT(NULL); + if (have_percpu_arena && percpu_arena_mode != percpu_arena_disabled) { + unsigned choose = percpu_arena_choose(); + ret = arena_get(tsd_tsdn(tsd), choose, true); + assert(ret != NULL); + arena_bind(tsd, arena_ind_get(ret), false); + arena_bind(tsd, arena_ind_get(ret), true); + + return ret; + } + if (narenas_auto > 1) { unsigned i, j, choose[2], first_null; @@ -1095,6 +1106,30 @@ malloc_conf_init(void) { "lg_tcache_max", -1, (sizeof(size_t) << 3) - 1) } + if (strncmp("percpu_arena", k, klen) == 0) { + int i; + bool match = false; + for (i = 0; i < percpu_arena_mode_limit; i++) { + if (strncmp(percpu_arena_mode_names[i], + v, vlen) == 0) { + if (!have_percpu_arena) { + malloc_conf_error( + "No getcpu support", + k, klen, v, vlen); + } + percpu_arena_mode = i; + opt_percpu_arena = + percpu_arena_mode_names[i]; + match = true; + break; + } + } + if (!match) { + malloc_conf_error("Invalid conf value", + k, klen, v, vlen); + } + continue; + } if (config_prof) { CONF_HANDLE_BOOL(opt_prof, "prof", true) CONF_HANDLE_CHAR_P(opt_prof_prefix, @@ -1204,8 +1239,6 @@ malloc_init_hard_a0_locked() { * malloc_ncpus(). */ narenas_auto = 1; - narenas_total_set(narenas_auto); - arenas = &a0; memset(arenas, 0, sizeof(arena_t *) * narenas_auto); /* * Initialize one arena here. The rest are lazily created in @@ -1215,7 +1248,7 @@ malloc_init_hard_a0_locked() { == NULL) { return true; } - + a0 = arena_get(TSDN_NULL, 0, false); malloc_init_state = malloc_init_a0_initialized; return false; @@ -1255,23 +1288,76 @@ malloc_init_hard_recursible(void) { return false; } -static bool -malloc_init_hard_finish(tsdn_t *tsdn) { - if (malloc_mutex_boot()) { - return true; +static unsigned +malloc_narenas_default(void) { + assert(ncpus > 0); + /* + * For SMP systems, create more than one arena per CPU by + * default. + */ + if (ncpus > 1) { + return ncpus << 2; + } else { + return 1; } +} - if (opt_narenas == 0) { - /* - * For SMP systems, create more than one arena per CPU by - * default. - */ - if (ncpus > 1) { - opt_narenas = ncpus << 2; +static bool +malloc_init_narenas(void) { + assert(ncpus > 0); + + if (percpu_arena_mode != percpu_arena_disabled) { + if (!have_percpu_arena || malloc_getcpu() < 0) { + percpu_arena_mode = percpu_arena_disabled; + malloc_printf(": perCPU arena getcpu() not " + "available. Setting narenas to %u.\n", opt_narenas ? + opt_narenas : malloc_narenas_default()); + if (opt_abort) { + abort(); + } } else { - opt_narenas = 1; + if (ncpus > MALLOCX_ARENA_MAX) { + malloc_printf(": narenas w/ percpu" + "arena beyond limit (%d)\n", ncpus); + if (opt_abort) { + abort(); + } + return true; + } + if ((percpu_arena_mode == per_phycpu_arena) && + (ncpus % 2 != 0)) { + malloc_printf(": invalid " + "configuration -- per physical CPU arena " + "with odd number (%u) of CPUs (no hyper " + "threading?).\n", ncpus); + if (opt_abort) + abort(); + } + unsigned n = percpu_arena_ind_limit(); + if (opt_narenas < n) { + /* + * If narenas is specified with percpu_arena + * enabled, actual narenas is set as the greater + * of the two. percpu_arena_choose will be free + * to use any of the arenas based on CPU + * id. This is conservative (at a small cost) + * but ensures correctness. + * + * If for some reason the ncpus determined at + * boot is not the actual number (e.g. because + * of affinity setting from numactl), reserving + * narenas this way provides a workaround for + * percpu_arena. + */ + opt_narenas = n; + } } } + if (opt_narenas == 0) { + opt_narenas = malloc_narenas_default(); + } + assert(opt_narenas > 0); + narenas_auto = opt_narenas; /* * Limit the number of arenas to the indexing range of MALLOCX_ARENA(). @@ -1283,14 +1369,13 @@ malloc_init_hard_finish(tsdn_t *tsdn) { } narenas_total_set(narenas_auto); - /* Allocate and initialize arenas. */ - arenas = (arena_t **)base_alloc(tsdn, a0->base, sizeof(arena_t *) * - (MALLOCX_ARENA_MAX+1), CACHELINE); - if (arenas == NULL) { + return false; +} + +static bool +malloc_init_hard_finish(void) { + if (malloc_mutex_boot()) return true; - } - /* Copy the pointer to the one arena that was already initialized. */ - arena_set(0, a0); malloc_init_state = malloc_init_initialized; malloc_slow_flag_init(); @@ -1328,12 +1413,18 @@ malloc_init_hard(void) { } malloc_mutex_lock(tsd_tsdn(tsd), &init_lock); + /* Need this before prof_boot2 (for allocation). */ + if (malloc_init_narenas()) { + malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); + return true; + } + if (config_prof && prof_boot2(tsd)) { malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); return true; } - if (malloc_init_hard_finish(tsd_tsdn(tsd))) { + if (malloc_init_hard_finish()) { malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); return true; } diff --git a/src/stats.c b/src/stats.c index ae360e1b..776fb862 100644 --- a/src/stats.c +++ b/src/stats.c @@ -621,6 +621,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, OPT_WRITE_BOOL(abort, ",") OPT_WRITE_CHAR_P(dss, ",") OPT_WRITE_UNSIGNED(narenas, ",") + OPT_WRITE_CHAR_P(percpu_arena, ",") OPT_WRITE_SSIZE_T_MUTABLE(decay_time, arenas.decay_time, ",") OPT_WRITE_CHAR_P(junk, ",") OPT_WRITE_BOOL(zero, ",") diff --git a/src/tcache.c b/src/tcache.c index 78570663..266bd1f5 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -357,12 +357,8 @@ tcache_create(tsdn_t *tsdn, arena_t *arena) { static void tcache_destroy(tsd_t *tsd, tcache_t *tcache) { - arena_t *arena; unsigned i; - arena = arena_choose(tsd, NULL); - tcache_arena_dissociate(tsd_tsdn(tsd), tcache); - for (i = 0; i < NBINS; i++) { tcache_bin_t *tbin = &tcache->tbins[i]; tcache_bin_flush_small(tsd, tcache, tbin, i, 0); @@ -381,6 +377,13 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache) { } } + /* + * Get arena after flushing -- when using percpu arena, the associated + * arena could change during flush. + */ + arena_t *arena = arena_choose(tsd, NULL); + tcache_arena_dissociate(tsd_tsdn(tsd), tcache); + if (config_prof && tcache->prof_accumbytes > 0 && arena_prof_accum(tsd_tsdn(tsd), arena, tcache->prof_accumbytes)) { prof_idump(tsd_tsdn(tsd)); diff --git a/test/integration/thread_arena.c b/test/integration/thread_arena.c index 9991a42f..1e5ec05d 100644 --- a/test/integration/thread_arena.c +++ b/test/integration/thread_arena.c @@ -37,10 +37,16 @@ thd_start(void *arg) { return NULL; } +static void +mallctl_failure(int err) { + char buf[BUFERROR_BUF]; + + buferror(err, buf, sizeof(buf)); + test_fail("Error in mallctl(): %s", buf); +} + TEST_BEGIN(test_thread_arena) { void *p; - unsigned arena_ind; - size_t size; int err; thd_t thds[NTHREADS]; unsigned i; @@ -48,13 +54,15 @@ TEST_BEGIN(test_thread_arena) { p = malloc(1); assert_ptr_not_null(p, "Error in malloc()"); - size = sizeof(arena_ind); - if ((err = mallctl("thread.arena", (void *)&arena_ind, &size, NULL, - 0))) { - char buf[BUFERROR_BUF]; + unsigned arena_ind, old_arena_ind; + size_t sz = sizeof(unsigned); + assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), + 0, "Arena creation failure"); - buferror(err, buf, sizeof(buf)); - test_fail("Error in mallctl(): %s", buf); + size_t size = sizeof(arena_ind); + if ((err = mallctl("thread.arena", (void *)&old_arena_ind, &size, + (void *)&arena_ind, sizeof(arena_ind))) != 0) { + mallctl_failure(err); } for (i = 0; i < NTHREADS; i++) { @@ -67,6 +75,7 @@ TEST_BEGIN(test_thread_arena) { thd_join(thds[i], (void *)&join_ret); assert_zd_eq(join_ret, 0, "Unexpected thread join error"); } + free(p); } TEST_END diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index c931e378..1aedbe8a 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -160,6 +160,7 @@ TEST_BEGIN(test_mallctl_opt) { TEST_MALLCTL_OPT(bool, abort, always); TEST_MALLCTL_OPT(const char *, dss, always); TEST_MALLCTL_OPT(unsigned, narenas, always); + TEST_MALLCTL_OPT(const char *, percpu_arena, always); TEST_MALLCTL_OPT(ssize_t, decay_time, always); TEST_MALLCTL_OPT(bool, stats_print, always); TEST_MALLCTL_OPT(const char *, junk, fill); @@ -327,20 +328,38 @@ TEST_BEGIN(test_tcache) { TEST_END TEST_BEGIN(test_thread_arena) { - unsigned arena_old, arena_new, narenas; - size_t sz = sizeof(unsigned); + unsigned old_arena_ind, new_arena_ind, narenas; + const char *opt_percpu_arena; + + size_t sz = sizeof(opt_percpu_arena); + assert_d_eq(mallctl("opt.percpu_arena", &opt_percpu_arena, &sz, NULL, + 0), 0, "Unexpected mallctl() failure"); + sz = sizeof(unsigned); assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); assert_u_eq(narenas, opt_narenas, "Number of arenas incorrect"); - arena_new = narenas - 1; - assert_d_eq(mallctl("thread.arena", (void *)&arena_old, &sz, - (void *)&arena_new, sizeof(unsigned)), 0, - "Unexpected mallctl() failure"); - arena_new = 0; - assert_d_eq(mallctl("thread.arena", (void *)&arena_old, &sz, - (void *)&arena_new, sizeof(unsigned)), 0, - "Unexpected mallctl() failure"); + + if (strcmp(opt_percpu_arena, "disabled") == 0) { + new_arena_ind = narenas - 1; + assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz, + (void *)&new_arena_ind, sizeof(unsigned)), 0, + "Unexpected mallctl() failure"); + new_arena_ind = 0; + assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz, + (void *)&new_arena_ind, sizeof(unsigned)), 0, + "Unexpected mallctl() failure"); + } else { + assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz, + NULL, 0), 0, "Unexpected mallctl() failure"); + new_arena_ind = percpu_arena_ind_limit() - 1; + if (old_arena_ind != new_arena_ind) { + assert_d_eq(mallctl("thread.arena", + (void *)&old_arena_ind, &sz, (void *)&new_arena_ind, + sizeof(unsigned)), EPERM, "thread.arena ctl " + "should not be allowed with percpu arena"); + } + } } TEST_END diff --git a/test/unit/stats.c b/test/unit/stats.c index 948132cb..c458d3f9 100644 --- a/test/unit/stats.c +++ b/test/unit/stats.c @@ -33,7 +33,7 @@ TEST_BEGIN(test_stats_large) { size_t sz; int expected = config_stats ? 0 : ENOENT; - p = mallocx(SMALL_MAXCLASS+1, 0); + p = mallocx(SMALL_MAXCLASS+1, MALLOCX_ARENA(0)); assert_ptr_not_null(p, "Unexpected mallocx() failure"); assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), @@ -66,7 +66,6 @@ TEST_BEGIN(test_stats_large) { TEST_END TEST_BEGIN(test_stats_arenas_summary) { - unsigned arena; void *little, *large; uint64_t epoch; size_t sz; @@ -74,13 +73,9 @@ TEST_BEGIN(test_stats_arenas_summary) { size_t mapped; uint64_t npurge, nmadvise, purged; - arena = 0; - assert_d_eq(mallctl("thread.arena", NULL, NULL, (void *)&arena, - sizeof(arena)), 0, "Unexpected mallctl() failure"); - - little = mallocx(SMALL_MAXCLASS, 0); + little = mallocx(SMALL_MAXCLASS, MALLOCX_ARENA(0)); assert_ptr_not_null(little, "Unexpected mallocx() failure"); - large = mallocx((1U << LG_LARGE_MINCLASS), 0); + large = mallocx((1U << LG_LARGE_MINCLASS), MALLOCX_ARENA(0)); assert_ptr_not_null(large, "Unexpected mallocx() failure"); dallocx(little, 0); @@ -128,7 +123,6 @@ no_lazy_lock(void) { } TEST_BEGIN(test_stats_arenas_small) { - unsigned arena; void *p; size_t sz, allocated; uint64_t epoch, nmalloc, ndalloc, nrequests; @@ -136,11 +130,7 @@ TEST_BEGIN(test_stats_arenas_small) { no_lazy_lock(); /* Lazy locking would dodge tcache testing. */ - arena = 0; - assert_d_eq(mallctl("thread.arena", NULL, NULL, (void *)&arena, - sizeof(arena)), 0, "Unexpected mallctl() failure"); - - p = mallocx(SMALL_MAXCLASS, 0); + p = mallocx(SMALL_MAXCLASS, MALLOCX_ARENA(0)); assert_ptr_not_null(p, "Unexpected mallocx() failure"); assert_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), @@ -178,17 +168,12 @@ TEST_BEGIN(test_stats_arenas_small) { TEST_END TEST_BEGIN(test_stats_arenas_large) { - unsigned arena; void *p; size_t sz, allocated; uint64_t epoch, nmalloc, ndalloc; int expected = config_stats ? 0 : ENOENT; - arena = 0; - assert_d_eq(mallctl("thread.arena", NULL, NULL, (void *)&arena, - sizeof(arena)), 0, "Unexpected mallctl() failure"); - - p = mallocx((1U << LG_LARGE_MINCLASS), 0); + p = mallocx((1U << LG_LARGE_MINCLASS), MALLOCX_ARENA(0)); assert_ptr_not_null(p, "Unexpected mallocx() failure"); assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), @@ -217,20 +202,29 @@ TEST_BEGIN(test_stats_arenas_large) { } TEST_END +static void +gen_mallctl_str(char *cmd, char *name, unsigned arena_ind) { + sprintf(cmd, "stats.arenas.%u.bins.0.%s", arena_ind, name); +} + TEST_BEGIN(test_stats_arenas_bins) { - unsigned arena; void *p; size_t sz, curslabs, curregs; uint64_t epoch, nmalloc, ndalloc, nrequests, nfills, nflushes; uint64_t nslabs, nreslabs; int expected = config_stats ? 0 : ENOENT; - arena = 0; - assert_d_eq(mallctl("thread.arena", NULL, NULL, (void *)&arena, - sizeof(arena)), 0, "Unexpected mallctl() failure"); + unsigned arena_ind, old_arena_ind; + sz = sizeof(unsigned); + assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), + 0, "Arena creation failure"); + sz = sizeof(arena_ind); + assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz, + (void *)&arena_ind, sizeof(arena_ind)), 0, + "Unexpected mallctl() failure"); - p = mallocx(arena_bin_info[0].reg_size, 0); - assert_ptr_not_null(p, "Unexpected mallocx() failure"); + p = malloc(arena_bin_info[0].reg_size); + assert_ptr_not_null(p, "Unexpected malloc() failure"); assert_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), config_tcache ? 0 : ENOENT, "Unexpected mallctl() result"); @@ -238,33 +232,40 @@ TEST_BEGIN(test_stats_arenas_bins) { assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), 0, "Unexpected mallctl() failure"); + char cmd[128]; sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.bins.0.nmalloc", (void *)&nmalloc, - &sz, NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.bins.0.ndalloc", (void *)&ndalloc, - &sz, NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.bins.0.nrequests", - (void *)&nrequests, &sz, NULL, 0), expected, + gen_mallctl_str(cmd, "nmalloc", arena_ind); + assert_d_eq(mallctl(cmd, (void *)&nmalloc, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); + gen_mallctl_str(cmd, "ndalloc", arena_ind); + assert_d_eq(mallctl(cmd, (void *)&ndalloc, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); + gen_mallctl_str(cmd, "nrequests", arena_ind); + assert_d_eq(mallctl(cmd, (void *)&nrequests, &sz, NULL, 0), expected, "Unexpected mallctl() result"); sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.bins.0.curregs", (void *)&curregs, - &sz, NULL, 0), expected, "Unexpected mallctl() result"); + gen_mallctl_str(cmd, "curregs", arena_ind); + assert_d_eq(mallctl(cmd, (void *)&curregs, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.bins.0.nfills", (void *)&nfills, - &sz, NULL, 0), config_tcache ? expected : ENOENT, + gen_mallctl_str(cmd, "nfills", arena_ind); + assert_d_eq(mallctl(cmd, (void *)&nfills, &sz, NULL, 0), + config_tcache ? expected : ENOENT, "Unexpected mallctl() result"); + gen_mallctl_str(cmd, "nflushes", arena_ind); + assert_d_eq(mallctl(cmd, (void *)&nflushes, &sz, NULL, 0), + config_tcache ? expected : ENOENT, "Unexpected mallctl() result"); + + gen_mallctl_str(cmd, "nslabs", arena_ind); + assert_d_eq(mallctl(cmd, (void *)&nslabs, &sz, NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.bins.0.nflushes", (void *)&nflushes, - &sz, NULL, 0), config_tcache ? expected : ENOENT, + gen_mallctl_str(cmd, "nreslabs", arena_ind); + assert_d_eq(mallctl(cmd, (void *)&nreslabs, &sz, NULL, 0), expected, "Unexpected mallctl() result"); - - assert_d_eq(mallctl("stats.arenas.0.bins.0.nslabs", (void *)&nslabs, - &sz, NULL, 0), expected, "Unexpected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.bins.0.nreslabs", (void *)&nreslabs, - &sz, NULL, 0), expected, "Unexpected mallctl() result"); sz = sizeof(size_t); - assert_d_eq(mallctl("stats.arenas.0.bins.0.curslabs", (void *)&curslabs, - &sz, NULL, 0), expected, "Unexpected mallctl() result"); + gen_mallctl_str(cmd, "curslabs", arena_ind); + assert_d_eq(mallctl(cmd, (void *)&curslabs, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); if (config_stats) { assert_u64_gt(nmalloc, 0, @@ -292,21 +293,16 @@ TEST_BEGIN(test_stats_arenas_bins) { TEST_END TEST_BEGIN(test_stats_arenas_lextents) { - unsigned arena; void *p; uint64_t epoch, nmalloc, ndalloc; size_t curlextents, sz, hsize; int expected = config_stats ? 0 : ENOENT; - arena = 0; - assert_d_eq(mallctl("thread.arena", NULL, NULL, (void *)&arena, - sizeof(arena)), 0, "Unexpected mallctl() failure"); - sz = sizeof(size_t); assert_d_eq(mallctl("arenas.lextent.0.size", (void *)&hsize, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); - p = mallocx(hsize, 0); + p = mallocx(hsize, MALLOCX_ARENA(0)); assert_ptr_not_null(p, "Unexpected mallocx() failure"); assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), -- GitLab From f84471edc37dbf8ff86a36d71c988ee4d8e6c5f9 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 7 Mar 2017 15:08:29 -0800 Subject: [PATCH 318/544] Add documentation for percpu_arena in jemalloc.xml.in. --- doc/jemalloc.xml.in | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 36ec140b..937879a8 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -926,6 +926,24 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", number of CPUs, or one if there is a single CPU. + + + opt.percpu_arena + (const char *) + r- + + Per CPU arena mode. Use the percpu + setting to enable this feature, which uses number of CPUs to determine + number of arenas, and bind threads to arenas dynamically based on the + CPU the thread runs on currently. phycpu setting uses + one arena per physical CPU, which means the two hyper threads on the + same CPU share one arena. Note that no runtime checking regarding the + availability of hyper threading is done at the moment. When set to + disabled, narenas and thread to arena association will + not be impacted by this option. The default is + percpu. + + opt.decay_time -- GitLab From 75fddc786c9d5476cab1d5d4699e95d8907d0b51 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 8 Mar 2017 23:32:53 -0800 Subject: [PATCH 319/544] Fix ATOMIC_{ACQUIRE,RELEASE,ACQ_REL} definitions. --- include/jemalloc/internal/atomic.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/jemalloc/internal/atomic.h b/include/jemalloc/internal/atomic.h index acbb6216..b68440c4 100644 --- a/include/jemalloc/internal/atomic.h +++ b/include/jemalloc/internal/atomic.h @@ -39,9 +39,9 @@ * quite so often. */ #define ATOMIC_RELAXED atomic_memory_order_relaxed -#define ATOMIC_ACQUIRE atomic_memory_order_acquire, -#define ATOMIC_RELEASE atomic_memory_order_release, -#define ATOMIC_ACQ_REL atomic_memory_order_acq_rel, +#define ATOMIC_ACQUIRE atomic_memory_order_acquire +#define ATOMIC_RELEASE atomic_memory_order_release +#define ATOMIC_ACQ_REL atomic_memory_order_acq_rel #define ATOMIC_SEQ_CST atomic_memory_order_seq_cst /* -- GitLab From 3a2b183d5fe86132d0830f720b3b8dbd6a29f7e9 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 7 Mar 2017 19:18:27 -0800 Subject: [PATCH 320/544] Convert arena_t's purging field to non-atomic bool. The decay mutex already protects all accesses. --- include/jemalloc/internal/arena_structs_b.h | 15 +++++++-------- src/arena.c | 9 +++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index ba8bb8ad..84c179e8 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -167,14 +167,6 @@ struct arena_s { /* Synchronization: atomic. */ dss_prec_t dss_prec; - /* - * 1/0 (true/false) if a thread is currently executing - * arena_purge_to_limit(). - * - * Synchronization: atomic. - */ - unsigned purging; - /* * Number of pages in active extents. * @@ -207,6 +199,13 @@ struct arena_s { extents_t extents_cached; extents_t extents_retained; + /* + * True if a thread is currently executing arena_purge_to_limit(). + * + * Synchronization: decay.mtx. + */ + bool purging; + /* * Next extent size class in a growing series to use when satisfying a * request via the extent hooks (only if !config_munmap). This limits diff --git a/src/arena.c b/src/arena.c index a3a1fdd7..cb0194ae 100644 --- a/src/arena.c +++ b/src/arena.c @@ -777,9 +777,10 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 1); malloc_mutex_assert_owner(tsdn, &arena->decay.mtx); - if (atomic_cas_u(&arena->purging, 0, 1)) { + if (arena->purging) { return; } + arena->purging = true; extent_hooks_t *extent_hooks = extent_hooks_get(arena); size_t npurge, npurged; @@ -809,7 +810,7 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) { } label_return: - atomic_write_u(&arena->purging, 0); + arena->purging = false; } void @@ -934,7 +935,6 @@ arena_reset(tsd_t *tsd, arena_t *arena) { malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); } - assert(atomic_read_u(&arena->purging) == 0); atomic_write_zu(&arena->nactive, 0); } @@ -1676,7 +1676,6 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena->dss_prec = extent_dss_prec_get(); - atomic_write_u(&arena->purging, 0); atomic_write_zu(&arena->nactive, 0); if (arena_decay_init(arena, arena_decay_time_default_get())) { @@ -1710,6 +1709,8 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { goto label_error; } + arena->purging = false; + if (!config_munmap) { arena->extent_grow_next = psz2ind(HUGEPAGE); } -- GitLab From 21a68e2d22da08e0f60ff79d6866dd3add19775b Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Thu, 9 Mar 2017 14:49:32 -0800 Subject: [PATCH 321/544] Convert rtree code to use C11 atomics In the process, I changed the implementation of rtree_elm_acquire so that it won't even try to CAS if its initial read (getting the extent + lock bit) indicates that the CAS is doomed to fail. This can significantly improve performance under contention. --- include/jemalloc/internal/rtree_inlines.h | 36 ++++++++++------ include/jemalloc/internal/rtree_structs.h | 15 +++---- src/rtree.c | 50 +++++++++++++++-------- 3 files changed, 62 insertions(+), 39 deletions(-) diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index f2efd710..b3301095 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -55,14 +55,16 @@ rtree_elm_read(rtree_elm_t *elm, bool dependent) { * synchronization, because the rtree update became visible in * memory before the pointer came into existence. */ - extent = elm->extent; + extent = (extent_t *)atomic_load_p(&elm->child_or_extent, + ATOMIC_RELAXED); } else { /* * An arbitrary read, e.g. on behalf of ivsalloc(), may not be * dependent on a previous rtree write, which means a stale read * could result if synchronization were omitted here. */ - extent = (extent_t *)atomic_read_p(&elm->pun); + extent = (extent_t *)atomic_load_p(&elm->child_or_extent, + ATOMIC_ACQUIRE); } /* Mask the lock bit. */ @@ -73,7 +75,7 @@ rtree_elm_read(rtree_elm_t *elm, bool dependent) { JEMALLOC_INLINE void rtree_elm_write(rtree_elm_t *elm, const extent_t *extent) { - atomic_write_p(&elm->pun, extent); + atomic_store_p(&elm->child_or_extent, (void *)extent, ATOMIC_RELEASE); } JEMALLOC_ALWAYS_INLINE rtree_elm_t * @@ -161,11 +163,18 @@ rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, spin_t spinner = SPIN_INITIALIZER; while (true) { - extent_t *extent = rtree_elm_read(elm, false); /* The least significant bit serves as a lock. */ - void *s = (void *)((uintptr_t)extent | (uintptr_t)0x1); - if (!atomic_cas_p(&elm->pun, (void *)extent, s)) { - break; + void *extent_and_lock = atomic_load_p(&elm->child_or_extent, + ATOMIC_RELAXED); + if (likely(((uintptr_t)extent_and_lock & (uintptr_t)0x1) == 0)) + { + void *locked = (void *)((uintptr_t)extent_and_lock + | (uintptr_t)0x1); + if (likely(atomic_compare_exchange_strong_p( + &elm->child_or_extent, &extent_and_lock, locked, + ATOMIC_ACQUIRE, ATOMIC_RELAXED))) { + break; + } } spin_adaptive(&spinner); } @@ -180,9 +189,9 @@ rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, JEMALLOC_INLINE extent_t * rtree_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm) { extent_t *extent; - - assert(((uintptr_t)elm->pun & (uintptr_t)0x1) == (uintptr_t)0x1); - extent = (extent_t *)((uintptr_t)elm->pun & ~((uintptr_t)0x1)); + void *ptr = atomic_load_p(&elm->child_or_extent, ATOMIC_RELAXED); + assert(((uintptr_t)ptr & (uintptr_t)0x1) == (uintptr_t)0x1); + extent = (extent_t *)((uintptr_t)ptr & ~((uintptr_t)0x1)); assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); if (config_debug) { @@ -196,13 +205,14 @@ JEMALLOC_INLINE void rtree_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm, const extent_t *extent) { assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); - assert(((uintptr_t)elm->pun & (uintptr_t)0x1) == (uintptr_t)0x1); + assert(((uintptr_t)atomic_load_p(&elm->child_or_extent, ATOMIC_RELAXED) + & (uintptr_t)0x1) == (uintptr_t)0x1); if (config_debug) { rtree_elm_witness_access(tsdn, rtree, elm); } - - elm->pun = (void *)((uintptr_t)extent | (uintptr_t)0x1); + atomic_store_p(&elm->child_or_extent, (void *)((uintptr_t)extent + | (uintptr_t)0x1), ATOMIC_RELEASE); assert(rtree_elm_read_acquired(tsdn, rtree, elm) == extent); } diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h index 312171e3..b62c489d 100644 --- a/include/jemalloc/internal/rtree_structs.h +++ b/include/jemalloc/internal/rtree_structs.h @@ -2,11 +2,8 @@ #define JEMALLOC_INTERNAL_RTREE_STRUCTS_H struct rtree_elm_s { - union { - void *pun; - rtree_elm_t *child; - extent_t *extent; - }; + /* Either "rtree_elm_t *child;" or "extent_t *extent;". */ + atomic_p_t child_or_extent; }; struct rtree_elm_witness_s { @@ -41,11 +38,9 @@ struct rtree_ctx_s { }; struct rtree_s { - union { - void *root_pun; - rtree_elm_t *root; - }; - malloc_mutex_t init_lock; + /* An rtree_elm_t *. */ + atomic_p_t root; + malloc_mutex_t init_lock; }; #endif /* JEMALLOC_INTERNAL_RTREE_STRUCTS_H */ diff --git a/src/rtree.c b/src/rtree.c index a86fa45d..54dc3487 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -7,7 +7,7 @@ */ bool rtree_new(rtree_t *rtree) { - rtree->root_pun = NULL; + atomic_store_p(&rtree->root, NULL, ATOMIC_RELAXED); if (malloc_mutex_init(&rtree->init_lock, "rtree", WITNESS_RANK_RTREE)) { return true; } @@ -54,7 +54,8 @@ rtree_delete_subtree(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node, nchildren = ZU(1) << rtree_levels[level].bits; for (i = 0; i < nchildren; i++) { - rtree_elm_t *child = node[i].child; + rtree_elm_t *child = (rtree_elm_t *)atomic_load_p( + &node[i].child_or_extent, ATOMIC_RELAXED); if (child != NULL) { rtree_delete_subtree(tsdn, rtree, child, level + 1); @@ -66,19 +67,25 @@ rtree_delete_subtree(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node, void rtree_delete(tsdn_t *tsdn, rtree_t *rtree) { - if (rtree->root_pun != NULL) { - rtree_delete_subtree(tsdn, rtree, rtree->root, 0); + rtree_elm_t *rtree_root = (rtree_elm_t *)atomic_load_p(&rtree->root, + ATOMIC_RELAXED); + if (rtree_root != NULL) { + rtree_delete_subtree(tsdn, rtree, rtree_root, 0); } } #endif static rtree_elm_t * rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level, - rtree_elm_t **elmp) { + atomic_p_t *elmp) { rtree_elm_t *node; malloc_mutex_lock(tsdn, &rtree->init_lock); - node = atomic_read_p((void**)elmp); + /* + * If *elmp is non-null, then it was initialized with the init lock + * held, so we can get by with 'relaxed' here. + */ + node = atomic_load_p(elmp, ATOMIC_RELAXED); if (node == NULL) { node = rtree_node_alloc(tsdn, rtree, ZU(1) << rtree_levels[level].bits); @@ -86,7 +93,11 @@ rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level, malloc_mutex_unlock(tsdn, &rtree->init_lock); return NULL; } - atomic_write_p((void **)elmp, node); + /* + * Even though we hold the lock, a later reader might not; we + * need release semantics. + */ + atomic_store_p(elmp, node, ATOMIC_RELEASE); } malloc_mutex_unlock(tsdn, &rtree->init_lock); @@ -102,11 +113,14 @@ static rtree_elm_t * rtree_child_tryread(rtree_elm_t *elm, bool dependent) { rtree_elm_t *child; - /* Double-checked read (first read may be stale). */ - child = elm->child; - if (!dependent && !rtree_node_valid(child)) { - child = (rtree_elm_t *)atomic_read_p(&elm->pun); + if (dependent) { + child = (rtree_elm_t *)atomic_load_p(&elm->child_or_extent, + ATOMIC_RELAXED); + } else { + child = (rtree_elm_t *)atomic_load_p(&elm->child_or_extent, + ATOMIC_ACQUIRE); } + assert(!dependent || child != NULL); return child; } @@ -118,7 +132,8 @@ rtree_child_read(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level, child = rtree_child_tryread(elm, dependent); if (!dependent && unlikely(!rtree_node_valid(child))) { - child = rtree_node_init(tsdn, rtree, level+1, &elm->child); + child = rtree_node_init(tsdn, rtree, level + 1, + &elm->child_or_extent); } assert(!dependent || child != NULL); return child; @@ -126,10 +141,13 @@ rtree_child_read(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level, static rtree_elm_t * rtree_subtree_tryread(rtree_t *rtree, bool dependent) { - /* Double-checked read (first read may be stale). */ - rtree_elm_t *subtree = rtree->root; - if (!dependent && unlikely(!rtree_node_valid(subtree))) { - subtree = (rtree_elm_t *)atomic_read_p(&rtree->root_pun); + rtree_elm_t *subtree; + if (dependent) { + subtree = (rtree_elm_t *)atomic_load_p(&rtree->root, + ATOMIC_RELAXED); + } else { + subtree = (rtree_elm_t *)atomic_load_p(&rtree->root, + ATOMIC_ACQUIRE); } assert(!dependent || subtree != NULL); return subtree; -- GitLab From 7cbcd2e2b70d9a8547030b5a8640c85b2b7b50ab Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 9 Mar 2017 18:20:02 -0800 Subject: [PATCH 322/544] Fix pages_purge_forced() to discard pages on non-Linux systems. madvise(..., MADV_DONTNEED) only causes demand-zeroing on Linux, so fall back to overlaying a new mapping. --- configure.ac | 2 ++ include/jemalloc/internal/jemalloc_internal_defs.h.in | 11 ++++++++--- include/jemalloc/internal/pages_types.h | 4 +++- src/pages.c | 9 ++++++++- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 96b105f3..db42a505 100644 --- a/configure.ac +++ b/configure.ac @@ -547,6 +547,7 @@ case "${host}" in dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE) abi="elf" + AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS]) AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) @@ -558,6 +559,7 @@ case "${host}" in dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE) abi="elf" + AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS]) AC_DEFINE([JEMALLOC_HAS_ALLOCA_H]) AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 500f4274..28eb0b34 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -265,12 +265,17 @@ * * madvise(..., MADV_FREE) : This marks pages as being unused, such that they * will be discarded rather than swapped out. - * madvise(..., MADV_DONTNEED) : This immediately discards pages, such that - * new pages will be demand-zeroed if the - * address region is later touched. + * madvise(..., MADV_DONTNEED) : If JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS is + * defined, this immediately discards pages, + * such that new pages will be demand-zeroed if + * the address region is later touched; + * otherwise this behaves similarly to + * MADV_FREE, though typically with higher + * system overhead. */ #undef JEMALLOC_PURGE_MADVISE_FREE #undef JEMALLOC_PURGE_MADVISE_DONTNEED +#undef JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS /* * Defined if transparent huge pages are supported via the MADV_[NO]HUGEPAGE diff --git a/include/jemalloc/internal/pages_types.h b/include/jemalloc/internal/pages_types.h index 9e6e7c5c..e44ee2a4 100644 --- a/include/jemalloc/internal/pages_types.h +++ b/include/jemalloc/internal/pages_types.h @@ -37,7 +37,9 @@ * next step after purging on Windows anyway, there's no point in adding such * complexity. */ -#if !defined(_WIN32) && defined(JEMALLOC_PURGE_MADVISE_DONTNEED) +#if !defined(_WIN32) && ((defined(JEMALLOC_PURGE_MADVISE_DONTNEED) && \ + defined(JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS)) || \ + defined(JEMALLOC_MAPS_COALESCE)) # define PAGES_CAN_PURGE_FORCED #endif diff --git a/src/pages.c b/src/pages.c index 444a97c2..e80c3652 100644 --- a/src/pages.c +++ b/src/pages.c @@ -170,6 +170,9 @@ pages_purge_lazy(void *addr, size_t size) { VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE); #elif defined(JEMALLOC_PURGE_MADVISE_FREE) madvise(addr, size, MADV_FREE); +#elif defined(JEMALLOC_PURGE_MADVISE_DONTNEED) && \ + !defined(JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS) + madvise(addr, size, MADV_DONTNEED); #else not_reached(); #endif @@ -182,8 +185,12 @@ pages_purge_forced(void *addr, size_t size) { return true; } -#if defined(JEMALLOC_PURGE_MADVISE_DONTNEED) +#if defined(JEMALLOC_PURGE_MADVISE_DONTNEED) && \ + defined(JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS) return (madvise(addr, size, MADV_DONTNEED) != 0); +#elif defined(JEMALLOC_MAPS_COALESCE) + /* Try to overlay a new demand-zeroed mapping. */ + return pages_commit(addr, size); #else not_reached(); #endif -- GitLab From 28078274c4885c5d98cbbb12dd7cb138397cde8f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 9 Mar 2017 16:39:17 -0800 Subject: [PATCH 323/544] Add alignment/size assertions to pages_*(). These sanity checks prevent what otherwise might result in failed system calls and unintended fallback execution paths. --- src/pages.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/pages.c b/src/pages.c index e80c3652..9846e19e 100644 --- a/src/pages.c +++ b/src/pages.c @@ -19,6 +19,9 @@ static bool os_overcommits; void * pages_map(void *addr, size_t size, bool *commit) { + assert(PAGE_ADDR2BASE(addr) == addr); + assert(PAGE_CEILING(size) == size); + void *ret; assert(size != 0); @@ -63,6 +66,9 @@ pages_map(void *addr, size_t size, bool *commit) { void pages_unmap(void *addr, size_t size) { + assert(PAGE_ADDR2BASE(addr) == addr); + assert(PAGE_CEILING(size) == size); + #ifdef _WIN32 if (VirtualFree(addr, 0, MEM_RELEASE) == 0) #else @@ -122,6 +128,9 @@ pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size, static bool pages_commit_impl(void *addr, size_t size, bool commit) { + assert(PAGE_ADDR2BASE(addr) == addr); + assert(PAGE_CEILING(size) == size); + if (os_overcommits) { return true; } @@ -162,6 +171,9 @@ pages_decommit(void *addr, size_t size) { bool pages_purge_lazy(void *addr, size_t size) { + assert(PAGE_ADDR2BASE(addr) == addr); + assert(PAGE_CEILING(size) == size); + if (!pages_can_purge_lazy) { return true; } @@ -181,6 +193,9 @@ pages_purge_lazy(void *addr, size_t size) { bool pages_purge_forced(void *addr, size_t size) { + assert(PAGE_ADDR2BASE(addr) == addr); + assert(PAGE_CEILING(size) == size); + if (!pages_can_purge_forced) { return true; } -- GitLab From 26d23da6cd91e4d7d6210c89de5194dedf0f0f60 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 9 Mar 2017 17:20:00 -0800 Subject: [PATCH 324/544] Prefer pages_purge_forced() over memset(). This has the dual advantages of allowing for sparsely used large allocations, and relying on the kernel to supply zeroed pages, which tends to be very fast on modern systems. --- src/extent.c | 13 ++++++++++--- src/large.c | 33 ++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/extent.c b/src/extent.c index 33589394..c44ecb89 100644 --- a/src/extent.c +++ b/src/extent.c @@ -759,8 +759,11 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, if (*zero) { if (!extent_zeroed_get(extent)) { - memset(extent_addr_get(extent), 0, - extent_usize_get(extent)); + if (pages_purge_forced(extent_base_get(extent), + extent_size_get(extent))) { + memset(extent_addr_get(extent), 0, + extent_usize_get(extent)); + } } else if (config_debug) { size_t i; size_t *p = (size_t *)(uintptr_t) @@ -971,7 +974,11 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, extent_interior_register(tsdn, rtree_ctx, extent); } if (*zero && !extent_zeroed_get(extent)) { - memset(extent_addr_get(extent), 0, extent_usize_get(extent)); + if (pages_purge_forced(extent_base_get(extent), + extent_size_get(extent))) { + memset(extent_addr_get(extent), 0, + extent_usize_get(extent)); + } } /* * Increment extent_grow_next, but take care to do so atomically and diff --git a/src/large.c b/src/large.c index e9536bca..5145f418 100644 --- a/src/large.c +++ b/src/large.c @@ -25,9 +25,13 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, return NULL; } + if (config_fill && unlikely(opt_zero)) { + zero = true; + } /* - * Copy zero into is_zeroed and pass the copy to extent_alloc(), so that - * it is possible to make correct junk/zero fill decisions below. + * Copy zero into is_zeroed and pass the copy when allocating the + * extent, so that it is possible to make correct junk/zero fill + * decisions below, even if is_zeroed ends up true when zero is false. */ is_zeroed = zero; if (likely(!tsdn_null(tsdn))) { @@ -46,11 +50,8 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, prof_idump(tsdn); } - if (zero || (config_fill && unlikely(opt_zero))) { - if (!is_zeroed) { - memset(extent_addr_get(extent), 0, - extent_usize_get(extent)); - } + if (zero) { + assert(is_zeroed); } else if (config_fill && unlikely(opt_junk_alloc)) { memset(extent_addr_get(extent), JEMALLOC_ALLOC_JUNK, extent_usize_get(extent)); @@ -144,7 +145,16 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, return true; } - bool is_zeroed_trail = false; + if (config_fill && unlikely(opt_zero)) { + zero = true; + } + /* + * Copy zero into is_zeroed_trail and pass the copy when allocating the + * extent, so that it is possible to make correct junk/zero fill + * decisions below, even if is_zeroed_trail ends up true when zero is + * false. + */ + bool is_zeroed_trail = zero; bool commit = true; extent_t *trail; bool new_mapping; @@ -174,7 +184,7 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, arena_stats_mapped_add(tsdn, &arena->stats, trailsize); } - if (zero || (config_fill && unlikely(opt_zero))) { + if (zero) { if (config_cache_oblivious) { /* * Zero the trailing bytes of the original allocation's @@ -191,10 +201,7 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, assert(nzero > 0); memset(zbase, 0, nzero); } - if (!is_zeroed_trail) { - memset((void *)((uintptr_t)extent_addr_get(extent) + - oldusize), 0, usize - oldusize); - } + assert(is_zeroed_trail); } else if (config_fill && unlikely(opt_junk_alloc)) { memset((void *)((uintptr_t)extent_addr_get(extent) + oldusize), JEMALLOC_ALLOC_JUNK, usize - oldusize); -- GitLab From 4fc2acf5aef9ea8fe7e2dd39ee8b6a5050c5ff7f Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 8 Mar 2017 15:56:31 -0800 Subject: [PATCH 325/544] Switch atomic uint64_ts in arena_stats_t to C11 atomics I expect this to be the trickiest conversion we will see, since we want atomics on 64-bit platforms, but are also always able to piggyback on some sort of external synchronization on non-64 bit platforms. --- include/jemalloc/internal/stats_structs.h | 37 ++++++----- src/arena.c | 60 +++++++++++------ src/ctl.c | 80 +++++++++++++++++------ 3 files changed, 121 insertions(+), 56 deletions(-) diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index 06ba95fc..b64ba2d2 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -1,6 +1,13 @@ #ifndef JEMALLOC_INTERNAL_STATS_STRUCTS_H #define JEMALLOC_INTERNAL_STATS_STRUCTS_H +#ifdef JEMALLOC_ATOMIC_U64 +typedef atomic_u64_t arena_stats_u64_t; +#else +/* Must hold the arena stats mutex while reading atomically. */ +typedef uint64_t arena_stats_u64_t; +#endif + struct tcache_bin_stats_s { /* * Number of allocation requests that corresponded to the size of this @@ -56,15 +63,15 @@ struct malloc_large_stats_s { * Total number of allocation/deallocation requests served directly by * the arena. */ - uint64_t nmalloc; - uint64_t ndalloc; + arena_stats_u64_t nmalloc; + arena_stats_u64_t ndalloc; /* * Number of allocation requests that correspond to this size class. * This includes requests served by tcache, though tcache only * periodically merges into this counter. */ - uint64_t nrequests; /* Partially derived. */ + arena_stats_u64_t nrequests; /* Partially derived. */ /* Current number of allocations of this size class. */ size_t curlextents; /* Derived. */ @@ -96,18 +103,18 @@ struct arena_stats_s { * and total pages purged in order to keep dirty unused memory under * control. */ - uint64_t npurge; - uint64_t nmadvise; - uint64_t purged; - - size_t base; /* Derived. */ - size_t internal; - size_t resident; /* Derived. */ - - size_t allocated_large; /* Derived. */ - uint64_t nmalloc_large; /* Derived. */ - uint64_t ndalloc_large; /* Derived. */ - uint64_t nrequests_large; /* Derived. */ + arena_stats_u64_t npurge; + arena_stats_u64_t nmadvise; + arena_stats_u64_t purged; + + size_t base; /* Derived. */ + size_t internal; + size_t resident; /* Derived. */ + + size_t allocated_large; /* Derived. */ + arena_stats_u64_t nmalloc_large; /* Derived. */ + arena_stats_u64_t ndalloc_large; /* Derived. */ + arena_stats_u64_t nrequests_large; /* Derived. */ /* Number of bytes cached in tcache associated with this arena. */ size_t tcache_bytes; /* Derived. */ diff --git a/src/arena.c b/src/arena.c index cb0194ae..1fbf87dd 100644 --- a/src/arena.c +++ b/src/arena.c @@ -78,9 +78,10 @@ arena_stats_unlock(tsdn_t *tsdn, arena_stats_t *arena_stats) { } static uint64_t -arena_stats_read_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, uint64_t *p) { +arena_stats_read_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, + arena_stats_u64_t *p) { #ifdef JEMALLOC_ATOMIC_U64 - return atomic_read_u64(p); + return atomic_load_u64(p, ATOMIC_RELAXED); #else malloc_mutex_assert_owner(tsdn, &arena_stats->mtx); return *p; @@ -88,10 +89,10 @@ arena_stats_read_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, uint64_t *p) { } static void -arena_stats_add_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, uint64_t *p, - uint64_t x) { +arena_stats_add_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, + arena_stats_u64_t *p, uint64_t x) { #ifdef JEMALLOC_ATOMIC_U64 - atomic_add_u64(p, x); + atomic_fetch_add_u64(p, x, ATOMIC_RELAXED); #else malloc_mutex_assert_owner(tsdn, &arena_stats->mtx); *p += x; @@ -99,11 +100,11 @@ arena_stats_add_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, uint64_t *p, } UNUSED static void -arena_stats_sub_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, uint64_t *p, - uint64_t x) { +arena_stats_sub_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, + arena_stats_u64_t *p, uint64_t x) { #ifdef JEMALLOC_ATOMIC_U64 - UNUSED uint64_t r = atomic_sub_u64(p, x); - assert(r + x >= r); + UNUSED uint64_t r = atomic_fetch_sub_u64(p, x, ATOMIC_RELAXED); + assert(r - x <= r); #else malloc_mutex_assert_owner(tsdn, &arena_stats->mtx); *p -= x; @@ -111,6 +112,21 @@ arena_stats_sub_u64(tsdn_t *tsdn, arena_stats_t *arena_stats, uint64_t *p, #endif } +/* + * Non-atomically sets *dst += src. *dst needs external synchronization. + * This lets us avoid the cost of a fetch_add when its unnecessary (note that + * the types here are atomic). + */ +static void +arena_stats_accum_u64(arena_stats_u64_t *dst, uint64_t src) { +#ifdef JEMALLOC_ATOMIC_U64 + uint64_t cur_dst = atomic_load_u64(dst, ATOMIC_RELAXED); + atomic_store_u64(dst, src + cur_dst, ATOMIC_RELAXED); +#else + *dst += src; +#endif +} + static size_t arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t *p) { #ifdef JEMALLOC_ATOMIC_U64 @@ -191,12 +207,12 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, &arena->stats.mapped); astats->retained += (extents_npages_get(&arena->extents_retained) << LG_PAGE); - astats->npurge += arena_stats_read_u64(tsdn, &arena->stats, - &arena->stats.npurge); - astats->nmadvise += arena_stats_read_u64(tsdn, &arena->stats, - &arena->stats.nmadvise); - astats->purged += arena_stats_read_u64(tsdn, &arena->stats, - &arena->stats.purged); + arena_stats_accum_u64(&astats->npurge, arena_stats_read_u64(tsdn, + &arena->stats, &arena->stats.npurge)); + arena_stats_accum_u64(&astats->nmadvise, arena_stats_read_u64(tsdn, + &arena->stats, &arena->stats.nmadvise)); + arena_stats_accum_u64(&astats->purged, arena_stats_read_u64(tsdn, + &arena->stats, &arena->stats.purged)); astats->base += base_allocated; astats->internal += arena_internal_get(arena); astats->resident += base_resident + (((atomic_read_zu(&arena->nactive) + @@ -205,18 +221,20 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, for (szind_t i = 0; i < NSIZES - NBINS; i++) { uint64_t nmalloc = arena_stats_read_u64(tsdn, &arena->stats, &arena->stats.lstats[i].nmalloc); - lstats[i].nmalloc += nmalloc; - astats->nmalloc_large += nmalloc; + arena_stats_accum_u64(&lstats[i].nmalloc, nmalloc); + arena_stats_accum_u64(&astats->nmalloc_large, nmalloc); uint64_t ndalloc = arena_stats_read_u64(tsdn, &arena->stats, &arena->stats.lstats[i].ndalloc); - lstats[i].ndalloc += ndalloc; - astats->ndalloc_large += ndalloc; + arena_stats_accum_u64(&lstats[i].ndalloc, ndalloc); + arena_stats_accum_u64(&astats->ndalloc_large, ndalloc); uint64_t nrequests = arena_stats_read_u64(tsdn, &arena->stats, &arena->stats.lstats[i].nrequests); - lstats[i].nrequests += nmalloc + nrequests; - astats->nrequests_large += nmalloc + nrequests; + arena_stats_accum_u64(&lstats[i].nrequests, + nmalloc + nrequests); + arena_stats_accum_u64(&astats->nrequests_large, + nmalloc + nrequests); assert(nmalloc >= ndalloc); assert(nmalloc - ndalloc <= SIZE_T_MAX); diff --git a/src/ctl.c b/src/ctl.c index d4ab699f..bb835836 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -431,6 +431,33 @@ static const ctl_named_node_t super_root_node[] = { /******************************************************************************/ +/* + * Sets *dst + *src non-atomically. This is safe, since everything is + * synchronized by the ctl mutex. + */ +static void +accum_arena_stats_u64(arena_stats_u64_t *dst, arena_stats_u64_t *src) { +#ifdef JEMALLOC_ATOMIC_U64 + uint64_t cur_dst = atomic_load_u64(dst, ATOMIC_RELAXED); + uint64_t cur_src = atomic_load_u64(src, ATOMIC_RELAXED); + atomic_store_u64(dst, cur_dst + cur_src, ATOMIC_RELAXED); +#else + *dst += *src; +#endif +} + +/* Likewise: with ctl mutex synchronization, reading is simple. */ +static uint64_t +arena_stats_read_u64(arena_stats_u64_t *p) { +#ifdef JEMALLOC_ATOMIC_U64 + return atomic_load_u64(p, ATOMIC_RELAXED); +#else + return *p; +#endif +} + +/******************************************************************************/ + static unsigned arenas_i2a_impl(size_t i, bool compat, bool validate) { unsigned a; @@ -589,9 +616,12 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, sdstats->astats.mapped += astats->astats.mapped; sdstats->astats.retained += astats->astats.retained; } - sdstats->astats.npurge += astats->astats.npurge; - sdstats->astats.nmadvise += astats->astats.nmadvise; - sdstats->astats.purged += astats->astats.purged; + accum_arena_stats_u64(&sdstats->astats.npurge, + &astats->astats.npurge); + accum_arena_stats_u64(&sdstats->astats.nmadvise, + &astats->astats.nmadvise); + accum_arena_stats_u64(&sdstats->astats.purged, + &astats->astats.purged); if (!destroyed) { sdstats->astats.base += astats->astats.base; @@ -616,10 +646,12 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, } else { assert(astats->astats.allocated_large == 0); } - sdstats->astats.nmalloc_large += astats->astats.nmalloc_large; - sdstats->astats.ndalloc_large += astats->astats.ndalloc_large; - sdstats->astats.nrequests_large += - astats->astats.nrequests_large; + accum_arena_stats_u64(&sdstats->astats.nmalloc_large, + &astats->astats.nmalloc_large); + accum_arena_stats_u64(&sdstats->astats.ndalloc_large, + &astats->astats.ndalloc_large); + accum_arena_stats_u64(&sdstats->astats.nrequests_large, + &astats->astats.nrequests_large); if (config_tcache) { sdstats->astats.tcache_bytes += @@ -654,10 +686,12 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, } for (i = 0; i < NSIZES - NBINS; i++) { - sdstats->lstats[i].nmalloc += astats->lstats[i].nmalloc; - sdstats->lstats[i].ndalloc += astats->lstats[i].ndalloc; - sdstats->lstats[i].nrequests += - astats->lstats[i].nrequests; + accum_arena_stats_u64(&sdstats->lstats[i].nmalloc, + &astats->lstats[i].nmalloc); + accum_arena_stats_u64(&sdstats->lstats[i].ndalloc, + &astats->lstats[i].ndalloc); + accum_arena_stats_u64(&sdstats->lstats[i].nrequests, + &astats->lstats[i].nrequests); if (!destroyed) { sdstats->lstats[i].curlextents += astats->lstats[i].curlextents; @@ -2139,11 +2173,11 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_mapped, CTL_RO_CGEN(config_stats, stats_arenas_i_retained, arenas_i(mib[2])->astats->astats.retained, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_npurge, - arenas_i(mib[2])->astats->astats.npurge, uint64_t) + arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.npurge), uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise, - arenas_i(mib[2])->astats->astats.nmadvise, uint64_t) + arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.nmadvise), uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_purged, - arenas_i(mib[2])->astats->astats.purged, uint64_t) + arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.purged), uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_base, arenas_i(mib[2])->astats->astats.base, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_internal, @@ -2164,11 +2198,14 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests, CTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated, arenas_i(mib[2])->astats->astats.allocated_large, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc, - arenas_i(mib[2])->astats->astats.nmalloc_large, uint64_t) + arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.nmalloc_large), + uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc, - arenas_i(mib[2])->astats->astats.ndalloc_large, uint64_t) + arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.ndalloc_large), + uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests, - arenas_i(mib[2])->astats->astats.nmalloc_large, uint64_t) /* Intentional. */ + arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.nmalloc_large), + uint64_t) /* Intentional. */ CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc, arenas_i(mib[2])->astats->bstats[mib[4]].nmalloc, uint64_t) @@ -2199,11 +2236,14 @@ stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, } CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nmalloc, - arenas_i(mib[2])->astats->lstats[mib[4]].nmalloc, uint64_t) + arena_stats_read_u64(&arenas_i(mib[2])->astats->lstats[mib[4]].nmalloc), + uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_ndalloc, - arenas_i(mib[2])->astats->lstats[mib[4]].ndalloc, uint64_t) + arena_stats_read_u64(&arenas_i(mib[2])->astats->lstats[mib[4]].ndalloc), + uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nrequests, - arenas_i(mib[2])->astats->lstats[mib[4]].nrequests, uint64_t) + arena_stats_read_u64( + &arenas_i(mib[2])->astats->lstats[mib[4]].nrequests), uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_curlextents, arenas_i(mib[2])->astats->lstats[mib[4]].curlextents, size_t) -- GitLab From ee202efc79d650e16e3ecb1569efccbc5666e116 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 13 Mar 2017 16:18:40 -0700 Subject: [PATCH 326/544] Convert remaining arena_stats_t fields to atomics These were all size_ts, so we have atomics support for them on all platforms, so the conversion is straightforward. Left non-atomic is curlextents, which AFAICT is not used atomically anywhere. --- include/jemalloc/internal/arena_inlines_a.h | 6 +- include/jemalloc/internal/stats_structs.h | 14 ++-- src/arena.c | 56 +++++++++------- src/ctl.c | 74 ++++++++++++++------- 4 files changed, 93 insertions(+), 57 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_a.h b/include/jemalloc/internal/arena_inlines_a.h index 9dd5304c..e1c47652 100644 --- a/include/jemalloc/internal/arena_inlines_a.h +++ b/include/jemalloc/internal/arena_inlines_a.h @@ -19,17 +19,17 @@ arena_ind_get(const arena_t *arena) { JEMALLOC_INLINE void arena_internal_add(arena_t *arena, size_t size) { - atomic_add_zu(&arena->stats.internal, size); + atomic_fetch_add_zu(&arena->stats.internal, size, ATOMIC_RELAXED); } JEMALLOC_INLINE void arena_internal_sub(arena_t *arena, size_t size) { - atomic_sub_zu(&arena->stats.internal, size); + atomic_fetch_sub_zu(&arena->stats.internal, size, ATOMIC_RELAXED); } JEMALLOC_INLINE size_t arena_internal_get(arena_t *arena) { - return atomic_read_zu(&arena->stats.internal); + return atomic_load_zu(&arena->stats.internal, ATOMIC_RELAXED); } JEMALLOC_INLINE bool diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index b64ba2d2..4e9c898a 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -88,7 +88,7 @@ struct arena_stats_s { #endif /* Number of bytes currently mapped, excluding retained memory. */ - size_t mapped; /* Partially derived. */ + atomic_zu_t mapped; /* Partially derived. */ /* * Number of bytes currently retained as a side effect of munmap() being @@ -96,7 +96,7 @@ struct arena_stats_s { * always decommitted or purged), but they are excluded from the mapped * statistic (above). */ - size_t retained; /* Derived. */ + atomic_zu_t retained; /* Derived. */ /* * Total number of purge sweeps, total number of madvise calls made, @@ -107,17 +107,17 @@ struct arena_stats_s { arena_stats_u64_t nmadvise; arena_stats_u64_t purged; - size_t base; /* Derived. */ - size_t internal; - size_t resident; /* Derived. */ + atomic_zu_t base; /* Derived. */ + atomic_zu_t internal; + atomic_zu_t resident; /* Derived. */ - size_t allocated_large; /* Derived. */ + atomic_zu_t allocated_large; /* Derived. */ arena_stats_u64_t nmalloc_large; /* Derived. */ arena_stats_u64_t ndalloc_large; /* Derived. */ arena_stats_u64_t nrequests_large; /* Derived. */ /* Number of bytes cached in tcache associated with this arena. */ - size_t tcache_bytes; /* Derived. */ + atomic_zu_t tcache_bytes; /* Derived. */ /* One element for each large size class. */ malloc_large_stats_t lstats[NSIZES - NBINS]; diff --git a/src/arena.c b/src/arena.c index 1fbf87dd..417778b4 100644 --- a/src/arena.c +++ b/src/arena.c @@ -128,39 +128,47 @@ arena_stats_accum_u64(arena_stats_u64_t *dst, uint64_t src) { } static size_t -arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t *p) { +arena_stats_read_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p) { #ifdef JEMALLOC_ATOMIC_U64 - return atomic_read_zu(p); + return atomic_load_zu(p, ATOMIC_RELAXED); #else malloc_mutex_assert_owner(tsdn, &arena_stats->mtx); - return *p; + return atomic_load_zu(p, ATOMIC_RELAXED); #endif } static void -arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t *p, +arena_stats_add_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p, size_t x) { #ifdef JEMALLOC_ATOMIC_U64 - atomic_add_zu(p, x); + atomic_fetch_add_zu(p, x, ATOMIC_RELAXED); #else malloc_mutex_assert_owner(tsdn, &arena_stats->mtx); - *p += x; + size_t cur = atomic_load_zu(p, ATOMIC_RELAXED); + atomic_store_zu(p, cur + x, ATOMIC_RELAXED); #endif } static void -arena_stats_sub_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t *p, +arena_stats_sub_zu(tsdn_t *tsdn, arena_stats_t *arena_stats, atomic_zu_t *p, size_t x) { #ifdef JEMALLOC_ATOMIC_U64 - UNUSED size_t r = atomic_sub_zu(p, x); - assert(r + x >= r); + UNUSED size_t r = atomic_fetch_sub_zu(p, x, ATOMIC_RELAXED); + assert(r - x <= r); #else malloc_mutex_assert_owner(tsdn, &arena_stats->mtx); - *p -= x; - assert(*p + x >= *p); + size_t cur = atomic_load_zu(p, ATOMIC_RELAXED); + atomic_store_zu(p, cur - x, ATOMIC_RELAXED); #endif } +/* Like the _u64 variant, needs an externally synchronized *dst. */ +static void +arena_stats_accum_zu(atomic_zu_t *dst, size_t src) { + size_t cur_dst = atomic_load_zu(dst, ATOMIC_RELAXED); + atomic_store_zu(dst, src + cur_dst, ATOMIC_RELAXED); +} + void arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats, szind_t szind, uint64_t nrequests) { @@ -203,20 +211,21 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, arena_stats_lock(tsdn, &arena->stats); - astats->mapped += base_mapped + arena_stats_read_zu(tsdn, &arena->stats, - &arena->stats.mapped); - astats->retained += (extents_npages_get(&arena->extents_retained) << - LG_PAGE); + arena_stats_accum_zu(&astats->mapped, base_mapped + + arena_stats_read_zu(tsdn, &arena->stats, &arena->stats.mapped)); + arena_stats_accum_zu(&astats->retained, + extents_npages_get(&arena->extents_retained) << LG_PAGE); arena_stats_accum_u64(&astats->npurge, arena_stats_read_u64(tsdn, &arena->stats, &arena->stats.npurge)); arena_stats_accum_u64(&astats->nmadvise, arena_stats_read_u64(tsdn, &arena->stats, &arena->stats.nmadvise)); arena_stats_accum_u64(&astats->purged, arena_stats_read_u64(tsdn, &arena->stats, &arena->stats.purged)); - astats->base += base_allocated; - astats->internal += arena_internal_get(arena); - astats->resident += base_resident + (((atomic_read_zu(&arena->nactive) + - extents_npages_get(&arena->extents_cached)) << LG_PAGE)); + arena_stats_accum_zu(&astats->base, base_allocated); + arena_stats_accum_zu(&astats->internal, arena_internal_get(arena)); + arena_stats_accum_zu(&astats->resident, base_resident + + (((atomic_read_zu(&arena->nactive) + + extents_npages_get(&arena->extents_cached)) << LG_PAGE))); for (szind_t i = 0; i < NSIZES - NBINS; i++) { uint64_t nmalloc = arena_stats_read_u64(tsdn, &arena->stats, @@ -240,7 +249,8 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, assert(nmalloc - ndalloc <= SIZE_T_MAX); size_t curlextents = (size_t)(nmalloc - ndalloc); lstats[i].curlextents += curlextents; - astats->allocated_large += curlextents * index2size(NBINS + i); + arena_stats_accum_zu(&astats->allocated_large, + curlextents * index2size(NBINS + i)); } arena_stats_unlock(tsdn, &arena->stats); @@ -250,13 +260,13 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, tcache_t *tcache; /* tcache_bytes counts currently cached bytes. */ - astats->tcache_bytes = 0; + atomic_store_zu(&astats->tcache_bytes, 0, ATOMIC_RELAXED); malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx); ql_foreach(tcache, &arena->tcache_ql, link) { for (szind_t i = 0; i < nhbins; i++) { tbin = &tcache->tbins[i]; - astats->tcache_bytes += tbin->ncached * - index2size(i); + arena_stats_accum_zu(&astats->tcache_bytes, + tbin->ncached * index2size(i)); } } malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx); diff --git a/src/ctl.c b/src/ctl.c index bb835836..70721584 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -456,6 +456,12 @@ arena_stats_read_u64(arena_stats_u64_t *p) { #endif } +static void accum_atomic_zu(atomic_zu_t *dst, atomic_zu_t *src) { + size_t cur_dst = atomic_load_zu(dst, ATOMIC_RELAXED); + size_t cur_src = atomic_load_zu(src, ATOMIC_RELAXED); + atomic_store_zu(dst, cur_dst + cur_src, ATOMIC_RELAXED); +} + /******************************************************************************/ static unsigned @@ -613,8 +619,10 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, ctl_arena_stats_t *astats = ctl_arena->astats; if (!destroyed) { - sdstats->astats.mapped += astats->astats.mapped; - sdstats->astats.retained += astats->astats.retained; + accum_atomic_zu(&sdstats->astats.mapped, + &astats->astats.mapped); + accum_atomic_zu(&sdstats->astats.retained, + &astats->astats.retained); } accum_arena_stats_u64(&sdstats->astats.npurge, &astats->astats.npurge); @@ -624,11 +632,15 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, &astats->astats.purged); if (!destroyed) { - sdstats->astats.base += astats->astats.base; - sdstats->astats.internal += astats->astats.internal; - sdstats->astats.resident += astats->astats.resident; + accum_atomic_zu(&sdstats->astats.base, + &astats->astats.base); + accum_atomic_zu(&sdstats->astats.internal, + &astats->astats.internal); + accum_atomic_zu(&sdstats->astats.resident, + &astats->astats.resident); } else { - assert(astats->astats.internal == 0); + assert(atomic_load_zu( + &astats->astats.internal, ATOMIC_RELAXED) == 0); } if (!destroyed) { @@ -641,10 +653,11 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, sdstats->nrequests_small += astats->nrequests_small; if (!destroyed) { - sdstats->astats.allocated_large += - astats->astats.allocated_large; + accum_atomic_zu(&sdstats->astats.allocated_large, + &astats->astats.allocated_large); } else { - assert(astats->astats.allocated_large == 0); + assert(atomic_load_zu(&astats->astats.allocated_large, + ATOMIC_RELAXED) == 0); } accum_arena_stats_u64(&sdstats->astats.nmalloc_large, &astats->astats.nmalloc_large); @@ -654,8 +667,8 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, &astats->astats.nrequests_large); if (config_tcache) { - sdstats->astats.tcache_bytes += - astats->astats.tcache_bytes; + accum_atomic_zu(&sdstats->astats.tcache_bytes, + &astats->astats.tcache_bytes); } for (i = 0; i < NBINS; i++) { @@ -772,13 +785,19 @@ ctl_refresh(tsdn_t *tsdn) { if (config_stats) { ctl_stats->allocated = ctl_sarena->astats->allocated_small + - ctl_sarena->astats->astats.allocated_large; + atomic_load_zu(&ctl_sarena->astats->astats.allocated_large, + ATOMIC_RELAXED); ctl_stats->active = (ctl_sarena->pactive << LG_PAGE); - ctl_stats->metadata = ctl_sarena->astats->astats.base + - ctl_sarena->astats->astats.internal; - ctl_stats->resident = ctl_sarena->astats->astats.resident; - ctl_stats->mapped = ctl_sarena->astats->astats.mapped; - ctl_stats->retained = ctl_sarena->astats->astats.retained; + ctl_stats->metadata = atomic_load_zu( + &ctl_sarena->astats->astats.base, ATOMIC_RELAXED) + + atomic_load_zu(&ctl_sarena->astats->astats.internal, + ATOMIC_RELAXED); + ctl_stats->resident = atomic_load_zu( + &ctl_sarena->astats->astats.resident, ATOMIC_RELAXED); + ctl_stats->mapped = atomic_load_zu( + &ctl_sarena->astats->astats.mapped, ATOMIC_RELAXED); + ctl_stats->retained = atomic_load_zu( + &ctl_sarena->astats->astats.retained, ATOMIC_RELAXED); } ctl_arenas->epoch++; } @@ -2169,9 +2188,11 @@ CTL_RO_GEN(stats_arenas_i_nthreads, arenas_i(mib[2])->nthreads, unsigned) CTL_RO_GEN(stats_arenas_i_pactive, arenas_i(mib[2])->pactive, size_t) CTL_RO_GEN(stats_arenas_i_pdirty, arenas_i(mib[2])->pdirty, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_mapped, - arenas_i(mib[2])->astats->astats.mapped, size_t) + atomic_load_zu(&arenas_i(mib[2])->astats->astats.mapped, ATOMIC_RELAXED), + size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_retained, - arenas_i(mib[2])->astats->astats.retained, size_t) + atomic_load_zu(&arenas_i(mib[2])->astats->astats.retained, ATOMIC_RELAXED), + size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_npurge, arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.npurge), uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise, @@ -2179,13 +2200,17 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise, CTL_RO_CGEN(config_stats, stats_arenas_i_purged, arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.purged), uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_base, - arenas_i(mib[2])->astats->astats.base, size_t) + atomic_load_zu(&arenas_i(mib[2])->astats->astats.base, ATOMIC_RELAXED), + size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_internal, - arenas_i(mib[2])->astats->astats.internal, size_t) + atomic_load_zu(&arenas_i(mib[2])->astats->astats.internal, ATOMIC_RELAXED), + size_t) CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_tcache_bytes, - arenas_i(mib[2])->astats->astats.tcache_bytes, size_t) + atomic_load_zu(&arenas_i(mib[2])->astats->astats.tcache_bytes, + ATOMIC_RELAXED), size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_resident, - arenas_i(mib[2])->astats->astats.resident, size_t) + atomic_load_zu(&arenas_i(mib[2])->astats->astats.resident, ATOMIC_RELAXED), + size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated, arenas_i(mib[2])->astats->allocated_small, size_t) @@ -2196,7 +2221,8 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc, CTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests, arenas_i(mib[2])->astats->nrequests_small, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated, - arenas_i(mib[2])->astats->astats.allocated_large, size_t) + atomic_load_zu(&arenas_i(mib[2])->astats->astats.allocated_large, + ATOMIC_RELAXED), size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc, arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.nmalloc_large), uint64_t) -- GitLab From 765edd67b4915a392439a53141606d9e242a6618 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 7 Mar 2017 09:22:33 -0800 Subject: [PATCH 327/544] Refactor decay-related function parametrization. Refactor most of the decay-related functions to take as parameters the decay_t and associated extents_t structures to operate on. This prepares for supporting both lazy and forced purging on different decay schedules. --- include/jemalloc/internal/arena_structs_b.h | 14 +- src/arena.c | 182 +++++++++++--------- 2 files changed, 103 insertions(+), 93 deletions(-) diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 84c179e8..369b4cd2 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -174,13 +174,6 @@ struct arena_s { */ size_t nactive; - /* - * Decay-based purging state. - * - * Synchronization: lock. - */ - arena_decay_t decay; - /* * Extant large allocations. * @@ -199,6 +192,13 @@ struct arena_s { extents_t extents_cached; extents_t extents_retained; + /* + * Decay-based purging state. + * + * Synchronization: internal. + */ + arena_decay_t decay; + /* * True if a thread is currently executing arena_purge_to_limit(). * diff --git a/src/arena.c b/src/arena.c index 417778b4..ea8e6a55 100644 --- a/src/arena.c +++ b/src/arena.c @@ -38,7 +38,7 @@ const arena_bin_info_t arena_bin_info[NBINS] = { */ static void arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, - size_t ndirty_limit); + arena_decay_t *decay, extents_t *extents, size_t ndirty_limit); static void arena_dalloc_bin_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, arena_bin_t *bin); static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, @@ -506,39 +506,39 @@ arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, } static ssize_t -arena_decay_time_read(arena_t *arena) { - return atomic_read_zd(&arena->decay.time); +arena_decay_time_read(arena_decay_t *decay) { + return atomic_read_zd(&decay->time); } static void -arena_decay_time_write(arena_t *arena, ssize_t decay_time) { - atomic_write_zd(&arena->decay.time, decay_time); +arena_decay_time_write(arena_decay_t *decay, ssize_t decay_time) { + atomic_write_zd(&decay->time, decay_time); } static void -arena_decay_deadline_init(arena_t *arena) { +arena_decay_deadline_init(arena_decay_t *decay) { /* * Generate a new deadline that is uniformly random within the next * epoch after the current one. */ - nstime_copy(&arena->decay.deadline, &arena->decay.epoch); - nstime_add(&arena->decay.deadline, &arena->decay.interval); - if (arena_decay_time_read(arena) > 0) { + nstime_copy(&decay->deadline, &decay->epoch); + nstime_add(&decay->deadline, &decay->interval); + if (arena_decay_time_read(decay) > 0) { nstime_t jitter; - nstime_init(&jitter, prng_range_u64(&arena->decay.jitter_state, - nstime_ns(&arena->decay.interval))); - nstime_add(&arena->decay.deadline, &jitter); + nstime_init(&jitter, prng_range_u64(&decay->jitter_state, + nstime_ns(&decay->interval))); + nstime_add(&decay->deadline, &jitter); } } static bool -arena_decay_deadline_reached(const arena_t *arena, const nstime_t *time) { - return (nstime_compare(&arena->decay.deadline, time) <= 0); +arena_decay_deadline_reached(const arena_decay_t *decay, const nstime_t *time) { + return (nstime_compare(&decay->deadline, time) <= 0); } static size_t -arena_decay_backlog_npages_limit(const arena_t *arena) { +arena_decay_backlog_npages_limit(const arena_decay_t *decay) { static const uint64_t h_steps[] = { #define STEP(step, h, x, y) \ h, @@ -556,7 +556,7 @@ arena_decay_backlog_npages_limit(const arena_t *arena) { */ sum = 0; for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) { - sum += arena->decay.backlog[i] * h_steps[i]; + sum += decay->backlog[i] * h_steps[i]; } npages_limit_backlog = (size_t)(sum >> SMOOTHSTEP_BFP); @@ -564,101 +564,106 @@ arena_decay_backlog_npages_limit(const arena_t *arena) { } static void -arena_decay_backlog_update_last(arena_t *arena) { - size_t ndirty = extents_npages_get(&arena->extents_cached); - size_t ndirty_delta = (ndirty > arena->decay.nunpurged) ? ndirty - - arena->decay.nunpurged : 0; - arena->decay.backlog[SMOOTHSTEP_NSTEPS-1] = ndirty_delta; +arena_decay_backlog_update_last(arena_decay_t *decay, extents_t *extents) { + size_t ndirty = extents_npages_get(extents); + size_t ndirty_delta = (ndirty > decay->nunpurged) ? ndirty - + decay->nunpurged : 0; + decay->backlog[SMOOTHSTEP_NSTEPS-1] = ndirty_delta; } static void -arena_decay_backlog_update(arena_t *arena, uint64_t nadvance_u64) { +arena_decay_backlog_update(arena_decay_t *decay, extents_t *extents, + uint64_t nadvance_u64) { if (nadvance_u64 >= SMOOTHSTEP_NSTEPS) { - memset(arena->decay.backlog, 0, (SMOOTHSTEP_NSTEPS-1) * + memset(decay->backlog, 0, (SMOOTHSTEP_NSTEPS-1) * sizeof(size_t)); } else { size_t nadvance_z = (size_t)nadvance_u64; assert((uint64_t)nadvance_z == nadvance_u64); - memmove(arena->decay.backlog, &arena->decay.backlog[nadvance_z], + memmove(decay->backlog, &decay->backlog[nadvance_z], (SMOOTHSTEP_NSTEPS - nadvance_z) * sizeof(size_t)); if (nadvance_z > 1) { - memset(&arena->decay.backlog[SMOOTHSTEP_NSTEPS - + memset(&decay->backlog[SMOOTHSTEP_NSTEPS - nadvance_z], 0, (nadvance_z-1) * sizeof(size_t)); } } - arena_decay_backlog_update_last(arena); + arena_decay_backlog_update_last(decay, extents); } static void -arena_decay_epoch_advance_helper(arena_t *arena, const nstime_t *time) { +arena_decay_epoch_advance_helper(arena_decay_t *decay, extents_t *extents, + const nstime_t *time) { uint64_t nadvance_u64; nstime_t delta; - assert(arena_decay_deadline_reached(arena, time)); + assert(arena_decay_deadline_reached(decay, time)); nstime_copy(&delta, time); - nstime_subtract(&delta, &arena->decay.epoch); - nadvance_u64 = nstime_divide(&delta, &arena->decay.interval); + nstime_subtract(&delta, &decay->epoch); + nadvance_u64 = nstime_divide(&delta, &decay->interval); assert(nadvance_u64 > 0); /* Add nadvance_u64 decay intervals to epoch. */ - nstime_copy(&delta, &arena->decay.interval); + nstime_copy(&delta, &decay->interval); nstime_imultiply(&delta, nadvance_u64); - nstime_add(&arena->decay.epoch, &delta); + nstime_add(&decay->epoch, &delta); /* Set a new deadline. */ - arena_decay_deadline_init(arena); + arena_decay_deadline_init(decay); /* Update the backlog. */ - arena_decay_backlog_update(arena, nadvance_u64); + arena_decay_backlog_update(decay, extents, nadvance_u64); } static void -arena_decay_epoch_advance_purge(tsdn_t *tsdn, arena_t *arena) { - size_t ndirty_limit = arena_decay_backlog_npages_limit(arena); +arena_decay_epoch_advance_purge(tsdn_t *tsdn, arena_t *arena, + arena_decay_t *decay, extents_t *extents) { + size_t ndirty_limit = arena_decay_backlog_npages_limit(decay); - if (extents_npages_get(&arena->extents_cached) > ndirty_limit) { - arena_purge_to_limit(tsdn, arena, ndirty_limit); + if (extents_npages_get(extents) > ndirty_limit) { + arena_purge_to_limit(tsdn, arena, decay, extents, ndirty_limit); } /* * There may be concurrent ndirty fluctuation between the purge above * and the nunpurged update below, but this is inconsequential to decay * machinery correctness. */ - arena->decay.nunpurged = extents_npages_get(&arena->extents_cached); + decay->nunpurged = extents_npages_get(extents); } static void -arena_decay_epoch_advance(tsdn_t *tsdn, arena_t *arena, const nstime_t *time) { - arena_decay_epoch_advance_helper(arena, time); - arena_decay_epoch_advance_purge(tsdn, arena); +arena_decay_epoch_advance(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, + extents_t *extents, const nstime_t *time) { + arena_decay_epoch_advance_helper(decay, extents, time); + arena_decay_epoch_advance_purge(tsdn, arena, decay, extents); } static void -arena_decay_reinit(arena_t *arena, ssize_t decay_time) { - arena_decay_time_write(arena, decay_time); +arena_decay_reinit(arena_decay_t *decay, extents_t *extents, + ssize_t decay_time) { + arena_decay_time_write(decay, decay_time); if (decay_time > 0) { - nstime_init2(&arena->decay.interval, decay_time, 0); - nstime_idivide(&arena->decay.interval, SMOOTHSTEP_NSTEPS); + nstime_init2(&decay->interval, decay_time, 0); + nstime_idivide(&decay->interval, SMOOTHSTEP_NSTEPS); } - nstime_init(&arena->decay.epoch, 0); - nstime_update(&arena->decay.epoch); - arena->decay.jitter_state = (uint64_t)(uintptr_t)arena; - arena_decay_deadline_init(arena); - arena->decay.nunpurged = extents_npages_get(&arena->extents_cached); - memset(arena->decay.backlog, 0, SMOOTHSTEP_NSTEPS * sizeof(size_t)); + nstime_init(&decay->epoch, 0); + nstime_update(&decay->epoch); + decay->jitter_state = (uint64_t)(uintptr_t)decay; + arena_decay_deadline_init(decay); + decay->nunpurged = extents_npages_get(extents); + memset(decay->backlog, 0, SMOOTHSTEP_NSTEPS * sizeof(size_t)); } static bool -arena_decay_init(arena_t *arena, ssize_t decay_time) { - if (malloc_mutex_init(&arena->decay.mtx, "decay", WITNESS_RANK_DECAY)) { +arena_decay_init(arena_decay_t *decay, extents_t *extents, ssize_t decay_time) { + if (malloc_mutex_init(&decay->mtx, "decay", WITNESS_RANK_DECAY)) { return true; } - arena_decay_reinit(arena, decay_time); + arena_decay_reinit(decay, extents, decay_time); return false; } @@ -674,14 +679,15 @@ arena_decay_time_valid(ssize_t decay_time) { } static void -arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_assert_owner(tsdn, &arena->decay.mtx); +arena_maybe_purge(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, + extents_t *extents) { + malloc_mutex_assert_owner(tsdn, &decay->mtx); /* Purge all or nothing if the option is disabled. */ - ssize_t decay_time = arena_decay_time_read(arena); + ssize_t decay_time = arena_decay_time_read(decay); if (decay_time <= 0) { if (decay_time == 0) { - arena_purge_to_limit(tsdn, arena, 0); + arena_purge_to_limit(tsdn, arena, decay, extents, 0); } return; } @@ -689,8 +695,8 @@ arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) { nstime_t time; nstime_init(&time, 0); nstime_update(&time); - if (unlikely(!nstime_monotonic() && nstime_compare(&arena->decay.epoch, - &time) > 0)) { + if (unlikely(!nstime_monotonic() && nstime_compare(&decay->epoch, &time) + > 0)) { /* * Time went backwards. Move the epoch back in time and * generate a new deadline, with the expectation that time @@ -700,11 +706,11 @@ arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) { * clock jitter estimation and compensation isn't feasible here * because calls into this code are event-driven. */ - nstime_copy(&arena->decay.epoch, &time); - arena_decay_deadline_init(arena); + nstime_copy(&decay->epoch, &time); + arena_decay_deadline_init(decay); } else { /* Verify that time does not go backwards. */ - assert(nstime_compare(&arena->decay.epoch, &time) <= 0); + assert(nstime_compare(&decay->epoch, &time) <= 0); } /* @@ -713,14 +719,14 @@ arena_maybe_purge(tsdn_t *tsdn, arena_t *arena) { * during the current epoch are not subject to purge until a future * epoch, so as a result purging only happens during epoch advances. */ - if (arena_decay_deadline_reached(arena, &time)) { - arena_decay_epoch_advance(tsdn, arena, &time); + if (arena_decay_deadline_reached(decay, &time)) { + arena_decay_epoch_advance(tsdn, arena, decay, extents, &time); } } ssize_t arena_decay_time_get(arena_t *arena) { - return arena_decay_time_read(arena); + return arena_decay_time_read(&arena->decay); } bool @@ -738,8 +744,8 @@ arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { * infrequent, either between the {-1, 0, >0} states, or a one-time * arbitrary change during initial arena configuration. */ - arena_decay_reinit(arena, decay_time); - arena_maybe_purge(tsdn, arena); + arena_decay_reinit(&arena->decay, &arena->extents_cached, decay_time); + arena_maybe_purge(tsdn, arena, &arena->decay, &arena->extents_cached); malloc_mutex_unlock(tsdn, &arena->decay.mtx); return false; @@ -747,14 +753,14 @@ arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { static size_t arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - size_t ndirty_limit, extent_list_t *purge_extents) { + extents_t *extents, size_t ndirty_limit, extent_list_t *purge_extents) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); /* Stash extents according to ndirty_limit. */ size_t nstashed = 0; extent_t *extent; - while ((extent = extents_evict(tsdn, arena, r_extent_hooks, - &arena->extents_cached, ndirty_limit)) != NULL) { + while ((extent = extents_evict(tsdn, arena, r_extent_hooks, extents, + ndirty_limit)) != NULL) { extent_list_append(purge_extents, extent); nstashed += extent_size_get(extent) >> LG_PAGE; } @@ -798,12 +804,13 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, /* * ndirty_limit: Purge as many dirty extents as possible without violating the - * invariant: (extents_npages_get(&arena->extents_cached) >= ndirty_limit) + * invariant: (extents_npages_get(extents) >= ndirty_limit) */ static void -arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) { +arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, + extents_t *extents, size_t ndirty_limit) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 1); - malloc_mutex_assert_owner(tsdn, &arena->decay.mtx); + malloc_mutex_assert_owner(tsdn, &decay->mtx); if (arena->purging) { return; @@ -816,19 +823,19 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, size_t ndirty_limit) { extent_list_init(&purge_extents); - malloc_mutex_unlock(tsdn, &arena->decay.mtx); + malloc_mutex_unlock(tsdn, &decay->mtx); - npurge = arena_stash_dirty(tsdn, arena, &extent_hooks, ndirty_limit, - &purge_extents); + npurge = arena_stash_dirty(tsdn, arena, &extent_hooks, extents, + ndirty_limit, &purge_extents); if (npurge == 0) { - malloc_mutex_lock(tsdn, &arena->decay.mtx); + malloc_mutex_lock(tsdn, &decay->mtx); goto label_return; } npurged = arena_purge_stashed(tsdn, arena, &extent_hooks, &purge_extents); assert(npurged == npurge); - malloc_mutex_lock(tsdn, &arena->decay.mtx); + malloc_mutex_lock(tsdn, &decay->mtx); if (config_stats) { arena_stats_lock(tsdn, &arena->stats); @@ -845,9 +852,11 @@ void arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) { malloc_mutex_lock(tsdn, &arena->decay.mtx); if (all) { - arena_purge_to_limit(tsdn, arena, 0); + arena_purge_to_limit(tsdn, arena, &arena->decay, + &arena->extents_cached, 0); } else { - arena_maybe_purge(tsdn, arena); + arena_maybe_purge(tsdn, arena, &arena->decay, + &arena->extents_cached); } malloc_mutex_unlock(tsdn, &arena->decay.mtx); } @@ -1706,10 +1715,6 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { atomic_write_zu(&arena->nactive, 0); - if (arena_decay_init(arena, arena_decay_time_default_get())) { - goto label_error; - } - extent_list_init(&arena->large); if (malloc_mutex_init(&arena->large_mtx, "arena_large", WITNESS_RANK_ARENA_LARGE)) { @@ -1737,6 +1742,11 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { goto label_error; } + if (arena_decay_init(&arena->decay, &arena->extents_cached, + arena_decay_time_default_get())) { + goto label_error; + } + arena->purging = false; if (!config_munmap) { -- GitLab From 38a5bfc8169b018b5b71cc72daad14c3b2f5b206 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 7 Mar 2017 19:52:57 -0800 Subject: [PATCH 328/544] Move arena_t's purging field into arena_decay_t. --- include/jemalloc/internal/arena_structs_b.h | 12 +++++------- src/arena.c | 9 ++++----- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 369b4cd2..612b4e7d 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -39,6 +39,11 @@ struct arena_bin_info_s { struct arena_decay_s { /* Synchronizes all non-atomic fields. */ malloc_mutex_t mtx; + /* + * True if a thread is currently purging the extents associated with + * this decay structure. + */ + bool purging; /* * Approximate time in seconds from the creation of a set of unused * dirty pages until an equivalent set of unused dirty pages is purged @@ -199,13 +204,6 @@ struct arena_s { */ arena_decay_t decay; - /* - * True if a thread is currently executing arena_purge_to_limit(). - * - * Synchronization: decay.mtx. - */ - bool purging; - /* * Next extent size class in a growing series to use when satisfying a * request via the extent hooks (only if !config_munmap). This limits diff --git a/src/arena.c b/src/arena.c index ea8e6a55..c253760b 100644 --- a/src/arena.c +++ b/src/arena.c @@ -663,6 +663,7 @@ arena_decay_init(arena_decay_t *decay, extents_t *extents, ssize_t decay_time) { if (malloc_mutex_init(&decay->mtx, "decay", WITNESS_RANK_DECAY)) { return true; } + decay->purging = false; arena_decay_reinit(decay, extents, decay_time); return false; } @@ -812,10 +813,10 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 1); malloc_mutex_assert_owner(tsdn, &decay->mtx); - if (arena->purging) { + if (decay->purging) { return; } - arena->purging = true; + decay->purging = true; extent_hooks_t *extent_hooks = extent_hooks_get(arena); size_t npurge, npurged; @@ -845,7 +846,7 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, } label_return: - arena->purging = false; + decay->purging = false; } void @@ -1747,8 +1748,6 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { goto label_error; } - arena->purging = false; - if (!config_munmap) { arena->extent_grow_next = psz2ind(HUGEPAGE); } -- GitLab From 64e458f5cdd64f9b67cb495f177ef96bf3ce4e0e Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 8 Mar 2017 22:42:57 -0800 Subject: [PATCH 329/544] Implement two-phase decay-based purging. Split decay-based purging into two phases, the first of which uses lazy purging to convert dirty pages to "muzzy", and the second of which uses forced purging, decommit, or unmapping to convert pages to clean or destroy them altogether. Not all operating systems support lazy purging, yet the application may provide extent hooks that implement lazy purging, so care must be taken to dynamically omit the first phase when necessary. The mallctl interfaces change as follows: - opt.decay_time --> opt.{dirty,muzzy}_decay_time - arena..decay_time --> arena..{dirty,muzzy}_decay_time - arenas.decay_time --> arenas.{dirty,muzzy}_decay_time - stats.arenas..pdirty --> stats.arenas..p{dirty,muzzy} - stats.arenas..{npurge,nmadvise,purged} --> stats.arenas..{dirty,muzzy}_{npurge,nmadvise,purged} This resolves #521. --- Makefile.in | 4 +- doc/jemalloc.xml.in | 239 ++++++++--- include/jemalloc/internal/arena_externs.h | 31 +- include/jemalloc/internal/arena_inlines_b.h | 5 +- include/jemalloc/internal/arena_structs_b.h | 29 +- include/jemalloc/internal/arena_types.h | 5 +- include/jemalloc/internal/ctl_structs.h | 4 +- include/jemalloc/internal/extent_externs.h | 11 +- include/jemalloc/internal/extent_structs.h | 3 +- include/jemalloc/internal/private_symbols.txt | 22 +- include/jemalloc/internal/stats_structs.h | 21 +- include/jemalloc/internal/stats_types.h | 1 + src/arena.c | 380 ++++++++++++------ src/ctl.c | 188 ++++++--- src/extent.c | 73 ++-- src/jemalloc.c | 6 +- src/large.c | 21 +- src/stats.c | 99 +++-- test/unit/decay.c | 192 ++++++--- test/unit/decay.sh | 2 +- test/unit/mallctl.c | 154 +++++-- test/unit/pack.sh | 2 +- test/unit/stats.c | 36 +- 23 files changed, 1058 insertions(+), 470 deletions(-) diff --git a/Makefile.in b/Makefile.in index 04ce288a..4fb852da 100644 --- a/Makefile.in +++ b/Makefile.in @@ -442,8 +442,8 @@ ifeq ($(enable_prof), 1) $(MALLOC_CONF)="prof:true,prof_active:false" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) endif check_integration_decay: tests_integration check_integration_dir - $(MALLOC_CONF)="decay_time:-1" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) - $(MALLOC_CONF)="decay_time:0" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) + $(MALLOC_CONF)="dirty_decay_time:-1,muzzy_decay_time:-1" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) + $(MALLOC_CONF)="dirty_decay_time:0,muzzy_decay_time:0" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) check_integration: tests_integration check_integration_dir $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) stress: tests_stress stress_dir diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 937879a8..7faa474d 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -944,24 +944,54 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", percpu. - + - opt.decay_time + opt.dirty_decay_time (ssize_t) r- Approximate time in seconds from the creation of a set of unused dirty pages until an equivalent set of unused dirty pages is - purged and/or reused. The pages are incrementally purged according to a - sigmoidal decay curve that starts and ends with zero purge rate. A - decay time of 0 causes all unused dirty pages to be purged immediately - upon creation. A decay time of -1 disables purging. The default decay - time is 10 seconds. See arenas.decay_time + purged (i.e. converted to muzzy via e.g. + madvise(...MADV_FREE) + if supported by the operating system, or converted to clean otherwise) + and/or reused. Dirty pages are defined as previously having been + potentially written to by the application, and therefore consuming + physical memory, yet having no current use. The pages are incrementally + purged according to a sigmoidal decay curve that starts and ends with + zero purge rate. A decay time of 0 causes all unused dirty pages to be + purged immediately upon creation. A decay time of -1 disables purging. + The default decay time is 10 seconds. See arenas.dirty_decay_time and arena.<i>.decay_time - for related dynamic control options. - + linkend="arena.i.muzzy_decay_time">arena.<i>.muzzy_decay_time + for related dynamic control options. See opt.muzzy_decay_time + for a description of muzzy pages. + + + + + opt.muzzy_decay_time + (ssize_t) + r- + + Approximate time in seconds from the creation of a set + of unused muzzy pages until an equivalent set of unused muzzy pages is + purged (i.e. converted to clean) and/or reused. Muzzy pages are defined + as previously having been unused dirty pages that were subsequently + purged in a manner that left them subject to the reclamation whims of + the operating system (e.g. + madvise(...MADV_FREE)), + and therefore in an indeterminate state. The pages are incrementally + purged according to a sigmoidal decay curve that starts and ends with + zero purge rate. A decay time of 0 causes all unused muzzy pages to be + purged immediately upon creation. A decay time of -1 disables purging. + The default decay time is 10 seconds. See arenas.muzzy_decay_time + and arena.<i>.muzzy_decay_time + for related dynamic control options. @@ -1460,29 +1490,31 @@ malloc_conf = "xmalloc:true";]]> initialized (always true). - + - arena.<i>.purge + arena.<i>.decay (void) -- - Purge all unused dirty pages for arena <i>, or for - all arenas if <i> equals MALLCTL_ARENAS_ALL. - + Trigger decay-based purging of unused dirty/muzzy pages + for arena <i>, or for all arenas if <i> equals + MALLCTL_ARENAS_ALL. The proportion of unused + dirty/muzzy pages to be purged depends on the current time; see opt.dirty_decay_time + and opt.muzy_decay_time + for details. - + - arena.<i>.decay + arena.<i>.purge (void) -- - Trigger decay-based purging of unused dirty pages for - arena <i>, or for all arenas if <i> equals - MALLCTL_ARENAS_ALL. The proportion of unused dirty - pages to be purged depends on the current time; see opt.decay_time for - details. + Purge all unused dirty pages for arena <i>, or for + all arenas if <i> equals MALLCTL_ARENAS_ALL. + @@ -1532,9 +1564,9 @@ malloc_conf = "xmalloc:true";]]> settings. - + - arena.<i>.decay_time + arena.<i>.dirty_decay_time (ssize_t) rw @@ -1544,8 +1576,24 @@ malloc_conf = "xmalloc:true";]]> set, all currently unused dirty pages are considered to have fully decayed, which causes immediate purging of all unused dirty pages unless the decay time is set to -1 (i.e. purging disabled). See opt.decay_time for - additional information. + linkend="opt.dirty_decay_time">opt.dirty_decay_time + for additional information. + + + + + arena.<i>.muzzy_decay_time + (ssize_t) + rw + + Current per-arena approximate time in seconds from the + creation of a set of unused muzzy pages until an equivalent set of + unused muzzy pages is purged and/or reused. Each time this interface is + set, all currently unused muzzy pages are considered to have fully + decayed, which causes immediate purging of all unused muzzy pages unless + the decay time is set to -1 (i.e. purging disabled). See opt.muzzy_decay_time + for additional information. @@ -1584,7 +1632,7 @@ struct extent_hooks_s { mapped committed memory, in the simplest case followed by deallocation. However, there are performance and platform reasons to retain extents for later reuse. Cleanup attempts cascade from deallocation to decommit - to lazy purging to forced purging, which gives the extent management + to forced purging to lazy purging, which gives the extent management functions opportunities to reject the most permanent cleanup operations in favor of less permanent (and often less costly) operations. All operations except allocation can be universally opted out of by setting @@ -1707,12 +1755,14 @@ struct extent_hooks_s { addr and size at offset bytes, extending for length on behalf of arena - arena_ind. A lazy extent purge function can - delay purging indefinitely and leave the pages within the purged virtual - memory range in an indeterminite state, whereas a forced extent purge - function immediately purges, and the pages within the virtual memory - range will be zero-filled the next time they are accessed. If the - function returns true, this indicates failure to purge. + arena_ind. A lazy extent purge function (e.g. + implemented via + madvise(...MADV_FREE)) + can delay purging indefinitely and leave the pages within the purged + virtual memory range in an indeterminite state, whereas a forced extent + purge function immediately purges, and the pages within the virtual + memory range will be zero-filled the next time they are accessed. If + the function returns true, this indicates failure to purge. typedef bool (extent_split_t) @@ -1769,19 +1819,34 @@ struct extent_hooks_s { Current limit on number of arenas. - + - arenas.decay_time + arenas.dirty_decay_time (ssize_t) rw Current default per-arena approximate time in seconds from the creation of a set of unused dirty pages until an equivalent set of unused dirty pages is purged and/or reused, used to initialize arena.<i>.decay_time + linkend="arena.i.dirty_decay_time">arena.<i>.dirty_decay_time during arena creation. See opt.decay_time for - additional information. + linkend="opt.dirty_decay_time">opt.dirty_decay_time + for additional information. + + + + + arenas.muzzy_decay_time + (ssize_t) + rw + + Current default per-arena approximate time in seconds + from the creation of a set of unused muzzy pages until an equivalent set + of unused muzzy pages is purged and/or reused, used to initialize arena.<i>.muzzy_decay_time + during arena creation. See opt.muzzy_decay_time + for additional information. @@ -2014,7 +2079,9 @@ struct extent_hooks_s { equal to stats.allocated. This does not include - stats.arenas.<i>.pdirty, nor pages + stats.arenas.<i>.pdirty, + + stats.arenas.<i>.pmuzzy, nor pages entirely devoted to allocator metadata. @@ -2099,16 +2166,29 @@ struct extent_hooks_s { - + - stats.arenas.<i>.decay_time + stats.arenas.<i>.dirty_decay_time (ssize_t) r- Approximate time in seconds from the creation of a set of unused dirty pages until an equivalent set of unused dirty pages is purged and/or reused. See opt.decay_time + linkend="opt.dirty_decay_time">opt.dirty_decay_time + for details. + + + + + stats.arenas.<i>.muzzy_decay_time + (ssize_t) + r- + + Approximate time in seconds from the creation of a set + of unused muzzy pages until an equivalent set of unused muzzy pages is + purged and/or reused. See opt.muzzy_decay_time for details. @@ -2138,10 +2218,22 @@ struct extent_hooks_s { r- Number of pages within unused extents that are - potentially dirty, and for which - madvise(... - MADV_DONTNEED) or - similar has not been called. + potentially dirty, and for which madvise() or + similar has not been called. See opt.dirty_decay_time + for a description of dirty pages. + + + + + stats.arenas.<i>.pmuzzy + (size_t) + r- + + Number of pages within unused extents that are muzzy. + See opt.muzzy_decay_time + for a description of muzzy pages. @@ -2207,9 +2299,9 @@ struct extent_hooks_s { size. - + - stats.arenas.<i>.npurge + stats.arenas.<i>.dirty_npurge (uint64_t) r- [] @@ -2218,26 +2310,57 @@ struct extent_hooks_s { - + + + stats.arenas.<i>.dirty_nmadvise + (uint64_t) + r- + [] + + Number of madvise() or similar + calls made to purge dirty pages. + + + + + stats.arenas.<i>.dirty_purged + (uint64_t) + r- + [] + + Number of dirty pages purged. + + + + + stats.arenas.<i>.muzzy_npurge + (uint64_t) + r- + [] + + Number of muzzy page purge sweeps performed. + + + + - stats.arenas.<i>.nmadvise + stats.arenas.<i>.muzzy_nmadvise (uint64_t) r- [] - Number of madvise(... - MADV_DONTNEED) or - similar calls made to purge dirty pages. + Number of madvise() or similar + calls made to purge muzzy pages. - + - stats.arenas.<i>.purged + stats.arenas.<i>.muzzy_purged (uint64_t) r- [] - Number of pages purged. + Number of muzzy pages purged. diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 349bae99..9603d74f 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -9,7 +9,8 @@ static const size_t large_pad = #endif ; -extern ssize_t opt_decay_time; +extern ssize_t opt_dirty_decay_time; +extern ssize_t opt_muzzy_decay_time; extern const arena_bin_info_t arena_bin_info[NBINS]; @@ -22,13 +23,13 @@ void arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats, void arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t size); void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, - unsigned *nthreads, const char **dss, ssize_t *decay_time, size_t *nactive, - size_t *ndirty); + unsigned *nthreads, const char **dss, ssize_t *dirty_decay_time, + ssize_t *muzzy_decay_time, size_t *nactive, size_t *ndirty, size_t *nmuzzy); void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty, - arena_stats_t *astats, malloc_bin_stats_t *bstats, - malloc_large_stats_t *lstats); -void arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, + const char **dss, ssize_t *dirty_decay_time, ssize_t *muzzy_decay_time, + size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats, + malloc_bin_stats_t *bstats, malloc_large_stats_t *lstats); +void arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent); #ifdef JEMALLOC_JET size_t arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr); @@ -41,9 +42,13 @@ void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); -ssize_t arena_decay_time_get(arena_t *arena); -bool arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time); -void arena_purge(tsdn_t *tsdn, arena_t *arena, bool all); +ssize_t arena_dirty_decay_time_get(arena_t *arena); +bool arena_dirty_decay_time_set(tsdn_t *tsdn, arena_t *arena, + ssize_t decay_time); +ssize_t arena_muzzy_decay_time_get(arena_t *arena); +bool arena_muzzy_decay_time_set(tsdn_t *tsdn, arena_t *arena, + ssize_t decay_time); +void arena_decay(tsdn_t *tsdn, arena_t *arena, bool all); void arena_reset(tsd_t *tsd, arena_t *arena); void arena_destroy(tsd_t *tsd, arena_t *arena); void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, @@ -74,8 +79,10 @@ void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache); dss_prec_t arena_dss_prec_get(arena_t *arena); bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec); -ssize_t arena_decay_time_default_get(void); -bool arena_decay_time_default_set(ssize_t decay_time); +ssize_t arena_dirty_decay_time_default_get(void); +bool arena_dirty_decay_time_default_set(ssize_t decay_time); +ssize_t arena_muzzy_decay_time_default_get(void); +bool arena_muzzy_decay_time_default_set(ssize_t decay_time); unsigned arena_nthreads_get(arena_t *arena, bool internal); void arena_nthreads_inc(arena_t *arena, bool internal); void arena_nthreads_dec(arena_t *arena, bool internal); diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 275866a4..b718451b 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -75,13 +75,14 @@ arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) { return; } if (unlikely(ticker_ticks(decay_ticker, nticks))) { - arena_purge(tsdn, arena, false); + arena_decay(tsdn, arena, false); } } JEMALLOC_ALWAYS_INLINE void arena_decay_tick(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_assert_not_owner(tsdn, &arena->decay.mtx); + malloc_mutex_assert_not_owner(tsdn, &arena->decay_dirty.mtx); + malloc_mutex_assert_not_owner(tsdn, &arena->decay_muzzy.mtx); arena_decay_ticks(tsdn, arena, 1); } diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 612b4e7d..a5191d16 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -48,10 +48,8 @@ struct arena_decay_s { * Approximate time in seconds from the creation of a set of unused * dirty pages until an equivalent set of unused dirty pages is purged * and/or reused. - * - * Synchronization: atomic. */ - ssize_t time; + atomic_zd_t time; /* time / SMOOTHSTEP_NSTEPS. */ nstime_t interval; /* @@ -73,10 +71,10 @@ struct arena_decay_s { */ nstime_t deadline; /* - * Number of dirty pages at beginning of current epoch. During epoch - * advancement we use the delta between arena->decay.ndirty and - * extents_npages_get(&arena->extents_cached) to determine how many - * dirty pages, if any, were generated. + * Number of unpurged pages at beginning of current epoch. During epoch + * advancement we use the delta between arena->decay_*.nunpurged and + * extents_npages_get(&arena->extents_*) to determine how many dirty + * pages, if any, were generated. */ size_t nunpurged; /* @@ -86,6 +84,14 @@ struct arena_decay_s { * relative to epoch. */ size_t backlog[SMOOTHSTEP_NSTEPS]; + + /* + * Pointer to associated stats. These stats are embedded directly in + * the arena's stats due to how stats structures are shared between the + * arena and ctl code. + * + * Synchronization: Same as associated arena's stats field. */ + decay_stats_t *stats; }; struct arena_bin_s { @@ -194,15 +200,18 @@ struct arena_s { * * Synchronization: internal. */ - extents_t extents_cached; + extents_t extents_dirty; + extents_t extents_muzzy; extents_t extents_retained; /* - * Decay-based purging state. + * Decay-based purging state, responsible for scheduling extent state + * transitions. * * Synchronization: internal. */ - arena_decay_t decay; + arena_decay_t decay_dirty; /* dirty --> muzzy */ + arena_decay_t decay_muzzy; /* muzzy --> retained */ /* * Next extent size class in a growing series to use when satisfying a diff --git a/include/jemalloc/internal/arena_types.h b/include/jemalloc/internal/arena_types.h index 067c9ee9..ba53c408 100644 --- a/include/jemalloc/internal/arena_types.h +++ b/include/jemalloc/internal/arena_types.h @@ -7,8 +7,9 @@ #define LG_SLAB_MAXREGS (LG_PAGE - LG_TINY_MIN) #define SLAB_MAXREGS (1U << LG_SLAB_MAXREGS) -/* Default decay time in seconds. */ -#define DECAY_TIME_DEFAULT 10 +/* Default decay times in seconds. */ +#define DIRTY_DECAY_TIME_DEFAULT 10 +#define MUZZY_DECAY_TIME_DEFAULT 10 /* Number of event ticks between time checks. */ #define DECAY_NTICKS_PER_UPDATE 1000 diff --git a/include/jemalloc/internal/ctl_structs.h b/include/jemalloc/internal/ctl_structs.h index 18806a59..4df43d90 100644 --- a/include/jemalloc/internal/ctl_structs.h +++ b/include/jemalloc/internal/ctl_structs.h @@ -51,9 +51,11 @@ struct ctl_arena_s { /* Basic stats, supported even if !config_stats. */ unsigned nthreads; const char *dss; - ssize_t decay_time; + ssize_t dirty_decay_time; + ssize_t muzzy_decay_time; size_t pactive; size_t pdirty; + size_t pmuzzy; /* NULL if !config_stats. */ ctl_arena_stats_t *astats; diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index ef2467e1..e8f632f8 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -21,20 +21,21 @@ bool extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state, bool delay_coalesce); extent_state_t extents_state_get(const extents_t *extents); size_t extents_npages_get(extents_t *extents); +extent_t *extents_alloc(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extents_t *extents, void *new_addr, + size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, + bool slab); +void extents_dalloc(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extents_t *extents, extent_t *extent); extent_t *extents_evict(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extents_t *extents, size_t npages_min); void extents_prefork(tsdn_t *tsdn, extents_t *extents); void extents_postfork_parent(tsdn_t *tsdn, extents_t *extents); void extents_postfork_child(tsdn_t *tsdn, extents_t *extents); -extent_t *extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab); extent_t *extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, bool slab); void extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent); -void extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent); bool extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent); void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index c14aef86..001b7c13 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -4,7 +4,8 @@ typedef enum { extent_state_active = 0, extent_state_dirty = 1, - extent_state_retained = 2 + extent_state_muzzy = 2, + extent_state_retained = 3 } extent_state_t; /* Extent (span of pages). Use accessor functions for e_* fields. */ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index c0211e58..5ca72818 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -15,21 +15,26 @@ arena_dalloc_bin_junked_locked arena_dalloc_junk_small arena_dalloc_promoted arena_dalloc_small +arena_decay arena_decay_tick arena_decay_ticks -arena_decay_time_default_get -arena_decay_time_default_set -arena_decay_time_get -arena_decay_time_set +arena_dirty_decay_time_default_get +arena_dirty_decay_time_default_set +arena_dirty_decay_time_get +arena_dirty_decay_time_set +arena_muzzy_decay_time_default_get +arena_muzzy_decay_time_default_set +arena_muzzy_decay_time_get +arena_muzzy_decay_time_set arena_destroy arena_dss_prec_get arena_dss_prec_set arena_extent_alloc_large -arena_extent_cache_dalloc arena_extent_dalloc_large_prep arena_extent_ralloc_large_expand arena_extent_ralloc_large_shrink arena_extent_sn_next +arena_extents_dirty_dalloc arena_get arena_ichoose arena_ind_get @@ -59,7 +64,6 @@ arena_prof_promote arena_prof_tctx_get arena_prof_tctx_reset arena_prof_tctx_set -arena_purge arena_ralloc arena_ralloc_no_move arena_reset @@ -138,7 +142,6 @@ extent_commit_wrapper extent_committed_get extent_committed_set extent_dalloc -extent_dalloc_cache extent_dalloc_gap extent_dalloc_mmap extent_dalloc_wrapper @@ -192,6 +195,8 @@ extent_usize_get extent_usize_set extent_zeroed_get extent_zeroed_set +extents_alloc +extents_dalloc extents_evict extents_init extents_npages_get @@ -299,7 +304,8 @@ nstime_sec nstime_subtract nstime_update opt_abort -opt_decay_time +opt_dirty_decay_time +opt_muzzy_decay_time opt_dss opt_junk opt_junk_alloc diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index 4e9c898a..ffcb3c18 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -77,6 +77,15 @@ struct malloc_large_stats_s { size_t curlextents; /* Derived. */ }; +struct decay_stats_s { + /* Total number of purge sweeps. */ + arena_stats_u64_t npurge; + /* Total number of madvise calls made. */ + arena_stats_u64_t nmadvise; + /* Total number of pages purged. */ + arena_stats_u64_t purged; +}; + /* * Arena stats. Note that fields marked "derived" are not directly maintained * within the arena code; rather their values are derived during stats merge @@ -84,7 +93,7 @@ struct malloc_large_stats_s { */ struct arena_stats_s { #ifndef JEMALLOC_ATOMIC_U64 - malloc_mutex_t mtx; + malloc_mutex_t mtx; #endif /* Number of bytes currently mapped, excluding retained memory. */ @@ -98,14 +107,8 @@ struct arena_stats_s { */ atomic_zu_t retained; /* Derived. */ - /* - * Total number of purge sweeps, total number of madvise calls made, - * and total pages purged in order to keep dirty unused memory under - * control. - */ - arena_stats_u64_t npurge; - arena_stats_u64_t nmadvise; - arena_stats_u64_t purged; + decay_stats_t decay_dirty; + decay_stats_t decay_muzzy; atomic_zu_t base; /* Derived. */ atomic_zu_t internal; diff --git a/include/jemalloc/internal/stats_types.h b/include/jemalloc/internal/stats_types.h index f202b231..48483388 100644 --- a/include/jemalloc/internal/stats_types.h +++ b/include/jemalloc/internal/stats_types.h @@ -4,6 +4,7 @@ typedef struct tcache_bin_stats_s tcache_bin_stats_t; typedef struct malloc_bin_stats_s malloc_bin_stats_t; typedef struct malloc_large_stats_s malloc_large_stats_t; +typedef struct decay_stats_s decay_stats_t; typedef struct arena_stats_s arena_stats_t; #endif /* JEMALLOC_INTERNAL_STATS_TYPES_H */ diff --git a/src/arena.c b/src/arena.c index c253760b..d861fff6 100644 --- a/src/arena.c +++ b/src/arena.c @@ -13,8 +13,10 @@ const char *percpu_arena_mode_names[] = { const char *opt_percpu_arena = OPT_PERCPU_ARENA_DEFAULT; percpu_arena_mode_t percpu_arena_mode = PERCPU_ARENA_MODE_DEFAULT; -ssize_t opt_decay_time = DECAY_TIME_DEFAULT; -static ssize_t decay_time_default; +ssize_t opt_dirty_decay_time = DIRTY_DECAY_TIME_DEFAULT; +ssize_t opt_muzzy_decay_time = MUZZY_DECAY_TIME_DEFAULT; +static ssize_t dirty_decay_time_default; +static ssize_t muzzy_decay_time_default; const arena_bin_info_t arena_bin_info[NBINS] = { #define BIN_INFO_bin_yes(reg_size, slab_size, nregs) \ @@ -37,12 +39,13 @@ const arena_bin_info_t arena_bin_info[NBINS] = { * definition. */ -static void arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, - arena_decay_t *decay, extents_t *extents, size_t ndirty_limit); -static void arena_dalloc_bin_slab(tsdn_t *tsdn, arena_t *arena, - extent_t *slab, arena_bin_t *bin); -static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, - extent_t *slab, arena_bin_t *bin); +static void arena_decay_to_limit(tsdn_t *tsdn, arena_t *arena, + arena_decay_t *decay, extents_t *extents, bool all, size_t npages_limit); +static void arena_decay_dirty(tsdn_t *tsdn, arena_t *arena, bool all); +static void arena_dalloc_bin_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, + arena_bin_t *bin); +static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, + arena_bin_t *bin); /******************************************************************************/ @@ -50,7 +53,7 @@ static bool arena_stats_init(tsdn_t *tsdn, arena_stats_t *arena_stats) { if (config_debug) { for (size_t i = 0; i < sizeof(arena_stats_t); i++) { - assert(((char *)arena_stats)[0] == 0); + assert(((char *)arena_stats)[i] == 0); } } #ifndef JEMALLOC_ATOMIC_U64 @@ -187,23 +190,27 @@ arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t size) { void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty) { + const char **dss, ssize_t *dirty_decay_time, ssize_t *muzzy_decay_time, + size_t *nactive, size_t *ndirty, + size_t *nmuzzy) { *nthreads += arena_nthreads_get(arena, false); *dss = dss_prec_names[arena_dss_prec_get(arena)]; - *decay_time = arena_decay_time_get(arena); + *dirty_decay_time = arena_dirty_decay_time_get(arena); + *muzzy_decay_time = arena_muzzy_decay_time_get(arena); *nactive += atomic_read_zu(&arena->nactive); - *ndirty += extents_npages_get(&arena->extents_cached); + *ndirty += extents_npages_get(&arena->extents_dirty); + *nmuzzy += extents_npages_get(&arena->extents_muzzy); } void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *decay_time, size_t *nactive, size_t *ndirty, - arena_stats_t *astats, malloc_bin_stats_t *bstats, - malloc_large_stats_t *lstats) { + const char **dss, ssize_t *dirty_decay_time, ssize_t *muzzy_decay_time, + size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats, + malloc_bin_stats_t *bstats, malloc_large_stats_t *lstats) { cassert(config_stats); - arena_basic_stats_merge(tsdn, arena, nthreads, dss, decay_time, - nactive, ndirty); + arena_basic_stats_merge(tsdn, arena, nthreads, dss, dirty_decay_time, + muzzy_decay_time, nactive, ndirty, nmuzzy); size_t base_allocated, base_resident, base_mapped; base_stats_get(tsdn, arena->base, &base_allocated, &base_resident, @@ -215,17 +222,33 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, + arena_stats_read_zu(tsdn, &arena->stats, &arena->stats.mapped)); arena_stats_accum_zu(&astats->retained, extents_npages_get(&arena->extents_retained) << LG_PAGE); - arena_stats_accum_u64(&astats->npurge, arena_stats_read_u64(tsdn, - &arena->stats, &arena->stats.npurge)); - arena_stats_accum_u64(&astats->nmadvise, arena_stats_read_u64(tsdn, - &arena->stats, &arena->stats.nmadvise)); - arena_stats_accum_u64(&astats->purged, arena_stats_read_u64(tsdn, - &arena->stats, &arena->stats.purged)); + + arena_stats_accum_u64(&astats->decay_dirty.npurge, + arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.decay_dirty.npurge)); + arena_stats_accum_u64(&astats->decay_dirty.nmadvise, + arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.decay_dirty.nmadvise)); + arena_stats_accum_u64(&astats->decay_dirty.purged, + arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.decay_dirty.purged)); + + arena_stats_accum_u64(&astats->decay_muzzy.npurge, + arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.decay_muzzy.npurge)); + arena_stats_accum_u64(&astats->decay_muzzy.nmadvise, + arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.decay_muzzy.nmadvise)); + arena_stats_accum_u64(&astats->decay_muzzy.purged, + arena_stats_read_u64(tsdn, &arena->stats, + &arena->stats.decay_muzzy.purged)); + arena_stats_accum_zu(&astats->base, base_allocated); arena_stats_accum_zu(&astats->internal, arena_internal_get(arena)); - arena_stats_accum_zu(&astats->resident, base_resident - + (((atomic_read_zu(&arena->nactive) - + extents_npages_get(&arena->extents_cached)) << LG_PAGE))); + arena_stats_accum_zu(&astats->resident, base_resident + + (((atomic_read_zu(&arena->nactive) + + extents_npages_get(&arena->extents_dirty) + + extents_npages_get(&arena->extents_muzzy)) << LG_PAGE))); for (szind_t i = 0; i < NSIZES - NBINS; i++) { uint64_t nmalloc = arena_stats_read_u64(tsdn, &arena->stats, @@ -292,13 +315,14 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, } void -arena_extent_cache_dalloc(tsdn_t *tsdn, arena_t *arena, +arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - extent_dalloc_cache(tsdn, arena, r_extent_hooks, extent); - if (arena_decay_time_get(arena) == 0) { - arena_purge(tsdn, arena, true); + extents_dalloc(tsdn, arena, r_extent_hooks, &arena->extents_dirty, + extent); + if (arena_dirty_decay_time_get(arena) == 0) { + arena_decay_dirty(tsdn, arena, true); } } @@ -432,8 +456,14 @@ arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t mapped_add; bool commit = true; - extent = extent_alloc_cache(tsdn, arena, &extent_hooks, NULL, usize, - large_pad, alignment, zero, &commit, false); + extent = extents_alloc(tsdn, arena, &extent_hooks, + &arena->extents_dirty, NULL, usize, large_pad, alignment, zero, + &commit, false); + if (extent == NULL) { + extent = extents_alloc(tsdn, arena, &extent_hooks, + &arena->extents_muzzy, NULL, usize, large_pad, alignment, + zero, &commit, false); + } size_t size = usize + large_pad; if (extent == NULL) { extent = extent_alloc_wrapper(tsdn, arena, &extent_hooks, NULL, @@ -507,12 +537,12 @@ arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, static ssize_t arena_decay_time_read(arena_decay_t *decay) { - return atomic_read_zd(&decay->time); + return atomic_load_zd(&decay->time, ATOMIC_RELAXED); } static void arena_decay_time_write(arena_decay_t *decay, ssize_t decay_time) { - atomic_write_zd(&decay->time, decay_time); + atomic_store_zd(&decay->time, decay_time, ATOMIC_RELAXED); } static void @@ -621,10 +651,11 @@ arena_decay_epoch_advance_helper(arena_decay_t *decay, extents_t *extents, static void arena_decay_epoch_advance_purge(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, extents_t *extents) { - size_t ndirty_limit = arena_decay_backlog_npages_limit(decay); + size_t npages_limit = arena_decay_backlog_npages_limit(decay); - if (extents_npages_get(extents) > ndirty_limit) { - arena_purge_to_limit(tsdn, arena, decay, extents, ndirty_limit); + if (extents_npages_get(extents) > npages_limit) { + arena_decay_to_limit(tsdn, arena, decay, extents, false, + npages_limit); } /* * There may be concurrent ndirty fluctuation between the purge above @@ -659,12 +690,22 @@ arena_decay_reinit(arena_decay_t *decay, extents_t *extents, } static bool -arena_decay_init(arena_decay_t *decay, extents_t *extents, ssize_t decay_time) { +arena_decay_init(arena_decay_t *decay, extents_t *extents, ssize_t decay_time, + decay_stats_t *stats) { + if (config_debug) { + for (size_t i = 0; i < sizeof(arena_decay_t); i++) { + assert(((char *)decay)[i] == 0); + } + } if (malloc_mutex_init(&decay->mtx, "decay", WITNESS_RANK_DECAY)) { return true; } decay->purging = false; arena_decay_reinit(decay, extents, decay_time); + /* Memory is zeroed, so there is no need to clear stats. */ + if (config_stats) { + decay->stats = stats; + } return false; } @@ -680,7 +721,7 @@ arena_decay_time_valid(ssize_t decay_time) { } static void -arena_maybe_purge(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, +arena_maybe_decay(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, extents_t *extents) { malloc_mutex_assert_owner(tsdn, &decay->mtx); @@ -688,7 +729,8 @@ arena_maybe_purge(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, ssize_t decay_time = arena_decay_time_read(decay); if (decay_time <= 0) { if (decay_time == 0) { - arena_purge_to_limit(tsdn, arena, decay, extents, 0); + arena_decay_to_limit(tsdn, arena, decay, extents, false, + 0); } return; } @@ -725,18 +767,29 @@ arena_maybe_purge(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, } } +static ssize_t +arena_decay_time_get(arena_decay_t *decay) { + return arena_decay_time_read(decay); +} + ssize_t -arena_decay_time_get(arena_t *arena) { - return arena_decay_time_read(&arena->decay); +arena_dirty_decay_time_get(arena_t *arena) { + return arena_decay_time_get(&arena->decay_dirty); } -bool -arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { +ssize_t +arena_muzzy_decay_time_get(arena_t *arena) { + return arena_decay_time_get(&arena->decay_muzzy); +} + +static bool +arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, + extents_t *extents, ssize_t decay_time) { if (!arena_decay_time_valid(decay_time)) { return true; } - malloc_mutex_lock(tsdn, &arena->decay.mtx); + malloc_mutex_lock(tsdn, &decay->mtx); /* * Restart decay backlog from scratch, which may cause many dirty pages * to be immediately purged. It would conceptually be possible to map @@ -745,58 +798,100 @@ arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { * infrequent, either between the {-1, 0, >0} states, or a one-time * arbitrary change during initial arena configuration. */ - arena_decay_reinit(&arena->decay, &arena->extents_cached, decay_time); - arena_maybe_purge(tsdn, arena, &arena->decay, &arena->extents_cached); - malloc_mutex_unlock(tsdn, &arena->decay.mtx); + arena_decay_reinit(decay, extents, decay_time); + arena_maybe_decay(tsdn, arena, decay, extents); + malloc_mutex_unlock(tsdn, &decay->mtx); return false; } +bool +arena_dirty_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { + return arena_decay_time_set(tsdn, arena, &arena->decay_dirty, + &arena->extents_dirty, decay_time); +} + +bool +arena_muzzy_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { + return arena_decay_time_set(tsdn, arena, &arena->decay_muzzy, + &arena->extents_muzzy, decay_time); +} + static size_t -arena_stash_dirty(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extents_t *extents, size_t ndirty_limit, extent_list_t *purge_extents) { +arena_stash_decayed(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extents_t *extents, size_t npages_limit, + extent_list_t *decay_extents) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - /* Stash extents according to ndirty_limit. */ + /* Stash extents according to npages_limit. */ size_t nstashed = 0; extent_t *extent; while ((extent = extents_evict(tsdn, arena, r_extent_hooks, extents, - ndirty_limit)) != NULL) { - extent_list_append(purge_extents, extent); + npages_limit)) != NULL) { + extent_list_append(decay_extents, extent); nstashed += extent_size_get(extent) >> LG_PAGE; } return nstashed; } static size_t -arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_list_t *purge_extents) { - UNUSED size_t nmadvise; +arena_decay_stashed(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, arena_decay_t *decay, extents_t *extents, + bool all, extent_list_t *decay_extents) { + UNUSED size_t nmadvise, nunmapped; size_t npurged; if (config_stats) { nmadvise = 0; + nunmapped = 0; } npurged = 0; - for (extent_t *extent = extent_list_first(purge_extents); extent != - NULL; extent = extent_list_first(purge_extents)) { + ssize_t muzzy_decay_time = arena_muzzy_decay_time_get(arena); + for (extent_t *extent = extent_list_first(decay_extents); extent != + NULL; extent = extent_list_first(decay_extents)) { if (config_stats) { nmadvise++; } - npurged += extent_size_get(extent) >> LG_PAGE; - extent_list_remove(purge_extents, extent); - extent_dalloc_wrapper(tsdn, arena, r_extent_hooks, extent); + size_t npages = extent_size_get(extent) >> LG_PAGE; + npurged += npages; + extent_list_remove(decay_extents, extent); + switch (extents_state_get(extents)) { + case extent_state_active: + not_reached(); + case extent_state_dirty: + if (!all && muzzy_decay_time != 0 && + !extent_purge_lazy_wrapper(tsdn, arena, + r_extent_hooks, extent, 0, + extent_size_get(extent))) { + extents_dalloc(tsdn, arena, r_extent_hooks, + &arena->extents_muzzy, extent); + break; + } + /* Fall through. */ + case extent_state_muzzy: + extent_dalloc_wrapper(tsdn, arena, r_extent_hooks, + extent); + if (config_stats) { + nunmapped += npages; + } + break; + case extent_state_retained: + default: + not_reached(); + } } if (config_stats) { arena_stats_lock(tsdn, &arena->stats); - arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.nmadvise, - nmadvise); - arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.purged, + arena_stats_add_u64(tsdn, &arena->stats, &decay->stats->npurge, + 1); + arena_stats_add_u64(tsdn, &arena->stats, + &decay->stats->nmadvise, nmadvise); + arena_stats_add_u64(tsdn, &arena->stats, &decay->stats->purged, npurged); arena_stats_sub_zu(tsdn, &arena->stats, &arena->stats.mapped, - npurged << LG_PAGE); + nunmapped); arena_stats_unlock(tsdn, &arena->stats); } @@ -804,12 +899,12 @@ arena_purge_stashed(tsdn_t *tsdn, arena_t *arena, } /* - * ndirty_limit: Purge as many dirty extents as possible without violating the - * invariant: (extents_npages_get(extents) >= ndirty_limit) + * npages_limit: Decay as many dirty extents as possible without violating the + * invariant: (extents_npages_get(extents) >= npages_limit) */ static void -arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, - extents_t *extents, size_t ndirty_limit) { +arena_decay_to_limit(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, + extents_t *extents, bool all, size_t npages_limit) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 1); malloc_mutex_assert_owner(tsdn, &decay->mtx); @@ -817,49 +912,53 @@ arena_purge_to_limit(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, return; } decay->purging = true; + malloc_mutex_unlock(tsdn, &decay->mtx); extent_hooks_t *extent_hooks = extent_hooks_get(arena); - size_t npurge, npurged; - extent_list_t purge_extents; - extent_list_init(&purge_extents); + extent_list_t decay_extents; + extent_list_init(&decay_extents); - malloc_mutex_unlock(tsdn, &decay->mtx); - - npurge = arena_stash_dirty(tsdn, arena, &extent_hooks, extents, - ndirty_limit, &purge_extents); - if (npurge == 0) { - malloc_mutex_lock(tsdn, &decay->mtx); - goto label_return; + size_t npurge = arena_stash_decayed(tsdn, arena, &extent_hooks, extents, + npages_limit, &decay_extents); + if (npurge != 0) { + UNUSED size_t npurged = arena_decay_stashed(tsdn, arena, + &extent_hooks, decay, extents, all, &decay_extents); + assert(npurged == npurge); } - npurged = arena_purge_stashed(tsdn, arena, &extent_hooks, - &purge_extents); - assert(npurged == npurge); malloc_mutex_lock(tsdn, &decay->mtx); - - if (config_stats) { - arena_stats_lock(tsdn, &arena->stats); - arena_stats_add_u64(tsdn, &arena->stats, &arena->stats.npurge, - 1); - arena_stats_unlock(tsdn, &arena->stats); - } - -label_return: decay->purging = false; } -void -arena_purge(tsdn_t *tsdn, arena_t *arena, bool all) { - malloc_mutex_lock(tsdn, &arena->decay.mtx); +static void +arena_decay_impl(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, + extents_t *extents, bool all) { + malloc_mutex_lock(tsdn, &decay->mtx); if (all) { - arena_purge_to_limit(tsdn, arena, &arena->decay, - &arena->extents_cached, 0); + arena_decay_to_limit(tsdn, arena, decay, extents, all, 0); } else { - arena_maybe_purge(tsdn, arena, &arena->decay, - &arena->extents_cached); + arena_maybe_decay(tsdn, arena, decay, extents); } - malloc_mutex_unlock(tsdn, &arena->decay.mtx); + malloc_mutex_unlock(tsdn, &decay->mtx); +} + +static void +arena_decay_dirty(tsdn_t *tsdn, arena_t *arena, bool all) { + arena_decay_impl(tsdn, arena, &arena->decay_dirty, + &arena->extents_dirty, all); +} + +static void +arena_decay_muzzy(tsdn_t *tsdn, arena_t *arena, bool all) { + arena_decay_impl(tsdn, arena, &arena->decay_muzzy, + &arena->extents_muzzy, all); +} + +void +arena_decay(tsdn_t *tsdn, arena_t *arena, bool all) { + arena_decay_dirty(tsdn, arena, all); + arena_decay_muzzy(tsdn, arena, all); } static void @@ -867,7 +966,7 @@ arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) { arena_nactive_sub(arena, extent_size_get(slab) >> LG_PAGE); extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; - arena_extent_cache_dalloc(tsdn, arena, &extent_hooks, slab); + arena_extents_dirty_dalloc(tsdn, arena, &extent_hooks, slab); } static void @@ -1008,7 +1107,7 @@ arena_destroy(tsd_t *tsd, arena_t *arena) { * Furthermore, the caller (arena_i_destroy_ctl()) purged all cached * extents, so only retained extents may remain. */ - assert(extents_npages_get(&arena->extents_cached) == 0); + assert(extents_npages_get(&arena->extents_dirty) == 0); /* Attempt to deallocate retained memory. */ arena_destroy_retained(tsd_tsdn(tsd), arena); @@ -1061,8 +1160,14 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; bool zero = false; bool commit = true; - extent_t *slab = extent_alloc_cache(tsdn, arena, &extent_hooks, NULL, - bin_info->slab_size, 0, PAGE, &zero, &commit, true); + extent_t *slab = extents_alloc(tsdn, arena, &extent_hooks, + &arena->extents_dirty, NULL, bin_info->slab_size, 0, PAGE, &zero, + &commit, true); + if (slab == NULL) { + slab = extents_alloc(tsdn, arena, &extent_hooks, + &arena->extents_muzzy, NULL, bin_info->slab_size, 0, PAGE, + &zero, &commit, true); + } if (slab == NULL) { slab = arena_slab_alloc_hard(tsdn, arena, &extent_hooks, bin_info); @@ -1622,16 +1727,32 @@ arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec) { } ssize_t -arena_decay_time_default_get(void) { - return (ssize_t)atomic_read_zu((size_t *)&decay_time_default); +arena_dirty_decay_time_default_get(void) { + return (ssize_t)atomic_read_zu((size_t *)&dirty_decay_time_default); +} + +bool +arena_dirty_decay_time_default_set(ssize_t decay_time) { + if (!arena_decay_time_valid(decay_time)) { + return true; + } + atomic_write_zu((size_t *)&dirty_decay_time_default, + (size_t)decay_time); + return false; +} + +ssize_t +arena_muzzy_decay_time_default_get(void) { + return (ssize_t)atomic_read_zu((size_t *)&muzzy_decay_time_default); } bool -arena_decay_time_default_set(ssize_t decay_time) { +arena_muzzy_decay_time_default_set(ssize_t decay_time) { if (!arena_decay_time_valid(decay_time)) { return true; } - atomic_write_zu((size_t *)&decay_time_default, (size_t)decay_time); + atomic_write_zu((size_t *)&muzzy_decay_time_default, + (size_t)decay_time); return false; } @@ -1723,28 +1844,40 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { } /* - * Delay coalescing for cached extents despite the disruptive effect on + * Delay coalescing for dirty extents despite the disruptive effect on * memory layout for best-fit extent allocation, since cached extents * are likely to be reused soon after deallocation, and the cost of * merging/splitting extents is non-trivial. */ - if (extents_init(tsdn, &arena->extents_cached, extent_state_dirty, + if (extents_init(tsdn, &arena->extents_dirty, extent_state_dirty, true)) { goto label_error; } + /* + * Coalesce muzzy extents immediately, because operations on them are in + * the critical path much less often than for dirty extents. + */ + if (extents_init(tsdn, &arena->extents_muzzy, extent_state_muzzy, + false)) { + goto label_error; + } /* * Coalesce retained extents immediately, in part because they will * never be evicted (and therefore there's no opportunity for delayed * coalescing), but also because operations on retained extents are not * in the critical path. */ - if (extents_init(tsdn, &arena->extents_retained, - extent_state_retained, false)) { + if (extents_init(tsdn, &arena->extents_retained, extent_state_retained, + false)) { goto label_error; } - if (arena_decay_init(&arena->decay, &arena->extents_cached, - arena_decay_time_default_get())) { + if (arena_decay_init(&arena->decay_dirty, &arena->extents_dirty, + arena_dirty_decay_time_default_get(), &arena->stats.decay_dirty)) { + goto label_error; + } + if (arena_decay_init(&arena->decay_muzzy, &arena->extents_muzzy, + arena_muzzy_decay_time_default_get(), &arena->stats.decay_muzzy)) { goto label_error; } @@ -1785,12 +1918,14 @@ label_error: void arena_boot(void) { - arena_decay_time_default_set(opt_decay_time); + arena_dirty_decay_time_default_set(opt_dirty_decay_time); + arena_muzzy_decay_time_default_set(opt_muzzy_decay_time); } void arena_prefork0(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_prefork(tsdn, &arena->decay.mtx); + malloc_mutex_prefork(tsdn, &arena->decay_dirty.mtx); + malloc_mutex_prefork(tsdn, &arena->decay_muzzy.mtx); } void @@ -1802,7 +1937,8 @@ arena_prefork1(tsdn_t *tsdn, arena_t *arena) { void arena_prefork2(tsdn_t *tsdn, arena_t *arena) { - extents_prefork(tsdn, &arena->extents_cached); + extents_prefork(tsdn, &arena->extents_dirty); + extents_prefork(tsdn, &arena->extents_muzzy); extents_prefork(tsdn, &arena->extents_retained); } @@ -1838,9 +1974,11 @@ arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_postfork_parent(tsdn, &arena->large_mtx); base_postfork_parent(tsdn, arena->base); malloc_mutex_postfork_parent(tsdn, &arena->extent_freelist_mtx); - extents_postfork_parent(tsdn, &arena->extents_cached); + extents_postfork_parent(tsdn, &arena->extents_dirty); + extents_postfork_parent(tsdn, &arena->extents_muzzy); extents_postfork_parent(tsdn, &arena->extents_retained); - malloc_mutex_postfork_parent(tsdn, &arena->decay.mtx); + malloc_mutex_postfork_parent(tsdn, &arena->decay_dirty.mtx); + malloc_mutex_postfork_parent(tsdn, &arena->decay_muzzy.mtx); if (config_stats && config_tcache) { malloc_mutex_postfork_parent(tsdn, &arena->tcache_ql_mtx); } @@ -1856,9 +1994,11 @@ arena_postfork_child(tsdn_t *tsdn, arena_t *arena) { malloc_mutex_postfork_child(tsdn, &arena->large_mtx); base_postfork_child(tsdn, arena->base); malloc_mutex_postfork_child(tsdn, &arena->extent_freelist_mtx); - extents_postfork_child(tsdn, &arena->extents_cached); + extents_postfork_child(tsdn, &arena->extents_dirty); + extents_postfork_child(tsdn, &arena->extents_muzzy); extents_postfork_child(tsdn, &arena->extents_retained); - malloc_mutex_postfork_child(tsdn, &arena->decay.mtx); + malloc_mutex_postfork_child(tsdn, &arena->decay_dirty.mtx); + malloc_mutex_postfork_child(tsdn, &arena->decay_muzzy.mtx); if (config_stats && config_tcache) { malloc_mutex_postfork_child(tsdn, &arena->tcache_ql_mtx); } diff --git a/src/ctl.c b/src/ctl.c index 70721584..ee69be6d 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -73,7 +73,8 @@ CTL_PROTO(opt_abort) CTL_PROTO(opt_dss) CTL_PROTO(opt_narenas) CTL_PROTO(opt_percpu_arena) -CTL_PROTO(opt_decay_time) +CTL_PROTO(opt_dirty_decay_time) +CTL_PROTO(opt_muzzy_decay_time) CTL_PROTO(opt_stats_print) CTL_PROTO(opt_junk) CTL_PROTO(opt_zero) @@ -95,12 +96,13 @@ CTL_PROTO(tcache_create) CTL_PROTO(tcache_flush) CTL_PROTO(tcache_destroy) CTL_PROTO(arena_i_initialized) -CTL_PROTO(arena_i_purge) CTL_PROTO(arena_i_decay) +CTL_PROTO(arena_i_purge) CTL_PROTO(arena_i_reset) CTL_PROTO(arena_i_destroy) CTL_PROTO(arena_i_dss) -CTL_PROTO(arena_i_decay_time) +CTL_PROTO(arena_i_dirty_decay_time) +CTL_PROTO(arena_i_muzzy_decay_time) CTL_PROTO(arena_i_extent_hooks) INDEX_PROTO(arena_i) CTL_PROTO(arenas_bin_i_size) @@ -110,7 +112,8 @@ INDEX_PROTO(arenas_bin_i) CTL_PROTO(arenas_lextent_i_size) INDEX_PROTO(arenas_lextent_i) CTL_PROTO(arenas_narenas) -CTL_PROTO(arenas_decay_time) +CTL_PROTO(arenas_dirty_decay_time) +CTL_PROTO(arenas_muzzy_decay_time) CTL_PROTO(arenas_quantum) CTL_PROTO(arenas_page) CTL_PROTO(arenas_tcache_max) @@ -150,14 +153,19 @@ CTL_PROTO(stats_arenas_i_lextents_j_curlextents) INDEX_PROTO(stats_arenas_i_lextents_j) CTL_PROTO(stats_arenas_i_nthreads) CTL_PROTO(stats_arenas_i_dss) -CTL_PROTO(stats_arenas_i_decay_time) +CTL_PROTO(stats_arenas_i_dirty_decay_time) +CTL_PROTO(stats_arenas_i_muzzy_decay_time) CTL_PROTO(stats_arenas_i_pactive) CTL_PROTO(stats_arenas_i_pdirty) +CTL_PROTO(stats_arenas_i_pmuzzy) CTL_PROTO(stats_arenas_i_mapped) CTL_PROTO(stats_arenas_i_retained) -CTL_PROTO(stats_arenas_i_npurge) -CTL_PROTO(stats_arenas_i_nmadvise) -CTL_PROTO(stats_arenas_i_purged) +CTL_PROTO(stats_arenas_i_dirty_npurge) +CTL_PROTO(stats_arenas_i_dirty_nmadvise) +CTL_PROTO(stats_arenas_i_dirty_purged) +CTL_PROTO(stats_arenas_i_muzzy_npurge) +CTL_PROTO(stats_arenas_i_muzzy_nmadvise) +CTL_PROTO(stats_arenas_i_muzzy_purged) CTL_PROTO(stats_arenas_i_base) CTL_PROTO(stats_arenas_i_internal) CTL_PROTO(stats_arenas_i_tcache_bytes) @@ -231,7 +239,8 @@ static const ctl_named_node_t opt_node[] = { {NAME("dss"), CTL(opt_dss)}, {NAME("narenas"), CTL(opt_narenas)}, {NAME("percpu_arena"), CTL(opt_percpu_arena)}, - {NAME("decay_time"), CTL(opt_decay_time)}, + {NAME("dirty_decay_time"), CTL(opt_dirty_decay_time)}, + {NAME("muzzy_decay_time"), CTL(opt_muzzy_decay_time)}, {NAME("stats_print"), CTL(opt_stats_print)}, {NAME("junk"), CTL(opt_junk)}, {NAME("zero"), CTL(opt_zero)}, @@ -259,12 +268,13 @@ static const ctl_named_node_t tcache_node[] = { static const ctl_named_node_t arena_i_node[] = { {NAME("initialized"), CTL(arena_i_initialized)}, - {NAME("purge"), CTL(arena_i_purge)}, {NAME("decay"), CTL(arena_i_decay)}, + {NAME("purge"), CTL(arena_i_purge)}, {NAME("reset"), CTL(arena_i_reset)}, {NAME("destroy"), CTL(arena_i_destroy)}, {NAME("dss"), CTL(arena_i_dss)}, - {NAME("decay_time"), CTL(arena_i_decay_time)}, + {NAME("dirty_decay_time"), CTL(arena_i_dirty_decay_time)}, + {NAME("muzzy_decay_time"), CTL(arena_i_muzzy_decay_time)}, {NAME("extent_hooks"), CTL(arena_i_extent_hooks)} }; static const ctl_named_node_t super_arena_i_node[] = { @@ -301,7 +311,8 @@ static const ctl_indexed_node_t arenas_lextent_node[] = { static const ctl_named_node_t arenas_node[] = { {NAME("narenas"), CTL(arenas_narenas)}, - {NAME("decay_time"), CTL(arenas_decay_time)}, + {NAME("dirty_decay_time"), CTL(arenas_dirty_decay_time)}, + {NAME("muzzy_decay_time"), CTL(arenas_muzzy_decay_time)}, {NAME("quantum"), CTL(arenas_quantum)}, {NAME("page"), CTL(arenas_page)}, {NAME("tcache_max"), CTL(arenas_tcache_max)}, @@ -373,14 +384,19 @@ static const ctl_indexed_node_t stats_arenas_i_lextents_node[] = { static const ctl_named_node_t stats_arenas_i_node[] = { {NAME("nthreads"), CTL(stats_arenas_i_nthreads)}, {NAME("dss"), CTL(stats_arenas_i_dss)}, - {NAME("decay_time"), CTL(stats_arenas_i_decay_time)}, + {NAME("dirty_decay_time"), CTL(stats_arenas_i_dirty_decay_time)}, + {NAME("muzzy_decay_time"), CTL(stats_arenas_i_muzzy_decay_time)}, {NAME("pactive"), CTL(stats_arenas_i_pactive)}, {NAME("pdirty"), CTL(stats_arenas_i_pdirty)}, + {NAME("pmuzzy"), CTL(stats_arenas_i_pmuzzy)}, {NAME("mapped"), CTL(stats_arenas_i_mapped)}, {NAME("retained"), CTL(stats_arenas_i_retained)}, - {NAME("npurge"), CTL(stats_arenas_i_npurge)}, - {NAME("nmadvise"), CTL(stats_arenas_i_nmadvise)}, - {NAME("purged"), CTL(stats_arenas_i_purged)}, + {NAME("dirty_npurge"), CTL(stats_arenas_i_dirty_npurge)}, + {NAME("dirty_nmadvise"), CTL(stats_arenas_i_dirty_nmadvise)}, + {NAME("dirty_purged"), CTL(stats_arenas_i_dirty_purged)}, + {NAME("muzzy_npurge"), CTL(stats_arenas_i_muzzy_npurge)}, + {NAME("muzzy_nmadvise"), CTL(stats_arenas_i_muzzy_nmadvise)}, + {NAME("muzzy_purged"), CTL(stats_arenas_i_muzzy_purged)}, {NAME("base"), CTL(stats_arenas_i_base)}, {NAME("internal"), CTL(stats_arenas_i_internal)}, {NAME("tcache_bytes"), CTL(stats_arenas_i_tcache_bytes)}, @@ -554,9 +570,11 @@ static void ctl_arena_clear(ctl_arena_t *ctl_arena) { ctl_arena->nthreads = 0; ctl_arena->dss = dss_prec_names[dss_prec_limit]; - ctl_arena->decay_time = -1; + ctl_arena->dirty_decay_time = -1; + ctl_arena->muzzy_decay_time = -1; ctl_arena->pactive = 0; ctl_arena->pdirty = 0; + ctl_arena->pmuzzy = 0; if (config_stats) { memset(&ctl_arena->astats->astats, 0, sizeof(arena_stats_t)); ctl_arena->astats->allocated_small = 0; @@ -576,8 +594,9 @@ ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_t *ctl_arena, arena_t *arena) { if (config_stats) { arena_stats_merge(tsdn, arena, &ctl_arena->nthreads, - &ctl_arena->dss, &ctl_arena->decay_time, - &ctl_arena->pactive, &ctl_arena->pdirty, + &ctl_arena->dss, &ctl_arena->dirty_decay_time, + &ctl_arena->muzzy_decay_time, &ctl_arena->pactive, + &ctl_arena->pdirty, &ctl_arena->pmuzzy, &ctl_arena->astats->astats, ctl_arena->astats->bstats, ctl_arena->astats->lstats); @@ -594,8 +613,9 @@ ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_t *ctl_arena, arena_t *arena) { } } else { arena_basic_stats_merge(tsdn, arena, &ctl_arena->nthreads, - &ctl_arena->dss, &ctl_arena->decay_time, - &ctl_arena->pactive, &ctl_arena->pdirty); + &ctl_arena->dss, &ctl_arena->dirty_decay_time, + &ctl_arena->muzzy_decay_time, &ctl_arena->pactive, + &ctl_arena->pdirty, &ctl_arena->pmuzzy); } } @@ -608,10 +628,12 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, ctl_sdarena->nthreads += ctl_arena->nthreads; ctl_sdarena->pactive += ctl_arena->pactive; ctl_sdarena->pdirty += ctl_arena->pdirty; + ctl_sdarena->pmuzzy += ctl_arena->pmuzzy; } else { assert(ctl_arena->nthreads == 0); assert(ctl_arena->pactive == 0); assert(ctl_arena->pdirty == 0); + assert(ctl_arena->pmuzzy == 0); } if (config_stats) { @@ -624,12 +646,20 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, accum_atomic_zu(&sdstats->astats.retained, &astats->astats.retained); } - accum_arena_stats_u64(&sdstats->astats.npurge, - &astats->astats.npurge); - accum_arena_stats_u64(&sdstats->astats.nmadvise, - &astats->astats.nmadvise); - accum_arena_stats_u64(&sdstats->astats.purged, - &astats->astats.purged); + + accum_arena_stats_u64(&sdstats->astats.decay_dirty.npurge, + &astats->astats.decay_dirty.npurge); + accum_arena_stats_u64(&sdstats->astats.decay_dirty.nmadvise, + &astats->astats.decay_dirty.nmadvise); + accum_arena_stats_u64(&sdstats->astats.decay_dirty.purged, + &astats->astats.decay_dirty.purged); + + accum_arena_stats_u64(&sdstats->astats.decay_muzzy.npurge, + &astats->astats.decay_muzzy.npurge); + accum_arena_stats_u64(&sdstats->astats.decay_muzzy.nmadvise, + &astats->astats.decay_muzzy.nmadvise); + accum_arena_stats_u64(&sdstats->astats.decay_muzzy.purged, + &astats->astats.decay_muzzy.purged); if (!destroyed) { accum_atomic_zu(&sdstats->astats.base, @@ -1340,7 +1370,8 @@ CTL_RO_NL_GEN(opt_abort, opt_abort, bool) CTL_RO_NL_GEN(opt_dss, opt_dss, const char *) CTL_RO_NL_GEN(opt_narenas, opt_narenas, unsigned) CTL_RO_NL_GEN(opt_percpu_arena, opt_percpu_arena, const char *) -CTL_RO_NL_GEN(opt_decay_time, opt_decay_time, ssize_t) +CTL_RO_NL_GEN(opt_dirty_decay_time, opt_dirty_decay_time, ssize_t) +CTL_RO_NL_GEN(opt_muzzy_decay_time, opt_muzzy_decay_time, ssize_t) CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool) CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *) CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool) @@ -1630,7 +1661,7 @@ label_return: } static void -arena_i_purge(tsdn_t *tsdn, unsigned arena_ind, bool all) { +arena_i_decay(tsdn_t *tsdn, unsigned arena_ind, bool all) { malloc_mutex_lock(tsdn, &ctl_mtx); { unsigned narenas = ctl_arenas->narenas; @@ -1655,7 +1686,7 @@ arena_i_purge(tsdn_t *tsdn, unsigned arena_ind, bool all) { for (i = 0; i < narenas; i++) { if (tarenas[i] != NULL) { - arena_purge(tsdn, tarenas[i], all); + arena_decay(tsdn, tarenas[i], all); } } } else { @@ -1669,14 +1700,14 @@ arena_i_purge(tsdn_t *tsdn, unsigned arena_ind, bool all) { malloc_mutex_unlock(tsdn, &ctl_mtx); if (tarena != NULL) { - arena_purge(tsdn, tarena, all); + arena_decay(tsdn, tarena, all); } } } } static int -arena_i_purge_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, +arena_i_decay_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; unsigned arena_ind; @@ -1684,7 +1715,7 @@ arena_i_purge_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, READONLY(); WRITEONLY(); MIB_UNSIGNED(arena_ind, 1); - arena_i_purge(tsd_tsdn(tsd), arena_ind, true); + arena_i_decay(tsd_tsdn(tsd), arena_ind, false); ret = 0; label_return: @@ -1692,7 +1723,7 @@ label_return: } static int -arena_i_decay_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, +arena_i_purge_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; unsigned arena_ind; @@ -1700,7 +1731,7 @@ arena_i_decay_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, READONLY(); WRITEONLY(); MIB_UNSIGNED(arena_ind, 1); - arena_i_purge(tsd_tsdn(tsd), arena_ind, false); + arena_i_decay(tsd_tsdn(tsd), arena_ind, true); ret = 0; label_return: @@ -1773,7 +1804,7 @@ arena_i_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, /* Merge stats after resetting and purging arena. */ arena_reset(tsd, arena); - arena_purge(tsd_tsdn(tsd), arena, true); + arena_decay(tsd_tsdn(tsd), arena, true); ctl_darena = arenas_i(MALLCTL_ARENAS_DESTROYED); ctl_darena->initialized = true; ctl_arena_refresh(tsd_tsdn(tsd), arena, ctl_darena, arena_ind, true); @@ -1852,8 +1883,8 @@ label_return: } static int -arena_i_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) { +arena_i_decay_time_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen, + void *oldp, size_t *oldlenp, void *newp, size_t newlen, bool dirty) { int ret; unsigned arena_ind; arena_t *arena; @@ -1866,7 +1897,8 @@ arena_i_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, } if (oldp != NULL && oldlenp != NULL) { - size_t oldval = arena_decay_time_get(arena); + size_t oldval = dirty ? arena_dirty_decay_time_get(arena) : + arena_muzzy_decay_time_get(arena); READ(oldval, ssize_t); } if (newp != NULL) { @@ -1874,7 +1906,9 @@ arena_i_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = EINVAL; goto label_return; } - if (arena_decay_time_set(tsd_tsdn(tsd), arena, + if (dirty ? arena_dirty_decay_time_set(tsd_tsdn(tsd), arena, + *(ssize_t *)newp) : + arena_muzzy_decay_time_set(tsd_tsdn(tsd), arena, *(ssize_t *)newp)) { ret = EFAULT; goto label_return; @@ -1886,6 +1920,20 @@ label_return: return ret; } +static int +arena_i_dirty_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, + void *oldp, size_t *oldlenp, void *newp, size_t newlen) { + return arena_i_decay_time_ctl_impl(tsd, mib, miblen, oldp, oldlenp, + newp, newlen, true); +} + +static int +arena_i_muzzy_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, + void *oldp, size_t *oldlenp, void *newp, size_t newlen) { + return arena_i_decay_time_ctl_impl(tsd, mib, miblen, oldp, oldlenp, + newp, newlen, false); +} + static int arena_i_extent_hooks_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { @@ -1967,12 +2015,13 @@ label_return: } static int -arenas_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen) { +arenas_decay_time_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen, + void *oldp, size_t *oldlenp, void *newp, size_t newlen, bool dirty) { int ret; if (oldp != NULL && oldlenp != NULL) { - size_t oldval = arena_decay_time_default_get(); + size_t oldval = (dirty ? arena_dirty_decay_time_default_get() : + arena_muzzy_decay_time_default_get()); READ(oldval, ssize_t); } if (newp != NULL) { @@ -1980,7 +2029,8 @@ arenas_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, ret = EINVAL; goto label_return; } - if (arena_decay_time_default_set(*(ssize_t *)newp)) { + if (dirty ? arena_dirty_decay_time_default_set(*(ssize_t *)newp) + : arena_muzzy_decay_time_default_set(*(ssize_t *)newp)) { ret = EFAULT; goto label_return; } @@ -1991,6 +2041,20 @@ label_return: return ret; } +static int +arenas_dirty_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, + void *oldp, size_t *oldlenp, void *newp, size_t newlen) { + return arenas_decay_time_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp, + newlen, true); +} + +static int +arenas_muzzy_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, + void *oldp, size_t *oldlenp, void *newp, size_t newlen) { + return arenas_decay_time_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp, + newlen, false); +} + CTL_RO_NL_GEN(arenas_quantum, QUANTUM, size_t) CTL_RO_NL_GEN(arenas_page, PAGE, size_t) CTL_RO_NL_CGEN(config_tcache, arenas_tcache_max, tcache_maxclass, size_t) @@ -2182,23 +2246,41 @@ CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats->mapped, size_t) CTL_RO_CGEN(config_stats, stats_retained, ctl_stats->retained, size_t) CTL_RO_GEN(stats_arenas_i_dss, arenas_i(mib[2])->dss, const char *) -CTL_RO_GEN(stats_arenas_i_decay_time, arenas_i(mib[2])->decay_time, +CTL_RO_GEN(stats_arenas_i_dirty_decay_time, arenas_i(mib[2])->dirty_decay_time, + ssize_t) +CTL_RO_GEN(stats_arenas_i_muzzy_decay_time, arenas_i(mib[2])->muzzy_decay_time, ssize_t) CTL_RO_GEN(stats_arenas_i_nthreads, arenas_i(mib[2])->nthreads, unsigned) CTL_RO_GEN(stats_arenas_i_pactive, arenas_i(mib[2])->pactive, size_t) CTL_RO_GEN(stats_arenas_i_pdirty, arenas_i(mib[2])->pdirty, size_t) +CTL_RO_GEN(stats_arenas_i_pmuzzy, arenas_i(mib[2])->pmuzzy, size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_mapped, atomic_load_zu(&arenas_i(mib[2])->astats->astats.mapped, ATOMIC_RELAXED), size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_retained, atomic_load_zu(&arenas_i(mib[2])->astats->astats.retained, ATOMIC_RELAXED), size_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_npurge, - arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.npurge), uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise, - arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.nmadvise), uint64_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_purged, - arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.purged), uint64_t) + +CTL_RO_CGEN(config_stats, stats_arenas_i_dirty_npurge, + arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.decay_dirty.npurge), + uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_dirty_nmadvise, + arena_stats_read_u64( + &arenas_i(mib[2])->astats->astats.decay_dirty.nmadvise), uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_dirty_purged, + arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.decay_dirty.purged), + uint64_t) + +CTL_RO_CGEN(config_stats, stats_arenas_i_muzzy_npurge, + arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.decay_muzzy.npurge), + uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_muzzy_nmadvise, + arena_stats_read_u64( + &arenas_i(mib[2])->astats->astats.decay_muzzy.nmadvise), uint64_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_muzzy_purged, + arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.decay_muzzy.purged), + uint64_t) + CTL_RO_CGEN(config_stats, stats_arenas_i_base, atomic_load_zu(&arenas_i(mib[2])->astats->astats.base, ATOMIC_RELAXED), size_t) @@ -2268,8 +2350,8 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_ndalloc, arena_stats_read_u64(&arenas_i(mib[2])->astats->lstats[mib[4]].ndalloc), uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nrequests, - arena_stats_read_u64( - &arenas_i(mib[2])->astats->lstats[mib[4]].nrequests), uint64_t) + arena_stats_read_u64(&arenas_i(mib[2])->astats->lstats[mib[4]].nrequests), + uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_curlextents, arenas_i(mib[2])->astats->lstats[mib[4]].curlextents, size_t) diff --git a/src/extent.c b/src/extent.c index c44ecb89..c690b98e 100644 --- a/src/extent.c +++ b/src/extent.c @@ -69,6 +69,10 @@ static size_t highpages; */ static void extent_deregister(tsdn_t *tsdn, extent_t *extent); +static extent_t *extent_recycle(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extents_t *extents, void *new_addr, + size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, + bool slab); static extent_t *extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, extent_t *extent, bool *coalesced); @@ -293,6 +297,31 @@ extent_try_delayed_coalesce(tsdn_t *tsdn, arena_t *arena, return false; } +extent_t * +extents_alloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, + extents_t *extents, void *new_addr, size_t usize, size_t pad, + size_t alignment, bool *zero, bool *commit, bool slab) { + assert(usize + pad != 0); + assert(alignment != 0); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + + return extent_recycle(tsdn, arena, r_extent_hooks, extents, new_addr, + usize, pad, alignment, zero, commit, slab); +} + +void +extents_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, + extents_t *extents, extent_t *extent) { + assert(extent_base_get(extent) != NULL); + assert(extent_size_get(extent) != 0); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + + extent_addr_set(extent, extent_base_get(extent)); + extent_zeroed_set(extent, false); + + extent_record(tsdn, arena, r_extent_hooks, extents, extent); +} + extent_t * extents_evict(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extents_t *extents, size_t npages_min) { @@ -340,7 +369,10 @@ extents_evict(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, * concurrent operations. */ switch (extents_state_get(extents)) { + case extent_state_active: + not_reached(); case extent_state_dirty: + case extent_state_muzzy: extent_state_set(extent, extent_state_active); break; case extent_state_retained: @@ -813,19 +845,6 @@ extent_alloc_core(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, return NULL; } -extent_t * -extent_alloc_cache(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) { - assert(usize + pad != 0); - assert(alignment != 0); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - - return extent_recycle(tsdn, arena, r_extent_hooks, - &arena->extents_cached, new_addr, usize, pad, alignment, zero, - commit, slab); -} - static void * extent_alloc_default_impl(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit) { @@ -1206,7 +1225,8 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - assert(extents_state_get(extents) != extent_state_dirty || + assert((extents_state_get(extents) != extent_state_dirty && + extents_state_get(extents) != extent_state_muzzy) || !extent_zeroed_get(extent)); malloc_mutex_lock(tsdn, &extents->mtx); @@ -1244,20 +1264,6 @@ extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { extent_dalloc_wrapper(tsdn, arena, &extent_hooks, extent); } -void -extent_dalloc_cache(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent) { - assert(extent_base_get(extent) != NULL); - assert(extent_size_get(extent) != 0); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - - extent_addr_set(extent, extent_base_get(extent)); - extent_zeroed_set(extent, false); - - extent_record(tsdn, arena, r_extent_hooks, &arena->extents_cached, - extent); -} - static bool extent_dalloc_default_impl(void *addr, size_t size) { if (!have_dss || !extent_in_dss(addr)) { @@ -1327,16 +1333,17 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, } else if (!extent_decommit_wrapper(tsdn, arena, r_extent_hooks, extent, 0, extent_size_get(extent))) { zeroed = true; - } else if ((*r_extent_hooks)->purge_lazy != NULL && - !(*r_extent_hooks)->purge_lazy(*r_extent_hooks, - extent_base_get(extent), extent_size_get(extent), 0, - extent_size_get(extent), arena_ind_get(arena))) { - zeroed = false; } else if ((*r_extent_hooks)->purge_forced != NULL && !(*r_extent_hooks)->purge_forced(*r_extent_hooks, extent_base_get(extent), extent_size_get(extent), 0, extent_size_get(extent), arena_ind_get(arena))) { zeroed = true; + } else if (extent_state_get(extent) == extent_state_muzzy || + ((*r_extent_hooks)->purge_lazy != NULL && + !(*r_extent_hooks)->purge_lazy(*r_extent_hooks, + extent_base_get(extent), extent_size_get(extent), 0, + extent_size_get(extent), arena_ind_get(arena)))) { + zeroed = false; } else { zeroed = false; } diff --git a/src/jemalloc.c b/src/jemalloc.c index ce84b3cf..c1b05dbb 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1064,8 +1064,10 @@ malloc_conf_init(void) { } CONF_HANDLE_UNSIGNED(opt_narenas, "narenas", 1, UINT_MAX, yes, no, false) - CONF_HANDLE_SSIZE_T(opt_decay_time, "decay_time", -1, - NSTIME_SEC_MAX); + CONF_HANDLE_SSIZE_T(opt_dirty_decay_time, + "dirty_decay_time", -1, NSTIME_SEC_MAX); + CONF_HANDLE_SSIZE_T(opt_muzzy_decay_time, + "muzzy_decay_time", -1, NSTIME_SEC_MAX); CONF_HANDLE_BOOL(opt_stats_print, "stats_print", true) if (config_fill) { if (CONF_MATCH("junk")) { diff --git a/src/large.c b/src/large.c index 5145f418..c578995c 100644 --- a/src/large.c +++ b/src/large.c @@ -125,7 +125,7 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { extent_usize_get(trail)); } - arena_extent_cache_dalloc(tsdn, arena, &extent_hooks, trail); + arena_extents_dirty_dalloc(tsdn, arena, &extent_hooks, trail); } arena_extent_ralloc_large_shrink(tsdn, arena, extent, oldusize); @@ -158,9 +158,16 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, bool commit = true; extent_t *trail; bool new_mapping; - if ((trail = extent_alloc_cache(tsdn, arena, &extent_hooks, - extent_past_get(extent), trailsize, 0, CACHELINE, &is_zeroed_trail, - &commit, false)) == NULL) { + if ((trail = extents_alloc(tsdn, arena, &extent_hooks, + &arena->extents_dirty, extent_past_get(extent), trailsize, 0, + CACHELINE, &is_zeroed_trail, &commit, false)) != NULL + || (trail = extents_alloc(tsdn, arena, &extent_hooks, + &arena->extents_muzzy, extent_past_get(extent), trailsize, 0, + CACHELINE, &is_zeroed_trail, &commit, false)) != NULL) { + if (config_stats) { + new_mapping = false; + } + } else { if ((trail = extent_alloc_wrapper(tsdn, arena, &extent_hooks, extent_past_get(extent), trailsize, 0, CACHELINE, &is_zeroed_trail, &commit, false)) == NULL) { @@ -169,10 +176,6 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, if (config_stats) { new_mapping = true; } - } else { - if (config_stats) { - new_mapping = false; - } } if (extent_merge_wrapper(tsdn, arena, &extent_hooks, extent, trail)) { @@ -327,7 +330,7 @@ large_dalloc_prep_impl(tsdn_t *tsdn, arena_t *arena, extent_t *extent, static void large_dalloc_finish_impl(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; - arena_extent_cache_dalloc(tsdn, arena, &extent_hooks, extent); + arena_extents_dirty_dalloc(tsdn, arena, &extent_hooks, extent); } void diff --git a/src/stats.c b/src/stats.c index 776fb862..58b9a04f 100644 --- a/src/stats.c +++ b/src/stats.c @@ -259,10 +259,11 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, bool json, unsigned i, bool bins, bool large) { unsigned nthreads; const char *dss; - ssize_t decay_time; - size_t page, pactive, pdirty, mapped, retained; + ssize_t dirty_decay_time, muzzy_decay_time; + size_t page, pactive, pdirty, pmuzzy, mapped, retained; size_t base, internal, resident; - uint64_t npurge, nmadvise, purged; + uint64_t dirty_npurge, dirty_nmadvise, dirty_purged; + uint64_t muzzy_npurge, muzzy_nmadvise, muzzy_purged; size_t small_allocated; uint64_t small_nmalloc, small_ndalloc, small_nrequests; size_t large_allocated; @@ -289,39 +290,70 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, "dss allocation precedence: %s\n", dss); } - CTL_M2_GET("stats.arenas.0.decay_time", i, &decay_time, ssize_t); - if (json) { - malloc_cprintf(write_cb, cbopaque, - "\t\t\t\t\"decay_time\": %zd,\n", decay_time); - } else { - if (decay_time >= 0) { - malloc_cprintf(write_cb, cbopaque, "decay time: %zd\n", - decay_time); - } else { - malloc_cprintf(write_cb, cbopaque, "decay time: N/A\n"); - } - } - + CTL_M2_GET("stats.arenas.0.dirty_decay_time", i, &dirty_decay_time, + ssize_t); + CTL_M2_GET("stats.arenas.0.muzzy_decay_time", i, &muzzy_decay_time, + ssize_t); CTL_M2_GET("stats.arenas.0.pactive", i, &pactive, size_t); CTL_M2_GET("stats.arenas.0.pdirty", i, &pdirty, size_t); - CTL_M2_GET("stats.arenas.0.npurge", i, &npurge, uint64_t); - CTL_M2_GET("stats.arenas.0.nmadvise", i, &nmadvise, uint64_t); - CTL_M2_GET("stats.arenas.0.purged", i, &purged, uint64_t); + CTL_M2_GET("stats.arenas.0.pmuzzy", i, &pmuzzy, size_t); + CTL_M2_GET("stats.arenas.0.dirty_npurge", i, &dirty_npurge, uint64_t); + CTL_M2_GET("stats.arenas.0.dirty_nmadvise", i, &dirty_nmadvise, + uint64_t); + CTL_M2_GET("stats.arenas.0.dirty_purged", i, &dirty_purged, uint64_t); + CTL_M2_GET("stats.arenas.0.muzzy_npurge", i, &muzzy_npurge, uint64_t); + CTL_M2_GET("stats.arenas.0.muzzy_nmadvise", i, &muzzy_nmadvise, + uint64_t); + CTL_M2_GET("stats.arenas.0.muzzy_purged", i, &muzzy_purged, uint64_t); if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"dirty_decay_time\": %zd,\n", dirty_decay_time); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"muzzy_decay_time\": %zd,\n", muzzy_decay_time); malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\"pactive\": %zu,\n", pactive); malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\"pdirty\": %zu,\n", pdirty); malloc_cprintf(write_cb, cbopaque, - "\t\t\t\t\"npurge\": %"FMTu64",\n", npurge); + "\t\t\t\t\"pmuzzy\": %zu,\n", pmuzzy); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"dirty_npurge\": %"FMTu64",\n", dirty_npurge); malloc_cprintf(write_cb, cbopaque, - "\t\t\t\t\"nmadvise\": %"FMTu64",\n", nmadvise); + "\t\t\t\t\"dirty_nmadvise\": %"FMTu64",\n", dirty_nmadvise); malloc_cprintf(write_cb, cbopaque, - "\t\t\t\t\"purged\": %"FMTu64",\n", purged); + "\t\t\t\t\"dirty_purged\": %"FMTu64",\n", dirty_purged); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"muzzy_npurge\": %"FMTu64",\n", muzzy_npurge); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"muzzy_nmadvise\": %"FMTu64",\n", muzzy_nmadvise); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"muzzy_purged\": %"FMTu64",\n", muzzy_purged); } else { malloc_cprintf(write_cb, cbopaque, - "purging: dirty: %zu, sweeps: %"FMTu64", madvises: %"FMTu64 - ", purged: %"FMTu64"\n", pdirty, npurge, nmadvise, purged); + "decaying: time npages sweeps madvises" + " purged\n"); + if (dirty_decay_time >= 0) { + malloc_cprintf(write_cb, cbopaque, + " dirty: %5zd %12zu %12"FMTu64" %12"FMTu64" %12" + FMTu64"\n", dirty_decay_time, pdirty, dirty_npurge, + dirty_nmadvise, dirty_purged); + } else { + malloc_cprintf(write_cb, cbopaque, + " dirty: N/A %12zu %12"FMTu64" %12"FMTu64" %12" + FMTu64"\n", pdirty, dirty_npurge, dirty_nmadvise, + dirty_purged); + } + if (muzzy_decay_time >= 0) { + malloc_cprintf(write_cb, cbopaque, + " muzzy: %5zd %12zu %12"FMTu64" %12"FMTu64" %12" + FMTu64"\n", muzzy_decay_time, pmuzzy, muzzy_npurge, + muzzy_nmadvise, muzzy_purged); + } else { + malloc_cprintf(write_cb, cbopaque, + " muzzy: N/A %12zu %12"FMTu64" %12"FMTu64" %12" + FMTu64"\n", pmuzzy, muzzy_npurge, muzzy_nmadvise, + muzzy_purged); + } } CTL_M2_GET("stats.arenas.0.small.allocated", i, &small_allocated, @@ -622,7 +654,10 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, OPT_WRITE_CHAR_P(dss, ",") OPT_WRITE_UNSIGNED(narenas, ",") OPT_WRITE_CHAR_P(percpu_arena, ",") - OPT_WRITE_SSIZE_T_MUTABLE(decay_time, arenas.decay_time, ",") + OPT_WRITE_SSIZE_T_MUTABLE(dirty_decay_time, arenas.dirty_decay_time, + ",") + OPT_WRITE_SSIZE_T_MUTABLE(muzzy_decay_time, arenas.muzzy_decay_time, + ",") OPT_WRITE_CHAR_P(junk, ",") OPT_WRITE_BOOL(zero, ",") OPT_WRITE_BOOL(utrace, ",") @@ -670,16 +705,26 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "Arenas: %u\n", uv); } - CTL_GET("arenas.decay_time", &ssv, ssize_t); + CTL_GET("arenas.dirty_decay_time", &ssv, ssize_t); if (json) { malloc_cprintf(write_cb, cbopaque, - "\t\t\t\"decay_time\": %zd,\n", ssv); + "\t\t\t\"dirty_decay_time\": %zd,\n", ssv); } else { malloc_cprintf(write_cb, cbopaque, "Unused dirty page decay time: %zd%s\n", ssv, (ssv < 0) ? " (no decay)" : ""); } + CTL_GET("arenas.muzzy_decay_time", &ssv, ssize_t); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"muzzy_decay_time\": %zd,\n", ssv); + } else { + malloc_cprintf(write_cb, cbopaque, + "Unused muzzy page decay time: %zd%s\n", ssv, (ssv < 0) ? + " (no decay)" : ""); + } + CTL_GET("arenas.quantum", &sv, size_t); if (json) { malloc_cprintf(write_cb, cbopaque, diff --git a/test/unit/decay.c b/test/unit/decay.c index eb4df9d7..471a558c 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -22,18 +22,28 @@ nstime_update_mock(nstime_t *time) { } static unsigned -do_arena_create(ssize_t decay_time) { +do_arena_create(ssize_t dirty_decay_time, ssize_t muzzy_decay_time) { unsigned arena_ind; size_t sz = sizeof(unsigned); assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); size_t mib[3]; size_t miblen = sizeof(mib)/sizeof(size_t); - assert_d_eq(mallctlnametomib("arena.0.decay_time", mib, &miblen), 0, - "Unexpected mallctlnametomib() failure"); + + assert_d_eq(mallctlnametomib("arena.0.dirty_decay_time", mib, &miblen), + 0, "Unexpected mallctlnametomib() failure"); + mib[1] = (size_t)arena_ind; + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, + (void *)&dirty_decay_time, + sizeof(dirty_decay_time)), 0, "Unexpected mallctlbymib() failure"); + + assert_d_eq(mallctlnametomib("arena.0.muzzy_decay_time", mib, &miblen), + 0, "Unexpected mallctlnametomib() failure"); mib[1] = (size_t)arena_ind; - assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&decay_time, - sizeof(decay_time)), 0, "Unexpected mallctlbymib() failure"); + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, + (void *)&muzzy_decay_time, + sizeof(muzzy_decay_time)), 0, "Unexpected mallctlbymib() failure"); + return arena_ind; } @@ -78,11 +88,10 @@ do_decay(unsigned arena_ind) { } static uint64_t -get_arena_npurge(unsigned arena_ind) { - do_epoch(); +get_arena_npurge_impl(const char *mibname, unsigned arena_ind) { size_t mib[4]; size_t miblen = sizeof(mib)/sizeof(size_t); - assert_d_eq(mallctlnametomib("stats.arenas.0.npurge", mib, &miblen), 0, + assert_d_eq(mallctlnametomib(mibname, mib, &miblen), 0, "Unexpected mallctlnametomib() failure"); mib[2] = (size_t)arena_ind; uint64_t npurge = 0; @@ -92,6 +101,25 @@ get_arena_npurge(unsigned arena_ind) { return npurge; } +static uint64_t +get_arena_dirty_npurge(unsigned arena_ind) { + do_epoch(); + return get_arena_npurge_impl("stats.arenas.0.dirty_npurge", arena_ind); +} + +static uint64_t +get_arena_muzzy_npurge(unsigned arena_ind) { + do_epoch(); + return get_arena_npurge_impl("stats.arenas.0.muzzy_npurge", arena_ind); +} + +static uint64_t +get_arena_npurge(unsigned arena_ind) { + do_epoch(); + return get_arena_npurge_impl("stats.arenas.0.dirty_npurge", arena_ind) + + get_arena_npurge_impl("stats.arenas.0.muzzy_npurge", arena_ind); +} + static size_t get_arena_pdirty(unsigned arena_ind) { do_epoch(); @@ -107,6 +135,21 @@ get_arena_pdirty(unsigned arena_ind) { return pdirty; } +static size_t +get_arena_pmuzzy(unsigned arena_ind) { + do_epoch(); + size_t mib[4]; + size_t miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("stats.arenas.0.pmuzzy", mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + mib[2] = (size_t)arena_ind; + size_t pmuzzy; + size_t sz = sizeof(pmuzzy); + assert_d_eq(mallctlbymib(mib, miblen, (void *)&pmuzzy, &sz, NULL, 0), 0, + "Unexpected mallctlbymib() failure"); + return pmuzzy; +} + static void * do_mallocx(size_t size, int flags) { void *p = mallocx(size, flags); @@ -133,7 +176,7 @@ TEST_BEGIN(test_decay_ticks) { int err; /* Set up a manually managed arena for test. */ - arena_ind = do_arena_create(0); + arena_ind = do_arena_create(0, 0); /* Migrate to the new arena, and get the ticker. */ unsigned old_arena_ind; @@ -317,19 +360,66 @@ TEST_BEGIN(test_decay_ticks) { } TEST_END -TEST_BEGIN(test_decay_ticker) { -#define NPS 1024 +static void +decay_ticker_helper(unsigned arena_ind, int flags, bool dirty, ssize_t dt, + uint64_t dirty_npurge0, uint64_t muzzy_npurge0, bool terminate_asap) { #define NINTERVALS 101 - ssize_t dt = opt_decay_time; - unsigned arena_ind = do_arena_create(dt); + nstime_t time, update_interval, decay_time, deadline; + + nstime_init(&time, 0); + nstime_update(&time); + + nstime_init2(&decay_time, dt, 0); + nstime_copy(&deadline, &time); + nstime_add(&deadline, &decay_time); + + nstime_init2(&update_interval, dt, 0); + nstime_idivide(&update_interval, NINTERVALS); + + /* + * Keep q's slab from being deallocated during the looping below. If a + * cached slab were to repeatedly come and go during looping, it could + * prevent the decay backlog ever becoming empty. + */ + void *p = do_mallocx(1, flags); + uint64_t dirty_npurge1, muzzy_npurge1; + do { + for (unsigned i = 0; i < DECAY_NTICKS_PER_UPDATE / 2; + i++) { + void *q = do_mallocx(1, flags); + dallocx(q, flags); + } + dirty_npurge1 = get_arena_dirty_npurge(arena_ind); + muzzy_npurge1 = get_arena_muzzy_npurge(arena_ind); + + nstime_add(&time_mock, &update_interval); + nstime_update(&time); + } while (nstime_compare(&time, &deadline) <= 0 && ((dirty_npurge1 == + dirty_npurge0 && muzzy_npurge1 == muzzy_npurge0) || + !terminate_asap)); + dallocx(p, flags); + + if (config_stats) { + assert_u64_gt(dirty_npurge1 + muzzy_npurge1, dirty_npurge0 + + muzzy_npurge0, "Expected purging to occur"); + } +#undef NINTERVALS +} + +TEST_BEGIN(test_decay_ticker) { +#define NPS 2048 + ssize_t ddt = opt_dirty_decay_time; + ssize_t mdt = opt_muzzy_decay_time; + unsigned arena_ind = do_arena_create(ddt, mdt); int flags = (MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE); void *ps[NPS]; size_t large; /* - * Allocate a bunch of large objects, pause the clock, deallocate the - * objects, restore the clock, then [md]allocx() in a tight loop while - * advancing time rapidly to verify the ticker triggers purging. + * Allocate a bunch of large objects, pause the clock, deallocate every + * other object (to fragment virtual memory), restore the clock, then + * [md]allocx() in a tight loop while advancing time rapidly to verify + * the ticker triggers purging. */ if (config_tcache) { @@ -346,7 +436,8 @@ TEST_BEGIN(test_decay_ticker) { } do_purge(arena_ind); - uint64_t npurge0 = get_arena_npurge(arena_ind); + uint64_t dirty_npurge0 = get_arena_dirty_npurge(arena_ind); + uint64_t muzzy_npurge0 = get_arena_muzzy_npurge(arena_ind); for (unsigned i = 0; i < NPS; i++) { ps[i] = do_mallocx(large, flags); @@ -362,7 +453,7 @@ TEST_BEGIN(test_decay_ticker) { nstime_monotonic = nstime_monotonic_mock; nstime_update = nstime_update_mock; - for (unsigned i = 0; i < NPS; i++) { + for (unsigned i = 0; i < NPS; i += 2) { dallocx(ps[i], flags); unsigned nupdates0 = nupdates_mock; do_decay(arena_ind); @@ -370,51 +461,16 @@ TEST_BEGIN(test_decay_ticker) { "Expected nstime_update() to be called"); } - nstime_t time, update_interval, decay_time, deadline; - - nstime_init(&time, 0); - nstime_update(&time); - - nstime_init2(&decay_time, dt, 0); - nstime_copy(&deadline, &time); - nstime_add(&deadline, &decay_time); - - nstime_init2(&update_interval, dt, 0); - nstime_idivide(&update_interval, NINTERVALS); - - nstime_init2(&decay_time, dt, 0); - nstime_copy(&deadline, &time); - nstime_add(&deadline, &decay_time); - - /* - * Keep q's slab from being deallocated during the looping below. If - * a cached slab were to repeatedly come and go during looping, it could - * prevent the decay backlog ever becoming empty. - */ - void *p = do_mallocx(1, flags); - uint64_t npurge1; - do { - for (unsigned i = 0; i < DECAY_NTICKS_PER_UPDATE / 2; i++) { - void *q = do_mallocx(1, flags); - dallocx(q, flags); - } - npurge1 = get_arena_npurge(arena_ind); + decay_ticker_helper(arena_ind, flags, true, ddt, dirty_npurge0, + muzzy_npurge0, true); + decay_ticker_helper(arena_ind, flags, false, ddt+mdt, dirty_npurge0, + muzzy_npurge0, false); - nstime_add(&time_mock, &update_interval); - nstime_update(&time); - } while (nstime_compare(&time, &deadline) <= 0 && npurge1 == npurge0); - dallocx(p, flags); + do_arena_destroy(arena_ind); nstime_monotonic = nstime_monotonic_orig; nstime_update = nstime_update_orig; - - if (config_stats) { - assert_u64_gt(npurge1, npurge0, "Expected purging to occur"); - } - - do_arena_destroy(arena_ind); #undef NPS -#undef NINTERVALS } TEST_END @@ -435,8 +491,7 @@ TEST_BEGIN(test_decay_nonmonotonic) { "Unexpected mallctl failure"); do_epoch(); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge0, &sz, - NULL, 0), config_stats ? 0 : ENOENT, "Unexpected mallctl result"); + npurge0 = get_arena_npurge(0); nupdates_mock = 0; nstime_init(&time_mock, 0); @@ -464,8 +519,7 @@ TEST_BEGIN(test_decay_nonmonotonic) { do_epoch(); sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge1, &sz, - NULL, 0), config_stats ? 0 : ENOENT, "Unexpected mallctl result"); + npurge1 = get_arena_npurge(0); if (config_stats) { assert_u64_eq(npurge0, npurge1, "Unexpected purging occurred"); @@ -478,24 +532,28 @@ TEST_BEGIN(test_decay_nonmonotonic) { TEST_END TEST_BEGIN(test_decay_now) { - unsigned arena_ind = do_arena_create(0); + unsigned arena_ind = do_arena_create(0, 0); assert_zu_eq(get_arena_pdirty(arena_ind), 0, "Unexpected dirty pages"); + assert_zu_eq(get_arena_pmuzzy(arena_ind), 0, "Unexpected muzzy pages"); size_t sizes[] = {16, PAGE<<2, HUGEPAGE<<2}; - /* Verify that dirty pages never linger after deallocation. */ + /* Verify that dirty/muzzy pages never linger after deallocation. */ for (unsigned i = 0; i < sizeof(sizes)/sizeof(size_t); i++) { size_t size = sizes[i]; generate_dirty(arena_ind, size); assert_zu_eq(get_arena_pdirty(arena_ind), 0, "Unexpected dirty pages"); + assert_zu_eq(get_arena_pmuzzy(arena_ind), 0, + "Unexpected muzzy pages"); } do_arena_destroy(arena_ind); } TEST_END TEST_BEGIN(test_decay_never) { - unsigned arena_ind = do_arena_create(-1); + unsigned arena_ind = do_arena_create(-1, -1); int flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; assert_zu_eq(get_arena_pdirty(arena_ind), 0, "Unexpected dirty pages"); + assert_zu_eq(get_arena_pmuzzy(arena_ind), 0, "Unexpected muzzy pages"); size_t sizes[] = {16, PAGE<<2, HUGEPAGE<<2}; void *ptrs[sizeof(sizes)/sizeof(size_t)]; for (unsigned i = 0; i < sizeof(sizes)/sizeof(size_t); i++) { @@ -503,12 +561,16 @@ TEST_BEGIN(test_decay_never) { } /* Verify that each deallocation generates additional dirty pages. */ size_t pdirty_prev = get_arena_pdirty(arena_ind); + size_t pmuzzy_prev = get_arena_pmuzzy(arena_ind); assert_zu_eq(pdirty_prev, 0, "Unexpected dirty pages"); + assert_zu_eq(pmuzzy_prev, 0, "Unexpected muzzy pages"); for (unsigned i = 0; i < sizeof(sizes)/sizeof(size_t); i++) { dallocx(ptrs[i], flags); size_t pdirty = get_arena_pdirty(arena_ind); + size_t pmuzzy = get_arena_pmuzzy(arena_ind); assert_zu_gt(pdirty, pdirty_prev, "Expected dirty pages to increase."); + assert_zu_eq(pmuzzy, 0, "Unexpected muzzy pages"); pdirty_prev = pdirty; } do_arena_destroy(arena_ind); diff --git a/test/unit/decay.sh b/test/unit/decay.sh index 284af815..0df17884 100644 --- a/test/unit/decay.sh +++ b/test/unit/decay.sh @@ -1,6 +1,6 @@ #!/bin/sh -export MALLOC_CONF="decay_time:1" +export MALLOC_CONF="dirty_decay_time:1,muzzy_decay_time:1" if [ "x${enable_tcache}" = "x1" ] ; then export MALLOC_CONF="${MALLOC_CONF},lg_tcache_max:0" fi diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 1aedbe8a..4241063e 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -161,7 +161,8 @@ TEST_BEGIN(test_mallctl_opt) { TEST_MALLCTL_OPT(const char *, dss, always); TEST_MALLCTL_OPT(unsigned, narenas, always); TEST_MALLCTL_OPT(const char *, percpu_arena, always); - TEST_MALLCTL_OPT(ssize_t, decay_time, always); + TEST_MALLCTL_OPT(ssize_t, dirty_decay_time, always); + TEST_MALLCTL_OPT(ssize_t, muzzy_decay_time, always); TEST_MALLCTL_OPT(bool, stats_print, always); TEST_MALLCTL_OPT(const char *, junk, fill); TEST_MALLCTL_OPT(bool, zero, fill); @@ -401,32 +402,68 @@ TEST_BEGIN(test_arena_i_initialized) { } TEST_END -TEST_BEGIN(test_arena_i_decay_time) { - ssize_t decay_time, orig_decay_time, prev_decay_time; +TEST_BEGIN(test_arena_i_dirty_decay_time) { + ssize_t dirty_decay_time, orig_dirty_decay_time, prev_dirty_decay_time; size_t sz = sizeof(ssize_t); - assert_d_eq(mallctl("arena.0.decay_time", (void *)&orig_decay_time, &sz, - NULL, 0), 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("arena.0.dirty_decay_time", + (void *)&orig_dirty_decay_time, &sz, NULL, 0), 0, + "Unexpected mallctl() failure"); - decay_time = -2; - assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL, - (void *)&decay_time, sizeof(ssize_t)), EFAULT, + dirty_decay_time = -2; + assert_d_eq(mallctl("arena.0.dirty_decay_time", NULL, NULL, + (void *)&dirty_decay_time, sizeof(ssize_t)), EFAULT, "Unexpected mallctl() success"); - decay_time = 0x7fffffff; - assert_d_eq(mallctl("arena.0.decay_time", NULL, NULL, - (void *)&decay_time, sizeof(ssize_t)), 0, + dirty_decay_time = 0x7fffffff; + assert_d_eq(mallctl("arena.0.dirty_decay_time", NULL, NULL, + (void *)&dirty_decay_time, sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); - for (prev_decay_time = decay_time, decay_time = -1; - decay_time < 20; prev_decay_time = decay_time, decay_time++) { - ssize_t old_decay_time; + for (prev_dirty_decay_time = dirty_decay_time, dirty_decay_time = -1; + dirty_decay_time < 20; prev_dirty_decay_time = dirty_decay_time, + dirty_decay_time++) { + ssize_t old_dirty_decay_time; - assert_d_eq(mallctl("arena.0.decay_time", (void *)&old_decay_time, - &sz, (void *)&decay_time, sizeof(ssize_t)), 0, + assert_d_eq(mallctl("arena.0.dirty_decay_time", + (void *)&old_dirty_decay_time, &sz, + (void *)&dirty_decay_time, sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); - assert_zd_eq(old_decay_time, prev_decay_time, - "Unexpected old arena.0.decay_time"); + assert_zd_eq(old_dirty_decay_time, prev_dirty_decay_time, + "Unexpected old arena.0.dirty_decay_time"); + } +} +TEST_END + +TEST_BEGIN(test_arena_i_muzzy_decay_time) { + ssize_t muzzy_decay_time, orig_muzzy_decay_time, prev_muzzy_decay_time; + size_t sz = sizeof(ssize_t); + + assert_d_eq(mallctl("arena.0.muzzy_decay_time", + (void *)&orig_muzzy_decay_time, &sz, NULL, 0), 0, + "Unexpected mallctl() failure"); + + muzzy_decay_time = -2; + assert_d_eq(mallctl("arena.0.muzzy_decay_time", NULL, NULL, + (void *)&muzzy_decay_time, sizeof(ssize_t)), EFAULT, + "Unexpected mallctl() success"); + + muzzy_decay_time = 0x7fffffff; + assert_d_eq(mallctl("arena.0.muzzy_decay_time", NULL, NULL, + (void *)&muzzy_decay_time, sizeof(ssize_t)), 0, + "Unexpected mallctl() failure"); + + for (prev_muzzy_decay_time = muzzy_decay_time, muzzy_decay_time = -1; + muzzy_decay_time < 20; prev_muzzy_decay_time = muzzy_decay_time, + muzzy_decay_time++) { + ssize_t old_muzzy_decay_time; + + assert_d_eq(mallctl("arena.0.muzzy_decay_time", + (void *)&old_muzzy_decay_time, &sz, + (void *)&muzzy_decay_time, sizeof(ssize_t)), 0, + "Unexpected mallctl() failure"); + assert_zd_eq(old_muzzy_decay_time, prev_muzzy_decay_time, + "Unexpected old arena.0.muzzy_decay_time"); } } TEST_END @@ -522,32 +559,68 @@ TEST_BEGIN(test_arena_i_dss) { } TEST_END -TEST_BEGIN(test_arenas_decay_time) { - ssize_t decay_time, orig_decay_time, prev_decay_time; +TEST_BEGIN(test_arenas_dirty_decay_time) { + ssize_t dirty_decay_time, orig_dirty_decay_time, prev_dirty_decay_time; size_t sz = sizeof(ssize_t); - assert_d_eq(mallctl("arenas.decay_time", (void *)&orig_decay_time, &sz, - NULL, 0), 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("arenas.dirty_decay_time", + (void *)&orig_dirty_decay_time, &sz, NULL, 0), 0, + "Unexpected mallctl() failure"); + + dirty_decay_time = -2; + assert_d_eq(mallctl("arenas.dirty_decay_time", NULL, NULL, + (void *)&dirty_decay_time, sizeof(ssize_t)), EFAULT, + "Unexpected mallctl() success"); + + dirty_decay_time = 0x7fffffff; + assert_d_eq(mallctl("arenas.dirty_decay_time", NULL, NULL, + (void *)&dirty_decay_time, sizeof(ssize_t)), 0, + "Expected mallctl() failure"); + + for (prev_dirty_decay_time = dirty_decay_time, dirty_decay_time = -1; + dirty_decay_time < 20; prev_dirty_decay_time = dirty_decay_time, + dirty_decay_time++) { + ssize_t old_dirty_decay_time; + + assert_d_eq(mallctl("arenas.dirty_decay_time", + (void *)&old_dirty_decay_time, &sz, + (void *)&dirty_decay_time, sizeof(ssize_t)), 0, + "Unexpected mallctl() failure"); + assert_zd_eq(old_dirty_decay_time, prev_dirty_decay_time, + "Unexpected old arenas.dirty_decay_time"); + } +} +TEST_END + +TEST_BEGIN(test_arenas_muzzy_decay_time) { + ssize_t muzzy_decay_time, orig_muzzy_decay_time, prev_muzzy_decay_time; + size_t sz = sizeof(ssize_t); + + assert_d_eq(mallctl("arenas.muzzy_decay_time", + (void *)&orig_muzzy_decay_time, &sz, NULL, 0), 0, + "Unexpected mallctl() failure"); - decay_time = -2; - assert_d_eq(mallctl("arenas.decay_time", NULL, NULL, - (void *)&decay_time, sizeof(ssize_t)), EFAULT, + muzzy_decay_time = -2; + assert_d_eq(mallctl("arenas.muzzy_decay_time", NULL, NULL, + (void *)&muzzy_decay_time, sizeof(ssize_t)), EFAULT, "Unexpected mallctl() success"); - decay_time = 0x7fffffff; - assert_d_eq(mallctl("arenas.decay_time", NULL, NULL, - (void *)&decay_time, sizeof(ssize_t)), 0, + muzzy_decay_time = 0x7fffffff; + assert_d_eq(mallctl("arenas.muzzy_decay_time", NULL, NULL, + (void *)&muzzy_decay_time, sizeof(ssize_t)), 0, "Expected mallctl() failure"); - for (prev_decay_time = decay_time, decay_time = -1; - decay_time < 20; prev_decay_time = decay_time, decay_time++) { - ssize_t old_decay_time; + for (prev_muzzy_decay_time = muzzy_decay_time, muzzy_decay_time = -1; + muzzy_decay_time < 20; prev_muzzy_decay_time = muzzy_decay_time, + muzzy_decay_time++) { + ssize_t old_muzzy_decay_time; - assert_d_eq(mallctl("arenas.decay_time", - (void *)&old_decay_time, &sz, (void *)&decay_time, - sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); - assert_zd_eq(old_decay_time, prev_decay_time, - "Unexpected old arenas.decay_time"); + assert_d_eq(mallctl("arenas.muzzy_decay_time", + (void *)&old_muzzy_decay_time, &sz, + (void *)&muzzy_decay_time, sizeof(ssize_t)), 0, + "Unexpected mallctl() failure"); + assert_zd_eq(old_muzzy_decay_time, prev_muzzy_decay_time, + "Unexpected old arenas.muzzy_decay_time"); } } TEST_END @@ -630,7 +703,8 @@ TEST_BEGIN(test_stats_arenas) { TEST_STATS_ARENAS(unsigned, nthreads); TEST_STATS_ARENAS(const char *, dss); - TEST_STATS_ARENAS(ssize_t, decay_time); + TEST_STATS_ARENAS(ssize_t, dirty_decay_time); + TEST_STATS_ARENAS(ssize_t, muzzy_decay_time); TEST_STATS_ARENAS(size_t, pactive); TEST_STATS_ARENAS(size_t, pdirty); @@ -653,11 +727,13 @@ main(void) { test_tcache, test_thread_arena, test_arena_i_initialized, - test_arena_i_decay_time, + test_arena_i_dirty_decay_time, + test_arena_i_muzzy_decay_time, test_arena_i_purge, test_arena_i_decay, test_arena_i_dss, - test_arenas_decay_time, + test_arenas_dirty_decay_time, + test_arenas_muzzy_decay_time, test_arenas_constants, test_arenas_bin_constants, test_arenas_lextent_constants, diff --git a/test/unit/pack.sh b/test/unit/pack.sh index de12e553..76757ac3 100644 --- a/test/unit/pack.sh +++ b/test/unit/pack.sh @@ -1,4 +1,4 @@ #!/bin/sh # Immediately purge to minimize fragmentation. -export MALLOC_CONF="decay_time:-1" +export MALLOC_CONF="dirty_decay_time:0,muzzy_decay_time:0" diff --git a/test/unit/stats.c b/test/unit/stats.c index c458d3f9..f8c6b104 100644 --- a/test/unit/stats.c +++ b/test/unit/stats.c @@ -71,7 +71,8 @@ TEST_BEGIN(test_stats_arenas_summary) { size_t sz; int expected = config_stats ? 0 : ENOENT; size_t mapped; - uint64_t npurge, nmadvise, purged; + uint64_t dirty_npurge, dirty_nmadvise, dirty_purged; + uint64_t muzzy_npurge, muzzy_nmadvise, muzzy_purged; little = mallocx(SMALL_MAXCLASS, MALLOCX_ARENA(0)); assert_ptr_not_null(little, "Unexpected mallocx() failure"); @@ -92,19 +93,34 @@ TEST_BEGIN(test_stats_arenas_summary) { sz = sizeof(size_t); assert_d_eq(mallctl("stats.arenas.0.mapped", (void *)&mapped, &sz, NULL, 0), expected, "Unexepected mallctl() result"); + sz = sizeof(uint64_t); - assert_d_eq(mallctl("stats.arenas.0.npurge", (void *)&npurge, &sz, NULL, - 0), expected, "Unexepected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.nmadvise", (void *)&nmadvise, &sz, - NULL, 0), expected, "Unexepected mallctl() result"); - assert_d_eq(mallctl("stats.arenas.0.purged", (void *)&purged, &sz, NULL, - 0), expected, "Unexepected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.dirty_npurge", + (void *)&dirty_npurge, &sz, NULL, 0), expected, + "Unexepected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.dirty_nmadvise", + (void *)&dirty_nmadvise, &sz, NULL, 0), expected, + "Unexepected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.dirty_purged", + (void *)&dirty_purged, &sz, NULL, 0), expected, + "Unexepected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.muzzy_npurge", + (void *)&muzzy_npurge, &sz, NULL, 0), expected, + "Unexepected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.muzzy_nmadvise", + (void *)&muzzy_nmadvise, &sz, NULL, 0), expected, + "Unexepected mallctl() result"); + assert_d_eq(mallctl("stats.arenas.0.muzzy_purged", + (void *)&muzzy_purged, &sz, NULL, 0), expected, + "Unexepected mallctl() result"); if (config_stats) { - assert_u64_gt(npurge, 0, + assert_u64_gt(dirty_npurge + muzzy_npurge, 0, "At least one purge should have occurred"); - assert_u64_le(nmadvise, purged, - "nmadvise should be no greater than purged"); + assert_u64_le(dirty_nmadvise, dirty_purged, + "dirty_nmadvise should be no greater than dirty_purged"); + assert_u64_le(muzzy_nmadvise, muzzy_purged, + "muzzy_nmadvise should be no greater than muzzy_purged"); } } TEST_END -- GitLab From afb46ce23617f1315a6e75f846fd4169e8aaa455 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 15 Mar 2017 13:09:43 -0700 Subject: [PATCH 330/544] Propagate madvise() success/failure from pages_purge_lazy(). --- src/pages.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages.c b/src/pages.c index 9846e19e..fa986ba6 100644 --- a/src/pages.c +++ b/src/pages.c @@ -180,15 +180,15 @@ pages_purge_lazy(void *addr, size_t size) { #ifdef _WIN32 VirtualAlloc(addr, size, MEM_RESET, PAGE_READWRITE); + return false; #elif defined(JEMALLOC_PURGE_MADVISE_FREE) - madvise(addr, size, MADV_FREE); + return (madvise(addr, size, MADV_FREE) != 0); #elif defined(JEMALLOC_PURGE_MADVISE_DONTNEED) && \ !defined(JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS) - madvise(addr, size, MADV_DONTNEED); + return (madvise(addr, size, MADV_DONTNEED) != 0); #else not_reached(); #endif - return false; } bool -- GitLab From 3a1363bcf82fc93d99b5a796ffd4cebc93c2375f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 15 Mar 2017 12:50:37 -0700 Subject: [PATCH 331/544] Refactor tcaches flush/destroy to reduce lock duration. Drop tcaches_mtx before calling tcache_destroy(). --- src/tcache.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/tcache.c b/src/tcache.c index 266bd1f5..2250425f 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -500,32 +500,39 @@ label_return: return err; } -static void -tcaches_elm_flush(tsd_t *tsd, tcaches_t *elm) { +static tcache_t * +tcaches_elm_remove(tsd_t *tsd, tcaches_t *elm) { malloc_mutex_assert_owner(tsd_tsdn(tsd), &tcaches_mtx); if (elm->tcache == NULL) { - return; + return NULL; } - tcache_destroy(tsd, elm->tcache); + tcache_t *tcache = elm->tcache; elm->tcache = NULL; + return tcache; } void tcaches_flush(tsd_t *tsd, unsigned ind) { malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx); - tcaches_elm_flush(tsd, &tcaches[ind]); + tcache_t *tcache = tcaches_elm_remove(tsd, &tcaches[ind]); malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx); + if (tcache != NULL) { + tcache_destroy(tsd, tcache); + } } void tcaches_destroy(tsd_t *tsd, unsigned ind) { malloc_mutex_lock(tsd_tsdn(tsd), &tcaches_mtx); tcaches_t *elm = &tcaches[ind]; - tcaches_elm_flush(tsd, elm); + tcache_t *tcache = tcaches_elm_remove(tsd, elm); elm->next = tcaches_avail; tcaches_avail = elm; malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx); + if (tcache != NULL) { + tcache_destroy(tsd, tcache); + } } bool -- GitLab From ad917626356a507a2f4fac9e0289d653b977ed31 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 17 Mar 2017 18:06:51 -0700 Subject: [PATCH 332/544] Not re-binding iarena when migrate between arenas. --- src/jemalloc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index c1b05dbb..3c595bab 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -447,7 +447,6 @@ arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind) { arena_nthreads_dec(oldarena, false); arena_nthreads_inc(newarena, false); tsd_arena_set(tsd, newarena); - tsd_iarena_set(tsd, newarena); } static void -- GitLab From bda12bd925a174955ec12ae798f4d48a482a085b Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 20 Mar 2017 17:37:02 -0700 Subject: [PATCH 333/544] Clamp LG_VADDR for 32-bit builds on x64. --- configure.ac | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure.ac b/configure.ac index db42a505..37745c40 100644 --- a/configure.ac +++ b/configure.ac @@ -442,6 +442,9 @@ typedef unsigned __int32 uint32_t; if (f == NULL) { return 1; } + if (vaddr > (sizeof(void *) << 3)) { + vaddr = sizeof(void *) << 3; + } fprintf(f, "%u", vaddr); fclose(f); return 0; -- GitLab From e8921cf2eb1d049b688e29e14187c26ca05193ee Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 13 Mar 2017 17:36:57 -0700 Subject: [PATCH 334/544] Convert extent_t's usize to szind. Rather than storing usize only for large (and prof-promoted) allocations, store the size class index for allocations that reside within the extent, such that the size class index is valid for all extents that contain extant allocations, and invalid otherwise (mainly to make debugging simpler). --- include/jemalloc/internal/arena_inlines_b.h | 20 +- include/jemalloc/internal/extent_externs.h | 44 ++--- include/jemalloc/internal/extent_inlines.h | 91 +++++---- include/jemalloc/internal/extent_structs.h | 6 +- .../jemalloc/internal/jemalloc_internal.h.in | 7 +- include/jemalloc/internal/private_symbols.txt | 3 +- include/jemalloc/internal/tcache_inlines.h | 9 +- src/arena.c | 34 ++-- src/base.c | 9 +- src/extent.c | 187 +++++++++--------- src/extent_dss.c | 8 +- src/large.c | 49 +++-- test/unit/slab.c | 4 +- 13 files changed, 233 insertions(+), 238 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index b718451b..0d4aff39 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -147,15 +147,15 @@ arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, extent, ptr); } } else { - size_t usize = extent_usize_get(extent); + szind_t szind = extent_szind_get(extent); - if (likely(tcache != NULL) && usize <= tcache_maxclass) { - if (config_prof && unlikely(usize <= SMALL_MAXCLASS)) { + if (likely(tcache != NULL) && szind < nhbins) { + if (config_prof && unlikely(szind < NBINS)) { arena_dalloc_promoted(tsdn, extent, ptr, tcache, slow_path); } else { tcache_dalloc_large(tsdn_tsd(tsdn), tcache, - ptr, usize, slow_path); + ptr, szind, slow_path); } } else { large_dalloc(tsdn, extent); @@ -169,25 +169,25 @@ arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); + szind_t szind = size2index(size); if (likely(extent_slab_get(extent))) { /* Small allocation. */ if (likely(tcache != NULL)) { - szind_t binind = size2index(size); - assert(binind == extent_slab_data_get(extent)->binind); - tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, binind, + assert(szind == extent_slab_data_get(extent)->binind); + tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind, slow_path); } else { arena_dalloc_small(tsdn, extent_arena_get(extent), extent, ptr); } } else { - if (likely(tcache != NULL) && size <= tcache_maxclass) { - if (config_prof && unlikely(size <= SMALL_MAXCLASS)) { + if (likely(tcache != NULL) && szind < nhbins) { + if (config_prof && unlikely(szind < NBINS)) { arena_dalloc_promoted(tsdn, extent, ptr, tcache, slow_path); } else { tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, - size, slow_path); + szind, slow_path); } } else { large_dalloc(tsdn, extent); diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index e8f632f8..68c49a17 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -4,15 +4,15 @@ extern rtree_t extents_rtree; extern const extent_hooks_t extent_hooks_default; -extent_t *extent_alloc(tsdn_t *tsdn, arena_t *arena); -void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent); +extent_t *extent_alloc(tsdn_t *tsdn, arena_t *arena); +void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent); -extent_hooks_t *extent_hooks_get(arena_t *arena); -extent_hooks_t *extent_hooks_set(arena_t *arena, extent_hooks_t *extent_hooks); +extent_hooks_t *extent_hooks_get(arena_t *arena); +extent_hooks_t *extent_hooks_set(arena_t *arena, extent_hooks_t *extent_hooks); #ifdef JEMALLOC_JET -size_t extent_size_quantize_floor(size_t size); -size_t extent_size_quantize_ceil(size_t size); +size_t extent_size_quantize_floor(size_t size); +size_t extent_size_quantize_ceil(size_t size); #endif ph_proto(, extent_heap_, extent_heap_t, extent_t) @@ -23,8 +23,8 @@ extent_state_t extents_state_get(const extents_t *extents); size_t extents_npages_get(extents_t *extents); extent_t *extents_alloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extents_t *extents, void *new_addr, - size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, - bool slab); + size_t size, size_t pad, size_t alignment, bool slab, szind_t szind, + bool *zero, bool *commit); void extents_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extents_t *extents, extent_t *extent); extent_t *extents_evict(tsdn_t *tsdn, arena_t *arena, @@ -32,32 +32,32 @@ extent_t *extents_evict(tsdn_t *tsdn, arena_t *arena, void extents_prefork(tsdn_t *tsdn, extents_t *extents); void extents_postfork_parent(tsdn_t *tsdn, extents_t *extents); void extents_postfork_child(tsdn_t *tsdn, extents_t *extents); -extent_t *extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab); -void extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent); -bool extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, +extent_t *extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, size_t pad, + size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit); +void extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent); +bool extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent); -void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, +void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent); -bool extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, +bool extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length); -bool extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, +bool extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length); -bool extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, +bool extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length); -bool extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, +bool extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length); -extent_t *extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, +extent_t *extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a, - size_t usize_a, size_t size_b, size_t usize_b); -bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, + szind_t szind_a, size_t size_b, szind_t szind_b); +bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b); -bool extent_boot(void); +bool extent_boot(void); #endif /* JEMALLOC_INTERNAL_EXTENT_EXTERNS_H */ diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index 989c0d19..549c8f2f 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -2,37 +2,38 @@ #define JEMALLOC_INTERNAL_EXTENT_INLINES_H #ifndef JEMALLOC_ENABLE_INLINE -extent_t *extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent); -arena_t *extent_arena_get(const extent_t *extent); -void *extent_base_get(const extent_t *extent); -void *extent_addr_get(const extent_t *extent); -size_t extent_size_get(const extent_t *extent); -size_t extent_usize_get(const extent_t *extent); -void *extent_before_get(const extent_t *extent); -void *extent_last_get(const extent_t *extent); -void *extent_past_get(const extent_t *extent); -size_t extent_sn_get(const extent_t *extent); -extent_state_t extent_state_get(const extent_t *extent); -bool extent_zeroed_get(const extent_t *extent); -bool extent_committed_get(const extent_t *extent); -bool extent_slab_get(const extent_t *extent); -arena_slab_data_t *extent_slab_data_get(extent_t *extent); -const arena_slab_data_t *extent_slab_data_get_const(const extent_t *extent); -prof_tctx_t *extent_prof_tctx_get(const extent_t *extent); -void extent_arena_set(extent_t *extent, arena_t *arena); -void extent_addr_set(extent_t *extent, void *addr); -void extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment); -void extent_size_set(extent_t *extent, size_t size); -void extent_usize_set(extent_t *extent, size_t usize); -void extent_sn_set(extent_t *extent, size_t sn); -void extent_state_set(extent_t *extent, extent_state_t state); -void extent_zeroed_set(extent_t *extent, bool zeroed); -void extent_committed_set(extent_t *extent, bool committed); -void extent_slab_set(extent_t *extent, bool slab); -void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx); -void extent_init(extent_t *extent, arena_t *arena, void *addr, - size_t size, size_t usize, size_t sn, extent_state_t state, bool zeroed, - bool committed, bool slab); +extent_t *extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent); +arena_t *extent_arena_get(const extent_t *extent); +void *extent_base_get(const extent_t *extent); +void *extent_addr_get(const extent_t *extent); +size_t extent_size_get(const extent_t *extent); +szind_t extent_szind_get(const extent_t *extent); +size_t extent_usize_get(const extent_t *extent); +void *extent_before_get(const extent_t *extent); +void *extent_last_get(const extent_t *extent); +void *extent_past_get(const extent_t *extent); +size_t extent_sn_get(const extent_t *extent); +extent_state_t extent_state_get(const extent_t *extent); +bool extent_zeroed_get(const extent_t *extent); +bool extent_committed_get(const extent_t *extent); +bool extent_slab_get(const extent_t *extent); +arena_slab_data_t *extent_slab_data_get(extent_t *extent); +const arena_slab_data_t *extent_slab_data_get_const(const extent_t *extent); +prof_tctx_t *extent_prof_tctx_get(const extent_t *extent); +void extent_arena_set(extent_t *extent, arena_t *arena); +void extent_addr_set(extent_t *extent, void *addr); +void extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment); +void extent_size_set(extent_t *extent, size_t size); +void extent_szind_set(extent_t *extent, szind_t szind); +void extent_sn_set(extent_t *extent, size_t sn); +void extent_state_set(extent_t *extent, extent_state_t state); +void extent_zeroed_set(extent_t *extent, bool zeroed); +void extent_committed_set(extent_t *extent, bool committed); +void extent_slab_set(extent_t *extent, bool slab); +void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx); +void extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, + bool slab, szind_t szind, size_t sn, extent_state_t state, bool zeroed, + bool committed); void extent_list_init(extent_list_t *list); extent_t *extent_list_first(const extent_list_t *list); extent_t *extent_list_last(const extent_list_t *list); @@ -40,9 +41,9 @@ void extent_list_append(extent_list_t *list, extent_t *extent); void extent_list_replace(extent_list_t *list, extent_t *to_remove, extent_t *to_insert); void extent_list_remove(extent_list_t *list, extent_t *extent); -int extent_sn_comp(const extent_t *a, const extent_t *b); -int extent_ad_comp(const extent_t *a, const extent_t *b); -int extent_snad_comp(const extent_t *a, const extent_t *b); +int extent_sn_comp(const extent_t *a, const extent_t *b); +int extent_ad_comp(const extent_t *a, const extent_t *b); +int extent_snad_comp(const extent_t *a, const extent_t *b); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_)) @@ -79,10 +80,15 @@ extent_size_get(const extent_t *extent) { return extent->e_size; } +JEMALLOC_INLINE szind_t +extent_szind_get(const extent_t *extent) { + assert(extent->e_szind < NSIZES); /* Never call when "invalid". */ + return extent->e_szind; +} + JEMALLOC_INLINE size_t extent_usize_get(const extent_t *extent) { - assert(!extent->e_slab); - return extent->e_usize; + return index2size(extent_szind_get(extent)); } JEMALLOC_INLINE void * @@ -180,8 +186,9 @@ extent_size_set(extent_t *extent, size_t size) { } JEMALLOC_INLINE void -extent_usize_set(extent_t *extent, size_t usize) { - extent->e_usize = usize; +extent_szind_set(extent_t *extent, szind_t szind) { + assert(szind <= NSIZES); /* NSIZES means "invalid". */ + extent->e_szind = szind; } JEMALLOC_INLINE void @@ -216,19 +223,19 @@ extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) { JEMALLOC_INLINE void extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, - size_t usize, size_t sn, extent_state_t state, bool zeroed, bool committed, - bool slab) { + bool slab, szind_t szind, size_t sn, extent_state_t state, bool zeroed, + bool committed) { assert(addr == PAGE_ADDR2BASE(addr) || !slab); extent_arena_set(extent, arena); extent_addr_set(extent, addr); extent_size_set(extent, size); - extent_usize_set(extent, usize); + extent_slab_set(extent, slab); + extent_szind_set(extent, szind); extent_sn_set(extent, sn); extent_state_set(extent, state); extent_zeroed_set(extent, zeroed); extent_committed_set(extent, committed); - extent_slab_set(extent, slab); if (config_prof) { extent_prof_tctx_set(extent, NULL); } diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 001b7c13..82cfa58a 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -20,10 +20,12 @@ struct extent_s { size_t e_size; /* - * Usable size, typically smaller than extent size due to large_pad or + * Usable size class index for allocations residing in this extent, + * regardless of whether the extent is a slab. Extent size and usable + * size often differ even for non-slabs, either due to large_pad or * promotion of sampled small regions. */ - size_t e_usize; + szind_t e_szind; /* * Serial number (potentially non-unique). diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 97b41bb0..b184380d 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -536,8 +536,6 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/witness_inlines.h" #include "jemalloc/internal/mutex_inlines.h" #include "jemalloc/internal/rtree_inlines.h" -#include "jemalloc/internal/extent_inlines.h" -#include "jemalloc/internal/base_inlines.h" #ifndef JEMALLOC_ENABLE_INLINE pszind_t psz2ind(size_t psz); @@ -565,7 +563,6 @@ ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind); malloc_cpuid_t malloc_getcpu(void); unsigned percpu_arena_choose(void); unsigned percpu_arena_ind_limit(void); - #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) @@ -882,8 +879,6 @@ percpu_arena_ind_limit(void) { } } - - JEMALLOC_INLINE arena_tdata_t * arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing) { arena_tdata_t *tdata; @@ -938,6 +933,8 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) { } #endif +#include "jemalloc/internal/extent_inlines.h" +#include "jemalloc/internal/base_inlines.h" #include "jemalloc/internal/bitmap_inlines.h" /* * Include portions of arena code interleaved with tcache code in order to diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 5ca72818..d68f6b61 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -191,8 +191,9 @@ extent_snad_comp extent_split_wrapper extent_state_get extent_state_set +extent_szind_get +extent_szind_set extent_usize_get -extent_usize_set extent_zeroed_get extent_zeroed_set extents_alloc diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index a90107f9..fd7e1764 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -15,7 +15,7 @@ void *tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, void tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, bool slow_path); void tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, - size_t size, bool slow_path); + szind_t binind, bool slow_path); tcache_t *tcaches_get(tsd_t *tsd, unsigned ind); #endif @@ -271,19 +271,16 @@ tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, } JEMALLOC_ALWAYS_INLINE void -tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, size_t size, +tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, bool slow_path) { - szind_t binind; tcache_bin_t *tbin; tcache_bin_info_t *tbin_info; assert(tcache_salloc(tsd_tsdn(tsd), ptr) > SMALL_MAXCLASS); assert(tcache_salloc(tsd_tsdn(tsd), ptr) <= tcache_maxclass); - binind = size2index(size); - if (slow_path && config_fill && unlikely(opt_junk_free)) { - large_dalloc_junk(ptr, size); + large_dalloc_junk(ptr, index2size(binind)); } tbin = &tcache->tbins[binind]; diff --git a/src/arena.c b/src/arena.c index d861fff6..2c432e6a 100644 --- a/src/arena.c +++ b/src/arena.c @@ -449,25 +449,25 @@ arena_large_ralloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t oldusize, extent_t * arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero) { - extent_t *extent; extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + szind_t szind = size2index(usize); size_t mapped_add; bool commit = true; - extent = extents_alloc(tsdn, arena, &extent_hooks, - &arena->extents_dirty, NULL, usize, large_pad, alignment, zero, - &commit, false); + extent_t *extent = extents_alloc(tsdn, arena, &extent_hooks, + &arena->extents_dirty, NULL, usize, large_pad, alignment, false, + szind, zero, &commit); if (extent == NULL) { extent = extents_alloc(tsdn, arena, &extent_hooks, &arena->extents_muzzy, NULL, usize, large_pad, alignment, - zero, &commit, false); + false, szind, zero, &commit); } size_t size = usize + large_pad; if (extent == NULL) { extent = extent_alloc_wrapper(tsdn, arena, &extent_hooks, NULL, - usize, large_pad, alignment, zero, &commit, false); + usize, large_pad, alignment, false, szind, zero, &commit); if (config_stats) { /* * extent may be NULL on OOM, but in that case @@ -1133,7 +1133,8 @@ arena_destroy(tsd_t *tsd, arena_t *arena) { static extent_t * arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, const arena_bin_info_t *bin_info) { + extent_hooks_t **r_extent_hooks, const arena_bin_info_t *bin_info, + szind_t szind) { extent_t *slab; bool zero, commit; @@ -1142,7 +1143,7 @@ arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, zero = false; commit = true; slab = extent_alloc_wrapper(tsdn, arena, r_extent_hooks, NULL, - bin_info->slab_size, 0, PAGE, &zero, &commit, true); + bin_info->slab_size, 0, PAGE, true, szind, &zero, &commit); if (config_stats && slab != NULL) { arena_stats_mapped_add(tsdn, &arena->stats, @@ -1158,19 +1159,20 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; + szind_t szind = size2index(bin_info->reg_size); bool zero = false; bool commit = true; extent_t *slab = extents_alloc(tsdn, arena, &extent_hooks, - &arena->extents_dirty, NULL, bin_info->slab_size, 0, PAGE, &zero, - &commit, true); + &arena->extents_dirty, NULL, bin_info->slab_size, 0, PAGE, true, + binind, &zero, &commit); if (slab == NULL) { slab = extents_alloc(tsdn, arena, &extent_hooks, &arena->extents_muzzy, NULL, bin_info->slab_size, 0, PAGE, - &zero, &commit, true); + true, binind, &zero, &commit); } if (slab == NULL) { slab = arena_slab_alloc_hard(tsdn, arena, &extent_hooks, - bin_info); + bin_info, szind); if (slab == NULL) { return NULL; } @@ -1467,7 +1469,7 @@ arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, assert(isalloc(tsdn, extent, ptr) == LARGE_MINCLASS); assert(usize <= SMALL_MAXCLASS); - extent_usize_set(extent, usize); + extent_szind_set(extent, size2index(usize)); prof_accum_cancel(tsdn, &arena->prof_accum, usize); @@ -1479,7 +1481,7 @@ arena_prof_demote(tsdn_t *tsdn, extent_t *extent, const void *ptr) { cassert(config_prof); assert(ptr != NULL); - extent_usize_set(extent, LARGE_MINCLASS); + extent_szind_set(extent, NBINS); assert(isalloc(tsdn, extent, ptr) == LARGE_MINCLASS); @@ -1496,8 +1498,8 @@ arena_dalloc_promoted(tsdn_t *tsdn, extent_t *extent, void *ptr, usize = arena_prof_demote(tsdn, extent, ptr); if (usize <= tcache_maxclass) { - tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, usize, - slow_path); + tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, + size2index(usize), slow_path); } else { large_dalloc(tsdn, extent); } diff --git a/src/base.c b/src/base.c index e7712a64..b1a4ae37 100644 --- a/src/base.c +++ b/src/base.c @@ -87,8 +87,8 @@ base_extent_init(size_t *extent_sn_next, extent_t *extent, void *addr, sn = *extent_sn_next; (*extent_sn_next)++; - extent_init(extent, NULL, addr, size, 0, sn, extent_state_active, true, - true, false); + extent_init(extent, NULL, addr, size, false, NSIZES, sn, + extent_state_active, true, true); } static void * @@ -104,8 +104,9 @@ base_extent_bump_alloc_helper(extent_t *extent, size_t *gap_size, size_t size, ret = (void *)((uintptr_t)extent_addr_get(extent) + *gap_size); assert(extent_size_get(extent) >= *gap_size + size); extent_init(extent, NULL, (void *)((uintptr_t)extent_addr_get(extent) + - *gap_size + size), extent_size_get(extent) - *gap_size - size, 0, - extent_sn_get(extent), extent_state_active, true, true, false); + *gap_size + size), extent_size_get(extent) - *gap_size - size, + false, NSIZES, extent_sn_get(extent), extent_state_active, true, + true); return ret; } diff --git a/src/extent.c b/src/extent.c index c690b98e..31dcbd76 100644 --- a/src/extent.c +++ b/src/extent.c @@ -71,8 +71,8 @@ static size_t highpages; static void extent_deregister(tsdn_t *tsdn, extent_t *extent); static extent_t *extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extents_t *extents, void *new_addr, - size_t usize, size_t pad, size_t alignment, bool *zero, bool *commit, - bool slab); + size_t usize, size_t pad, size_t alignment, bool slab, szind_t szind, + bool *zero, bool *commit); static extent_t *extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, extent_t *extent, bool *coalesced); @@ -299,14 +299,14 @@ extent_try_delayed_coalesce(tsdn_t *tsdn, arena_t *arena, extent_t * extents_alloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extents_t *extents, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) { - assert(usize + pad != 0); + extents_t *extents, void *new_addr, size_t size, size_t pad, + size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) { + assert(size + pad != 0); assert(alignment != 0); witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); return extent_recycle(tsdn, arena, r_extent_hooks, extents, new_addr, - usize, pad, alignment, zero, commit, slab); + size, pad, alignment, slab, szind, zero, commit); } void @@ -615,8 +615,8 @@ extent_deregister(tsdn_t *tsdn, extent_t *extent) { static extent_t * extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, - bool locked, void *new_addr, size_t usize, size_t pad, size_t alignment, - bool *zero, bool *commit) { + bool locked, void *new_addr, size_t size, size_t pad, size_t alignment, + bool slab, bool *zero, bool *commit) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, locked ? 1 : 0); if (locked) { malloc_mutex_assert_owner(tsdn, &extents->mtx); @@ -639,10 +639,10 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, assert(alignment <= PAGE); } - size_t size = usize + pad; - size_t alloc_size = size + PAGE_CEILING(alignment) - PAGE; + size_t esize = size + pad; + size_t alloc_size = esize + PAGE_CEILING(alignment) - PAGE; /* Beware size_t wrap-around. */ - if (alloc_size < usize) { + if (alloc_size < esize) { return NULL; } if (!locked) { @@ -661,7 +661,7 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, if (extent != NULL) { assert(extent_base_get(extent) == new_addr); if (extent_arena_get(extent) != arena || - extent_size_get(extent) < size || + extent_size_get(extent) < esize || extent_state_get(extent) != extents_state_get(extents)) { extent = NULL; @@ -700,21 +700,20 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, static extent_t * extent_recycle_split(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, - void *new_addr, size_t usize, size_t pad, size_t alignment, - extent_t *extent) { - size_t size = usize + pad; + void *new_addr, size_t size, size_t pad, size_t alignment, bool slab, + szind_t szind, extent_t *extent) { + size_t esize = size + pad; size_t leadsize = ALIGNMENT_CEILING((uintptr_t)extent_base_get(extent), PAGE_CEILING(alignment)) - (uintptr_t)extent_base_get(extent); assert(new_addr == NULL || leadsize == 0); - assert(extent_size_get(extent) >= leadsize + size); - size_t trailsize = extent_size_get(extent) - leadsize - size; + assert(extent_size_get(extent) >= leadsize + esize); + size_t trailsize = extent_size_get(extent) - leadsize - esize; /* Split the lead. */ if (leadsize != 0) { extent_t *lead = extent; extent = extent_split_wrapper(tsdn, arena, r_extent_hooks, - lead, leadsize, leadsize, size + trailsize, usize + - trailsize); + lead, leadsize, NSIZES, esize + trailsize, szind); if (extent == NULL) { extent_deregister(tsdn, lead); extents_leak(tsdn, arena, r_extent_hooks, extents, @@ -727,7 +726,7 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena, /* Split the trail. */ if (trailsize != 0) { extent_t *trail = extent_split_wrapper(tsdn, arena, - r_extent_hooks, extent, size, usize, trailsize, trailsize); + r_extent_hooks, extent, esize, szind, trailsize, NSIZES); if (trail == NULL) { extent_deregister(tsdn, extent); extents_leak(tsdn, arena, r_extent_hooks, extents, @@ -737,10 +736,10 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena, extent_deactivate(tsdn, arena, extents, trail, false); } else if (leadsize == 0) { /* - * Splitting causes usize to be set as a side effect, but no + * Splitting causes szind to be set as a side effect, but no * splitting occurred. */ - extent_usize_set(extent, usize); + extent_szind_set(extent, szind); } return extent; @@ -748,24 +747,25 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena, static extent_t * extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extents_t *extents, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) { + extents_t *extents, void *new_addr, size_t size, size_t pad, + size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); assert(new_addr == NULL || !slab); assert(pad == 0 || !slab); + assert(!*zero || !slab); rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); extent_t *extent = extent_recycle_extract(tsdn, arena, r_extent_hooks, - rtree_ctx, extents, false, new_addr, usize, pad, alignment, zero, - commit); + rtree_ctx, extents, false, new_addr, size, pad, alignment, slab, + zero, commit); if (extent == NULL) { return NULL; } extent = extent_recycle_split(tsdn, arena, r_extent_hooks, rtree_ctx, - extents, new_addr, usize, pad, alignment, extent); + extents, new_addr, size, pad, alignment, slab, szind, extent); if (extent == NULL) { return NULL; } @@ -790,18 +790,15 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, } if (*zero) { + void *addr = extent_base_get(extent); + size_t size = extent_size_get(extent); if (!extent_zeroed_get(extent)) { - if (pages_purge_forced(extent_base_get(extent), - extent_size_get(extent))) { - memset(extent_addr_get(extent), 0, - extent_usize_get(extent)); + if (pages_purge_forced(addr, size)) { + memset(addr, 0, size); } } else if (config_debug) { - size_t i; - size_t *p = (size_t *)(uintptr_t) - extent_addr_get(extent); - - for (i = 0; i < usize / sizeof(size_t); i++) { + size_t *p = (size_t *)(uintptr_t)addr; + for (size_t i = 0; i < size / sizeof(size_t); i++) { assert(p[i] == 0); } } @@ -882,12 +879,10 @@ extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, size_t size, */ static extent_t * extent_grow_retained(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) { - extent_t *extent; - void *ptr; - size_t size, alloc_size, alloc_size_min, leadsize, trailsize; - bool zeroed, committed; + extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, size_t pad, + size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) { + assert(pad == 0 || !slab); + assert(!*zero || !slab); /* * Check whether the next extent size in the series would be large @@ -895,37 +890,37 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, * series of unsatisfiable allocation requests doesn't cause unused * extent creation as a side effect. */ - size = usize + pad; - alloc_size = pind2sz(atomic_read_u(&arena->extent_grow_next)); - alloc_size_min = size + PAGE_CEILING(alignment) - PAGE; + size_t esize = size + pad; + size_t alloc_size = pind2sz(atomic_read_u(&arena->extent_grow_next)); + size_t alloc_size_min = esize + PAGE_CEILING(alignment) - PAGE; /* Beware size_t wrap-around. */ - if (alloc_size_min < usize) { + if (alloc_size_min < esize) { return NULL; } if (alloc_size < alloc_size_min) { return NULL; } - extent = extent_alloc(tsdn, arena); + extent_t *extent = extent_alloc(tsdn, arena); if (extent == NULL) { return NULL; } - zeroed = false; - committed = false; - ptr = extent_alloc_core(tsdn, arena, new_addr, alloc_size, PAGE, + bool zeroed = false; + bool committed = false; + void *ptr = extent_alloc_core(tsdn, arena, new_addr, alloc_size, PAGE, &zeroed, &committed, arena->dss_prec); - extent_init(extent, arena, ptr, alloc_size, alloc_size, + extent_init(extent, arena, ptr, alloc_size, false, NSIZES, arena_extent_sn_next(arena), extent_state_active, zeroed, - committed, false); + committed); if (ptr == NULL || extent_register_no_gdump_add(tsdn, extent)) { extent_dalloc(tsdn, arena, extent); return NULL; } - leadsize = ALIGNMENT_CEILING((uintptr_t)ptr, PAGE_CEILING(alignment)) - - (uintptr_t)ptr; + size_t leadsize = ALIGNMENT_CEILING((uintptr_t)ptr, + PAGE_CEILING(alignment)) - (uintptr_t)ptr; assert(new_addr == NULL || leadsize == 0); - assert(alloc_size >= leadsize + size); - trailsize = alloc_size - leadsize - size; + assert(alloc_size >= leadsize + esize); + size_t trailsize = alloc_size - leadsize - esize; if (extent_zeroed_get(extent)) { *zero = true; } @@ -937,7 +932,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, if (leadsize != 0) { extent_t *lead = extent; extent = extent_split_wrapper(tsdn, arena, r_extent_hooks, lead, - leadsize, leadsize, size + trailsize, usize + trailsize); + leadsize, NSIZES, esize + trailsize, szind); if (extent == NULL) { extent_deregister(tsdn, lead); extents_leak(tsdn, arena, r_extent_hooks, false, lead); @@ -950,7 +945,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, /* Split the trail. */ if (trailsize != 0) { extent_t *trail = extent_split_wrapper(tsdn, arena, - r_extent_hooks, extent, size, usize, trailsize, trailsize); + r_extent_hooks, extent, esize, szind, trailsize, NSIZES); if (trail == NULL) { extent_deregister(tsdn, extent); extents_leak(tsdn, arena, r_extent_hooks, @@ -961,10 +956,10 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, &arena->extents_retained, trail); } else if (leadsize == 0) { /* - * Splitting causes usize to be set as a side effect, but no + * Splitting causes szind to be set as a side effect, but no * splitting occurred. */ - extent_usize_set(extent, usize); + extent_szind_set(extent, szind); } if (*commit && !extent_committed_get(extent)) { @@ -993,10 +988,10 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, extent_interior_register(tsdn, rtree_ctx, extent); } if (*zero && !extent_zeroed_get(extent)) { - if (pages_purge_forced(extent_base_get(extent), - extent_size_get(extent))) { - memset(extent_addr_get(extent), 0, - extent_usize_get(extent)); + void *addr = extent_base_get(extent); + size_t size = extent_size_get(extent); + if (pages_purge_forced(addr, size)) { + memset(addr, 0, size); } } /* @@ -1019,16 +1014,16 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, static extent_t * extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) { + extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, size_t pad, + size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) { extent_t *extent; - assert(usize != 0); + assert(size != 0); assert(alignment != 0); extent = extent_recycle(tsdn, arena, r_extent_hooks, - &arena->extents_retained, new_addr, usize, pad, alignment, zero, - commit, slab); + &arena->extents_retained, new_addr, size, pad, alignment, slab, + szind, zero, commit); if (extent != NULL) { if (config_prof) { extent_gdump_add(tsdn, extent); @@ -1036,7 +1031,7 @@ extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, } if (!config_munmap && extent == NULL) { extent = extent_grow_retained(tsdn, arena, r_extent_hooks, - new_addr, usize, pad, alignment, zero, commit, slab); + new_addr, size, pad, alignment, slab, szind, zero, commit); } return extent; @@ -1044,32 +1039,28 @@ extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, static extent_t * extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) { - extent_t *extent; - size_t size; - void *addr; - - size = usize + pad; - extent = extent_alloc(tsdn, arena); + extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, size_t pad, + size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) { + size_t esize = size + pad; + extent_t *extent = extent_alloc(tsdn, arena); if (extent == NULL) { return NULL; } + void *addr; if (*r_extent_hooks == &extent_hooks_default) { /* Call directly to propagate tsdn. */ - addr = extent_alloc_default_impl(tsdn, arena, new_addr, size, + addr = extent_alloc_default_impl(tsdn, arena, new_addr, esize, alignment, zero, commit); } else { - addr = (*r_extent_hooks)->alloc(*r_extent_hooks, new_addr, size, - alignment, zero, commit, arena_ind_get(arena)); + addr = (*r_extent_hooks)->alloc(*r_extent_hooks, new_addr, + esize, alignment, zero, commit, arena_ind_get(arena)); } if (addr == NULL) { extent_dalloc(tsdn, arena, extent); return NULL; } - extent_init(extent, arena, addr, size, usize, - arena_extent_sn_next(arena), extent_state_active, zero, commit, - slab); + extent_init(extent, arena, addr, esize, slab, szind, + arena_extent_sn_next(arena), extent_state_active, zero, commit); if (pad != 0) { extent_addr_randomize(tsdn, extent, alignment); } @@ -1084,17 +1075,17 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, extent_t * extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t usize, size_t pad, - size_t alignment, bool *zero, bool *commit, bool slab) { + extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, size_t pad, + size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); extent_hooks_assure_initialized(arena, r_extent_hooks); extent_t *extent = extent_alloc_retained(tsdn, arena, r_extent_hooks, - new_addr, usize, pad, alignment, zero, commit, slab); + new_addr, size, pad, alignment, slab, szind, zero, commit); if (extent == NULL) { extent = extent_alloc_wrapper_hard(tsdn, arena, r_extent_hooks, - new_addr, usize, pad, alignment, zero, commit, slab); + new_addr, size, pad, alignment, slab, szind, zero, commit); } return extent; @@ -1232,7 +1223,7 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, malloc_mutex_lock(tsdn, &extents->mtx); extent_hooks_assure_initialized(arena, r_extent_hooks); - extent_usize_set(extent, 0); + extent_szind_set(extent, NSIZES); if (extent_slab_get(extent)) { extent_interior_deregister(tsdn, rtree_ctx, extent); extent_slab_set(extent, false); @@ -1474,7 +1465,7 @@ extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size, extent_t * extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a, - size_t usize_a, size_t size_b, size_t usize_b) { + szind_t szind_a, size_t size_b, szind_t szind_b) { assert(extent_size_get(extent) == size_a + size_b); witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); @@ -1498,9 +1489,9 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_t lead; extent_init(&lead, arena, extent_addr_get(extent), size_a, - usize_a, extent_sn_get(extent), extent_state_get(extent), - extent_zeroed_get(extent), extent_committed_get(extent), - extent_slab_get(extent)); + extent_slab_get(extent), szind_a, extent_sn_get(extent), + extent_state_get(extent), extent_zeroed_get(extent), + extent_committed_get(extent)); if (extent_rtree_acquire(tsdn, rtree_ctx, &lead, false, true, &lead_elm_a, &lead_elm_b)) { @@ -1509,9 +1500,9 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, } extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) + - size_a), size_b, usize_b, extent_sn_get(extent), - extent_state_get(extent), extent_zeroed_get(extent), - extent_committed_get(extent), extent_slab_get(extent)); + size_a), size_b, extent_slab_get(extent), szind_b, + extent_sn_get(extent), extent_state_get(extent), + extent_zeroed_get(extent), extent_committed_get(extent)); if (extent_rtree_acquire(tsdn, rtree_ctx, trail, false, true, &trail_elm_a, &trail_elm_b)) { goto label_error_c; @@ -1524,7 +1515,7 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, } extent_size_set(extent, size_a); - extent_usize_set(extent, usize_a); + extent_szind_set(extent, szind_a); extent_rtree_write_acquired(tsdn, lead_elm_a, lead_elm_b, extent); extent_rtree_write_acquired(tsdn, trail_elm_a, trail_elm_b, trail); @@ -1617,7 +1608,7 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, } extent_size_set(a, extent_size_get(a) + extent_size_get(b)); - extent_usize_set(a, extent_usize_get(a) + extent_usize_get(b)); + extent_szind_set(a, NSIZES); extent_sn_set(a, (extent_sn_get(a) < extent_sn_get(b)) ? extent_sn_get(a) : extent_sn_get(b)); extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b)); diff --git a/src/extent_dss.c b/src/extent_dss.c index 50825713..5074594e 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -139,9 +139,9 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, (uintptr_t)gap_addr_page; if (gap_size_page != 0) { extent_init(gap, arena, gap_addr_page, - gap_size_page, gap_size_page, + gap_size_page, false, NSIZES, arena_extent_sn_next(arena), - extent_state_active, false, true, false); + extent_state_active, false, true); } /* * Compute the address just past the end of the desired @@ -189,8 +189,8 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, extent_t extent; extent_init(&extent, arena, ret, size, - size, 0, extent_state_active, false, - true, false); + size, false, NSIZES, + extent_state_active, false, true); if (extent_purge_forced_wrapper(tsdn, arena, &extent_hooks, &extent, 0, size)) { diff --git a/src/large.c b/src/large.c index c578995c..0e9f0d72 100644 --- a/src/large.c +++ b/src/large.c @@ -114,15 +114,15 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { /* Split excess pages. */ if (diff != 0) { extent_t *trail = extent_split_wrapper(tsdn, arena, - &extent_hooks, extent, usize + large_pad, usize, diff, - diff); + &extent_hooks, extent, usize + large_pad, size2index(usize), + diff, NSIZES); if (trail == NULL) { return true; } if (config_fill && unlikely(opt_junk_free)) { large_dalloc_maybe_junk(extent_addr_get(trail), - extent_usize_get(trail)); + extent_size_get(trail)); } arena_extents_dirty_dalloc(tsdn, arena, &extent_hooks, trail); @@ -139,7 +139,7 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, arena_t *arena = extent_arena_get(extent); size_t oldusize = extent_usize_get(extent); extent_hooks_t *extent_hooks = extent_hooks_get(arena); - size_t trailsize = usize - extent_usize_get(extent); + size_t trailsize = usize - oldusize; if (extent_hooks->merge == NULL) { return true; @@ -160,17 +160,17 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, bool new_mapping; if ((trail = extents_alloc(tsdn, arena, &extent_hooks, &arena->extents_dirty, extent_past_get(extent), trailsize, 0, - CACHELINE, &is_zeroed_trail, &commit, false)) != NULL + CACHELINE, false, NSIZES, &is_zeroed_trail, &commit)) != NULL || (trail = extents_alloc(tsdn, arena, &extent_hooks, &arena->extents_muzzy, extent_past_get(extent), trailsize, 0, - CACHELINE, &is_zeroed_trail, &commit, false)) != NULL) { + CACHELINE, false, NSIZES, &is_zeroed_trail, &commit)) != NULL) { if (config_stats) { new_mapping = false; } } else { if ((trail = extent_alloc_wrapper(tsdn, arena, &extent_hooks, - extent_past_get(extent), trailsize, 0, CACHELINE, - &is_zeroed_trail, &commit, false)) == NULL) { + extent_past_get(extent), trailsize, 0, CACHELINE, false, + NSIZES, &is_zeroed_trail, &commit)) == NULL) { return true; } if (config_stats) { @@ -182,6 +182,7 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, extent_dalloc_wrapper(tsdn, arena, &extent_hooks, trail); return true; } + extent_szind_set(extent, size2index(usize)); if (config_stats && new_mapping) { arena_stats_mapped_add(tsdn, &arena->stats, trailsize); @@ -218,14 +219,14 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, bool large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, size_t usize_max, bool zero) { - assert(s2u(extent_usize_get(extent)) == extent_usize_get(extent)); + size_t oldusize = extent_usize_get(extent); + /* The following should have been caught by callers. */ assert(usize_min > 0 && usize_max <= LARGE_MAXCLASS); /* Both allocation sizes must be large to avoid a move. */ - assert(extent_usize_get(extent) >= LARGE_MINCLASS && usize_max >= - LARGE_MINCLASS); + assert(oldusize >= LARGE_MINCLASS && usize_max >= LARGE_MINCLASS); - if (usize_max > extent_usize_get(extent)) { + if (usize_max > oldusize) { /* Attempt to expand the allocation in-place. */ if (!large_ralloc_no_move_expand(tsdn, extent, usize_max, zero)) { @@ -233,8 +234,7 @@ large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, return false; } /* Try again, this time with usize_min. */ - if (usize_min < usize_max && usize_min > - extent_usize_get(extent) && + if (usize_min < usize_max && usize_min > oldusize && large_ralloc_no_move_expand(tsdn, extent, usize_min, zero)) { arena_decay_tick(tsdn, extent_arena_get(extent)); @@ -246,14 +246,13 @@ large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, * Avoid moving the allocation if the existing extent size accommodates * the new size. */ - if (extent_usize_get(extent) >= usize_min && extent_usize_get(extent) <= - usize_max) { + if (oldusize >= usize_min && oldusize <= usize_max) { arena_decay_tick(tsdn, extent_arena_get(extent)); return false; } /* Attempt to shrink the allocation in-place. */ - if (extent_usize_get(extent) > usize_max) { + if (oldusize > usize_max) { if (!large_ralloc_no_move_shrink(tsdn, extent, usize_max)) { arena_decay_tick(tsdn, extent_arena_get(extent)); return false; @@ -274,14 +273,12 @@ large_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, void * large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, size_t alignment, bool zero, tcache_t *tcache) { - void *ret; - size_t copysize; + size_t oldusize = extent_usize_get(extent); /* The following should have been caught by callers. */ assert(usize > 0 && usize <= LARGE_MAXCLASS); /* Both allocation sizes must be large to avoid a move. */ - assert(extent_usize_get(extent) >= LARGE_MINCLASS && usize >= - LARGE_MINCLASS); + assert(oldusize >= LARGE_MINCLASS && usize >= LARGE_MINCLASS); /* Try to avoid moving the allocation. */ if (!large_ralloc_no_move(tsdn, extent, usize, usize, zero)) { @@ -293,16 +290,16 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, * different size class. In that case, fall back to allocating new * space and copying. */ - ret = large_ralloc_move_helper(tsdn, arena, usize, alignment, zero); + void *ret = large_ralloc_move_helper(tsdn, arena, usize, alignment, + zero); if (ret == NULL) { return NULL; } - copysize = (usize < extent_usize_get(extent)) ? usize : - extent_usize_get(extent); + size_t copysize = (usize < oldusize) ? usize : oldusize; memcpy(ret, extent_addr_get(extent), copysize); - isdalloct(tsdn, extent, extent_addr_get(extent), - extent_usize_get(extent), tcache, true); + isdalloct(tsdn, extent, extent_addr_get(extent), oldusize, tcache, + true); return ret; } diff --git a/test/unit/slab.c b/test/unit/slab.c index 1f2a260c..6f40aeef 100644 --- a/test/unit/slab.c +++ b/test/unit/slab.c @@ -8,8 +8,8 @@ TEST_BEGIN(test_arena_slab_regind) { extent_t slab; const arena_bin_info_t *bin_info = &arena_bin_info[binind]; extent_init(&slab, NULL, mallocx(bin_info->slab_size, - MALLOCX_LG_ALIGN(LG_PAGE)), bin_info->slab_size, 0, 0, - extent_state_active, false, true, true); + MALLOCX_LG_ALIGN(LG_PAGE)), bin_info->slab_size, true, + binind, 0, extent_state_active, false, true); assert_ptr_not_null(extent_addr_get(&slab), "Unexpected malloc() failure"); for (regind = 0; regind < bin_info->nregs; regind++) { -- GitLab From f50d6009fe945f17584e4a004d1aae60d07bedb5 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 13 Mar 2017 17:48:26 -0700 Subject: [PATCH 335/544] Remove binind field from arena_slab_data_t. binind is now redundant; the containing extent_t's szind field always provides the same value. --- include/jemalloc/internal/arena_inlines_b.h | 17 +++-------------- include/jemalloc/internal/arena_structs_a.h | 3 --- src/arena.c | 10 +++++----- 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 0d4aff39..92c89a5b 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -117,17 +117,9 @@ arena_aalloc(tsdn_t *tsdn, const void *ptr) { /* Return the size of the allocation pointed to by ptr. */ JEMALLOC_ALWAYS_INLINE size_t arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { - size_t ret; - assert(ptr != NULL); - if (likely(extent_slab_get(extent))) { - ret = index2size(extent_slab_data_get_const(extent)->binind); - } else { - ret = large_salloc(tsdn, extent); - } - - return ret; + return index2size(extent_szind_get(extent)); } JEMALLOC_ALWAYS_INLINE void @@ -136,19 +128,17 @@ arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); + szind_t szind = extent_szind_get(extent); if (likely(extent_slab_get(extent))) { /* Small allocation. */ if (likely(tcache != NULL)) { - szind_t binind = extent_slab_data_get(extent)->binind; - tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, binind, + tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind, slow_path); } else { arena_dalloc_small(tsdn, extent_arena_get(extent), extent, ptr); } } else { - szind_t szind = extent_szind_get(extent); - if (likely(tcache != NULL) && szind < nhbins) { if (config_prof && unlikely(szind < NBINS)) { arena_dalloc_promoted(tsdn, extent, ptr, @@ -173,7 +163,6 @@ arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, if (likely(extent_slab_get(extent))) { /* Small allocation. */ if (likely(tcache != NULL)) { - assert(szind == extent_slab_data_get(extent)->binind); tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind, slow_path); } else { diff --git a/include/jemalloc/internal/arena_structs_a.h b/include/jemalloc/internal/arena_structs_a.h index ccb3b052..ed265b20 100644 --- a/include/jemalloc/internal/arena_structs_a.h +++ b/include/jemalloc/internal/arena_structs_a.h @@ -2,9 +2,6 @@ #define JEMALLOC_INTERNAL_ARENA_STRUCTS_A_H struct arena_slab_data_s { - /* Index of bin this slab is associated with. */ - szind_t binind; - /* Number of free regions in slab. */ unsigned nfree; diff --git a/src/arena.c b/src/arena.c index 2c432e6a..968343c0 100644 --- a/src/arena.c +++ b/src/arena.c @@ -384,7 +384,7 @@ arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr) { JEMALLOC_INLINE_C void arena_slab_reg_dalloc(tsdn_t *tsdn, extent_t *slab, arena_slab_data_t *slab_data, void *ptr) { - szind_t binind = slab_data->binind; + szind_t binind = extent_szind_get(slab); const arena_bin_info_t *bin_info = &arena_bin_info[binind]; size_t regind = arena_slab_regind(slab, binind, ptr); @@ -1181,7 +1181,6 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, /* Initialize slab internals. */ arena_slab_data_t *slab_data = extent_slab_data_get(slab); - slab_data->binind = binind; slab_data->nfree = bin_info->nregs; bitmap_init(slab_data->bitmap, &bin_info->bitmap_info); @@ -1511,7 +1510,7 @@ arena_dissociate_bin_slab(extent_t *slab, arena_bin_t *bin) { if (slab == bin->slabcur) { bin->slabcur = NULL; } else { - szind_t binind = extent_slab_data_get(slab)->binind; + szind_t binind = extent_szind_get(slab); const arena_bin_info_t *bin_info = &arena_bin_info[binind]; /* @@ -1573,7 +1572,7 @@ static void arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, extent_t *slab, void *ptr, bool junked) { arena_slab_data_t *slab_data = extent_slab_data_get(slab); - szind_t binind = slab_data->binind; + szind_t binind = extent_szind_get(slab); arena_bin_t *bin = &arena->bins[binind]; const arena_bin_info_t *bin_info = &arena_bin_info[binind]; @@ -1604,7 +1603,8 @@ arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, extent_t *extent, static void arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) { - arena_bin_t *bin = &arena->bins[extent_slab_data_get(extent)->binind]; + szind_t binind = extent_szind_get(extent); + arena_bin_t *bin = &arena->bins[binind]; malloc_mutex_lock(tsdn, &bin->lock); arena_dalloc_bin_locked_impl(tsdn, arena, extent, ptr, false); -- GitLab From 944c8a338307db0423077cb2a16149ff5b7feab8 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 16 Mar 2017 09:46:42 -0700 Subject: [PATCH 336/544] Split rtree_elm_t into rtree_{node,leaf}_elm_t. This allows leaf elements to differ in size from internal node elements. In principle it would be more correct to use a different type for each level of the tree, but due to implementation details related to atomic operations, we use casts anyway, thus counteracting the value of additional type correctness. Furthermore, such a scheme would require function code generation (via cpp macros), as well as either unwieldy type names for leaves or type aliases, e.g. typedef struct rtree_elm_d2_s rtree_leaf_elm_t; This alternate strategy would be more correct, and with less code duplication, but probably not worth the complexity. --- include/jemalloc/internal/private_symbols.txt | 26 +- include/jemalloc/internal/rtree_externs.h | 30 +- include/jemalloc/internal/rtree_inlines.h | 105 +++--- include/jemalloc/internal/rtree_structs.h | 23 +- include/jemalloc/internal/rtree_types.h | 27 +- include/jemalloc/internal/tsd_structs.h | 2 +- src/extent.c | 74 ++-- src/rtree.c | 353 ++++++++++++------ test/unit/rtree.c | 75 ++-- 9 files changed, 458 insertions(+), 257 deletions(-) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index d68f6b61..a0deef89 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -413,17 +413,19 @@ psz2ind psz2u rtree_clear rtree_delete -rtree_elm_acquire -rtree_elm_lookup -rtree_elm_lookup_hard -rtree_elm_read -rtree_elm_read_acquired -rtree_elm_release -rtree_elm_witness_access -rtree_elm_witness_acquire -rtree_elm_witness_release -rtree_elm_write -rtree_elm_write_acquired +rtree_leaf_alloc +rtree_leaf_dalloc +rtree_leaf_elm_acquire +rtree_leaf_elm_lookup +rtree_leaf_elm_lookup_hard +rtree_leaf_elm_read +rtree_leaf_elm_read_acquired +rtree_leaf_elm_release +rtree_leaf_elm_witness_access +rtree_leaf_elm_witness_acquire +rtree_leaf_elm_witness_release +rtree_leaf_elm_write +rtree_leaf_elm_write_acquired rtree_leafkey rtree_new rtree_node_alloc @@ -513,7 +515,7 @@ tsd_prof_tdata_get tsd_prof_tdata_set tsd_prof_tdatap_get tsd_rtree_ctxp_get -tsd_rtree_elm_witnessesp_get +tsd_rtree_leaf_elm_witnessesp_get tsd_set tsd_tcache_enabled_get tsd_tcache_enabled_set diff --git a/include/jemalloc/internal/rtree_externs.h b/include/jemalloc/internal/rtree_externs.h index fa53580a..842eb0b5 100644 --- a/include/jemalloc/internal/rtree_externs.h +++ b/include/jemalloc/internal/rtree_externs.h @@ -8,36 +8,40 @@ * level. */ static const rtree_level_t rtree_levels[] = { -#if RTREE_NSB <= 10 +#if RTREE_HEIGHT == 1 {RTREE_NSB, RTREE_NHIB + RTREE_NSB} -#elif RTREE_NSB <= 36 +#elif RTREE_HEIGHT == 2 {RTREE_NSB/2, RTREE_NHIB + RTREE_NSB/2}, {RTREE_NSB/2 + RTREE_NSB%2, RTREE_NHIB + RTREE_NSB} -#elif RTREE_NSB <= 52 +#elif RTREE_HEIGHT == 3 {RTREE_NSB/3, RTREE_NHIB + RTREE_NSB/3}, {RTREE_NSB/3 + RTREE_NSB%3/2, RTREE_NHIB + RTREE_NSB/3*2 + RTREE_NSB%3/2}, {RTREE_NSB/3 + RTREE_NSB%3 - RTREE_NSB%3/2, RTREE_NHIB + RTREE_NSB} #else -# error Unsupported number of significant virtual address bits +# error Unsupported rtree height #endif }; bool rtree_new(rtree_t *rtree); #ifdef JEMALLOC_JET -typedef rtree_elm_t *(rtree_node_alloc_t)(tsdn_t *, rtree_t *, size_t); +typedef rtree_node_elm_t *(rtree_node_alloc_t)(tsdn_t *, rtree_t *, size_t); extern rtree_node_alloc_t *rtree_node_alloc; -typedef void (rtree_node_dalloc_t)(tsdn_t *, rtree_t *, rtree_elm_t *); +typedef rtree_leaf_elm_t *(rtree_leaf_alloc_t)(tsdn_t *, rtree_t *, size_t); +extern rtree_leaf_alloc_t *rtree_leaf_alloc; +typedef void (rtree_node_dalloc_t)(tsdn_t *, rtree_t *, rtree_node_elm_t *); extern rtree_node_dalloc_t *rtree_node_dalloc; +typedef void (rtree_leaf_dalloc_t)(tsdn_t *, rtree_t *, rtree_leaf_elm_t *); +extern rtree_leaf_dalloc_t *rtree_leaf_dalloc; void rtree_delete(tsdn_t *tsdn, rtree_t *rtree); #endif -rtree_elm_t *rtree_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, +rtree_leaf_elm_t *rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); -void rtree_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, - uintptr_t key, const rtree_elm_t *elm); -void rtree_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, - const rtree_elm_t *elm); -void rtree_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, - const rtree_elm_t *elm); +void rtree_leaf_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, + uintptr_t key, const rtree_leaf_elm_t *elm); +void rtree_leaf_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, + const rtree_leaf_elm_t *elm); +void rtree_leaf_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, + const rtree_leaf_elm_t *elm); #endif /* JEMALLOC_INTERNAL_RTREE_EXTERNS_H */ diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index b3301095..3af17d36 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -4,21 +4,22 @@ #ifndef JEMALLOC_ENABLE_INLINE uintptr_t rtree_leafkey(uintptr_t key); uintptr_t rtree_subkey(uintptr_t key, unsigned level); -extent_t *rtree_elm_read(rtree_elm_t *elm, bool dependent); -void rtree_elm_write(rtree_elm_t *elm, const extent_t *extent); -rtree_elm_t *rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, +extent_t *rtree_leaf_elm_read(rtree_leaf_elm_t *elm, bool dependent); +void rtree_leaf_elm_write(rtree_leaf_elm_t *elm, const extent_t *extent); +rtree_leaf_elm_t *rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, const extent_t *extent); extent_t *rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent); -rtree_elm_t *rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, +rtree_leaf_elm_t *rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); -extent_t *rtree_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, - rtree_elm_t *elm); -void rtree_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, - rtree_elm_t *elm, const extent_t *extent); -void rtree_elm_release(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm); +extent_t *rtree_leaf_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, + rtree_leaf_elm_t *elm); +void rtree_leaf_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, + rtree_leaf_elm_t *elm, const extent_t *extent); +void rtree_leaf_elm_release(tsdn_t *tsdn, const rtree_t *rtree, + rtree_leaf_elm_t *elm); void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key); #endif @@ -45,7 +46,7 @@ rtree_subkey(uintptr_t key, unsigned level) { } JEMALLOC_ALWAYS_INLINE extent_t * -rtree_elm_read(rtree_elm_t *elm, bool dependent) { +rtree_leaf_elm_read(rtree_leaf_elm_t *elm, bool dependent) { extent_t *extent; if (dependent) { @@ -55,7 +56,7 @@ rtree_elm_read(rtree_elm_t *elm, bool dependent) { * synchronization, because the rtree update became visible in * memory before the pointer came into existence. */ - extent = (extent_t *)atomic_load_p(&elm->child_or_extent, + extent = (extent_t *)atomic_load_p(&elm->extent, ATOMIC_RELAXED); } else { /* @@ -63,7 +64,7 @@ rtree_elm_read(rtree_elm_t *elm, bool dependent) { * dependent on a previous rtree write, which means a stale read * could result if synchronization were omitted here. */ - extent = (extent_t *)atomic_load_p(&elm->child_or_extent, + extent = (extent_t *)atomic_load_p(&elm->extent, ATOMIC_ACQUIRE); } @@ -74,12 +75,12 @@ rtree_elm_read(rtree_elm_t *elm, bool dependent) { } JEMALLOC_INLINE void -rtree_elm_write(rtree_elm_t *elm, const extent_t *extent) { - atomic_store_p(&elm->child_or_extent, (void *)extent, ATOMIC_RELEASE); +rtree_leaf_elm_write(rtree_leaf_elm_t *elm, const extent_t *extent) { + atomic_store_p(&elm->extent, (void *)extent, ATOMIC_RELEASE); } -JEMALLOC_ALWAYS_INLINE rtree_elm_t * -rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, +JEMALLOC_ALWAYS_INLINE rtree_leaf_elm_t * +rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing) { assert(key != 0); assert(!dependent || !init_missing); @@ -87,7 +88,7 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t leafkey = rtree_leafkey(key); #define RTREE_CACHE_CHECK(i) do { \ if (likely(rtree_ctx->cache[i].leafkey == leafkey)) { \ - rtree_elm_t *leaf = rtree_ctx->cache[i].leaf; \ + rtree_leaf_elm_t *leaf = rtree_ctx->cache[i].leaf; \ if (likely(leaf != NULL)) { \ /* Reorder. */ \ memmove(&rtree_ctx->cache[1], \ @@ -117,24 +118,24 @@ rtree_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, } #undef RTREE_CACHE_CHECK - return rtree_elm_lookup_hard(tsdn, rtree, rtree_ctx, key, dependent, - init_missing); + return rtree_leaf_elm_lookup_hard(tsdn, rtree, rtree_ctx, key, + dependent, init_missing); } JEMALLOC_INLINE bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, const extent_t *extent) { - rtree_elm_t *elm; + rtree_leaf_elm_t *elm; assert(extent != NULL); /* Use rtree_clear() for this case. */ assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); - elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, false, true); + elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, key, false, true); if (elm == NULL) { return true; } - assert(rtree_elm_read(elm, false) == NULL); - rtree_elm_write(elm, extent); + assert(rtree_leaf_elm_read(elm, false) == NULL); + rtree_leaf_elm_write(elm, extent); return false; } @@ -142,21 +143,22 @@ rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, JEMALLOC_ALWAYS_INLINE extent_t * rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent) { - rtree_elm_t *elm; + rtree_leaf_elm_t *elm; - elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, dependent, false); + elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, key, dependent, + false); if (!dependent && elm == NULL) { return NULL; } - return rtree_elm_read(elm, dependent); + return rtree_leaf_elm_read(elm, dependent); } -JEMALLOC_INLINE rtree_elm_t * -rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, +JEMALLOC_INLINE rtree_leaf_elm_t * +rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing) { - rtree_elm_t *elm = rtree_elm_lookup(tsdn, rtree, rtree_ctx, key, - dependent, init_missing); + rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, + key, dependent, init_missing); if (!dependent && elm == NULL) { return NULL; } @@ -164,14 +166,14 @@ rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, spin_t spinner = SPIN_INITIALIZER; while (true) { /* The least significant bit serves as a lock. */ - void *extent_and_lock = atomic_load_p(&elm->child_or_extent, + void *extent_and_lock = atomic_load_p(&elm->extent, ATOMIC_RELAXED); if (likely(((uintptr_t)extent_and_lock & (uintptr_t)0x1) == 0)) { void *locked = (void *)((uintptr_t)extent_and_lock | (uintptr_t)0x1); if (likely(atomic_compare_exchange_strong_p( - &elm->child_or_extent, &extent_and_lock, locked, + &elm->extent, &extent_and_lock, locked, ATOMIC_ACQUIRE, ATOMIC_RELAXED))) { break; } @@ -180,58 +182,61 @@ rtree_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, } if (config_debug) { - rtree_elm_witness_acquire(tsdn, rtree, key, elm); + rtree_leaf_elm_witness_acquire(tsdn, rtree, key, elm); } return elm; } JEMALLOC_INLINE extent_t * -rtree_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm) { +rtree_leaf_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, + rtree_leaf_elm_t *elm) { extent_t *extent; - void *ptr = atomic_load_p(&elm->child_or_extent, ATOMIC_RELAXED); + void *ptr = atomic_load_p(&elm->extent, ATOMIC_RELAXED); assert(((uintptr_t)ptr & (uintptr_t)0x1) == (uintptr_t)0x1); extent = (extent_t *)((uintptr_t)ptr & ~((uintptr_t)0x1)); assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); if (config_debug) { - rtree_elm_witness_access(tsdn, rtree, elm); + rtree_leaf_elm_witness_access(tsdn, rtree, elm); } return extent; } JEMALLOC_INLINE void -rtree_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm, - const extent_t *extent) { +rtree_leaf_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, + rtree_leaf_elm_t *elm, const extent_t *extent) { assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); - assert(((uintptr_t)atomic_load_p(&elm->child_or_extent, ATOMIC_RELAXED) + assert(((uintptr_t)atomic_load_p(&elm->extent, ATOMIC_RELAXED) & (uintptr_t)0x1) == (uintptr_t)0x1); if (config_debug) { - rtree_elm_witness_access(tsdn, rtree, elm); + rtree_leaf_elm_witness_access(tsdn, rtree, elm); } - atomic_store_p(&elm->child_or_extent, (void *)((uintptr_t)extent - | (uintptr_t)0x1), ATOMIC_RELEASE); - assert(rtree_elm_read_acquired(tsdn, rtree, elm) == extent); + atomic_store_p(&elm->extent, (void *)((uintptr_t)extent | + (uintptr_t)0x1), ATOMIC_RELEASE); + assert(rtree_leaf_elm_read_acquired(tsdn, rtree, elm) == extent); } JEMALLOC_INLINE void -rtree_elm_release(tsdn_t *tsdn, const rtree_t *rtree, rtree_elm_t *elm) { - rtree_elm_write(elm, rtree_elm_read_acquired(tsdn, rtree, elm)); +rtree_leaf_elm_release(tsdn_t *tsdn, const rtree_t *rtree, + rtree_leaf_elm_t *elm) { + rtree_leaf_elm_write(elm, rtree_leaf_elm_read_acquired(tsdn, rtree, + elm)); if (config_debug) { - rtree_elm_witness_release(tsdn, rtree, elm); + rtree_leaf_elm_witness_release(tsdn, rtree, elm); } } JEMALLOC_INLINE void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key) { - rtree_elm_t *elm; + rtree_leaf_elm_t *elm; - elm = rtree_elm_acquire(tsdn, rtree, rtree_ctx, key, true, false); - rtree_elm_write_acquired(tsdn, rtree, elm, NULL); - rtree_elm_release(tsdn, rtree, elm); + elm = rtree_leaf_elm_acquire(tsdn, rtree, rtree_ctx, key, true, false); + rtree_leaf_elm_write_acquired(tsdn, rtree, elm, NULL); + rtree_leaf_elm_release(tsdn, rtree, elm); } #endif diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h index b62c489d..68554035 100644 --- a/include/jemalloc/internal/rtree_structs.h +++ b/include/jemalloc/internal/rtree_structs.h @@ -1,18 +1,21 @@ #ifndef JEMALLOC_INTERNAL_RTREE_STRUCTS_H #define JEMALLOC_INTERNAL_RTREE_STRUCTS_H -struct rtree_elm_s { - /* Either "rtree_elm_t *child;" or "extent_t *extent;". */ - atomic_p_t child_or_extent; +struct rtree_node_elm_s { + atomic_p_t child; }; -struct rtree_elm_witness_s { - const rtree_elm_t *elm; +struct rtree_leaf_elm_s { + atomic_p_t extent; +}; + +struct rtree_leaf_elm_witness_s { + const rtree_leaf_elm_t *elm; witness_t witness; }; -struct rtree_elm_witness_tsd_s { - rtree_elm_witness_t witnesses[RTREE_ELM_ACQUIRE_MAX]; +struct rtree_leaf_elm_witness_tsd_s { + rtree_leaf_elm_witness_t witnesses[RTREE_ELM_ACQUIRE_MAX]; }; struct rtree_level_s { @@ -26,8 +29,8 @@ struct rtree_level_s { }; struct rtree_ctx_cache_elm_s { - uintptr_t leafkey; - rtree_elm_t *leaf; + uintptr_t leafkey; + rtree_leaf_elm_t *leaf; }; struct rtree_ctx_s { @@ -38,7 +41,7 @@ struct rtree_ctx_s { }; struct rtree_s { - /* An rtree_elm_t *. */ + /* An rtree_{internal,leaf}_elm_t *. */ atomic_p_t root; malloc_mutex_t init_lock; }; diff --git a/include/jemalloc/internal/rtree_types.h b/include/jemalloc/internal/rtree_types.h index a654698b..18fc5b0f 100644 --- a/include/jemalloc/internal/rtree_types.h +++ b/include/jemalloc/internal/rtree_types.h @@ -8,9 +8,10 @@ ******************************************************************************* */ -typedef struct rtree_elm_s rtree_elm_t; -typedef struct rtree_elm_witness_s rtree_elm_witness_t; -typedef struct rtree_elm_witness_tsd_s rtree_elm_witness_tsd_t; +typedef struct rtree_node_elm_s rtree_node_elm_t; +typedef struct rtree_leaf_elm_s rtree_leaf_elm_t; +typedef struct rtree_leaf_elm_witness_s rtree_leaf_elm_witness_t; +typedef struct rtree_leaf_elm_witness_tsd_s rtree_leaf_elm_witness_tsd_t; typedef struct rtree_level_s rtree_level_t; typedef struct rtree_ctx_cache_elm_s rtree_ctx_cache_elm_t; typedef struct rtree_ctx_s rtree_ctx_t; @@ -23,7 +24,15 @@ typedef struct rtree_s rtree_t; /* Number of significant bits. */ #define RTREE_NSB (LG_VADDR - RTREE_NLIB) /* Number of levels in radix tree. */ -#define RTREE_HEIGHT (sizeof(rtree_levels)/sizeof(rtree_level_t)) +#if RTREE_NSB <= 10 +# define RTREE_HEIGHT 1 +#elif RTREE_NSB <= 36 +# define RTREE_HEIGHT 2 +#elif RTREE_NSB <= 52 +# define RTREE_HEIGHT 3 +#else +# error Unsupported number of significant virtual address bits +#endif /* * Number of leafkey/leaf pairs to cache. Each entry supports an entire leaf, @@ -47,16 +56,16 @@ typedef struct rtree_s rtree_t; /* * Maximum number of concurrently acquired elements per thread. This controls - * how many witness_t structures are embedded in tsd. Ideally rtree_elm_t would - * have a witness_t directly embedded, but that would dramatically bloat the - * tree. This must contain enough entries to e.g. coalesce two extents. + * how many witness_t structures are embedded in tsd. Ideally rtree_leaf_elm_t + * would have a witness_t directly embedded, but that would dramatically bloat + * the tree. This must contain enough entries to e.g. coalesce two extents. */ #define RTREE_ELM_ACQUIRE_MAX 4 -/* Initializers for rtree_elm_witness_tsd_t. */ +/* Initializers for rtree_leaf_elm_witness_tsd_t. */ #define RTREE_ELM_WITNESS_INITIALIZER { \ NULL, \ - WITNESS_INITIALIZER("rtree_elm", WITNESS_RANK_RTREE_ELM) \ + WITNESS_INITIALIZER("rtree_leaf_elm", WITNESS_RANK_RTREE_ELM) \ } #define RTREE_ELM_WITNESS_TSD_INITIALIZER { \ diff --git a/include/jemalloc/internal/tsd_structs.h b/include/jemalloc/internal/tsd_structs.h index 503021e7..722b9669 100644 --- a/include/jemalloc/internal/tsd_structs.h +++ b/include/jemalloc/internal/tsd_structs.h @@ -29,7 +29,7 @@ struct tsd_init_head_s { yes, no) \ O(rtree_ctx, rtree_ctx_t, no, no) \ O(witnesses, witness_list_t, no, yes) \ - O(rtree_elm_witnesses, rtree_elm_witness_tsd_t, \ + O(rtree_leaf_elm_witnesses, rtree_leaf_elm_witness_tsd_t, \ no, no) \ O(witness_fork, bool, yes, no) \ diff --git a/src/extent.c b/src/extent.c index 31dcbd76..2a16d387 100644 --- a/src/extent.c +++ b/src/extent.c @@ -450,8 +450,8 @@ extent_activate_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, static bool extent_rtree_acquire(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, const extent_t *extent, bool dependent, bool init_missing, - rtree_elm_t **r_elm_a, rtree_elm_t **r_elm_b) { - *r_elm_a = rtree_elm_acquire(tsdn, &extents_rtree, rtree_ctx, + rtree_leaf_elm_t **r_elm_a, rtree_leaf_elm_t **r_elm_b) { + *r_elm_a = rtree_leaf_elm_acquire(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_base_get(extent), dependent, init_missing); if (!dependent && *r_elm_a == NULL) { return true; @@ -459,11 +459,11 @@ extent_rtree_acquire(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, assert(*r_elm_a != NULL); if (extent_size_get(extent) > PAGE) { - *r_elm_b = rtree_elm_acquire(tsdn, &extents_rtree, rtree_ctx, - (uintptr_t)extent_last_get(extent), dependent, + *r_elm_b = rtree_leaf_elm_acquire(tsdn, &extents_rtree, + rtree_ctx, (uintptr_t)extent_last_get(extent), dependent, init_missing); if (!dependent && *r_elm_b == NULL) { - rtree_elm_release(tsdn, &extents_rtree, *r_elm_a); + rtree_leaf_elm_release(tsdn, &extents_rtree, *r_elm_a); return true; } assert(*r_elm_b != NULL); @@ -475,19 +475,21 @@ extent_rtree_acquire(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, } static void -extent_rtree_write_acquired(tsdn_t *tsdn, rtree_elm_t *elm_a, - rtree_elm_t *elm_b, const extent_t *extent) { - rtree_elm_write_acquired(tsdn, &extents_rtree, elm_a, extent); +extent_rtree_write_acquired(tsdn_t *tsdn, rtree_leaf_elm_t *elm_a, + rtree_leaf_elm_t *elm_b, const extent_t *extent) { + rtree_leaf_elm_write_acquired(tsdn, &extents_rtree, elm_a, extent); if (elm_b != NULL) { - rtree_elm_write_acquired(tsdn, &extents_rtree, elm_b, extent); + rtree_leaf_elm_write_acquired(tsdn, &extents_rtree, elm_b, + extent); } } static void -extent_rtree_release(tsdn_t *tsdn, rtree_elm_t *elm_a, rtree_elm_t *elm_b) { - rtree_elm_release(tsdn, &extents_rtree, elm_a); +extent_rtree_release(tsdn_t *tsdn, rtree_leaf_elm_t *elm_a, + rtree_leaf_elm_t *elm_b) { + rtree_leaf_elm_release(tsdn, &extents_rtree, elm_a); if (elm_b != NULL) { - rtree_elm_release(tsdn, &extents_rtree, elm_b); + rtree_leaf_elm_release(tsdn, &extents_rtree, elm_b); } } @@ -543,7 +545,7 @@ static bool extent_register_impl(tsdn_t *tsdn, const extent_t *extent, bool gdump_add) { rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - rtree_elm_t *elm_a, *elm_b; + rtree_leaf_elm_t *elm_a, *elm_b; if (extent_rtree_acquire(tsdn, rtree_ctx, extent, false, true, &elm_a, &elm_b)) { @@ -596,7 +598,7 @@ static void extent_deregister(tsdn_t *tsdn, extent_t *extent) { rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - rtree_elm_t *elm_a, *elm_b; + rtree_leaf_elm_t *elm_a, *elm_b; extent_rtree_acquire(tsdn, rtree_ctx, extent, true, false, &elm_a, &elm_b); @@ -651,13 +653,13 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, extent_hooks_assure_initialized(arena, r_extent_hooks); extent_t *extent; if (new_addr != NULL) { - rtree_elm_t *elm; + rtree_leaf_elm_t *elm; - elm = rtree_elm_acquire(tsdn, &extents_rtree, rtree_ctx, + elm = rtree_leaf_elm_acquire(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)new_addr, false, false); if (elm != NULL) { - extent = rtree_elm_read_acquired(tsdn, &extents_rtree, - elm); + extent = rtree_leaf_elm_read_acquired(tsdn, + &extents_rtree, elm); if (extent != NULL) { assert(extent_base_get(extent) == new_addr); if (extent_arena_get(extent) != arena || @@ -667,7 +669,7 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, extent = NULL; } } - rtree_elm_release(tsdn, &extents_rtree, elm); + rtree_leaf_elm_release(tsdn, &extents_rtree, elm); } else { extent = NULL; } @@ -1156,11 +1158,11 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, again = false; /* Try to coalesce forward. */ - rtree_elm_t *next_elm = rtree_elm_acquire(tsdn, &extents_rtree, - rtree_ctx, (uintptr_t)extent_past_get(extent), false, - false); + rtree_leaf_elm_t *next_elm = rtree_leaf_elm_acquire(tsdn, + &extents_rtree, rtree_ctx, + (uintptr_t)extent_past_get(extent), false, false); if (next_elm != NULL) { - extent_t *next = rtree_elm_read_acquired(tsdn, + extent_t *next = rtree_leaf_elm_read_acquired(tsdn, &extents_rtree, next_elm); /* * extents->mtx only protects against races for @@ -1169,7 +1171,7 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, */ bool can_coalesce = (next != NULL && extent_can_coalesce(arena, extents, extent, next)); - rtree_elm_release(tsdn, &extents_rtree, next_elm); + rtree_leaf_elm_release(tsdn, &extents_rtree, next_elm); if (can_coalesce && !extent_coalesce(tsdn, arena, r_extent_hooks, extents, extent, next, true)) { if (extents->delay_coalesce) { @@ -1182,15 +1184,15 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, } /* Try to coalesce backward. */ - rtree_elm_t *prev_elm = rtree_elm_acquire(tsdn, &extents_rtree, - rtree_ctx, (uintptr_t)extent_before_get(extent), false, - false); + rtree_leaf_elm_t *prev_elm = rtree_leaf_elm_acquire(tsdn, + &extents_rtree, rtree_ctx, + (uintptr_t)extent_before_get(extent), false, false); if (prev_elm != NULL) { - extent_t *prev = rtree_elm_read_acquired(tsdn, + extent_t *prev = rtree_leaf_elm_read_acquired(tsdn, &extents_rtree, prev_elm); bool can_coalesce = (prev != NULL && extent_can_coalesce(arena, extents, extent, prev)); - rtree_elm_release(tsdn, &extents_rtree, prev_elm); + rtree_leaf_elm_release(tsdn, &extents_rtree, prev_elm); if (can_coalesce && !extent_coalesce(tsdn, arena, r_extent_hooks, extents, extent, prev, false)) { extent = prev; @@ -1472,7 +1474,7 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_t *trail; rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - rtree_elm_t *lead_elm_a, *lead_elm_b, *trail_elm_a, *trail_elm_b; + rtree_leaf_elm_t *lead_elm_a, *lead_elm_b, *trail_elm_a, *trail_elm_b; extent_hooks_assure_initialized(arena, r_extent_hooks); @@ -1590,19 +1592,21 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, */ rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - rtree_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; + rtree_leaf_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; extent_rtree_acquire(tsdn, rtree_ctx, a, true, false, &a_elm_a, &a_elm_b); extent_rtree_acquire(tsdn, rtree_ctx, b, true, false, &b_elm_a, &b_elm_b); if (a_elm_b != NULL) { - rtree_elm_write_acquired(tsdn, &extents_rtree, a_elm_b, NULL); - rtree_elm_release(tsdn, &extents_rtree, a_elm_b); + rtree_leaf_elm_write_acquired(tsdn, &extents_rtree, a_elm_b, + NULL); + rtree_leaf_elm_release(tsdn, &extents_rtree, a_elm_b); } if (b_elm_b != NULL) { - rtree_elm_write_acquired(tsdn, &extents_rtree, b_elm_a, NULL); - rtree_elm_release(tsdn, &extents_rtree, b_elm_a); + rtree_leaf_elm_write_acquired(tsdn, &extents_rtree, b_elm_a, + NULL); + rtree_leaf_elm_release(tsdn, &extents_rtree, b_elm_a); } else { b_elm_b = b_elm_a; } diff --git a/src/rtree.c b/src/rtree.c index 54dc3487..18197390 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -19,10 +19,10 @@ rtree_new(rtree_t *rtree) { #undef rtree_node_alloc #define rtree_node_alloc JEMALLOC_N(rtree_node_alloc_impl) #endif -static rtree_elm_t * +static rtree_node_elm_t * rtree_node_alloc(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { - return (rtree_elm_t *)base_alloc(tsdn, b0get(), nelms * - sizeof(rtree_elm_t), CACHELINE); + return (rtree_node_elm_t *)base_alloc(tsdn, b0get(), nelms * + sizeof(rtree_node_elm_t), CACHELINE); } #ifdef JEMALLOC_JET #undef rtree_node_alloc @@ -35,7 +35,7 @@ rtree_node_alloc_t *rtree_node_alloc = JEMALLOC_N(rtree_node_alloc_impl); #define rtree_node_dalloc JEMALLOC_N(rtree_node_dalloc_impl) #endif UNUSED static void -rtree_node_dalloc(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) { +rtree_node_dalloc(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *node) { /* Nodes are never deleted during normal operation. */ not_reached(); } @@ -45,47 +45,93 @@ rtree_node_dalloc(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) { rtree_node_dalloc_t *rtree_node_dalloc = JEMALLOC_N(rtree_node_dalloc_impl); #endif +#ifdef JEMALLOC_JET +#undef rtree_leaf_alloc +#define rtree_leaf_alloc JEMALLOC_N(rtree_leaf_alloc_impl) +#endif +static rtree_leaf_elm_t * +rtree_leaf_alloc(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { + return (rtree_leaf_elm_t *)base_alloc(tsdn, b0get(), nelms * + sizeof(rtree_leaf_elm_t), CACHELINE); +} +#ifdef JEMALLOC_JET +#undef rtree_leaf_alloc +#define rtree_leaf_alloc JEMALLOC_N(rtree_leaf_alloc) +rtree_leaf_alloc_t *rtree_leaf_alloc = JEMALLOC_N(rtree_leaf_alloc_impl); +#endif + +#ifdef JEMALLOC_JET +#undef rtree_leaf_dalloc +#define rtree_leaf_dalloc JEMALLOC_N(rtree_leaf_dalloc_impl) +#endif +UNUSED static void +rtree_leaf_dalloc(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *leaf) { + /* Leaves are never deleted during normal operation. */ + not_reached(); +} +#ifdef JEMALLOC_JET +#undef rtree_leaf_dalloc +#define rtree_leaf_dalloc JEMALLOC_N(rtree_leaf_dalloc) +rtree_leaf_dalloc_t *rtree_leaf_dalloc = JEMALLOC_N(rtree_leaf_dalloc_impl); +#endif + #ifdef JEMALLOC_JET static void -rtree_delete_subtree(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node, +rtree_delete_subtree(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *subtree, unsigned level) { - if (level + 1 < RTREE_HEIGHT) { - size_t nchildren, i; - - nchildren = ZU(1) << rtree_levels[level].bits; - for (i = 0; i < nchildren; i++) { - rtree_elm_t *child = (rtree_elm_t *)atomic_load_p( - &node[i].child_or_extent, ATOMIC_RELAXED); - if (child != NULL) { - rtree_delete_subtree(tsdn, rtree, child, level + + size_t nchildren = ZU(1) << rtree_levels[level].bits; + if (level + 2 < RTREE_HEIGHT) { + for (size_t i = 0; i < nchildren; i++) { + rtree_node_elm_t *node = + (rtree_node_elm_t *)atomic_load_p(&subtree[i].child, + ATOMIC_RELAXED); + if (node != NULL) { + rtree_delete_subtree(tsdn, rtree, node, level + 1); } } + } else { + for (size_t i = 0; i < nchildren; i++) { + rtree_leaf_elm_t *leaf = + (rtree_leaf_elm_t *)atomic_load_p(&subtree[i].child, + ATOMIC_RELAXED); + if (leaf != NULL) { + rtree_leaf_dalloc(tsdn, rtree, leaf); + } + } } - rtree_node_dalloc(tsdn, rtree, node); + + rtree_node_dalloc(tsdn, rtree, subtree); } void rtree_delete(tsdn_t *tsdn, rtree_t *rtree) { - rtree_elm_t *rtree_root = (rtree_elm_t *)atomic_load_p(&rtree->root, - ATOMIC_RELAXED); - if (rtree_root != NULL) { - rtree_delete_subtree(tsdn, rtree, rtree_root, 0); + if (RTREE_HEIGHT > 1) { + rtree_node_elm_t *node = (rtree_node_elm_t *)atomic_load_p( + &rtree->root, ATOMIC_RELAXED); + if (node != NULL) { + rtree_delete_subtree(tsdn, rtree, node, 0); + } + } else { + rtree_leaf_elm_t *leaf = + (rtree_leaf_elm_t *)atomic_load_p(&rtree->root, + ATOMIC_RELAXED); + if (leaf != NULL) { + rtree_leaf_dalloc(tsdn, rtree, leaf); + } } } #endif -static rtree_elm_t * +static rtree_node_elm_t * rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level, atomic_p_t *elmp) { - rtree_elm_t *node; - malloc_mutex_lock(tsdn, &rtree->init_lock); /* * If *elmp is non-null, then it was initialized with the init lock * held, so we can get by with 'relaxed' here. */ - node = atomic_load_p(elmp, ATOMIC_RELAXED); + rtree_node_elm_t *node = atomic_load_p(elmp, ATOMIC_RELAXED); if (node == NULL) { node = rtree_node_alloc(tsdn, rtree, ZU(1) << rtree_levels[level].bits); @@ -104,90 +150,186 @@ rtree_node_init(tsdn_t *tsdn, rtree_t *rtree, unsigned level, return node; } +static rtree_leaf_elm_t * +rtree_leaf_init(tsdn_t *tsdn, rtree_t *rtree, atomic_p_t *elmp) { + malloc_mutex_lock(tsdn, &rtree->init_lock); + /* + * If *elmp is non-null, then it was initialized with the init lock + * held, so we can get by with 'relaxed' here. + */ + rtree_leaf_elm_t *leaf = atomic_load_p(elmp, ATOMIC_RELAXED); + if (leaf == NULL) { + leaf = rtree_leaf_alloc(tsdn, rtree, ZU(1) << + rtree_levels[RTREE_HEIGHT-1].bits); + if (leaf == NULL) { + malloc_mutex_unlock(tsdn, &rtree->init_lock); + return NULL; + } + /* + * Even though we hold the lock, a later reader might not; we + * need release semantics. + */ + atomic_store_p(elmp, leaf, ATOMIC_RELEASE); + } + malloc_mutex_unlock(tsdn, &rtree->init_lock); + + return leaf; +} + static bool -rtree_node_valid(rtree_elm_t *node) { +rtree_node_valid(rtree_node_elm_t *node) { return ((uintptr_t)node != (uintptr_t)0); } -static rtree_elm_t * -rtree_child_tryread(rtree_elm_t *elm, bool dependent) { - rtree_elm_t *child; +static bool +rtree_leaf_valid(rtree_leaf_elm_t *leaf) { + return ((uintptr_t)leaf != (uintptr_t)0); +} + +static rtree_node_elm_t * +rtree_child_node_tryread(rtree_node_elm_t *elm, bool dependent) { + rtree_node_elm_t *node; if (dependent) { - child = (rtree_elm_t *)atomic_load_p(&elm->child_or_extent, + node = (rtree_node_elm_t *)atomic_load_p(&elm->child, ATOMIC_RELAXED); } else { - child = (rtree_elm_t *)atomic_load_p(&elm->child_or_extent, + node = (rtree_node_elm_t *)atomic_load_p(&elm->child, ATOMIC_ACQUIRE); } - assert(!dependent || child != NULL); - return child; + assert(!dependent || node != NULL); + return node; } -static rtree_elm_t * -rtree_child_read(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *elm, unsigned level, - bool dependent) { - rtree_elm_t *child; +static rtree_node_elm_t * +rtree_child_node_read(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *elm, + unsigned level, bool dependent) { + rtree_node_elm_t *node; - child = rtree_child_tryread(elm, dependent); - if (!dependent && unlikely(!rtree_node_valid(child))) { - child = rtree_node_init(tsdn, rtree, level + 1, - &elm->child_or_extent); + node = rtree_child_node_tryread(elm, dependent); + if (!dependent && unlikely(!rtree_node_valid(node))) { + node = rtree_node_init(tsdn, rtree, level + 1, &elm->child); } - assert(!dependent || child != NULL); - return child; + assert(!dependent || node != NULL); + return node; } -static rtree_elm_t * -rtree_subtree_tryread(rtree_t *rtree, bool dependent) { - rtree_elm_t *subtree; +static rtree_leaf_elm_t * +rtree_child_leaf_tryread(rtree_node_elm_t *elm, bool dependent) { + rtree_leaf_elm_t *leaf; + if (dependent) { - subtree = (rtree_elm_t *)atomic_load_p(&rtree->root, + leaf = (rtree_leaf_elm_t *)atomic_load_p(&elm->child, ATOMIC_RELAXED); } else { - subtree = (rtree_elm_t *)atomic_load_p(&rtree->root, + leaf = (rtree_leaf_elm_t *)atomic_load_p(&elm->child, ATOMIC_ACQUIRE); } - assert(!dependent || subtree != NULL); - return subtree; + + assert(!dependent || leaf != NULL); + return leaf; } -static rtree_elm_t * -rtree_subtree_read(tsdn_t *tsdn, rtree_t *rtree, bool dependent) { - rtree_elm_t *subtree = rtree_subtree_tryread(rtree, dependent); - if (!dependent && unlikely(!rtree_node_valid(subtree))) { - subtree = rtree_node_init(tsdn, rtree, 0, &rtree->root); +static rtree_leaf_elm_t * +rtree_child_leaf_read(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *elm, + unsigned level, bool dependent) { + rtree_leaf_elm_t *leaf; + + leaf = rtree_child_leaf_tryread(elm, dependent); + if (!dependent && unlikely(!rtree_leaf_valid(leaf))) { + leaf = rtree_leaf_init(tsdn, rtree, &elm->child); } - assert(!dependent || subtree != NULL); - return subtree; + assert(!dependent || leaf != NULL); + return leaf; } -rtree_elm_t * -rtree_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, +UNUSED static rtree_node_elm_t * +rtree_root_node_tryread(rtree_t *rtree, bool dependent) { + rtree_node_elm_t *node; + if (dependent) { + node = (rtree_node_elm_t *)atomic_load_p(&rtree->root, + ATOMIC_RELAXED); + } else { + node = (rtree_node_elm_t *)atomic_load_p(&rtree->root, + ATOMIC_ACQUIRE); + } + assert(!dependent || node != NULL); + return node; +} + +UNUSED static rtree_node_elm_t * +rtree_root_node_read(tsdn_t *tsdn, rtree_t *rtree, bool dependent) { + rtree_node_elm_t *node = rtree_root_node_tryread(rtree, dependent); + if (!dependent && unlikely(!rtree_node_valid(node))) { + node = rtree_node_init(tsdn, rtree, 0, &rtree->root); + } + assert(!dependent || node != NULL); + return node; +} + +UNUSED static rtree_leaf_elm_t * +rtree_root_leaf_tryread(rtree_t *rtree, bool dependent) { + rtree_leaf_elm_t *leaf; + if (dependent) { + leaf = (rtree_leaf_elm_t *)atomic_load_p(&rtree->root, + ATOMIC_RELAXED); + } else { + leaf = (rtree_leaf_elm_t *)atomic_load_p(&rtree->root, + ATOMIC_ACQUIRE); + } + assert(!dependent || leaf != NULL); + return leaf; +} + +UNUSED static rtree_leaf_elm_t * +rtree_root_leaf_read(tsdn_t *tsdn, rtree_t *rtree, bool dependent) { + rtree_leaf_elm_t *leaf = rtree_root_leaf_tryread(rtree, dependent); + if (!dependent && unlikely(!rtree_leaf_valid(leaf))) { + leaf = rtree_leaf_init(tsdn, rtree, &rtree->root); + } + assert(!dependent || leaf != NULL); + return leaf; +} + +rtree_leaf_elm_t * +rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing) { - rtree_elm_t *node = init_missing ? rtree_subtree_read(tsdn, rtree, - dependent) : rtree_subtree_tryread(rtree, dependent); + rtree_node_elm_t *node; + rtree_leaf_elm_t *leaf; +#if RTREE_HEIGHT > 1 + node = init_missing ? rtree_root_node_read(tsdn, rtree, dependent) : + rtree_root_node_tryread(rtree, dependent); +#else + leaf = init_missing ? rtree_root_leaf_read(tsdn, rtree, dependent) : + rtree_root_leaf_tryread(rtree, dependent); +#endif -#define RTREE_GET_SUBTREE(level) { \ +#define RTREE_GET_CHILD(level) { \ assert(level < RTREE_HEIGHT-1); \ if (!dependent && unlikely(!rtree_node_valid(node))) { \ return NULL; \ } \ uintptr_t subkey = rtree_subkey(key, level); \ - node = init_missing ? rtree_child_read(tsdn, rtree, \ - &node[subkey], level, dependent) : \ - rtree_child_tryread(&node[subkey], dependent); \ + if (level + 2 < RTREE_HEIGHT) { \ + node = init_missing ? \ + rtree_child_node_read(tsdn, rtree, \ + &node[subkey], level, dependent) : \ + rtree_child_node_tryread(&node[subkey], \ + dependent); \ + } else { \ + leaf = init_missing ? \ + rtree_child_leaf_read(tsdn, rtree, \ + &node[subkey], level, dependent) : \ + rtree_child_leaf_tryread(&node[subkey], \ + dependent); \ + } \ } #define RTREE_GET_LEAF(level) { \ assert(level == RTREE_HEIGHT-1); \ - if (!dependent && unlikely(!rtree_node_valid(node))) { \ + if (!dependent && unlikely(!rtree_leaf_valid(leaf))) { \ return NULL; \ } \ - /* \ - * node is a leaf, so it contains values rather than \ - * child pointers. \ - */ \ if (RTREE_CTX_NCACHE > 1) { \ memmove(&rtree_ctx->cache[1], \ &rtree_ctx->cache[0], \ @@ -196,29 +338,29 @@ rtree_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, } \ uintptr_t leafkey = rtree_leafkey(key); \ rtree_ctx->cache[0].leafkey = leafkey; \ - rtree_ctx->cache[0].leaf = node; \ + rtree_ctx->cache[0].leaf = leaf; \ uintptr_t subkey = rtree_subkey(key, level); \ - return &node[subkey]; \ + return &leaf[subkey]; \ } if (RTREE_HEIGHT > 1) { - RTREE_GET_SUBTREE(0) + RTREE_GET_CHILD(0) } if (RTREE_HEIGHT > 2) { - RTREE_GET_SUBTREE(1) + RTREE_GET_CHILD(1) } if (RTREE_HEIGHT > 3) { for (unsigned i = 2; i < RTREE_HEIGHT-1; i++) { - RTREE_GET_SUBTREE(i) + RTREE_GET_CHILD(i) } } RTREE_GET_LEAF(RTREE_HEIGHT-1) -#undef RTREE_GET_SUBTREE +#undef RTREE_GET_CHILD #undef RTREE_GET_LEAF not_reached(); } static int -rtree_elm_witness_comp(const witness_t *a, void *oa, const witness_t *b, +rtree_leaf_elm_witness_comp(const witness_t *a, void *oa, const witness_t *b, void *ob) { uintptr_t ka = (uintptr_t)oa; uintptr_t kb = (uintptr_t)ob; @@ -230,23 +372,24 @@ rtree_elm_witness_comp(const witness_t *a, void *oa, const witness_t *b, } static witness_t * -rtree_elm_witness_alloc(tsd_t *tsd, uintptr_t key, const rtree_elm_t *elm) { +rtree_leaf_elm_witness_alloc(tsd_t *tsd, uintptr_t key, + const rtree_leaf_elm_t *elm) { witness_t *witness; size_t i; - rtree_elm_witness_tsd_t *witnesses = tsd_rtree_elm_witnessesp_get(tsd); + rtree_leaf_elm_witness_tsd_t *witnesses = + tsd_rtree_leaf_elm_witnessesp_get(tsd); /* Iterate over entire array to detect double allocation attempts. */ witness = NULL; - for (i = 0; i < sizeof(rtree_elm_witness_tsd_t) / sizeof(witness_t); - i++) { - rtree_elm_witness_t *rew = &witnesses->witnesses[i]; + for (i = 0; i < RTREE_ELM_ACQUIRE_MAX; i++) { + rtree_leaf_elm_witness_t *rew = &witnesses->witnesses[i]; assert(rew->elm != elm); if (rew->elm == NULL && witness == NULL) { rew->elm = elm; witness = &rew->witness; - witness_init(witness, "rtree_elm", - WITNESS_RANK_RTREE_ELM, rtree_elm_witness_comp, + witness_init(witness, "rtree_leaf_elm", + WITNESS_RANK_RTREE_ELM, rtree_leaf_elm_witness_comp, (void *)key); } } @@ -255,13 +398,13 @@ rtree_elm_witness_alloc(tsd_t *tsd, uintptr_t key, const rtree_elm_t *elm) { } static witness_t * -rtree_elm_witness_find(tsd_t *tsd, const rtree_elm_t *elm) { +rtree_leaf_elm_witness_find(tsd_t *tsd, const rtree_leaf_elm_t *elm) { size_t i; - rtree_elm_witness_tsd_t *witnesses = tsd_rtree_elm_witnessesp_get(tsd); + rtree_leaf_elm_witness_tsd_t *witnesses = + tsd_rtree_leaf_elm_witnessesp_get(tsd); - for (i = 0; i < sizeof(rtree_elm_witness_tsd_t) / sizeof(witness_t); - i++) { - rtree_elm_witness_t *rew = &witnesses->witnesses[i]; + for (i = 0; i < RTREE_ELM_ACQUIRE_MAX; i++) { + rtree_leaf_elm_witness_t *rew = &witnesses->witnesses[i]; if (rew->elm == elm) { return &rew->witness; @@ -271,19 +414,19 @@ rtree_elm_witness_find(tsd_t *tsd, const rtree_elm_t *elm) { } static void -rtree_elm_witness_dalloc(tsd_t *tsd, witness_t *witness, - const rtree_elm_t *elm) { +rtree_leaf_elm_witness_dalloc(tsd_t *tsd, witness_t *witness, + const rtree_leaf_elm_t *elm) { size_t i; - rtree_elm_witness_tsd_t *witnesses = tsd_rtree_elm_witnessesp_get(tsd); + rtree_leaf_elm_witness_tsd_t *witnesses = + tsd_rtree_leaf_elm_witnessesp_get(tsd); - for (i = 0; i < sizeof(rtree_elm_witness_tsd_t) / sizeof(witness_t); - i++) { - rtree_elm_witness_t *rew = &witnesses->witnesses[i]; + for (i = 0; i < RTREE_ELM_ACQUIRE_MAX; i++) { + rtree_leaf_elm_witness_t *rew = &witnesses->witnesses[i]; if (rew->elm == elm) { rew->elm = NULL; - witness_init(&rew->witness, "rtree_elm", - WITNESS_RANK_RTREE_ELM, rtree_elm_witness_comp, + witness_init(&rew->witness, "rtree_leaf_elm", + WITNESS_RANK_RTREE_ELM, rtree_leaf_elm_witness_comp, NULL); return; } @@ -292,41 +435,41 @@ rtree_elm_witness_dalloc(tsd_t *tsd, witness_t *witness, } void -rtree_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, uintptr_t key, - const rtree_elm_t *elm) { +rtree_leaf_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, + uintptr_t key, const rtree_leaf_elm_t *elm) { witness_t *witness; if (tsdn_null(tsdn)) { return; } - witness = rtree_elm_witness_alloc(tsdn_tsd(tsdn), key, elm); + witness = rtree_leaf_elm_witness_alloc(tsdn_tsd(tsdn), key, elm); witness_lock(tsdn, witness); } void -rtree_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, - const rtree_elm_t *elm) { +rtree_leaf_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, + const rtree_leaf_elm_t *elm) { witness_t *witness; if (tsdn_null(tsdn)) { return; } - witness = rtree_elm_witness_find(tsdn_tsd(tsdn), elm); + witness = rtree_leaf_elm_witness_find(tsdn_tsd(tsdn), elm); witness_assert_owner(tsdn, witness); } void -rtree_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, - const rtree_elm_t *elm) { +rtree_leaf_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, + const rtree_leaf_elm_t *elm) { witness_t *witness; if (tsdn_null(tsdn)) { return; } - witness = rtree_elm_witness_find(tsdn_tsd(tsdn), elm); + witness = rtree_leaf_elm_witness_find(tsdn_tsd(tsdn), elm); witness_unlock(tsdn, witness); - rtree_elm_witness_dalloc(tsdn_tsd(tsdn), witness, elm); + rtree_leaf_elm_witness_dalloc(tsdn_tsd(tsdn), witness, elm); } diff --git a/test/unit/rtree.c b/test/unit/rtree.c index 488fd54b..221f2f2c 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -2,19 +2,21 @@ rtree_node_alloc_t *rtree_node_alloc_orig; rtree_node_dalloc_t *rtree_node_dalloc_orig; +rtree_leaf_alloc_t *rtree_leaf_alloc_orig; +rtree_leaf_dalloc_t *rtree_leaf_dalloc_orig; rtree_t *test_rtree; -static rtree_elm_t * +static rtree_node_elm_t * rtree_node_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { - rtree_elm_t *node; + rtree_node_elm_t *node; if (rtree != test_rtree) { return rtree_node_alloc_orig(tsdn, rtree, nelms); } malloc_mutex_unlock(tsdn, &rtree->init_lock); - node = (rtree_elm_t *)calloc(nelms, sizeof(rtree_elm_t)); + node = (rtree_node_elm_t *)calloc(nelms, sizeof(rtree_node_elm_t)); assert_ptr_not_null(node, "Unexpected calloc() failure"); malloc_mutex_lock(tsdn, &rtree->init_lock); @@ -22,7 +24,8 @@ rtree_node_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { } static void -rtree_node_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) { +rtree_node_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree, + rtree_node_elm_t *node) { if (rtree != test_rtree) { rtree_node_dalloc_orig(tsdn, rtree, node); return; @@ -31,6 +34,33 @@ rtree_node_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree, rtree_elm_t *node) { free(node); } +static rtree_leaf_elm_t * +rtree_leaf_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { + rtree_leaf_elm_t *leaf; + + if (rtree != test_rtree) { + return rtree_leaf_alloc_orig(tsdn, rtree, nelms); + } + + malloc_mutex_unlock(tsdn, &rtree->init_lock); + leaf = (rtree_leaf_elm_t *)calloc(nelms, sizeof(rtree_leaf_elm_t)); + assert_ptr_not_null(leaf, "Unexpected calloc() failure"); + malloc_mutex_lock(tsdn, &rtree->init_lock); + + return leaf; +} + +static void +rtree_leaf_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree, + rtree_leaf_elm_t *leaf) { + if (rtree != test_rtree) { + rtree_leaf_dalloc_orig(tsdn, rtree, leaf); + return; + } + + free(leaf); +} + TEST_BEGIN(test_rtree_read_empty) { tsdn_t *tsdn; @@ -75,22 +105,20 @@ thd_start(void *varg) { uintptr_t key = (uintptr_t)(gen_rand64(sfmt) & ((ZU(1) << MAX_NBITS) - ZU(1))); if (i % 2 == 0) { - rtree_elm_t *elm; - - elm = rtree_elm_acquire(tsdn, &arg->rtree, &rtree_ctx, - key, false, true); + rtree_leaf_elm_t *elm = rtree_leaf_elm_acquire(tsdn, + &arg->rtree, &rtree_ctx, key, false, true); assert_ptr_not_null(elm, - "Unexpected rtree_elm_acquire() failure"); - rtree_elm_write_acquired(tsdn, &arg->rtree, elm, + "Unexpected rtree_leaf_elm_acquire() failure"); + rtree_leaf_elm_write_acquired(tsdn, &arg->rtree, elm, extent); - rtree_elm_release(tsdn, &arg->rtree, elm); + rtree_leaf_elm_release(tsdn, &arg->rtree, elm); - elm = rtree_elm_acquire(tsdn, &arg->rtree, &rtree_ctx, - key, true, false); + elm = rtree_leaf_elm_acquire(tsdn, &arg->rtree, + &rtree_ctx, key, true, false); assert_ptr_not_null(elm, - "Unexpected rtree_elm_acquire() failure"); - rtree_elm_read_acquired(tsdn, &arg->rtree, elm); - rtree_elm_release(tsdn, &arg->rtree, elm); + "Unexpected rtree_leaf_elm_acquire() failure"); + rtree_leaf_elm_read_acquired(tsdn, &arg->rtree, elm); + rtree_leaf_elm_release(tsdn, &arg->rtree, elm); } else { rtree_read(tsdn, &arg->rtree, &rtree_ctx, key, false); } @@ -201,19 +229,18 @@ TEST_BEGIN(test_rtree_random) { extent_t extent; rtree_t rtree; rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; - rtree_elm_t *elm; test_rtree = &rtree; assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure"); for (unsigned i = 0; i < NSET; i++) { keys[i] = (uintptr_t)gen_rand64(sfmt); - elm = rtree_elm_acquire(tsdn, &rtree, &rtree_ctx, keys[i], - false, true); + rtree_leaf_elm_t *elm = rtree_leaf_elm_acquire(tsdn, &rtree, + &rtree_ctx, keys[i], false, true); assert_ptr_not_null(elm, - "Unexpected rtree_elm_acquire() failure"); - rtree_elm_write_acquired(tsdn, &rtree, elm, &extent); - rtree_elm_release(tsdn, &rtree, elm); + "Unexpected rtree_leaf_elm_acquire() failure"); + rtree_leaf_elm_write_acquired(tsdn, &rtree, elm, &extent); + rtree_leaf_elm_release(tsdn, &rtree, elm); assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, keys[i], true), &extent, "rtree_read() should return previously set value"); @@ -248,6 +275,10 @@ main(void) { rtree_node_alloc = rtree_node_alloc_intercept; rtree_node_dalloc_orig = rtree_node_dalloc; rtree_node_dalloc = rtree_node_dalloc_intercept; + rtree_leaf_alloc_orig = rtree_leaf_alloc; + rtree_leaf_alloc = rtree_leaf_alloc_intercept; + rtree_leaf_dalloc_orig = rtree_leaf_dalloc; + rtree_leaf_dalloc = rtree_leaf_dalloc_intercept; test_rtree = NULL; return test( -- GitLab From 99d68445efa40edaf6c5317179faea4ecd07345a Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 16 Mar 2017 17:57:52 -0700 Subject: [PATCH 337/544] Incorporate szind/slab into rtree leaves. Expand and restructure the rtree API such that all common operations can be achieved with minimal work, regardless of whether the rtree leaf fields are independent versus packed into a single atomic pointer. --- include/jemalloc/internal/arena_inlines_b.h | 55 +++- include/jemalloc/internal/extent_externs.h | 2 +- include/jemalloc/internal/extent_inlines.h | 22 +- .../jemalloc/internal/jemalloc_internal.h.in | 28 +- include/jemalloc/internal/large_externs.h | 4 +- include/jemalloc/internal/private_symbols.txt | 17 +- include/jemalloc/internal/rtree_inlines.h | 295 ++++++++++++------ include/jemalloc/internal/rtree_structs.h | 6 +- src/arena.c | 11 +- src/extent.c | 127 +++++--- src/large.c | 17 +- test/unit/arena_reset.c | 15 +- test/unit/rtree.c | 94 ++++-- 13 files changed, 469 insertions(+), 224 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 92c89a5b..8c5f9c14 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -14,7 +14,8 @@ void arena_decay_tick(tsdn_t *tsdn, arena_t *arena); void *arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, tcache_t *tcache, bool slow_path); arena_t *arena_aalloc(tsdn_t *tsdn, const void *ptr); -size_t arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr); +size_t arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr); +size_t arena_vsalloc(tsdn_t *tsdn, const void *ptr); void arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, bool slow_path); void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, @@ -114,12 +115,60 @@ arena_aalloc(tsdn_t *tsdn, const void *ptr) { return extent_arena_get(iealloc(tsdn, ptr)); } -/* Return the size of the allocation pointed to by ptr. */ JEMALLOC_ALWAYS_INLINE size_t arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { assert(ptr != NULL); - return index2size(extent_szind_get(extent)); + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + + szind_t szind = rtree_szind_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true); + assert(szind != NSIZES); + + if (config_debug && unlikely(extent != NULL)) { + rtree_leaf_elm_t elm; + rtree_leaf_elm_read(rtree_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true), true, &elm); + + assert(extent == rtree_leaf_elm_extent_get(&elm)); + assert(szind == extent_szind_get(extent)); + } + + return index2size(szind); +} + +JEMALLOC_ALWAYS_INLINE size_t +arena_vsalloc(tsdn_t *tsdn, const void *ptr) { + /* + * Return 0 if ptr is not within an extent managed by jemalloc. This + * function has two extra costs relative to isalloc(): + * - The rtree calls cannot claim to be dependent lookups, which induces + * rtree lookup load dependencies. + * - The lookup may fail, so there is an extra branch to check for + * failure. + */ + + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + + extent_t *extent; + szind_t szind; + if (rtree_extent_szind_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, false, &extent, &szind)) { + return 0; + } + + if (extent == NULL) { + return 0; + } + assert(extent_state_get(extent) == extent_state_active); + /* Only slab members should be looked up via interior pointers. */ + assert(extent_addr_get(extent) == ptr || extent_slab_get(extent)); + + assert(szind != NSIZES); + + return index2size(szind); } JEMALLOC_ALWAYS_INLINE void diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index 68c49a17..6c153d04 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -54,7 +54,7 @@ bool extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, size_t length); extent_t *extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a, - szind_t szind_a, size_t size_b, szind_t szind_b); + szind_t szind_a, bool slab_a, size_t size_b, szind_t szind_b, bool slab_b); bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b); diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index 549c8f2f..56f306df 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -2,11 +2,11 @@ #define JEMALLOC_INTERNAL_EXTENT_INLINES_H #ifndef JEMALLOC_ENABLE_INLINE -extent_t *extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent); arena_t *extent_arena_get(const extent_t *extent); void *extent_base_get(const extent_t *extent); void *extent_addr_get(const extent_t *extent); size_t extent_size_get(const extent_t *extent); +szind_t extent_szind_get_maybe_invalid(const extent_t *extent); szind_t extent_szind_get(const extent_t *extent); size_t extent_usize_get(const extent_t *extent); void *extent_before_get(const extent_t *extent); @@ -47,15 +47,6 @@ int extent_snad_comp(const extent_t *a, const extent_t *b); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_)) -JEMALLOC_INLINE extent_t * -extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent) { - rtree_ctx_t rtree_ctx_fallback; - rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - - return rtree_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, - dependent); -} - JEMALLOC_INLINE arena_t * extent_arena_get(const extent_t *extent) { return extent->e_arena; @@ -81,11 +72,18 @@ extent_size_get(const extent_t *extent) { } JEMALLOC_INLINE szind_t -extent_szind_get(const extent_t *extent) { - assert(extent->e_szind < NSIZES); /* Never call when "invalid". */ +extent_szind_get_maybe_invalid(const extent_t *extent) { + assert(extent->e_szind <= NSIZES); return extent->e_szind; } +JEMALLOC_INLINE szind_t +extent_szind_get(const extent_t *extent) { + szind_t szind = extent_szind_get_maybe_invalid(extent); + assert(szind < NSIZES); /* Never call when "invalid". */ + return szind; +} + JEMALLOC_INLINE size_t extent_usize_get(const extent_t *extent) { return index2size(extent_szind_get(extent)); diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index b184380d..238ebdca 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -535,7 +535,6 @@ void jemalloc_postfork_child(void); #include "jemalloc/internal/tsd_inlines.h" #include "jemalloc/internal/witness_inlines.h" #include "jemalloc/internal/mutex_inlines.h" -#include "jemalloc/internal/rtree_inlines.h" #ifndef JEMALLOC_ENABLE_INLINE pszind_t psz2ind(size_t psz); @@ -934,6 +933,7 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) { #endif #include "jemalloc/internal/extent_inlines.h" +#include "jemalloc/internal/rtree_inlines.h" #include "jemalloc/internal/base_inlines.h" #include "jemalloc/internal/bitmap_inlines.h" /* @@ -994,7 +994,11 @@ arena_ichoose(tsd_t *tsd, arena_t *arena) { JEMALLOC_ALWAYS_INLINE extent_t * iealloc(tsdn_t *tsdn, const void *ptr) { - return extent_lookup(tsdn, ptr, true); + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + + return rtree_extent_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true); } #endif @@ -1113,25 +1117,7 @@ ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero) { JEMALLOC_ALWAYS_INLINE size_t ivsalloc(tsdn_t *tsdn, const void *ptr) { - extent_t *extent; - - /* - * Return 0 if ptr is not within an extent managed by jemalloc. This - * function has two extra costs relative to isalloc(): - * - The extent_lookup() call cannot claim to be a dependent lookup, - * which induces rtree lookup load dependencies. - * - The lookup may fail, so there is an extra branch to check for - * failure. - * */ - extent = extent_lookup(tsdn, ptr, false); - if (extent == NULL) { - return 0; - } - assert(extent_state_get(extent) == extent_state_active); - /* Only slab members should be looked up via interior pointers. */ - assert(extent_addr_get(extent) == ptr || extent_slab_get(extent)); - - return isalloc(tsdn, extent, ptr); + return arena_vsalloc(tsdn, ptr); } JEMALLOC_ALWAYS_INLINE void diff --git a/include/jemalloc/internal/large_externs.h b/include/jemalloc/internal/large_externs.h index 66aa755c..2a208c83 100644 --- a/include/jemalloc/internal/large_externs.h +++ b/include/jemalloc/internal/large_externs.h @@ -14,8 +14,8 @@ extern large_dalloc_junk_t *large_dalloc_junk; typedef void (large_dalloc_maybe_junk_t)(void *, size_t); extern large_dalloc_maybe_junk_t *large_dalloc_maybe_junk; #else -void large_dalloc_junk(void *ptr, size_t usize); -void large_dalloc_maybe_junk(void *ptr, size_t usize); +void large_dalloc_junk(void *ptr, size_t size); +void large_dalloc_maybe_junk(void *ptr, size_t size); #endif void large_dalloc_prep_junked_locked(tsdn_t *tsdn, extent_t *extent); void large_dalloc_finish(tsdn_t *tsdn, extent_t *extent); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index a0deef89..169e7d11 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -77,6 +77,7 @@ arena_stats_merge arena_tcache_fill_small arena_tdata_get arena_tdata_get_hard +arena_vsalloc arenas arenas_tdata_cleanup b0get @@ -169,7 +170,6 @@ extent_list_init extent_list_last extent_list_remove extent_list_replace -extent_lookup extent_merge_wrapper extent_past_get extent_prof_tctx_get @@ -192,6 +192,7 @@ extent_split_wrapper extent_state_get extent_state_set extent_szind_get +extent_szind_get_maybe_invalid extent_szind_set extent_usize_get extent_zeroed_get @@ -413,25 +414,33 @@ psz2ind psz2u rtree_clear rtree_delete +rtree_extent_read +rtree_extent_szind_read rtree_leaf_alloc rtree_leaf_dalloc rtree_leaf_elm_acquire +rtree_leaf_elm_extent_read +rtree_leaf_elm_extent_write rtree_leaf_elm_lookup rtree_leaf_elm_lookup_hard -rtree_leaf_elm_read -rtree_leaf_elm_read_acquired rtree_leaf_elm_release +rtree_leaf_elm_slab_read +rtree_leaf_elm_slab_write +rtree_leaf_elm_szind_read +rtree_leaf_elm_szind_write rtree_leaf_elm_witness_access rtree_leaf_elm_witness_acquire rtree_leaf_elm_witness_release rtree_leaf_elm_write -rtree_leaf_elm_write_acquired rtree_leafkey rtree_new rtree_node_alloc rtree_node_dalloc rtree_read rtree_subkey +rtree_szind_read +rtree_szind_slab_read +rtree_szind_slab_update rtree_write s2u s2u_compute diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 3af17d36..9c337b85 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -4,21 +4,40 @@ #ifndef JEMALLOC_ENABLE_INLINE uintptr_t rtree_leafkey(uintptr_t key); uintptr_t rtree_subkey(uintptr_t key, unsigned level); -extent_t *rtree_leaf_elm_read(rtree_leaf_elm_t *elm, bool dependent); -void rtree_leaf_elm_write(rtree_leaf_elm_t *elm, const extent_t *extent); +extent_t *rtree_leaf_elm_extent_read(tsdn_t *tsdn, rtree_t *rtree, + rtree_leaf_elm_t *elm, bool acquired, bool dependent); +szind_t rtree_leaf_elm_szind_read(tsdn_t *tsdn, rtree_t *rtree, + rtree_leaf_elm_t *elm, bool acquired, bool dependent); +bool rtree_leaf_elm_slab_read(tsdn_t *tsdn, rtree_t *rtree, + rtree_leaf_elm_t *elm, bool acquired, bool dependent); +void rtree_leaf_elm_extent_write(tsdn_t *tsdn, rtree_t *rtree, + rtree_leaf_elm_t *elm, bool acquired, extent_t *extent); +void rtree_leaf_elm_szind_write(tsdn_t *tsdn, rtree_t *rtree, + rtree_leaf_elm_t *elm, bool acquired, szind_t szind); +void rtree_leaf_elm_slab_write(tsdn_t *tsdn, rtree_t *rtree, + rtree_leaf_elm_t *elm, bool acquired, bool slab); +void rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, + bool acquired, extent_t *extent, szind_t szind, bool slab); rtree_leaf_elm_t *rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, - uintptr_t key, const extent_t *extent); -extent_t *rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, - uintptr_t key, bool dependent); + uintptr_t key, extent_t *extent, szind_t szind, bool slab); +rtree_leaf_elm_t *rtree_read(tsdn_t *tsdn, rtree_t *rtree, + rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent); +extent_t *rtree_extent_read(tsdn_t *tsdn, rtree_t *rtree, + rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent); +szind_t rtree_szind_read(tsdn_t *tsdn, rtree_t *rtree, + rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent); +bool rtree_extent_szind_read(tsdn_t *tsdn, rtree_t *rtree, + rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, extent_t **r_extent, + szind_t *r_szind); +bool rtree_szind_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, + uintptr_t key, bool dependent, szind_t *r_szind, bool *r_slab); +void rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, + rtree_ctx_t *rtree_ctx, uintptr_t key, szind_t szind, bool slab); rtree_leaf_elm_t *rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); -extent_t *rtree_leaf_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, - rtree_leaf_elm_t *elm); -void rtree_leaf_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, - rtree_leaf_elm_t *elm, const extent_t *extent); -void rtree_leaf_elm_release(tsdn_t *tsdn, const rtree_t *rtree, +void rtree_leaf_elm_release(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm); void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key); @@ -45,38 +64,104 @@ rtree_subkey(uintptr_t key, unsigned level) { return ((key >> shiftbits) & mask); } +/* + * Atomic getters. + * + * dependent: Reading a value on behalf of a pointer to a valid allocation + * is guaranteed to be a clean read even without synchronization, + * because the rtree update became visible in memory before the + * pointer came into existence. + * !dependent: An arbitrary read, e.g. on behalf of ivsalloc(), may not be + * dependent on a previous rtree write, which means a stale read + * could result if synchronization were omitted here. + */ JEMALLOC_ALWAYS_INLINE extent_t * -rtree_leaf_elm_read(rtree_leaf_elm_t *elm, bool dependent) { - extent_t *extent; - - if (dependent) { - /* - * Reading a value on behalf of a pointer to a valid allocation - * is guaranteed to be a clean read even without - * synchronization, because the rtree update became visible in - * memory before the pointer came into existence. - */ - extent = (extent_t *)atomic_load_p(&elm->extent, - ATOMIC_RELAXED); - } else { - /* - * An arbitrary read, e.g. on behalf of ivsalloc(), may not be - * dependent on a previous rtree write, which means a stale read - * could result if synchronization were omitted here. - */ - extent = (extent_t *)atomic_load_p(&elm->extent, - ATOMIC_ACQUIRE); +rtree_leaf_elm_extent_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, + bool acquired, bool dependent) { + if (config_debug && acquired) { + assert(dependent); + rtree_leaf_elm_witness_access(tsdn, rtree, elm); } - /* Mask the lock bit. */ + extent_t *extent = (extent_t *)atomic_load_p(&elm->le_extent, dependent + ? ATOMIC_RELAXED : ATOMIC_ACQUIRE); + assert(!acquired || ((uintptr_t)extent & (uintptr_t)0x1) == + (uintptr_t)0x1); + /* Mask lock bit. */ extent = (extent_t *)((uintptr_t)extent & ~((uintptr_t)0x1)); - return extent; } +JEMALLOC_ALWAYS_INLINE szind_t +rtree_leaf_elm_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, + bool acquired, bool dependent) { + if (config_debug && acquired) { + assert(dependent); + rtree_leaf_elm_witness_access(tsdn, rtree, elm); + } + + return (szind_t)atomic_load_u(&elm->le_szind, dependent ? ATOMIC_RELAXED + : ATOMIC_ACQUIRE); +} + +JEMALLOC_ALWAYS_INLINE bool +rtree_leaf_elm_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, + bool acquired, bool dependent) { + if (config_debug && acquired) { + assert(dependent); + rtree_leaf_elm_witness_access(tsdn, rtree, elm); + } + + return atomic_load_b(&elm->le_slab, dependent ? ATOMIC_RELAXED : + ATOMIC_ACQUIRE); +} + +JEMALLOC_INLINE void +rtree_leaf_elm_extent_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, + bool acquired, extent_t *extent) { + if (config_debug && acquired) { + rtree_leaf_elm_witness_access(tsdn, rtree, elm); + } + assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); + + if (acquired) { + /* Overlay lock bit. */ + extent = (extent_t *)((uintptr_t)extent | (uintptr_t)0x1); + } + atomic_store_p(&elm->le_extent, extent, ATOMIC_RELEASE); +} + JEMALLOC_INLINE void -rtree_leaf_elm_write(rtree_leaf_elm_t *elm, const extent_t *extent) { - atomic_store_p(&elm->extent, (void *)extent, ATOMIC_RELEASE); +rtree_leaf_elm_szind_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, + bool acquired, szind_t szind) { + if (config_debug && acquired) { + rtree_leaf_elm_witness_access(tsdn, rtree, elm); + } + assert(szind <= NSIZES); + + atomic_store_u(&elm->le_szind, szind, ATOMIC_RELEASE); +} + +JEMALLOC_INLINE void +rtree_leaf_elm_slab_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, + bool acquired, bool slab) { + if (config_debug && acquired) { + rtree_leaf_elm_witness_access(tsdn, rtree, elm); + } + + atomic_store_b(&elm->le_slab, slab, ATOMIC_RELEASE); +} + +JEMALLOC_INLINE void +rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, + bool acquired, extent_t *extent, szind_t szind, bool slab) { + rtree_leaf_elm_slab_write(tsdn, rtree, elm, acquired, slab); + rtree_leaf_elm_szind_write(tsdn, rtree, elm, acquired, szind); + /* + * Write extent last, since the element is atomically considered valid + * as soon as the extent field is non-NULL. + */ + rtree_leaf_elm_extent_write(tsdn, rtree, elm, acquired, extent); } JEMALLOC_ALWAYS_INLINE rtree_leaf_elm_t * @@ -124,34 +209,99 @@ rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, JEMALLOC_INLINE bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, - const extent_t *extent) { - rtree_leaf_elm_t *elm; + extent_t *extent, szind_t szind, bool slab) { + /* Use rtree_clear() to set the extent to NULL. */ + assert(extent != NULL); - assert(extent != NULL); /* Use rtree_clear() for this case. */ - assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); - - elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, key, false, true); + rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, + key, false, true); if (elm == NULL) { return true; } - assert(rtree_leaf_elm_read(elm, false) == NULL); - rtree_leaf_elm_write(elm, extent); + + assert(rtree_leaf_elm_extent_read(tsdn, rtree, elm, false, false) == + NULL); + rtree_leaf_elm_write(tsdn, rtree, elm, false, extent, szind, slab); return false; } -JEMALLOC_ALWAYS_INLINE extent_t * +JEMALLOC_ALWAYS_INLINE rtree_leaf_elm_t * rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent) { - rtree_leaf_elm_t *elm; + rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, + key, dependent, false); + if (!dependent && elm == NULL) { + return NULL; + } + assert(elm != NULL); + return elm; +} - elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, key, dependent, - false); +JEMALLOC_ALWAYS_INLINE extent_t * +rtree_extent_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, + uintptr_t key, bool dependent) { + rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, + dependent); if (!dependent && elm == NULL) { return NULL; } + return rtree_leaf_elm_extent_read(tsdn, rtree, elm, false, dependent); +} + +JEMALLOC_ALWAYS_INLINE szind_t +rtree_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, + uintptr_t key, bool dependent) { + rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, + dependent); + if (!dependent && elm == NULL) { + return NSIZES; + } + return rtree_leaf_elm_szind_read(tsdn, rtree, elm, false, dependent); +} + +/* + * rtree_slab_read() is intentionally omitted because slab is always read in + * conjunction with szind, which makes rtree_szind_slab_read() a better choice. + */ + +JEMALLOC_ALWAYS_INLINE bool +rtree_extent_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, + uintptr_t key, bool dependent, extent_t **r_extent, szind_t *r_szind) { + rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, + dependent); + if (!dependent && elm == NULL) { + return true; + } + *r_extent = rtree_leaf_elm_extent_read(tsdn, rtree, elm, false, + dependent); + *r_szind = rtree_leaf_elm_szind_read(tsdn, rtree, elm, false, + dependent); + return false; +} - return rtree_leaf_elm_read(elm, dependent); +JEMALLOC_ALWAYS_INLINE bool +rtree_szind_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, + uintptr_t key, bool dependent, szind_t *r_szind, bool *r_slab) { + rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, + dependent); + if (!dependent && elm == NULL) { + return true; + } + *r_szind = rtree_leaf_elm_szind_read(tsdn, rtree, elm, false, + dependent); + *r_slab = rtree_leaf_elm_slab_read(tsdn, rtree, elm, false, dependent); + return false; +} + +JEMALLOC_INLINE void +rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, + uintptr_t key, szind_t szind, bool slab) { + assert(!slab || szind < NBINS); + + rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true); + rtree_leaf_elm_slab_write(tsdn, rtree, elm, false, slab); + rtree_leaf_elm_szind_write(tsdn, rtree, elm, false, szind); } JEMALLOC_INLINE rtree_leaf_elm_t * @@ -162,18 +312,19 @@ rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, if (!dependent && elm == NULL) { return NULL; } + assert(elm != NULL); spin_t spinner = SPIN_INITIALIZER; while (true) { /* The least significant bit serves as a lock. */ - void *extent_and_lock = atomic_load_p(&elm->extent, + void *extent_and_lock = atomic_load_p(&elm->le_extent, ATOMIC_RELAXED); if (likely(((uintptr_t)extent_and_lock & (uintptr_t)0x1) == 0)) { void *locked = (void *)((uintptr_t)extent_and_lock | (uintptr_t)0x1); if (likely(atomic_compare_exchange_strong_p( - &elm->extent, &extent_and_lock, locked, + &elm->le_extent, &extent_and_lock, locked, ATOMIC_ACQUIRE, ATOMIC_RELAXED))) { break; } @@ -188,42 +339,11 @@ rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, return elm; } -JEMALLOC_INLINE extent_t * -rtree_leaf_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree, - rtree_leaf_elm_t *elm) { - extent_t *extent; - void *ptr = atomic_load_p(&elm->extent, ATOMIC_RELAXED); - assert(((uintptr_t)ptr & (uintptr_t)0x1) == (uintptr_t)0x1); - extent = (extent_t *)((uintptr_t)ptr & ~((uintptr_t)0x1)); - assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); - - if (config_debug) { - rtree_leaf_elm_witness_access(tsdn, rtree, elm); - } - - return extent; -} - -JEMALLOC_INLINE void -rtree_leaf_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree, - rtree_leaf_elm_t *elm, const extent_t *extent) { - assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); - assert(((uintptr_t)atomic_load_p(&elm->extent, ATOMIC_RELAXED) - & (uintptr_t)0x1) == (uintptr_t)0x1); - - if (config_debug) { - rtree_leaf_elm_witness_access(tsdn, rtree, elm); - } - atomic_store_p(&elm->extent, (void *)((uintptr_t)extent | - (uintptr_t)0x1), ATOMIC_RELEASE); - assert(rtree_leaf_elm_read_acquired(tsdn, rtree, elm) == extent); -} - JEMALLOC_INLINE void -rtree_leaf_elm_release(tsdn_t *tsdn, const rtree_t *rtree, - rtree_leaf_elm_t *elm) { - rtree_leaf_elm_write(elm, rtree_leaf_elm_read_acquired(tsdn, rtree, - elm)); +rtree_leaf_elm_release(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm) { + extent_t *extent = rtree_leaf_elm_extent_read(tsdn, rtree, elm, true, + true); + rtree_leaf_elm_extent_write(tsdn, rtree, elm, false, extent); if (config_debug) { rtree_leaf_elm_witness_release(tsdn, rtree, elm); } @@ -232,10 +352,9 @@ rtree_leaf_elm_release(tsdn_t *tsdn, const rtree_t *rtree, JEMALLOC_INLINE void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key) { - rtree_leaf_elm_t *elm; - - elm = rtree_leaf_elm_acquire(tsdn, rtree, rtree_ctx, key, true, false); - rtree_leaf_elm_write_acquired(tsdn, rtree, elm, NULL); + rtree_leaf_elm_t *elm = rtree_leaf_elm_acquire(tsdn, rtree, rtree_ctx, + key, true, false); + rtree_leaf_elm_write(tsdn, rtree, elm, true, NULL, NSIZES, false); rtree_leaf_elm_release(tsdn, rtree, elm); } #endif diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h index 68554035..e9a507ab 100644 --- a/include/jemalloc/internal/rtree_structs.h +++ b/include/jemalloc/internal/rtree_structs.h @@ -2,11 +2,13 @@ #define JEMALLOC_INTERNAL_RTREE_STRUCTS_H struct rtree_node_elm_s { - atomic_p_t child; + atomic_p_t child; /* (rtree_{node,leaf}_elm_t *) */ }; struct rtree_leaf_elm_s { - atomic_p_t extent; + atomic_p_t le_extent; /* (extent_t *) */ + atomic_u_t le_szind; /* (szind_t) */ + atomic_b_t le_slab; /* (bool) */ }; struct rtree_leaf_elm_witness_s { diff --git a/src/arena.c b/src/arena.c index 968343c0..2dd84761 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1468,7 +1468,12 @@ arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, assert(isalloc(tsdn, extent, ptr) == LARGE_MINCLASS); assert(usize <= SMALL_MAXCLASS); - extent_szind_set(extent, size2index(usize)); + szind_t szind = size2index(usize); + extent_szind_set(extent, szind); + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, + szind, false); prof_accum_cancel(tsdn, &arena->prof_accum, usize); @@ -1481,6 +1486,10 @@ arena_prof_demote(tsdn_t *tsdn, extent_t *extent, const void *ptr) { assert(ptr != NULL); extent_szind_set(extent, NBINS); + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, + NBINS, false); assert(isalloc(tsdn, extent, ptr) == LARGE_MINCLASS); diff --git a/src/extent.c b/src/extent.c index 2a16d387..a95e2748 100644 --- a/src/extent.c +++ b/src/extent.c @@ -476,11 +476,12 @@ extent_rtree_acquire(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, static void extent_rtree_write_acquired(tsdn_t *tsdn, rtree_leaf_elm_t *elm_a, - rtree_leaf_elm_t *elm_b, const extent_t *extent) { - rtree_leaf_elm_write_acquired(tsdn, &extents_rtree, elm_a, extent); + rtree_leaf_elm_t *elm_b, extent_t *extent, szind_t szind, bool slab) { + rtree_leaf_elm_write(tsdn, &extents_rtree, elm_a, true, extent, szind, + slab); if (elm_b != NULL) { - rtree_leaf_elm_write_acquired(tsdn, &extents_rtree, elm_b, - extent); + rtree_leaf_elm_write(tsdn, &extents_rtree, elm_b, true, extent, + szind, slab); } } @@ -494,16 +495,15 @@ extent_rtree_release(tsdn_t *tsdn, rtree_leaf_elm_t *elm_a, } static void -extent_interior_register(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, - const extent_t *extent) { - size_t i; - +extent_interior_register(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, extent_t *extent, + szind_t szind) { assert(extent_slab_get(extent)); - for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) { + /* Register interior. */ + for (size_t i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) { rtree_write(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_base_get(extent) + (uintptr_t)(i << - LG_PAGE), extent); + LG_PAGE), extent, szind, true); } } @@ -542,7 +542,7 @@ extent_gdump_sub(tsdn_t *tsdn, const extent_t *extent) { } static bool -extent_register_impl(tsdn_t *tsdn, const extent_t *extent, bool gdump_add) { +extent_register_impl(tsdn_t *tsdn, extent_t *extent, bool gdump_add) { rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_leaf_elm_t *elm_a, *elm_b; @@ -551,9 +551,11 @@ extent_register_impl(tsdn_t *tsdn, const extent_t *extent, bool gdump_add) { &elm_b)) { return true; } - extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent); - if (extent_slab_get(extent)) { - extent_interior_register(tsdn, rtree_ctx, extent); + szind_t szind = extent_szind_get_maybe_invalid(extent); + bool slab = extent_slab_get(extent); + extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent, szind, slab); + if (slab) { + extent_interior_register(tsdn, rtree_ctx, extent, szind); } extent_rtree_release(tsdn, elm_a, elm_b); @@ -565,24 +567,24 @@ extent_register_impl(tsdn_t *tsdn, const extent_t *extent, bool gdump_add) { } static bool -extent_register(tsdn_t *tsdn, const extent_t *extent) { +extent_register(tsdn_t *tsdn, extent_t *extent) { return extent_register_impl(tsdn, extent, true); } static bool -extent_register_no_gdump_add(tsdn_t *tsdn, const extent_t *extent) { +extent_register_no_gdump_add(tsdn_t *tsdn, extent_t *extent) { return extent_register_impl(tsdn, extent, false); } static void -extent_reregister(tsdn_t *tsdn, const extent_t *extent) { +extent_reregister(tsdn_t *tsdn, extent_t *extent) { bool err = extent_register(tsdn, extent); assert(!err); } static void extent_interior_deregister(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, - const extent_t *extent) { + extent_t *extent) { size_t i; assert(extent_slab_get(extent)); @@ -602,7 +604,7 @@ extent_deregister(tsdn_t *tsdn, extent_t *extent) { extent_rtree_acquire(tsdn, rtree_ctx, extent, true, false, &elm_a, &elm_b); - extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL); + extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL, NSIZES, false); if (extent_slab_get(extent)) { extent_interior_deregister(tsdn, rtree_ctx, extent); extent_slab_set(extent, false); @@ -653,13 +655,12 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, extent_hooks_assure_initialized(arena, r_extent_hooks); extent_t *extent; if (new_addr != NULL) { - rtree_leaf_elm_t *elm; - - elm = rtree_leaf_elm_acquire(tsdn, &extents_rtree, rtree_ctx, - (uintptr_t)new_addr, false, false); + rtree_leaf_elm_t *elm = rtree_leaf_elm_acquire(tsdn, + &extents_rtree, rtree_ctx, (uintptr_t)new_addr, false, + false); if (elm != NULL) { - extent = rtree_leaf_elm_read_acquired(tsdn, - &extents_rtree, elm); + extent = rtree_leaf_elm_extent_read(tsdn, + &extents_rtree, elm, true, true); if (extent != NULL) { assert(extent_base_get(extent) == new_addr); if (extent_arena_get(extent) != arena || @@ -715,7 +716,8 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena, if (leadsize != 0) { extent_t *lead = extent; extent = extent_split_wrapper(tsdn, arena, r_extent_hooks, - lead, leadsize, NSIZES, esize + trailsize, szind); + lead, leadsize, NSIZES, false, esize + trailsize, szind, + slab); if (extent == NULL) { extent_deregister(tsdn, lead); extents_leak(tsdn, arena, r_extent_hooks, extents, @@ -728,7 +730,8 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena, /* Split the trail. */ if (trailsize != 0) { extent_t *trail = extent_split_wrapper(tsdn, arena, - r_extent_hooks, extent, esize, szind, trailsize, NSIZES); + r_extent_hooks, extent, esize, szind, slab, trailsize, + NSIZES, false); if (trail == NULL) { extent_deregister(tsdn, extent); extents_leak(tsdn, arena, r_extent_hooks, extents, @@ -742,6 +745,16 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena, * splitting occurred. */ extent_szind_set(extent, szind); + if (szind != NSIZES) { + rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)extent_addr_get(extent), szind, slab); + if (slab && extent_size_get(extent) > PAGE) { + rtree_szind_slab_update(tsdn, &extents_rtree, + rtree_ctx, + (uintptr_t)extent_past_get(extent) - + (uintptr_t)PAGE, szind, slab); + } + } } return extent; @@ -788,7 +801,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, assert(extent_state_get(extent) == extent_state_active); if (slab) { extent_slab_set(extent, slab); - extent_interior_register(tsdn, rtree_ctx, extent); + extent_interior_register(tsdn, rtree_ctx, extent, szind); } if (*zero) { @@ -934,7 +947,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, if (leadsize != 0) { extent_t *lead = extent; extent = extent_split_wrapper(tsdn, arena, r_extent_hooks, lead, - leadsize, NSIZES, esize + trailsize, szind); + leadsize, NSIZES, false, esize + trailsize, szind, slab); if (extent == NULL) { extent_deregister(tsdn, lead); extents_leak(tsdn, arena, r_extent_hooks, false, lead); @@ -947,7 +960,8 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, /* Split the trail. */ if (trailsize != 0) { extent_t *trail = extent_split_wrapper(tsdn, arena, - r_extent_hooks, extent, esize, szind, trailsize, NSIZES); + r_extent_hooks, extent, esize, szind, slab, trailsize, + NSIZES, false); if (trail == NULL) { extent_deregister(tsdn, extent); extents_leak(tsdn, arena, r_extent_hooks, @@ -961,7 +975,21 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, * Splitting causes szind to be set as a side effect, but no * splitting occurred. */ + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, + &rtree_ctx_fallback); + extent_szind_set(extent, szind); + if (szind != NSIZES) { + rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)extent_addr_get(extent), szind, slab); + if (slab && extent_size_get(extent) > PAGE) { + rtree_szind_slab_update(tsdn, &extents_rtree, + rtree_ctx, + (uintptr_t)extent_past_get(extent) - + (uintptr_t)PAGE, szind, slab); + } + } } if (*commit && !extent_committed_get(extent)) { @@ -987,7 +1015,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, &rtree_ctx_fallback); extent_slab_set(extent, true); - extent_interior_register(tsdn, rtree_ctx, extent); + extent_interior_register(tsdn, rtree_ctx, extent, szind); } if (*zero && !extent_zeroed_get(extent)) { void *addr = extent_base_get(extent); @@ -1162,8 +1190,8 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, &extents_rtree, rtree_ctx, (uintptr_t)extent_past_get(extent), false, false); if (next_elm != NULL) { - extent_t *next = rtree_leaf_elm_read_acquired(tsdn, - &extents_rtree, next_elm); + extent_t *next = rtree_leaf_elm_extent_read(tsdn, + &extents_rtree, next_elm, true, true); /* * extents->mtx only protects against races for * like-state extents, so call extent_can_coalesce() @@ -1188,8 +1216,8 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, &extents_rtree, rtree_ctx, (uintptr_t)extent_before_get(extent), false, false); if (prev_elm != NULL) { - extent_t *prev = rtree_leaf_elm_read_acquired(tsdn, - &extents_rtree, prev_elm); + extent_t *prev = rtree_leaf_elm_extent_read(tsdn, + &extents_rtree, prev_elm, true, true); bool can_coalesce = (prev != NULL && extent_can_coalesce(arena, extents, extent, prev)); rtree_leaf_elm_release(tsdn, &extents_rtree, prev_elm); @@ -1231,7 +1259,8 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_slab_set(extent, false); } - assert(extent_lookup(tsdn, extent_base_get(extent), true) == extent); + assert(rtree_extent_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)extent_base_get(extent), true) == extent); if (!extents->delay_coalesce) { extent = extent_try_coalesce(tsdn, arena, r_extent_hooks, @@ -1467,7 +1496,7 @@ extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size, extent_t * extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a, - szind_t szind_a, size_t size_b, szind_t szind_b) { + szind_t szind_a, bool slab_a, size_t size_b, szind_t szind_b, bool slab_b) { assert(extent_size_get(extent) == size_a + size_b); witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); @@ -1491,7 +1520,7 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_t lead; extent_init(&lead, arena, extent_addr_get(extent), size_a, - extent_slab_get(extent), szind_a, extent_sn_get(extent), + slab_a, szind_a, extent_sn_get(extent), extent_state_get(extent), extent_zeroed_get(extent), extent_committed_get(extent)); @@ -1502,9 +1531,9 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, } extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) + - size_a), size_b, extent_slab_get(extent), szind_b, - extent_sn_get(extent), extent_state_get(extent), - extent_zeroed_get(extent), extent_committed_get(extent)); + size_a), size_b, slab_b, szind_b, extent_sn_get(extent), + extent_state_get(extent), extent_zeroed_get(extent), + extent_committed_get(extent)); if (extent_rtree_acquire(tsdn, rtree_ctx, trail, false, true, &trail_elm_a, &trail_elm_b)) { goto label_error_c; @@ -1519,8 +1548,10 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_size_set(extent, size_a); extent_szind_set(extent, szind_a); - extent_rtree_write_acquired(tsdn, lead_elm_a, lead_elm_b, extent); - extent_rtree_write_acquired(tsdn, trail_elm_a, trail_elm_b, trail); + extent_rtree_write_acquired(tsdn, lead_elm_a, lead_elm_b, extent, + szind_a, slab_a); + extent_rtree_write_acquired(tsdn, trail_elm_a, trail_elm_b, trail, + szind_b, slab_b); extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); extent_rtree_release(tsdn, trail_elm_a, trail_elm_b); @@ -1599,13 +1630,13 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, &b_elm_b); if (a_elm_b != NULL) { - rtree_leaf_elm_write_acquired(tsdn, &extents_rtree, a_elm_b, - NULL); + rtree_leaf_elm_write(tsdn, &extents_rtree, a_elm_b, true, NULL, + NSIZES, false); rtree_leaf_elm_release(tsdn, &extents_rtree, a_elm_b); } if (b_elm_b != NULL) { - rtree_leaf_elm_write_acquired(tsdn, &extents_rtree, b_elm_a, - NULL); + rtree_leaf_elm_write(tsdn, &extents_rtree, b_elm_a, true, NULL, + NSIZES, false); rtree_leaf_elm_release(tsdn, &extents_rtree, b_elm_a); } else { b_elm_b = b_elm_a; @@ -1617,7 +1648,7 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_sn_get(a) : extent_sn_get(b)); extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b)); - extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a); + extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a, NSIZES, false); extent_rtree_release(tsdn, a_elm_a, b_elm_b); extent_dalloc(tsdn, extent_arena_get(b), b); diff --git a/src/large.c b/src/large.c index 0e9f0d72..845202f9 100644 --- a/src/large.c +++ b/src/large.c @@ -66,8 +66,8 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, #define large_dalloc_junk JEMALLOC_N(n_large_dalloc_junk) #endif void -large_dalloc_junk(void *ptr, size_t usize) { - memset(ptr, JEMALLOC_FREE_JUNK, usize); +large_dalloc_junk(void *ptr, size_t size) { + memset(ptr, JEMALLOC_FREE_JUNK, size); } #ifdef JEMALLOC_JET #undef large_dalloc_junk @@ -80,14 +80,14 @@ large_dalloc_junk_t *large_dalloc_junk = JEMALLOC_N(n_large_dalloc_junk); #define large_dalloc_maybe_junk JEMALLOC_N(n_large_dalloc_maybe_junk) #endif void -large_dalloc_maybe_junk(void *ptr, size_t usize) { +large_dalloc_maybe_junk(void *ptr, size_t size) { if (config_fill && have_dss && unlikely(opt_junk_free)) { /* * Only bother junk filling if the extent isn't about to be * unmapped. */ if (!config_munmap || (have_dss && extent_in_dss(ptr))) { - large_dalloc_junk(ptr, usize); + large_dalloc_junk(ptr, size); } } } @@ -115,7 +115,7 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { if (diff != 0) { extent_t *trail = extent_split_wrapper(tsdn, arena, &extent_hooks, extent, usize + large_pad, size2index(usize), - diff, NSIZES); + false, diff, NSIZES, false); if (trail == NULL) { return true; } @@ -182,7 +182,12 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, extent_dalloc_wrapper(tsdn, arena, &extent_hooks, trail); return true; } - extent_szind_set(extent, size2index(usize)); + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + szind_t szind = size2index(usize); + extent_szind_set(extent, szind); + rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)extent_addr_get(extent), szind, false); if (config_stats && new_mapping) { arena_stats_mapped_add(tsdn, &arena->stats, trailsize); diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 24c7f526..589c652c 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -57,9 +57,16 @@ get_large_size(size_t ind) { /* Like ivsalloc(), but safe to call on discarded allocations. */ static size_t vsalloc(tsdn_t *tsdn, const void *ptr) { + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + extent_t *extent; + szind_t szind; + if (rtree_extent_szind_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, false, &extent, &szind)) { + return 0; + } - extent = extent_lookup(tsdn, ptr, false); if (extent == NULL) { return 0; } @@ -67,7 +74,11 @@ vsalloc(tsdn_t *tsdn, const void *ptr) { return 0; } - return isalloc(tsdn, extent, ptr); + if (szind == NSIZES) { + return 0; + } + + return index2size(szind); } static unsigned diff --git a/test/unit/rtree.c b/test/unit/rtree.c index 221f2f2c..b04e321b 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -70,8 +70,8 @@ TEST_BEGIN(test_rtree_read_empty) { rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; test_rtree = &rtree; assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure"); - assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, PAGE, false), - "rtree_read() should return NULL for empty tree"); + assert_ptr_null(rtree_extent_read(tsdn, &rtree, &rtree_ctx, PAGE, + false), "rtree_extent_read() should return NULL for empty tree"); rtree_delete(tsdn, &rtree); test_rtree = NULL; } @@ -99,6 +99,8 @@ thd_start(void *varg) { sfmt = init_gen_rand(arg->seed); extent = (extent_t *)malloc(sizeof(extent)); assert_ptr_not_null(extent, "Unexpected malloc() failure"); + extent_init(extent, NULL, NULL, 0, false, NSIZES, 0, + extent_state_active, false, false); tsdn = tsdn_fetch(); for (i = 0; i < NITERS; i++) { @@ -109,18 +111,24 @@ thd_start(void *varg) { &arg->rtree, &rtree_ctx, key, false, true); assert_ptr_not_null(elm, "Unexpected rtree_leaf_elm_acquire() failure"); - rtree_leaf_elm_write_acquired(tsdn, &arg->rtree, elm, - extent); + rtree_leaf_elm_write(tsdn, &arg->rtree, elm, true, + extent, NSIZES, false); rtree_leaf_elm_release(tsdn, &arg->rtree, elm); elm = rtree_leaf_elm_acquire(tsdn, &arg->rtree, &rtree_ctx, key, true, false); assert_ptr_not_null(elm, "Unexpected rtree_leaf_elm_acquire() failure"); - rtree_leaf_elm_read_acquired(tsdn, &arg->rtree, elm); + rtree_leaf_elm_extent_read(tsdn, &arg->rtree, elm, true, + true); + rtree_leaf_elm_szind_read(tsdn, &arg->rtree, elm, true, + true); + rtree_leaf_elm_slab_read(tsdn, &arg->rtree, elm, true, + true); rtree_leaf_elm_release(tsdn, &arg->rtree, elm); } else { - rtree_read(tsdn, &arg->rtree, &rtree_ctx, key, false); + rtree_extent_read(tsdn, &arg->rtree, &rtree_ctx, key, + false); } } @@ -158,26 +166,33 @@ TEST_END TEST_BEGIN(test_rtree_extrema) { extent_t extent_a, extent_b; - tsdn_t *tsdn; + extent_init(&extent_a, NULL, NULL, LARGE_MINCLASS, false, + size2index(LARGE_MINCLASS), 0, extent_state_active, false, false); + extent_init(&extent_b, NULL, NULL, 0, false, NSIZES, 0, + extent_state_active, false, false); - tsdn = tsdn_fetch(); + tsdn_t *tsdn = tsdn_fetch(); rtree_t rtree; rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; test_rtree = &rtree; assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure"); - assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, PAGE, &extent_a), + assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, PAGE, &extent_a, + extent_szind_get(&extent_a), extent_slab_get(&extent_a)), "Unexpected rtree_write() failure"); - assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, PAGE, true), + rtree_szind_slab_update(tsdn, &rtree, &rtree_ctx, PAGE, + extent_szind_get(&extent_a), extent_slab_get(&extent_a)); + assert_ptr_eq(rtree_extent_read(tsdn, &rtree, &rtree_ctx, PAGE, true), &extent_a, - "rtree_read() should return previously set value"); + "rtree_extent_read() should return previously set value"); assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, ~((uintptr_t)0), - &extent_b), "Unexpected rtree_write() failure"); - assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, ~((uintptr_t)0), - true), &extent_b, - "rtree_read() should return previously set value"); + &extent_b, extent_szind_get_maybe_invalid(&extent_b), + extent_slab_get(&extent_b)), "Unexpected rtree_write() failure"); + assert_ptr_eq(rtree_extent_read(tsdn, &rtree, &rtree_ctx, + ~((uintptr_t)0), true), &extent_b, + "rtree_extent_read() should return previously set value"); rtree_delete(tsdn, &rtree); test_rtree = NULL; @@ -191,6 +206,9 @@ TEST_BEGIN(test_rtree_bits) { PAGE + (((uintptr_t)1) << LG_PAGE) - 1}; extent_t extent; + extent_init(&extent, NULL, NULL, 0, false, NSIZES, 0, + extent_state_active, false, false); + rtree_t rtree; rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; @@ -200,16 +218,17 @@ TEST_BEGIN(test_rtree_bits) { for (unsigned i = 0; i < sizeof(keys)/sizeof(uintptr_t); i++) { assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, keys[i], - &extent), "Unexpected rtree_write() failure"); + &extent, NSIZES, false), + "Unexpected rtree_write() failure"); for (unsigned j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) { - assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, - keys[j], true), &extent, - "rtree_read() should return previously set " - "value and ignore insignificant key bits; " - "i=%u, j=%u, set key=%#"FMTxPTR", get " + assert_ptr_eq(rtree_extent_read(tsdn, &rtree, + &rtree_ctx, keys[j], true), + &extent, "rtree_extent_read() should return " + "previously set value and ignore insignificant key " + "bits; i=%u, j=%u, set key=%#"FMTxPTR", get " "key=%#"FMTxPTR, i, j, keys[i], keys[j]); } - assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, + assert_ptr_null(rtree_extent_read(tsdn, &rtree, &rtree_ctx, (((uintptr_t)2) << LG_PAGE), false), "Only leftmost rtree leaf should be set; i=%u", i); rtree_clear(tsdn, &rtree, &rtree_ctx, keys[i]); @@ -226,10 +245,13 @@ TEST_BEGIN(test_rtree_random) { sfmt_t *sfmt = init_gen_rand(SEED); tsdn_t *tsdn = tsdn_fetch(); uintptr_t keys[NSET]; - extent_t extent; rtree_t rtree; rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; + extent_t extent; + extent_init(&extent, NULL, NULL, 0, false, NSIZES, 0, + extent_state_active, false, false); + test_rtree = &rtree; assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure"); @@ -239,26 +261,30 @@ TEST_BEGIN(test_rtree_random) { &rtree_ctx, keys[i], false, true); assert_ptr_not_null(elm, "Unexpected rtree_leaf_elm_acquire() failure"); - rtree_leaf_elm_write_acquired(tsdn, &rtree, elm, &extent); + rtree_leaf_elm_write(tsdn, &rtree, elm, true, &extent, NSIZES, + false); rtree_leaf_elm_release(tsdn, &rtree, elm); - assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, keys[i], - true), &extent, - "rtree_read() should return previously set value"); + assert_ptr_eq(rtree_extent_read(tsdn, &rtree, &rtree_ctx, + keys[i], true), &extent, + "rtree_extent_read() should return previously set value"); } for (unsigned i = 0; i < NSET; i++) { - assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, keys[i], - true), &extent, - "rtree_read() should return previously set value, i=%u", i); + assert_ptr_eq(rtree_extent_read(tsdn, &rtree, &rtree_ctx, + keys[i], true), &extent, + "rtree_extent_read() should return previously set value, " + "i=%u", i); } for (unsigned i = 0; i < NSET; i++) { rtree_clear(tsdn, &rtree, &rtree_ctx, keys[i]); - assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, keys[i], - true), "rtree_read() should return previously set value"); + assert_ptr_null(rtree_extent_read(tsdn, &rtree, &rtree_ctx, + keys[i], true), + "rtree_extent_read() should return previously set value"); } for (unsigned i = 0; i < NSET; i++) { - assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, keys[i], - true), "rtree_read() should return previously set value"); + assert_ptr_null(rtree_extent_read(tsdn, &rtree, &rtree_ctx, + keys[i], true), + "rtree_extent_read() should return previously set value"); } rtree_delete(tsdn, &rtree); -- GitLab From ce41ab0c57d5f0c9310200d0fecea99ef334a834 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 22 Mar 2017 16:38:03 -0700 Subject: [PATCH 338/544] Embed root node into rtree_t. This avoids one atomic operation per tree access. --- include/jemalloc/internal/rtree_externs.h | 2 +- include/jemalloc/internal/rtree_structs.h | 12 ++- src/extent.c | 2 +- src/rtree.c | 91 ++++------------- test/unit/rtree.c | 119 ++++++++++------------ 5 files changed, 86 insertions(+), 140 deletions(-) diff --git a/include/jemalloc/internal/rtree_externs.h b/include/jemalloc/internal/rtree_externs.h index 842eb0b5..5145c12c 100644 --- a/include/jemalloc/internal/rtree_externs.h +++ b/include/jemalloc/internal/rtree_externs.h @@ -23,7 +23,7 @@ static const rtree_level_t rtree_levels[] = { #endif }; -bool rtree_new(rtree_t *rtree); +bool rtree_new(rtree_t *rtree, bool zeroed); #ifdef JEMALLOC_JET typedef rtree_node_elm_t *(rtree_node_alloc_t)(tsdn_t *, rtree_t *, size_t); extern rtree_node_alloc_t *rtree_node_alloc; diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h index e9a507ab..3ecdf810 100644 --- a/include/jemalloc/internal/rtree_structs.h +++ b/include/jemalloc/internal/rtree_structs.h @@ -39,13 +39,17 @@ struct rtree_ctx_s { #ifndef _MSC_VER JEMALLOC_ALIGNED(CACHELINE) #endif - rtree_ctx_cache_elm_t cache[RTREE_CTX_NCACHE]; + rtree_ctx_cache_elm_t cache[RTREE_CTX_NCACHE]; }; struct rtree_s { - /* An rtree_{internal,leaf}_elm_t *. */ - atomic_p_t root; - malloc_mutex_t init_lock; + malloc_mutex_t init_lock; + /* Number of elements based on rtree_levels[0].bits. */ +#if RTREE_HEIGHT > 1 + rtree_node_elm_t root[1U << (RTREE_NSB/RTREE_HEIGHT)]; +#else + rtree_leaf_elm_t root[1U << (RTREE_NSB/RTREE_HEIGHT)]; +#endif }; #endif /* JEMALLOC_INTERNAL_RTREE_STRUCTS_H */ diff --git a/src/extent.c b/src/extent.c index a95e2748..f1b513e4 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1658,7 +1658,7 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, bool extent_boot(void) { - if (rtree_new(&extents_rtree)) { + if (rtree_new(&extents_rtree, true)) { return true; } diff --git a/src/rtree.c b/src/rtree.c index 18197390..a07380f3 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -6,8 +6,15 @@ * used. */ bool -rtree_new(rtree_t *rtree) { - atomic_store_p(&rtree->root, NULL, ATOMIC_RELAXED); +rtree_new(rtree_t *rtree, bool zeroed) { +#ifdef JEMALLOC_JET + if (!zeroed) { + memset(rtree, 0, sizeof(rtree_t)); /* Clear root. */ + } +#else + assert(zeroed); +#endif + if (malloc_mutex_init(&rtree->init_lock, "rtree", WITNESS_RANK_RTREE)) { return true; } @@ -76,6 +83,7 @@ rtree_leaf_dalloc_t *rtree_leaf_dalloc = JEMALLOC_N(rtree_leaf_dalloc_impl); #endif #ifdef JEMALLOC_JET +# if RTREE_HEIGHT > 1 static void rtree_delete_subtree(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *subtree, unsigned level) { @@ -101,25 +109,17 @@ rtree_delete_subtree(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *subtree, } } - rtree_node_dalloc(tsdn, rtree, subtree); + if (subtree != rtree->root) { + rtree_node_dalloc(tsdn, rtree, subtree); + } } +# endif void rtree_delete(tsdn_t *tsdn, rtree_t *rtree) { - if (RTREE_HEIGHT > 1) { - rtree_node_elm_t *node = (rtree_node_elm_t *)atomic_load_p( - &rtree->root, ATOMIC_RELAXED); - if (node != NULL) { - rtree_delete_subtree(tsdn, rtree, node, 0); - } - } else { - rtree_leaf_elm_t *leaf = - (rtree_leaf_elm_t *)atomic_load_p(&rtree->root, - ATOMIC_RELAXED); - if (leaf != NULL) { - rtree_leaf_dalloc(tsdn, rtree, leaf); - } - } +# if RTREE_HEIGHT > 1 + rtree_delete_subtree(tsdn, rtree, rtree->root, 0); +# endif } #endif @@ -244,70 +244,21 @@ rtree_child_leaf_read(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *elm, return leaf; } -UNUSED static rtree_node_elm_t * -rtree_root_node_tryread(rtree_t *rtree, bool dependent) { - rtree_node_elm_t *node; - if (dependent) { - node = (rtree_node_elm_t *)atomic_load_p(&rtree->root, - ATOMIC_RELAXED); - } else { - node = (rtree_node_elm_t *)atomic_load_p(&rtree->root, - ATOMIC_ACQUIRE); - } - assert(!dependent || node != NULL); - return node; -} - -UNUSED static rtree_node_elm_t * -rtree_root_node_read(tsdn_t *tsdn, rtree_t *rtree, bool dependent) { - rtree_node_elm_t *node = rtree_root_node_tryread(rtree, dependent); - if (!dependent && unlikely(!rtree_node_valid(node))) { - node = rtree_node_init(tsdn, rtree, 0, &rtree->root); - } - assert(!dependent || node != NULL); - return node; -} - -UNUSED static rtree_leaf_elm_t * -rtree_root_leaf_tryread(rtree_t *rtree, bool dependent) { - rtree_leaf_elm_t *leaf; - if (dependent) { - leaf = (rtree_leaf_elm_t *)atomic_load_p(&rtree->root, - ATOMIC_RELAXED); - } else { - leaf = (rtree_leaf_elm_t *)atomic_load_p(&rtree->root, - ATOMIC_ACQUIRE); - } - assert(!dependent || leaf != NULL); - return leaf; -} - -UNUSED static rtree_leaf_elm_t * -rtree_root_leaf_read(tsdn_t *tsdn, rtree_t *rtree, bool dependent) { - rtree_leaf_elm_t *leaf = rtree_root_leaf_tryread(rtree, dependent); - if (!dependent && unlikely(!rtree_leaf_valid(leaf))) { - leaf = rtree_leaf_init(tsdn, rtree, &rtree->root); - } - assert(!dependent || leaf != NULL); - return leaf; -} - rtree_leaf_elm_t * rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing) { rtree_node_elm_t *node; rtree_leaf_elm_t *leaf; #if RTREE_HEIGHT > 1 - node = init_missing ? rtree_root_node_read(tsdn, rtree, dependent) : - rtree_root_node_tryread(rtree, dependent); + node = rtree->root; #else - leaf = init_missing ? rtree_root_leaf_read(tsdn, rtree, dependent) : - rtree_root_leaf_tryread(rtree, dependent); + leaf = rtree->root; #endif #define RTREE_GET_CHILD(level) { \ assert(level < RTREE_HEIGHT-1); \ - if (!dependent && unlikely(!rtree_node_valid(node))) { \ + if (level != 0 && !dependent && \ + unlikely(!rtree_node_valid(node))) { \ return NULL; \ } \ uintptr_t subkey = rtree_subkey(key, level); \ diff --git a/test/unit/rtree.c b/test/unit/rtree.c index b04e321b..7a25c47d 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -5,13 +5,14 @@ rtree_node_dalloc_t *rtree_node_dalloc_orig; rtree_leaf_alloc_t *rtree_leaf_alloc_orig; rtree_leaf_dalloc_t *rtree_leaf_dalloc_orig; -rtree_t *test_rtree; +/* Potentially too large to safely place on the stack. */ +rtree_t test_rtree; static rtree_node_elm_t * rtree_node_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { rtree_node_elm_t *node; - if (rtree != test_rtree) { + if (rtree != &test_rtree) { return rtree_node_alloc_orig(tsdn, rtree, nelms); } @@ -26,7 +27,7 @@ rtree_node_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { static void rtree_node_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *node) { - if (rtree != test_rtree) { + if (rtree != &test_rtree) { rtree_node_dalloc_orig(tsdn, rtree, node); return; } @@ -38,7 +39,7 @@ static rtree_leaf_elm_t * rtree_leaf_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { rtree_leaf_elm_t *leaf; - if (rtree != test_rtree) { + if (rtree != &test_rtree) { return rtree_leaf_alloc_orig(tsdn, rtree, nelms); } @@ -53,7 +54,7 @@ rtree_leaf_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { static void rtree_leaf_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *leaf) { - if (rtree != test_rtree) { + if (rtree != &test_rtree) { rtree_leaf_dalloc_orig(tsdn, rtree, leaf); return; } @@ -66,14 +67,12 @@ TEST_BEGIN(test_rtree_read_empty) { tsdn = tsdn_fetch(); - rtree_t rtree; + rtree_t *rtree = &test_rtree; rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; - test_rtree = &rtree; - assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure"); - assert_ptr_null(rtree_extent_read(tsdn, &rtree, &rtree_ctx, PAGE, + assert_false(rtree_new(rtree, false), "Unexpected rtree_new() failure"); + assert_ptr_null(rtree_extent_read(tsdn, rtree, &rtree_ctx, PAGE, false), "rtree_extent_read() should return NULL for empty tree"); - rtree_delete(tsdn, &rtree); - test_rtree = NULL; + rtree_delete(tsdn, rtree); } TEST_END @@ -83,7 +82,7 @@ TEST_END #define SEED 42 typedef struct { - rtree_t rtree; + rtree_t *rtree; uint32_t seed; } thd_start_arg_t; @@ -108,26 +107,26 @@ thd_start(void *varg) { MAX_NBITS) - ZU(1))); if (i % 2 == 0) { rtree_leaf_elm_t *elm = rtree_leaf_elm_acquire(tsdn, - &arg->rtree, &rtree_ctx, key, false, true); + arg->rtree, &rtree_ctx, key, false, true); assert_ptr_not_null(elm, "Unexpected rtree_leaf_elm_acquire() failure"); - rtree_leaf_elm_write(tsdn, &arg->rtree, elm, true, + rtree_leaf_elm_write(tsdn, arg->rtree, elm, true, extent, NSIZES, false); - rtree_leaf_elm_release(tsdn, &arg->rtree, elm); + rtree_leaf_elm_release(tsdn, arg->rtree, elm); - elm = rtree_leaf_elm_acquire(tsdn, &arg->rtree, + elm = rtree_leaf_elm_acquire(tsdn, arg->rtree, &rtree_ctx, key, true, false); assert_ptr_not_null(elm, "Unexpected rtree_leaf_elm_acquire() failure"); - rtree_leaf_elm_extent_read(tsdn, &arg->rtree, elm, true, + rtree_leaf_elm_extent_read(tsdn, arg->rtree, elm, true, true); - rtree_leaf_elm_szind_read(tsdn, &arg->rtree, elm, true, + rtree_leaf_elm_szind_read(tsdn, arg->rtree, elm, true, true); - rtree_leaf_elm_slab_read(tsdn, &arg->rtree, elm, true, + rtree_leaf_elm_slab_read(tsdn, arg->rtree, elm, true, true); - rtree_leaf_elm_release(tsdn, &arg->rtree, elm); + rtree_leaf_elm_release(tsdn, arg->rtree, elm); } else { - rtree_extent_read(tsdn, &arg->rtree, &rtree_ctx, key, + rtree_extent_read(tsdn, arg->rtree, &rtree_ctx, key, false); } } @@ -145,8 +144,9 @@ TEST_BEGIN(test_rtree_concurrent) { sfmt = init_gen_rand(SEED); tsdn = tsdn_fetch(); - test_rtree = &arg.rtree; - assert_false(rtree_new(&arg.rtree), "Unexpected rtree_new() failure"); + arg.rtree = &test_rtree; + assert_false(rtree_new(arg.rtree, false), + "Unexpected rtree_new() failure"); arg.seed = gen_rand32(sfmt); for (unsigned i = 0; i < NTHREADS; i++) { thd_create(&thds[i], thd_start, (void *)&arg); @@ -154,8 +154,7 @@ TEST_BEGIN(test_rtree_concurrent) { for (unsigned i = 0; i < NTHREADS; i++) { thd_join(thds[i], NULL); } - rtree_delete(tsdn, &arg.rtree); - test_rtree = NULL; + rtree_delete(tsdn, arg.rtree); fini_gen_rand(sfmt); } TEST_END @@ -173,29 +172,27 @@ TEST_BEGIN(test_rtree_extrema) { tsdn_t *tsdn = tsdn_fetch(); - rtree_t rtree; + rtree_t *rtree = &test_rtree; rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; - test_rtree = &rtree; - assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure"); + assert_false(rtree_new(rtree, false), "Unexpected rtree_new() failure"); - assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, PAGE, &extent_a, + assert_false(rtree_write(tsdn, rtree, &rtree_ctx, PAGE, &extent_a, extent_szind_get(&extent_a), extent_slab_get(&extent_a)), "Unexpected rtree_write() failure"); - rtree_szind_slab_update(tsdn, &rtree, &rtree_ctx, PAGE, + rtree_szind_slab_update(tsdn, rtree, &rtree_ctx, PAGE, extent_szind_get(&extent_a), extent_slab_get(&extent_a)); - assert_ptr_eq(rtree_extent_read(tsdn, &rtree, &rtree_ctx, PAGE, true), + assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx, PAGE, true), &extent_a, "rtree_extent_read() should return previously set value"); - assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, ~((uintptr_t)0), + assert_false(rtree_write(tsdn, rtree, &rtree_ctx, ~((uintptr_t)0), &extent_b, extent_szind_get_maybe_invalid(&extent_b), extent_slab_get(&extent_b)), "Unexpected rtree_write() failure"); - assert_ptr_eq(rtree_extent_read(tsdn, &rtree, &rtree_ctx, + assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx, ~((uintptr_t)0), true), &extent_b, "rtree_extent_read() should return previously set value"); - rtree_delete(tsdn, &rtree); - test_rtree = NULL; + rtree_delete(tsdn, rtree); } TEST_END @@ -209,33 +206,30 @@ TEST_BEGIN(test_rtree_bits) { extent_init(&extent, NULL, NULL, 0, false, NSIZES, 0, extent_state_active, false, false); - rtree_t rtree; + rtree_t *rtree = &test_rtree; rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; - test_rtree = &rtree; - assert_false(rtree_new(&rtree), - "Unexpected rtree_new() failure"); + assert_false(rtree_new(rtree, false), "Unexpected rtree_new() failure"); for (unsigned i = 0; i < sizeof(keys)/sizeof(uintptr_t); i++) { - assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, keys[i], + assert_false(rtree_write(tsdn, rtree, &rtree_ctx, keys[i], &extent, NSIZES, false), "Unexpected rtree_write() failure"); for (unsigned j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) { - assert_ptr_eq(rtree_extent_read(tsdn, &rtree, - &rtree_ctx, keys[j], true), - &extent, "rtree_extent_read() should return " - "previously set value and ignore insignificant key " - "bits; i=%u, j=%u, set key=%#"FMTxPTR", get " - "key=%#"FMTxPTR, i, j, keys[i], keys[j]); + assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx, + keys[j], true), &extent, + "rtree_extent_read() should return previously set " + "value and ignore insignificant key bits; i=%u, " + "j=%u, set key=%#"FMTxPTR", get key=%#"FMTxPTR, i, + j, keys[i], keys[j]); } - assert_ptr_null(rtree_extent_read(tsdn, &rtree, &rtree_ctx, + assert_ptr_null(rtree_extent_read(tsdn, rtree, &rtree_ctx, (((uintptr_t)2) << LG_PAGE), false), "Only leftmost rtree leaf should be set; i=%u", i); - rtree_clear(tsdn, &rtree, &rtree_ctx, keys[i]); + rtree_clear(tsdn, rtree, &rtree_ctx, keys[i]); } - rtree_delete(tsdn, &rtree); - test_rtree = NULL; + rtree_delete(tsdn, rtree); } TEST_END @@ -245,50 +239,48 @@ TEST_BEGIN(test_rtree_random) { sfmt_t *sfmt = init_gen_rand(SEED); tsdn_t *tsdn = tsdn_fetch(); uintptr_t keys[NSET]; - rtree_t rtree; + rtree_t *rtree = &test_rtree; rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; extent_t extent; extent_init(&extent, NULL, NULL, 0, false, NSIZES, 0, extent_state_active, false, false); - test_rtree = &rtree; - assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure"); + assert_false(rtree_new(rtree, false), "Unexpected rtree_new() failure"); for (unsigned i = 0; i < NSET; i++) { keys[i] = (uintptr_t)gen_rand64(sfmt); - rtree_leaf_elm_t *elm = rtree_leaf_elm_acquire(tsdn, &rtree, + rtree_leaf_elm_t *elm = rtree_leaf_elm_acquire(tsdn, rtree, &rtree_ctx, keys[i], false, true); assert_ptr_not_null(elm, "Unexpected rtree_leaf_elm_acquire() failure"); - rtree_leaf_elm_write(tsdn, &rtree, elm, true, &extent, NSIZES, + rtree_leaf_elm_write(tsdn, rtree, elm, true, &extent, NSIZES, false); - rtree_leaf_elm_release(tsdn, &rtree, elm); - assert_ptr_eq(rtree_extent_read(tsdn, &rtree, &rtree_ctx, + rtree_leaf_elm_release(tsdn, rtree, elm); + assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx, keys[i], true), &extent, "rtree_extent_read() should return previously set value"); } for (unsigned i = 0; i < NSET; i++) { - assert_ptr_eq(rtree_extent_read(tsdn, &rtree, &rtree_ctx, + assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx, keys[i], true), &extent, "rtree_extent_read() should return previously set value, " "i=%u", i); } for (unsigned i = 0; i < NSET; i++) { - rtree_clear(tsdn, &rtree, &rtree_ctx, keys[i]); - assert_ptr_null(rtree_extent_read(tsdn, &rtree, &rtree_ctx, + rtree_clear(tsdn, rtree, &rtree_ctx, keys[i]); + assert_ptr_null(rtree_extent_read(tsdn, rtree, &rtree_ctx, keys[i], true), "rtree_extent_read() should return previously set value"); } for (unsigned i = 0; i < NSET; i++) { - assert_ptr_null(rtree_extent_read(tsdn, &rtree, &rtree_ctx, + assert_ptr_null(rtree_extent_read(tsdn, rtree, &rtree_ctx, keys[i], true), "rtree_extent_read() should return previously set value"); } - rtree_delete(tsdn, &rtree); - test_rtree = NULL; + rtree_delete(tsdn, rtree); fini_gen_rand(sfmt); #undef NSET #undef SEED @@ -305,7 +297,6 @@ main(void) { rtree_leaf_alloc = rtree_leaf_alloc_intercept; rtree_leaf_dalloc_orig = rtree_leaf_dalloc; rtree_leaf_dalloc = rtree_leaf_dalloc_intercept; - test_rtree = NULL; return test( test_rtree_read_empty, -- GitLab From 0ee0e0c155a05d0d028a9972ad86b9eaac4ccabd Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 20 Mar 2017 16:38:21 -0700 Subject: [PATCH 339/544] Implement compact rtree leaf element representation. If a single virtual adddress pointer has enough unused bits to pack {szind_t, extent_t *, bool, bool}, use a single pointer-sized field in each rtree leaf element, rather than using three separate fields. This has little impact on access speed (fewer loads/stores, but more bit twiddling), except that denser representation increases TLB effectiveness. --- include/jemalloc/internal/private_symbols.txt | 5 + include/jemalloc/internal/rtree_inlines.h | 127 +++++++++++++++++- include/jemalloc/internal/rtree_structs.h | 19 ++- include/jemalloc/internal/rtree_types.h | 4 + include/jemalloc/internal/size_classes.sh | 15 +++ 5 files changed, 163 insertions(+), 7 deletions(-) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 169e7d11..35c7028b 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -419,6 +419,11 @@ rtree_extent_szind_read rtree_leaf_alloc rtree_leaf_dalloc rtree_leaf_elm_acquire +rtree_leaf_elm_bits_extent_get +rtree_leaf_elm_bits_locked_get +rtree_leaf_elm_bits_read +rtree_leaf_elm_bits_slab_get +rtree_leaf_elm_bits_szind_get rtree_leaf_elm_extent_read rtree_leaf_elm_extent_write rtree_leaf_elm_lookup diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 9c337b85..6f92df94 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -4,6 +4,14 @@ #ifndef JEMALLOC_ENABLE_INLINE uintptr_t rtree_leafkey(uintptr_t key); uintptr_t rtree_subkey(uintptr_t key, unsigned level); +# ifdef RTREE_LEAF_COMPACT +uintptr_t rtree_leaf_elm_bits_read(tsdn_t *tsdn, rtree_t *rtree, + rtree_leaf_elm_t *elm, bool acquired, bool dependent); +extent_t *rtree_leaf_elm_bits_extent_get(uintptr_t bits); +szind_t rtree_leaf_elm_bits_szind_get(uintptr_t bits); +bool rtree_leaf_elm_bits_slab_get(uintptr_t bits); +bool rtree_leaf_elm_bits_locked_get(uintptr_t bits); +# endif extent_t *rtree_leaf_elm_extent_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, bool acquired, bool dependent); szind_t rtree_leaf_elm_szind_read(tsdn_t *tsdn, rtree_t *rtree, @@ -75,6 +83,42 @@ rtree_subkey(uintptr_t key, unsigned level) { * dependent on a previous rtree write, which means a stale read * could result if synchronization were omitted here. */ +# ifdef RTREE_LEAF_COMPACT +JEMALLOC_ALWAYS_INLINE uintptr_t +rtree_leaf_elm_bits_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, + bool acquired, bool dependent) { + if (config_debug && acquired) { + assert(dependent); + rtree_leaf_elm_witness_access(tsdn, rtree, elm); + } + + return (uintptr_t)atomic_load_p(&elm->le_bits, dependent + ? ATOMIC_RELAXED : ATOMIC_ACQUIRE); +} + +JEMALLOC_ALWAYS_INLINE extent_t * +rtree_leaf_elm_bits_extent_get(uintptr_t bits) { + /* Restore sign-extended high bits, mask slab and lock bits. */ + return (extent_t *)((uintptr_t)((intptr_t)(bits << RTREE_NHIB) >> + RTREE_NHIB) & ~((uintptr_t)0x3)); +} + +JEMALLOC_ALWAYS_INLINE szind_t +rtree_leaf_elm_bits_szind_get(uintptr_t bits) { + return (szind_t)(bits >> LG_VADDR); +} + +JEMALLOC_ALWAYS_INLINE bool +rtree_leaf_elm_bits_slab_get(uintptr_t bits) { + return (bool)((bits >> 1) & (uintptr_t)0x1); +} + +JEMALLOC_ALWAYS_INLINE bool +rtree_leaf_elm_bits_locked_get(uintptr_t bits) { + return (bool)(bits & (uintptr_t)0x1); +} +# endif + JEMALLOC_ALWAYS_INLINE extent_t * rtree_leaf_elm_extent_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, bool acquired, bool dependent) { @@ -83,6 +127,12 @@ rtree_leaf_elm_extent_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, rtree_leaf_elm_witness_access(tsdn, rtree, elm); } +#ifdef RTREE_LEAF_COMPACT + uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, acquired, + dependent); + assert(!acquired || rtree_leaf_elm_bits_locked_get(bits)); + return rtree_leaf_elm_bits_extent_get(bits); +#else extent_t *extent = (extent_t *)atomic_load_p(&elm->le_extent, dependent ? ATOMIC_RELAXED : ATOMIC_ACQUIRE); assert(!acquired || ((uintptr_t)extent & (uintptr_t)0x1) == @@ -90,6 +140,7 @@ rtree_leaf_elm_extent_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, /* Mask lock bit. */ extent = (extent_t *)((uintptr_t)extent & ~((uintptr_t)0x1)); return extent; +#endif } JEMALLOC_ALWAYS_INLINE szind_t @@ -100,8 +151,15 @@ rtree_leaf_elm_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, rtree_leaf_elm_witness_access(tsdn, rtree, elm); } +#ifdef RTREE_LEAF_COMPACT + uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, acquired, + dependent); + assert(!acquired || rtree_leaf_elm_bits_locked_get(bits)); + return rtree_leaf_elm_bits_szind_get(bits); +#else return (szind_t)atomic_load_u(&elm->le_szind, dependent ? ATOMIC_RELAXED : ATOMIC_ACQUIRE); +#endif } JEMALLOC_ALWAYS_INLINE bool @@ -112,8 +170,15 @@ rtree_leaf_elm_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, rtree_leaf_elm_witness_access(tsdn, rtree, elm); } +#ifdef RTREE_LEAF_COMPACT + uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, acquired, + dependent); + assert(!acquired || rtree_leaf_elm_bits_locked_get(bits)); + return rtree_leaf_elm_bits_slab_get(bits); +#else return atomic_load_b(&elm->le_slab, dependent ? ATOMIC_RELAXED : ATOMIC_ACQUIRE); +#endif } JEMALLOC_INLINE void @@ -124,11 +189,21 @@ rtree_leaf_elm_extent_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, } assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); +#ifdef RTREE_LEAF_COMPACT + uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, + acquired, acquired); + uintptr_t bits = ((uintptr_t)rtree_leaf_elm_bits_szind_get(old_bits) << + LG_VADDR) | ((uintptr_t)extent & (((uintptr_t)0x1 << LG_VADDR) - 1)) + | ((uintptr_t)rtree_leaf_elm_bits_slab_get(old_bits) << 1) | + (uintptr_t)acquired; + atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE); +#else if (acquired) { /* Overlay lock bit. */ extent = (extent_t *)((uintptr_t)extent | (uintptr_t)0x1); } atomic_store_p(&elm->le_extent, extent, ATOMIC_RELEASE); +#endif } JEMALLOC_INLINE void @@ -139,7 +214,18 @@ rtree_leaf_elm_szind_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, } assert(szind <= NSIZES); +#ifdef RTREE_LEAF_COMPACT + uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, + acquired, acquired); + uintptr_t bits = ((uintptr_t)szind << LG_VADDR) | + ((uintptr_t)rtree_leaf_elm_bits_extent_get(old_bits) & + (((uintptr_t)0x1 << LG_VADDR) - 1)) | + ((uintptr_t)rtree_leaf_elm_bits_slab_get(old_bits) << 1) | + (uintptr_t)acquired; + atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE); +#else atomic_store_u(&elm->le_szind, szind, ATOMIC_RELEASE); +#endif } JEMALLOC_INLINE void @@ -149,12 +235,35 @@ rtree_leaf_elm_slab_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, rtree_leaf_elm_witness_access(tsdn, rtree, elm); } +#ifdef RTREE_LEAF_COMPACT + uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, + acquired, acquired); + uintptr_t bits = ((uintptr_t)rtree_leaf_elm_bits_szind_get(old_bits) << + LG_VADDR) | ((uintptr_t)rtree_leaf_elm_bits_extent_get(old_bits) & + (((uintptr_t)0x1 << LG_VADDR) - 1)) | ((uintptr_t)slab << 1) | + (uintptr_t)acquired; + atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE); +#else atomic_store_b(&elm->le_slab, slab, ATOMIC_RELEASE); +#endif } JEMALLOC_INLINE void rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, bool acquired, extent_t *extent, szind_t szind, bool slab) { +#ifdef RTREE_LEAF_COMPACT + if (config_debug && acquired) { + rtree_leaf_elm_witness_access(tsdn, rtree, elm); + } + assert(!slab || szind < NBINS); + + uintptr_t bits = ((uintptr_t)szind << LG_VADDR) | + ((uintptr_t)extent & (((uintptr_t)0x1 << LG_VADDR) - 1)) | + ((uintptr_t)slab << 1) | + (uintptr_t)acquired; + + atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE); +#else rtree_leaf_elm_slab_write(tsdn, rtree, elm, acquired, slab); rtree_leaf_elm_szind_write(tsdn, rtree, elm, acquired, szind); /* @@ -162,6 +271,7 @@ rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, * as soon as the extent field is non-NULL. */ rtree_leaf_elm_extent_write(tsdn, rtree, elm, acquired, extent); +#endif } JEMALLOC_ALWAYS_INLINE rtree_leaf_elm_t * @@ -317,19 +427,24 @@ rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, spin_t spinner = SPIN_INITIALIZER; while (true) { /* The least significant bit serves as a lock. */ - void *extent_and_lock = atomic_load_p(&elm->le_extent, +#ifdef RTREE_LEAF_COMPACT +# define RTREE_FIELD_WITH_LOCK le_bits +#else +# define RTREE_FIELD_WITH_LOCK le_extent +#endif + void *bits = atomic_load_p(&elm->RTREE_FIELD_WITH_LOCK, ATOMIC_RELAXED); - if (likely(((uintptr_t)extent_and_lock & (uintptr_t)0x1) == 0)) - { - void *locked = (void *)((uintptr_t)extent_and_lock - | (uintptr_t)0x1); + if (likely(((uintptr_t)bits & (uintptr_t)0x1) == 0)) { + void *locked = (void *)((uintptr_t)bits | + (uintptr_t)0x1); if (likely(atomic_compare_exchange_strong_p( - &elm->le_extent, &extent_and_lock, locked, + &elm->RTREE_FIELD_WITH_LOCK, &bits, locked, ATOMIC_ACQUIRE, ATOMIC_RELAXED))) { break; } } spin_adaptive(&spinner); +#undef RTREE_FIELD_WITH_LOCK } if (config_debug) { diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h index 3ecdf810..8dd9cdaa 100644 --- a/include/jemalloc/internal/rtree_structs.h +++ b/include/jemalloc/internal/rtree_structs.h @@ -6,9 +6,26 @@ struct rtree_node_elm_s { }; struct rtree_leaf_elm_s { - atomic_p_t le_extent; /* (extent_t *) */ +#ifdef RTREE_LEAF_COMPACT + /* + * Single pointer-width field containing all three leaf element fields. + * For example, on a 64-bit x64 system with 48 significant virtual + * memory address bits, the index, extent, and slab fields are packed as + * such: + * + * x: index + * e: extent + * b: slab + * k: lock + * + * 00000000 xxxxxxxx eeeeeeee [...] eeeeeeee eeee00bk + */ + atomic_p_t le_bits; +#else + atomic_p_t le_extent; /* (extent_t *), lock in low bit */ atomic_u_t le_szind; /* (szind_t) */ atomic_b_t le_slab; /* (bool) */ +#endif }; struct rtree_leaf_elm_witness_s { diff --git a/include/jemalloc/internal/rtree_types.h b/include/jemalloc/internal/rtree_types.h index 18fc5b0f..de3893be 100644 --- a/include/jemalloc/internal/rtree_types.h +++ b/include/jemalloc/internal/rtree_types.h @@ -33,6 +33,10 @@ typedef struct rtree_s rtree_t; #else # error Unsupported number of significant virtual address bits #endif +/* Use compact leaf representation if virtual address encoding allows. */ +#if RTREE_NHIB >= LG_CEIL_NSIZES +# define RTREE_LEAF_COMPACT +#endif /* * Number of leafkey/leaf pairs to cache. Each entry supports an entire leaf, diff --git a/include/jemalloc/internal/size_classes.sh b/include/jemalloc/internal/size_classes.sh index 06892d8d..60bdbd21 100755 --- a/include/jemalloc/internal/size_classes.sh +++ b/include/jemalloc/internal/size_classes.sh @@ -40,6 +40,17 @@ lg() { done } +lg_ceil() { + y=$1 + lg ${y}; lg_floor=${lg_result} + pow2 ${lg_floor}; pow2_floor=${pow2_result} + if [ ${pow2_floor} -lt ${y} ] ; then + lg_ceil_result=$((${lg_floor} + 1)) + else + lg_ceil_result=${lg_floor} + fi +} + reg_size_compute() { lg_grp=$1 lg_delta=$2 @@ -246,12 +257,14 @@ size_classes() { done echo nsizes=${index} + lg_ceil ${nsizes}; lg_ceil_nsizes=${lg_ceil_result} # Defined upon completion: # - ntbins # - nlbins # - nbins # - nsizes + # - lg_ceil_nsizes # - npsizes # - lg_tiny_maxclass # - lookup_maxclass @@ -286,6 +299,7 @@ cat < Date: Fri, 17 Mar 2017 01:25:12 -0700 Subject: [PATCH 340/544] Remove extent arg from isalloc() and arena_salloc(). --- include/jemalloc/internal/arena_inlines_b.h | 13 ++------- .../jemalloc/internal/jemalloc_internal.h.in | 22 ++++---------- include/jemalloc/internal/prof_inlines_b.h | 6 ++-- src/arena.c | 8 ++--- src/jemalloc.c | 29 +++++++++---------- src/tcache.c | 2 +- 6 files changed, 29 insertions(+), 51 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 8c5f9c14..47d62c15 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -14,7 +14,7 @@ void arena_decay_tick(tsdn_t *tsdn, arena_t *arena); void *arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, tcache_t *tcache, bool slow_path); arena_t *arena_aalloc(tsdn_t *tsdn, const void *ptr); -size_t arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr); +size_t arena_salloc(tsdn_t *tsdn, const void *ptr); size_t arena_vsalloc(tsdn_t *tsdn, const void *ptr); void arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, bool slow_path); @@ -116,7 +116,7 @@ arena_aalloc(tsdn_t *tsdn, const void *ptr) { } JEMALLOC_ALWAYS_INLINE size_t -arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { +arena_salloc(tsdn_t *tsdn, const void *ptr) { assert(ptr != NULL); rtree_ctx_t rtree_ctx_fallback; @@ -126,15 +126,6 @@ arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { (uintptr_t)ptr, true); assert(szind != NSIZES); - if (config_debug && unlikely(extent != NULL)) { - rtree_leaf_elm_t elm; - rtree_leaf_elm_read(rtree_read(tsdn, &extents_rtree, rtree_ctx, - (uintptr_t)ptr, true), true, &elm); - - assert(extent == rtree_leaf_elm_extent_get(&elm)); - assert(szind == extent_szind_get(extent)); - } - return index2size(szind); } diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 238ebdca..57b9ed8c 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -1008,7 +1008,7 @@ iealloc(tsdn_t *tsdn, const void *ptr) { #ifndef JEMALLOC_ENABLE_INLINE arena_t *iaalloc(tsdn_t *tsdn, const void *ptr); -size_t isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr); +size_t isalloc(tsdn_t *tsdn, const void *ptr); void *iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, bool is_internal, arena_t *arena, bool slow_path); void *ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, @@ -1043,18 +1043,11 @@ iaalloc(tsdn_t *tsdn, const void *ptr) { return arena_aalloc(tsdn, ptr); } -/* - * Typical usage: - * tsdn_t *tsdn = [...] - * void *ptr = [...] - * extent_t *extent = iealloc(tsdn, ptr); - * size_t sz = isalloc(tsdn, extent, ptr); - */ JEMALLOC_ALWAYS_INLINE size_t -isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { +isalloc(tsdn_t *tsdn, const void *ptr) { assert(ptr != NULL); - return arena_salloc(tsdn, extent, ptr); + return arena_salloc(tsdn, ptr); } JEMALLOC_ALWAYS_INLINE void * @@ -1070,8 +1063,7 @@ iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, ret = arena_malloc(tsdn, arena, size, ind, zero, tcache, slow_path); if (config_stats && is_internal && likely(ret != NULL)) { - arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn, - iealloc(tsdn, ret), ret)); + arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn, ret)); } return ret; } @@ -1097,8 +1089,7 @@ ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, ret = arena_palloc(tsdn, arena, usize, alignment, zero, tcache); assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret); if (config_stats && is_internal && likely(ret != NULL)) { - arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn, - iealloc(tsdn, ret), ret)); + arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn, ret)); } return ret; } @@ -1129,8 +1120,7 @@ idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, narenas_auto); witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); if (config_stats && is_internal) { - arena_internal_sub(iaalloc(tsdn, ptr), isalloc(tsdn, extent, - ptr)); + arena_internal_sub(iaalloc(tsdn, ptr), isalloc(tsdn, ptr)); } arena_dalloc(tsdn, extent, ptr, tcache, slow_path); diff --git a/include/jemalloc/internal/prof_inlines_b.h b/include/jemalloc/internal/prof_inlines_b.h index 9e969a07..29a2b528 100644 --- a/include/jemalloc/internal/prof_inlines_b.h +++ b/include/jemalloc/internal/prof_inlines_b.h @@ -155,7 +155,7 @@ prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); - assert(usize == isalloc(tsdn, extent, ptr)); + assert(usize == isalloc(tsdn, ptr)); if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) { prof_malloc_sample_object(tsdn, extent, ptr, usize, tctx); @@ -175,7 +175,7 @@ prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, assert(ptr != NULL || (uintptr_t)tctx <= (uintptr_t)1U); if (prof_active && !updated && ptr != NULL) { - assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr)); + assert(usize == isalloc(tsd_tsdn(tsd), ptr)); if (prof_sample_accum_update(tsd, usize, true, NULL)) { /* * Don't sample. The usize passed to prof_alloc_prep() @@ -229,7 +229,7 @@ prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, size_t usize) { prof_tctx_t *tctx = prof_tctx_get(tsd_tsdn(tsd), extent, ptr); cassert(config_prof); - assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr)); + assert(usize == isalloc(tsd_tsdn(tsd), ptr)); if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) { prof_free_sampled_object(tsd, usize, tctx); diff --git a/src/arena.c b/src/arena.c index 2dd84761..680c435f 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1029,7 +1029,7 @@ arena_reset(tsd_t *tsd, arena_t *arena) { malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx); if (config_stats || (config_prof && opt_prof)) { - usize = isalloc(tsd_tsdn(tsd), extent, ptr); + usize = isalloc(tsd_tsdn(tsd), ptr); } /* Remove large allocation from prof sample set. */ if (config_prof && opt_prof) { @@ -1465,7 +1465,7 @@ arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, cassert(config_prof); assert(ptr != NULL); - assert(isalloc(tsdn, extent, ptr) == LARGE_MINCLASS); + assert(isalloc(tsdn, ptr) == LARGE_MINCLASS); assert(usize <= SMALL_MAXCLASS); szind_t szind = size2index(usize); @@ -1477,7 +1477,7 @@ arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, prof_accum_cancel(tsdn, &arena->prof_accum, usize); - assert(isalloc(tsdn, extent, ptr) == usize); + assert(isalloc(tsdn, ptr) == usize); } static size_t @@ -1491,7 +1491,7 @@ arena_prof_demote(tsdn_t *tsdn, extent_t *extent, const void *ptr) { rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, NBINS, false); - assert(isalloc(tsdn, extent, ptr) == LARGE_MINCLASS); + assert(isalloc(tsdn, ptr) == LARGE_MINCLASS); return LARGE_MINCLASS; } diff --git a/src/jemalloc.c b/src/jemalloc.c index 3c595bab..8201c50a 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1766,8 +1766,7 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { || ((uintptr_t)allocation & (dopts->alignment - 1)) == ZU(0)); if (config_stats) { - assert(usize == isalloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), - allocation), allocation)); + assert(usize == isalloc(tsd_tsdn(tsd), allocation)); *tsd_thread_allocatedp_get(tsd) += usize; } @@ -2019,10 +2018,10 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { extent = iealloc(tsd_tsdn(tsd), ptr); if (config_prof && opt_prof) { - usize = isalloc(tsd_tsdn(tsd), extent, ptr); + usize = isalloc(tsd_tsdn(tsd), ptr); prof_free(tsd, extent, ptr, usize); } else if (config_stats) { - usize = isalloc(tsd_tsdn(tsd), extent, ptr); + usize = isalloc(tsd_tsdn(tsd), ptr); } if (config_stats) { *tsd_thread_deallocatedp_get(tsd) += usize; @@ -2089,7 +2088,7 @@ je_realloc(void *ptr, size_t size) { witness_assert_lockless(tsd_tsdn(tsd)); extent = iealloc(tsd_tsdn(tsd), ptr); - old_usize = isalloc(tsd_tsdn(tsd), extent, ptr); + old_usize = isalloc(tsd_tsdn(tsd), ptr); if (config_prof && opt_prof) { usize = s2u(size); ret = unlikely(usize == 0 || usize > LARGE_MAXCLASS) ? @@ -2119,7 +2118,7 @@ je_realloc(void *ptr, size_t size) { if (config_stats && likely(ret != NULL)) { tsd_t *tsd; - assert(usize == isalloc(tsdn, iealloc(tsdn, ret), ret)); + assert(usize == isalloc(tsdn, ret)); tsd = tsdn_tsd(tsdn); *tsd_thread_allocatedp_get(tsd) += usize; *tsd_thread_deallocatedp_get(tsd) += old_usize; @@ -2374,7 +2373,7 @@ irallocx_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, * reallocation. Therefore, query the actual value of usize. */ extent = old_extent; - *usize = isalloc(tsd_tsdn(tsd), extent, p); + *usize = isalloc(tsd_tsdn(tsd), p); } else { extent = iealloc(tsd_tsdn(tsd), p); } @@ -2425,7 +2424,7 @@ je_rallocx(void *ptr, size_t size, int flags) { tcache = tcache_get(tsd, true); } - old_usize = isalloc(tsd_tsdn(tsd), extent, ptr); + old_usize = isalloc(tsd_tsdn(tsd), ptr); if (config_prof && opt_prof) { usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment); @@ -2444,8 +2443,7 @@ je_rallocx(void *ptr, size_t size, int flags) { goto label_oom; } if (config_stats) { - usize = isalloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), - p), p); + usize = isalloc(tsd_tsdn(tsd), p); } } assert(alignment == 0 || ((uintptr_t)p & (alignment - 1)) == ZU(0)); @@ -2476,7 +2474,7 @@ ixallocx_helper(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t old_usize, zero)) { return old_usize; } - usize = isalloc(tsdn, extent, ptr); + usize = isalloc(tsdn, ptr); return usize; } @@ -2561,7 +2559,7 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) { witness_assert_lockless(tsd_tsdn(tsd)); extent = iealloc(tsd_tsdn(tsd), ptr); - old_usize = isalloc(tsd_tsdn(tsd), extent, ptr); + old_usize = isalloc(tsd_tsdn(tsd), ptr); /* * The API explicitly absolves itself of protecting against (size + @@ -2615,7 +2613,7 @@ je_sallocx(const void *ptr, int flags) { if (config_ivsalloc) { usize = ivsalloc(tsdn, ptr); } else { - usize = isalloc(tsdn, iealloc(tsdn, ptr), ptr); + usize = isalloc(tsdn, ptr); } witness_assert_lockless(tsdn); @@ -2678,7 +2676,7 @@ je_sdallocx(void *ptr, size_t size, int flags) { tsd = tsd_fetch(); extent = iealloc(tsd_tsdn(tsd), ptr); usize = inallocx(tsd_tsdn(tsd), size, flags); - assert(usize == isalloc(tsd_tsdn(tsd), extent, ptr)); + assert(usize == isalloc(tsd_tsdn(tsd), ptr)); witness_assert_lockless(tsd_tsdn(tsd)); if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { @@ -2798,8 +2796,7 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) { if (config_ivsalloc) { ret = ivsalloc(tsdn, ptr); } else { - ret = (ptr == NULL) ? 0 : isalloc(tsdn, iealloc(tsdn, ptr), - ptr); + ret = (ptr == NULL) ? 0 : isalloc(tsdn, ptr); } witness_assert_lockless(tsdn); diff --git a/src/tcache.c b/src/tcache.c index 2250425f..7ae89751 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -28,7 +28,7 @@ static malloc_mutex_t tcaches_mtx; size_t tcache_salloc(tsdn_t *tsdn, const void *ptr) { - return arena_salloc(tsdn, iealloc(tsdn, ptr), ptr); + return arena_salloc(tsdn, ptr); } void -- GitLab From 51a2ec92a10691bf5cee78093a0aa9a1fced351d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 17 Mar 2017 02:45:12 -0700 Subject: [PATCH 341/544] Remove extent dereferences from the deallocation fast paths. --- include/jemalloc/internal/arena_inlines_b.h | 71 +++++++++++++++---- .../jemalloc/internal/jemalloc_internal.h.in | 41 ++++++----- src/arena.c | 2 +- src/ckh.c | 15 ++-- src/jemalloc.c | 32 ++++----- src/large.c | 3 +- src/prof.c | 33 ++++----- src/tcache.c | 3 +- 8 files changed, 113 insertions(+), 87 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 47d62c15..cbd9e20a 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -16,10 +16,9 @@ void *arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, arena_t *arena_aalloc(tsdn_t *tsdn, const void *ptr); size_t arena_salloc(tsdn_t *tsdn, const void *ptr); size_t arena_vsalloc(tsdn_t *tsdn, const void *ptr); -void arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, - tcache_t *tcache, bool slow_path); -void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, - tcache_t *tcache, bool slow_path); +void arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path); +void arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, + bool slow_path); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) @@ -163,24 +162,39 @@ arena_vsalloc(tsdn_t *tsdn, const void *ptr) { } JEMALLOC_ALWAYS_INLINE void -arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, - bool slow_path) { +arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path) { assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); - szind_t szind = extent_szind_get(extent); - if (likely(extent_slab_get(extent))) { + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + + szind_t szind; + bool slab; + rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, + true, &szind, &slab); + + if (config_debug) { + extent_t *extent = rtree_extent_read(tsdn, &extents_rtree, + rtree_ctx, (uintptr_t)ptr, true); + assert(szind == extent_szind_get(extent)); + assert(slab == extent_slab_get(extent)); + } + + if (likely(slab)) { /* Small allocation. */ if (likely(tcache != NULL)) { tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind, slow_path); } else { + extent_t *extent = iealloc(tsdn, ptr); arena_dalloc_small(tsdn, extent_arena_get(extent), extent, ptr); } } else { if (likely(tcache != NULL) && szind < nhbins) { if (config_prof && unlikely(szind < NBINS)) { + extent_t *extent = iealloc(tsdn, ptr); arena_dalloc_promoted(tsdn, extent, ptr, tcache, slow_path); } else { @@ -188,30 +202,62 @@ arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, ptr, szind, slow_path); } } else { + extent_t *extent = iealloc(tsdn, ptr); large_dalloc(tsdn, extent); } } } JEMALLOC_ALWAYS_INLINE void -arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, - tcache_t *tcache, bool slow_path) { +arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, + bool slow_path) { assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); - szind_t szind = size2index(size); - if (likely(extent_slab_get(extent))) { + szind_t szind; + bool slab; + if (!config_prof || !opt_prof) { + /* + * There is no risk of being confused by a promoted sampled + * object, so base szind and slab on the given size. + */ + szind = size2index(size); + slab = (szind < NBINS); + } + + if ((config_prof && opt_prof) || config_debug) { + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, + &rtree_ctx_fallback); + + rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true, &szind, &slab); + + assert(szind == size2index(size)); + assert((config_prof && opt_prof) || slab == (szind < NBINS)); + + if (config_debug) { + extent_t *extent = rtree_extent_read(tsdn, + &extents_rtree, rtree_ctx, (uintptr_t)ptr, true); + assert(szind == extent_szind_get(extent)); + assert(slab == extent_slab_get(extent)); + } + } + + if (likely(slab)) { /* Small allocation. */ if (likely(tcache != NULL)) { tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind, slow_path); } else { + extent_t *extent = iealloc(tsdn, ptr); arena_dalloc_small(tsdn, extent_arena_get(extent), extent, ptr); } } else { if (likely(tcache != NULL) && szind < nhbins) { if (config_prof && unlikely(szind < NBINS)) { + extent_t *extent = iealloc(tsdn, ptr); arena_dalloc_promoted(tsdn, extent, ptr, tcache, slow_path); } else { @@ -219,6 +265,7 @@ arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, szind, slow_path); } } else { + extent_t *extent = iealloc(tsdn, ptr); large_dalloc(tsdn, extent); } } diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 57b9ed8c..b3510382 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -1019,14 +1019,14 @@ void *ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); void *ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero); size_t ivsalloc(tsdn_t *tsdn, const void *ptr); -void idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, - bool is_internal, bool slow_path); -void idalloc(tsd_t *tsd, extent_t *extent, void *ptr); -void isdalloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, - tcache_t *tcache, bool slow_path); -void *iralloct_realign(tsdn_t *tsdn, extent_t *extent, void *ptr, - size_t oldsize, size_t size, size_t extra, size_t alignment, bool zero, - tcache_t *tcache, arena_t *arena); +void idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool is_internal, + bool slow_path); +void idalloc(tsd_t *tsd, void *ptr); +void isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, + bool slow_path); +void *iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, + size_t extra, size_t alignment, bool zero, tcache_t *tcache, + arena_t *arena); void *iralloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); void *iralloc(tsd_t *tsd, extent_t *extent, void *ptr, size_t oldsize, @@ -1112,8 +1112,8 @@ ivsalloc(tsdn_t *tsdn, const void *ptr) { } JEMALLOC_ALWAYS_INLINE void -idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, - bool is_internal, bool slow_path) { +idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool is_internal, + bool slow_path) { assert(ptr != NULL); assert(!is_internal || tcache == NULL); assert(!is_internal || arena_ind_get(iaalloc(tsdn, ptr)) < @@ -1123,25 +1123,24 @@ idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache, arena_internal_sub(iaalloc(tsdn, ptr), isalloc(tsdn, ptr)); } - arena_dalloc(tsdn, extent, ptr, tcache, slow_path); + arena_dalloc(tsdn, ptr, tcache, slow_path); } JEMALLOC_ALWAYS_INLINE void -idalloc(tsd_t *tsd, extent_t *extent, void *ptr) { - idalloctm(tsd_tsdn(tsd), extent, ptr, tcache_get(tsd, false), false, - true); +idalloc(tsd_t *tsd, void *ptr) { + idalloctm(tsd_tsdn(tsd), ptr, tcache_get(tsd, false), false, true); } JEMALLOC_ALWAYS_INLINE void -isdalloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size, +isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, bool slow_path) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - arena_sdalloc(tsdn, extent, ptr, size, tcache, slow_path); + arena_sdalloc(tsdn, ptr, size, tcache, slow_path); } JEMALLOC_ALWAYS_INLINE void * -iralloct_realign(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, - size_t size, size_t extra, size_t alignment, bool zero, tcache_t *tcache, +iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, + size_t extra, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); void *p; @@ -1172,7 +1171,7 @@ iralloct_realign(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, */ copysize = (size < oldsize) ? size : oldsize; memcpy(p, ptr, copysize); - isdalloct(tsdn, extent, ptr, oldsize, tcache, true); + isdalloct(tsdn, ptr, oldsize, tcache, true); return p; } @@ -1189,8 +1188,8 @@ iralloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, * Existing object alignment is inadequate; allocate new space * and copy. */ - return iralloct_realign(tsdn, extent, ptr, oldsize, size, 0, - alignment, zero, tcache, arena); + return iralloct_realign(tsdn, ptr, oldsize, size, 0, alignment, + zero, tcache, arena); } return arena_ralloc(tsdn, arena, extent, ptr, oldsize, size, alignment, diff --git a/src/arena.c b/src/arena.c index 680c435f..f05249dc 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1719,7 +1719,7 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, copysize = (usize < oldsize) ? usize : oldsize; memcpy(ret, ptr, copysize); - isdalloct(tsdn, extent, ptr, oldsize, tcache, true); + isdalloct(tsdn, ptr, oldsize, tcache, true); return ret; } diff --git a/src/ckh.c b/src/ckh.c index 31d1ac21..463f8dd1 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -282,14 +282,12 @@ ckh_grow(tsd_t *tsd, ckh_t *ckh) { ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; if (!ckh_rebuild(ckh, tab)) { - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tab), - tab, NULL, true, true); + idalloctm(tsd_tsdn(tsd), tab, NULL, true, true); break; } /* Rebuilding failed, so back out partially rebuilt table. */ - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), ckh->tab), - ckh->tab, NULL, true, true); + idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, true, true); ckh->tab = tab; ckh->lg_curbuckets = lg_prevbuckets; } @@ -331,8 +329,7 @@ ckh_shrink(tsd_t *tsd, ckh_t *ckh) { ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; if (!ckh_rebuild(ckh, tab)) { - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tab), tab, NULL, - true, true); + idalloctm(tsd_tsdn(tsd), tab, NULL, true, true); #ifdef CKH_COUNT ckh->nshrinks++; #endif @@ -340,8 +337,7 @@ ckh_shrink(tsd_t *tsd, ckh_t *ckh) { } /* Rebuilding failed, so back out partially rebuilt table. */ - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), ckh->tab), ckh->tab, - NULL, true, true); + idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, true, true); ckh->tab = tab; ckh->lg_curbuckets = lg_prevbuckets; #ifdef CKH_COUNT @@ -422,8 +418,7 @@ ckh_delete(tsd_t *tsd, ckh_t *ckh) { (unsigned long long)ckh->nrelocs); #endif - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), ckh->tab), ckh->tab, - NULL, true, true); + idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, true, true); if (config_debug) { memset(ckh, JEMALLOC_FREE_JUNK, sizeof(ckh_t)); } diff --git a/src/jemalloc.c b/src/jemalloc.c index 8201c50a..1077ebf3 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -310,8 +310,8 @@ a0ialloc(size_t size, bool zero, bool is_internal) { } static void -a0idalloc(extent_t *extent, void *ptr, bool is_internal) { - idalloctm(TSDN_NULL, extent, ptr, false, is_internal, true); +a0idalloc(void *ptr, bool is_internal) { + idalloctm(TSDN_NULL, ptr, false, is_internal, true); } void * @@ -321,7 +321,7 @@ a0malloc(size_t size) { void a0dalloc(void *ptr) { - a0idalloc(iealloc(NULL, ptr), ptr, true); + a0idalloc(ptr, true); } /* @@ -358,7 +358,7 @@ bootstrap_free(void *ptr) { return; } - a0idalloc(iealloc(NULL, ptr), ptr, false); + a0idalloc(ptr, false); } void @@ -2008,17 +2008,15 @@ irealloc_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, JEMALLOC_INLINE_C void ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { - extent_t *extent; - size_t usize; - witness_assert_lockless(tsd_tsdn(tsd)); assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); - extent = iealloc(tsd_tsdn(tsd), ptr); + size_t usize; if (config_prof && opt_prof) { usize = isalloc(tsd_tsdn(tsd), ptr); + extent_t *extent = iealloc(tsd_tsdn(tsd), ptr); prof_free(tsd, extent, ptr, usize); } else if (config_stats) { usize = isalloc(tsd_tsdn(tsd), ptr); @@ -2028,21 +2026,21 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { } if (likely(!slow_path)) { - idalloctm(tsd_tsdn(tsd), extent, ptr, tcache, false, false); + idalloctm(tsd_tsdn(tsd), ptr, tcache, false, false); } else { - idalloctm(tsd_tsdn(tsd), extent, ptr, tcache, false, true); + idalloctm(tsd_tsdn(tsd), ptr, tcache, false, true); } } JEMALLOC_INLINE_C void -isfree(tsd_t *tsd, extent_t *extent, void *ptr, size_t usize, tcache_t *tcache, - bool slow_path) { +isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) { witness_assert_lockless(tsd_tsdn(tsd)); assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); if (config_prof && opt_prof) { + extent_t *extent = iealloc(tsd_tsdn(tsd), ptr); prof_free(tsd, extent, ptr, usize); } if (config_stats) { @@ -2050,9 +2048,9 @@ isfree(tsd_t *tsd, extent_t *extent, void *ptr, size_t usize, tcache_t *tcache, } if (likely(!slow_path)) { - isdalloct(tsd_tsdn(tsd), extent, ptr, usize, tcache, false); + isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, false); } else { - isdalloct(tsd_tsdn(tsd), extent, ptr, usize, tcache, true); + isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, true); } } @@ -2667,14 +2665,12 @@ inallocx(tsdn_t *tsdn, size_t size, int flags) { JEMALLOC_EXPORT void JEMALLOC_NOTHROW je_sdallocx(void *ptr, size_t size, int flags) { tsd_t *tsd; - extent_t *extent; size_t usize; tcache_t *tcache; assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); - extent = iealloc(tsd_tsdn(tsd), ptr); usize = inallocx(tsd_tsdn(tsd), size, flags); assert(usize == isalloc(tsd_tsdn(tsd), ptr)); @@ -2691,9 +2687,9 @@ je_sdallocx(void *ptr, size_t size, int flags) { UTRACE(ptr, 0, 0); if (likely(!malloc_slow)) { - isfree(tsd, extent, ptr, usize, tcache, false); + isfree(tsd, ptr, usize, tcache, false); } else { - isfree(tsd, extent, ptr, usize, tcache, true); + isfree(tsd, ptr, usize, tcache, true); } witness_assert_lockless(tsd_tsdn(tsd)); } diff --git a/src/large.c b/src/large.c index 845202f9..3f96c521 100644 --- a/src/large.c +++ b/src/large.c @@ -303,8 +303,7 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, size_t copysize = (usize < oldusize) ? usize : oldusize; memcpy(ret, extent_addr_get(extent), copysize); - isdalloct(tsdn, extent, extent_addr_get(extent), oldusize, tcache, - true); + isdalloct(tsdn, extent_addr_get(extent), oldusize, tcache, true); return ret; } diff --git a/src/prof.c b/src/prof.c index 13fa20d3..be06555b 100644 --- a/src/prof.c +++ b/src/prof.c @@ -582,8 +582,7 @@ prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self, prof_gctx_t *gctx, prof_leave(tsd, tdata_self); /* Destroy gctx. */ malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock); - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), gctx), gctx, - NULL, true, true); + idalloctm(tsd_tsdn(tsd), gctx, NULL, true, true); } else { /* * Compensate for increment in prof_tctx_destroy() or @@ -697,8 +696,7 @@ prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) { } if (destroy_tctx) { - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tctx), tctx, - NULL, true, true); + idalloctm(tsd_tsdn(tsd), tctx, NULL, true, true); } } @@ -730,8 +728,8 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, if (ckh_insert(tsd, &bt2gctx, btkey.v, gctx.v)) { /* OOM. */ prof_leave(tsd, tdata); - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), - gctx.v), gctx.v, NULL, true, true); + idalloctm(tsd_tsdn(tsd), gctx.v, NULL, true, + true); return true; } new_gctx = true; @@ -755,8 +753,7 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, if (tgctx.v != NULL) { /* Lost race to insert. */ - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), - tgctx.v), tgctx.v, NULL, true, true); + idalloctm(tsd_tsdn(tsd), tgctx.v, NULL, true, true); } } prof_leave(tsd, tdata); @@ -828,8 +825,7 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) { if (new_gctx) { prof_gctx_try_destroy(tsd, tdata, gctx, tdata); } - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), ret.v), - ret.v, NULL, true, true); + idalloctm(tsd_tsdn(tsd), ret.v, NULL, true, true); return NULL; } malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock); @@ -1240,9 +1236,8 @@ prof_gctx_finish(tsd_t *tsd, prof_gctx_tree_t *gctxs) { to_destroy); tctx_tree_remove(&gctx->tctxs, to_destroy); - idalloctm(tsd_tsdn(tsd), - iealloc(tsd_tsdn(tsd), to_destroy), - to_destroy, NULL, true, true); + idalloctm(tsd_tsdn(tsd), to_destroy, + NULL, true, true); } else { next = NULL; } @@ -1910,8 +1905,7 @@ prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim, if (ckh_new(tsd, &tdata->bt2tctx, PROF_CKH_MINITEMS, prof_bt_hash, prof_bt_keycomp)) { - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tdata), tdata, - NULL, true, true); + idalloctm(tsd_tsdn(tsd), tdata, NULL, true, true); return NULL; } @@ -1967,12 +1961,10 @@ prof_tdata_destroy_locked(tsd_t *tsd, prof_tdata_t *tdata, assert(prof_tdata_should_destroy_unlocked(tdata, even_if_attached)); if (tdata->thread_name != NULL) { - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), - tdata->thread_name), tdata->thread_name, NULL, true, true); + idalloctm(tsd_tsdn(tsd), tdata->thread_name, NULL, true, true); } ckh_delete(tsd, &tdata->bt2tctx); - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tdata), tdata, NULL, - true, true); + idalloctm(tsd_tsdn(tsd), tdata, NULL, true, true); } static void @@ -2169,8 +2161,7 @@ prof_thread_name_set(tsd_t *tsd, const char *thread_name) { } if (tdata->thread_name != NULL) { - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), - tdata->thread_name), tdata->thread_name, NULL, true, true); + idalloctm(tsd_tsdn(tsd), tdata->thread_name, NULL, true, true); tdata->thread_name = NULL; } if (strlen(s) > 0) { diff --git a/src/tcache.c b/src/tcache.c index 7ae89751..9c99c8b3 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -389,8 +389,7 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache) { prof_idump(tsd_tsdn(tsd)); } - idalloctm(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), tcache), tcache, NULL, - true, true); + idalloctm(tsd_tsdn(tsd), tcache, NULL, true, true); } void -- GitLab From 5e67fbc367dfe6a08f065167f831d5aa0316554f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 20 Mar 2017 11:00:07 -0700 Subject: [PATCH 342/544] Push down iealloc() calls. Call iealloc() as deep into call chains as possible without causing redundant calls. --- include/jemalloc/internal/arena_externs.h | 18 +-- include/jemalloc/internal/arena_inlines_b.h | 39 +++-- .../jemalloc/internal/jemalloc_internal.h.in | 59 ++++---- include/jemalloc/internal/prof_externs.h | 4 +- include/jemalloc/internal/prof_inlines_b.h | 63 ++++---- src/arena.c | 64 ++++---- src/jemalloc.c | 141 +++++++----------- src/prof.c | 6 +- test/unit/prof_tctx.c | 9 +- 9 files changed, 176 insertions(+), 227 deletions(-) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 9603d74f..a35fe184 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -65,18 +65,16 @@ void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero); void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero, tcache_t *tcache); -void arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize); -void arena_dalloc_promoted(tsdn_t *tsdn, extent_t *extent, void *ptr, - tcache_t *tcache, bool slow_path); +void arena_prof_promote(tsdn_t *tsdn, const void *ptr, size_t usize); +void arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache, + bool slow_path); void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr); -void arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - void *ptr); -bool arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, - size_t oldsize, size_t size, size_t extra, bool zero); -void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, - size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache); +void arena_dalloc_small(tsdn_t *tsdn, void *ptr); +bool arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, + size_t extra, bool zero); +void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, + size_t size, size_t alignment, bool zero, tcache_t *tcache); dss_prec_t arena_dss_prec_get(arena_t *arena); bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec); ssize_t arena_dirty_decay_time_default_get(void); diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index cbd9e20a..3c48ce4f 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -3,12 +3,10 @@ #ifndef JEMALLOC_ENABLE_INLINE szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin); -prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, - const void *ptr); -void arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize, prof_tctx_t *tctx); -void arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, +prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr); +void arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, prof_tctx_t *tctx); +void arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx); void arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks); void arena_decay_tick(tsdn_t *tsdn, arena_t *arena); void *arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, @@ -30,10 +28,11 @@ arena_bin_index(arena_t *arena, arena_bin_t *bin) { } JEMALLOC_INLINE prof_tctx_t * -arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { +arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr) { cassert(config_prof); assert(ptr != NULL); + const extent_t *extent = iealloc(tsdn, ptr); if (unlikely(!extent_slab_get(extent))) { return large_prof_tctx_get(tsdn, extent); } @@ -41,21 +40,23 @@ arena_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { } JEMALLOC_INLINE void -arena_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize, prof_tctx_t *tctx) { +arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, + prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); + extent_t *extent = iealloc(tsdn, ptr); if (unlikely(!extent_slab_get(extent))) { large_prof_tctx_set(tsdn, extent, tctx); } } JEMALLOC_INLINE void -arena_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, - prof_tctx_t *tctx) { +arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); + + extent_t *extent = iealloc(tsdn, ptr); assert(!extent_slab_get(extent)); large_prof_tctx_reset(tsdn, extent); @@ -187,16 +188,13 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path) { tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind, slow_path); } else { - extent_t *extent = iealloc(tsdn, ptr); - arena_dalloc_small(tsdn, extent_arena_get(extent), - extent, ptr); + arena_dalloc_small(tsdn, ptr); } } else { if (likely(tcache != NULL) && szind < nhbins) { if (config_prof && unlikely(szind < NBINS)) { - extent_t *extent = iealloc(tsdn, ptr); - arena_dalloc_promoted(tsdn, extent, ptr, - tcache, slow_path); + arena_dalloc_promoted(tsdn, ptr, tcache, + slow_path); } else { tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, szind, slow_path); @@ -250,16 +248,13 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind, slow_path); } else { - extent_t *extent = iealloc(tsdn, ptr); - arena_dalloc_small(tsdn, extent_arena_get(extent), - extent, ptr); + arena_dalloc_small(tsdn, ptr); } } else { if (likely(tcache != NULL) && szind < nhbins) { if (config_prof && unlikely(szind < NBINS)) { - extent_t *extent = iealloc(tsdn, ptr); - arena_dalloc_promoted(tsdn, extent, ptr, - tcache, slow_path); + arena_dalloc_promoted(tsdn, ptr, tcache, + slow_path); } else { tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, szind, slow_path); diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index b3510382..2fe21018 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -1007,32 +1007,32 @@ iealloc(tsdn_t *tsdn, const void *ptr) { #include "jemalloc/internal/hash_inlines.h" #ifndef JEMALLOC_ENABLE_INLINE -arena_t *iaalloc(tsdn_t *tsdn, const void *ptr); -size_t isalloc(tsdn_t *tsdn, const void *ptr); -void *iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, +arena_t *iaalloc(tsdn_t *tsdn, const void *ptr); +size_t isalloc(tsdn_t *tsdn, const void *ptr); +void *iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, bool is_internal, arena_t *arena, bool slow_path); -void *ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, +void *ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, bool slow_path); -void *ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, +void *ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, tcache_t *tcache, bool is_internal, arena_t *arena); -void *ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, +void *ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); -void *ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero); -size_t ivsalloc(tsdn_t *tsdn, const void *ptr); -void idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool is_internal, +void *ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero); +size_t ivsalloc(tsdn_t *tsdn, const void *ptr); +void idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool is_internal, bool slow_path); -void idalloc(tsd_t *tsd, void *ptr); -void isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, +void idalloc(tsd_t *tsd, void *ptr); +void isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, bool slow_path); -void *iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, +void *iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); -void *iralloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, - size_t size, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); -void *iralloc(tsd_t *tsd, extent_t *extent, void *ptr, size_t oldsize, - size_t size, size_t alignment, bool zero); -bool ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, - size_t size, size_t extra, size_t alignment, bool zero); +void *iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, + size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); +void *iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, + size_t alignment, bool zero); +bool ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, + size_t alignment, bool zero); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) @@ -1176,8 +1176,8 @@ iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, } JEMALLOC_ALWAYS_INLINE void * -iralloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, - size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) { +iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment, + bool zero, tcache_t *tcache, arena_t *arena) { assert(ptr != NULL); assert(size != 0); witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); @@ -1192,20 +1192,20 @@ iralloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, zero, tcache, arena); } - return arena_ralloc(tsdn, arena, extent, ptr, oldsize, size, alignment, - zero, tcache); + return arena_ralloc(tsdn, arena, ptr, oldsize, size, alignment, zero, + tcache); } JEMALLOC_ALWAYS_INLINE void * -iralloc(tsd_t *tsd, extent_t *extent, void *ptr, size_t oldsize, size_t size, - size_t alignment, bool zero) { - return iralloct(tsd_tsdn(tsd), extent, ptr, oldsize, size, alignment, - zero, tcache_get(tsd, true), NULL); +iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment, + bool zero) { + return iralloct(tsd_tsdn(tsd), ptr, oldsize, size, alignment, zero, + tcache_get(tsd, true), NULL); } JEMALLOC_ALWAYS_INLINE bool -ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, - size_t extra, size_t alignment, bool zero) { +ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, + size_t alignment, bool zero) { assert(ptr != NULL); assert(size != 0); witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); @@ -1216,8 +1216,7 @@ ixalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, size_t size, return true; } - return arena_ralloc_no_move(tsdn, extent, ptr, oldsize, size, extra, - zero); + return arena_ralloc_no_move(tsdn, ptr, oldsize, size, extra, zero); } #endif diff --git a/include/jemalloc/internal/prof_externs.h b/include/jemalloc/internal/prof_externs.h index f3b6f8d3..985532f6 100644 --- a/include/jemalloc/internal/prof_externs.h +++ b/include/jemalloc/internal/prof_externs.h @@ -39,8 +39,8 @@ extern uint64_t prof_interval; extern size_t lg_prof_sample; void prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated); -void prof_malloc_sample_object(tsdn_t *tsdn, extent_t *extent, - const void *ptr, size_t usize, prof_tctx_t *tctx); +void prof_malloc_sample_object(tsdn_t *tsdn, const void *ptr, size_t usize, + prof_tctx_t *tctx); void prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_tctx_t *tctx); void bt_init(prof_bt_t *bt, void **vec); void prof_backtrace(prof_bt_t *bt); diff --git a/include/jemalloc/internal/prof_inlines_b.h b/include/jemalloc/internal/prof_inlines_b.h index 29a2b528..5ee72c53 100644 --- a/include/jemalloc/internal/prof_inlines_b.h +++ b/include/jemalloc/internal/prof_inlines_b.h @@ -5,24 +5,20 @@ bool prof_active_get_unlocked(void); bool prof_gdump_get_unlocked(void); prof_tdata_t *prof_tdata_get(tsd_t *tsd, bool create); -prof_tctx_t *prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, - const void *ptr); -void prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize, prof_tctx_t *tctx); -void prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, +prof_tctx_t *prof_tctx_get(tsdn_t *tsdn, const void *ptr); +void prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, prof_tctx_t *tctx); +void prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx); bool prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update, prof_tdata_t **tdata_out); prof_tctx_t *prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update); -void prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize, prof_tctx_t *tctx); -void prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, - size_t usize, prof_tctx_t *tctx, bool prof_active, bool updated, - extent_t *old_extent, const void *old_ptr, size_t old_usize, - prof_tctx_t *old_tctx); -void prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, - size_t usize); +void prof_malloc(tsdn_t *tsdn, const void *ptr, size_t usize, + prof_tctx_t *tctx); +void prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, + prof_tctx_t *tctx, bool prof_active, bool updated, const void *old_ptr, + size_t old_usize, prof_tctx_t *old_tctx); +void prof_free(tsd_t *tsd, const void *ptr, size_t usize); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PROF_C_)) @@ -71,29 +67,27 @@ prof_tdata_get(tsd_t *tsd, bool create) { } JEMALLOC_ALWAYS_INLINE prof_tctx_t * -prof_tctx_get(tsdn_t *tsdn, const extent_t *extent, const void *ptr) { +prof_tctx_get(tsdn_t *tsdn, const void *ptr) { cassert(config_prof); assert(ptr != NULL); - return arena_prof_tctx_get(tsdn, extent, ptr); + return arena_prof_tctx_get(tsdn, ptr); } JEMALLOC_ALWAYS_INLINE void -prof_tctx_set(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, - prof_tctx_t *tctx) { +prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); - arena_prof_tctx_set(tsdn, extent, ptr, usize, tctx); + arena_prof_tctx_set(tsdn, ptr, usize, tctx); } JEMALLOC_ALWAYS_INLINE void -prof_tctx_reset(tsdn_t *tsdn, extent_t *extent, const void *ptr, - prof_tctx_t *tctx) { +prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); - arena_prof_tctx_reset(tsdn, extent, ptr, tctx); + arena_prof_tctx_reset(tsdn, ptr, tctx); } JEMALLOC_ALWAYS_INLINE bool @@ -151,24 +145,22 @@ prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update) { } JEMALLOC_ALWAYS_INLINE void -prof_malloc(tsdn_t *tsdn, extent_t *extent, const void *ptr, size_t usize, - prof_tctx_t *tctx) { +prof_malloc(tsdn_t *tsdn, const void *ptr, size_t usize, prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); assert(usize == isalloc(tsdn, ptr)); if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) { - prof_malloc_sample_object(tsdn, extent, ptr, usize, tctx); + prof_malloc_sample_object(tsdn, ptr, usize, tctx); } else { - prof_tctx_set(tsdn, extent, ptr, usize, - (prof_tctx_t *)(uintptr_t)1U); + prof_tctx_set(tsdn, ptr, usize, (prof_tctx_t *)(uintptr_t)1U); } } JEMALLOC_ALWAYS_INLINE void -prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, - prof_tctx_t *tctx, bool prof_active, bool updated, extent_t *old_extent, - const void *old_ptr, size_t old_usize, prof_tctx_t *old_tctx) { +prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, prof_tctx_t *tctx, + bool prof_active, bool updated, const void *old_ptr, size_t old_usize, + prof_tctx_t *old_tctx) { bool sampled, old_sampled, moved; cassert(config_prof); @@ -194,10 +186,9 @@ prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, moved = (ptr != old_ptr); if (unlikely(sampled)) { - prof_malloc_sample_object(tsd_tsdn(tsd), extent, ptr, usize, - tctx); + prof_malloc_sample_object(tsd_tsdn(tsd), ptr, usize, tctx); } else if (moved) { - prof_tctx_set(tsd_tsdn(tsd), extent, ptr, usize, + prof_tctx_set(tsd_tsdn(tsd), ptr, usize, (prof_tctx_t *)(uintptr_t)1U); } else if (unlikely(old_sampled)) { /* @@ -206,9 +197,9 @@ prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, * to do here in the presence of explicit knowledge re: moved * state. */ - prof_tctx_reset(tsd_tsdn(tsd), extent, ptr, tctx); + prof_tctx_reset(tsd_tsdn(tsd), ptr, tctx); } else { - assert((uintptr_t)prof_tctx_get(tsd_tsdn(tsd), extent, ptr) == + assert((uintptr_t)prof_tctx_get(tsd_tsdn(tsd), ptr) == (uintptr_t)1U); } @@ -225,8 +216,8 @@ prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize, } JEMALLOC_ALWAYS_INLINE void -prof_free(tsd_t *tsd, const extent_t *extent, const void *ptr, size_t usize) { - prof_tctx_t *tctx = prof_tctx_get(tsd_tsdn(tsd), extent, ptr); +prof_free(tsd_t *tsd, const void *ptr, size_t usize) { + prof_tctx_t *tctx = prof_tctx_get(tsd_tsdn(tsd), ptr); cassert(config_prof); assert(usize == isalloc(tsd_tsdn(tsd), ptr)); diff --git a/src/arena.c b/src/arena.c index f05249dc..ef7ec37b 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1033,7 +1033,7 @@ arena_reset(tsd_t *tsd, arena_t *arena) { } /* Remove large allocation from prof sample set. */ if (config_prof && opt_prof) { - prof_free(tsd, extent, ptr, usize); + prof_free(tsd, ptr, usize); } large_dalloc(tsd_tsdn(tsd), extent); malloc_mutex_lock(tsd_tsdn(tsd), &arena->large_mtx); @@ -1459,19 +1459,21 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, } void -arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize) { - arena_t *arena = extent_arena_get(extent); - +arena_prof_promote(tsdn_t *tsdn, const void *ptr, size_t usize) { cassert(config_prof); assert(ptr != NULL); assert(isalloc(tsdn, ptr) == LARGE_MINCLASS); assert(usize <= SMALL_MAXCLASS); - szind_t szind = size2index(usize); - extent_szind_set(extent, szind); rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + + extent_t *extent = rtree_extent_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true); + arena_t *arena = extent_arena_get(extent); + + szind_t szind = size2index(usize); + extent_szind_set(extent, szind); rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, szind, false); @@ -1497,14 +1499,13 @@ arena_prof_demote(tsdn_t *tsdn, extent_t *extent, const void *ptr) { } void -arena_dalloc_promoted(tsdn_t *tsdn, extent_t *extent, void *ptr, - tcache_t *tcache, bool slow_path) { - size_t usize; - +arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache, + bool slow_path) { cassert(config_prof); assert(opt_prof); - usize = arena_prof_demote(tsdn, extent, ptr); + extent_t *extent = iealloc(tsdn, ptr); + size_t usize = arena_prof_demote(tsdn, extent, ptr); if (usize <= tcache_maxclass) { tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, size2index(usize), slow_path); @@ -1621,16 +1622,17 @@ arena_dalloc_bin(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) { } void -arena_dalloc_small(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr) { +arena_dalloc_small(tsdn_t *tsdn, void *ptr) { + extent_t *extent = iealloc(tsdn, ptr); + arena_t *arena = extent_arena_get(extent); + arena_dalloc_bin(tsdn, arena, extent, ptr); arena_decay_tick(tsdn, arena); } bool -arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, - size_t size, size_t extra, bool zero) { - size_t usize_min, usize_max; - +arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, + size_t extra, bool zero) { /* Calls with non-zero extra had to clamp extra. */ assert(extra == 0 || size + extra <= LARGE_MAXCLASS); @@ -1638,8 +1640,9 @@ arena_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t oldsize, return true; } - usize_min = s2u(size); - usize_max = s2u(size + extra); + extent_t *extent = iealloc(tsdn, ptr); + size_t usize_min = s2u(size); + size_t usize_max = s2u(size + extra); if (likely(oldsize <= SMALL_MAXCLASS && usize_min <= SMALL_MAXCLASS)) { /* * Avoid moving the allocation if the size class can be left the @@ -1678,36 +1681,31 @@ arena_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, } void * -arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, - size_t oldsize, size_t size, size_t alignment, bool zero, - tcache_t *tcache) { - void *ret; - size_t usize, copysize; - - usize = s2u(size); +arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, + size_t size, size_t alignment, bool zero, tcache_t *tcache) { + size_t usize = s2u(size); if (unlikely(usize == 0 || size > LARGE_MAXCLASS)) { return NULL; } if (likely(usize <= SMALL_MAXCLASS)) { /* Try to avoid moving the allocation. */ - if (!arena_ralloc_no_move(tsdn, extent, ptr, oldsize, usize, 0, - zero)) { + if (!arena_ralloc_no_move(tsdn, ptr, oldsize, usize, 0, zero)) { return ptr; } } if (oldsize >= LARGE_MINCLASS && usize >= LARGE_MINCLASS) { - return large_ralloc(tsdn, arena, extent, usize, alignment, - zero, tcache); + return large_ralloc(tsdn, arena, iealloc(tsdn, ptr), usize, + alignment, zero, tcache); } /* * size and oldsize are different enough that we need to move the * object. In that case, fall back to allocating new space and copying. */ - ret = arena_ralloc_move_helper(tsdn, arena, usize, alignment, zero, - tcache); + void *ret = arena_ralloc_move_helper(tsdn, arena, usize, alignment, + zero, tcache); if (ret == NULL) { return NULL; } @@ -1717,7 +1715,7 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr, * ipalloc()/arena_malloc(). */ - copysize = (usize < oldsize) ? usize : oldsize; + size_t copysize = (usize < oldsize) ? usize : oldsize; memcpy(ret, ptr, copysize); isdalloct(tsdn, ptr, oldsize, tcache, true); return ret; diff --git a/src/jemalloc.c b/src/jemalloc.c index 1077ebf3..d8688bdd 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1589,8 +1589,7 @@ imalloc_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd, if (unlikely(ret == NULL)) { return NULL; } - arena_prof_promote(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), ret), - ret, usize); + arena_prof_promote(tsd_tsdn(tsd), ret, usize); } else { ret = imalloc_no_sample(sopts, dopts, tsd, usize, usize, ind); } @@ -1741,8 +1740,7 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { goto label_oom; } - prof_malloc(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), allocation), - allocation, usize, tctx); + prof_malloc(tsd_tsdn(tsd), allocation, usize, tctx); } else { /* @@ -1955,53 +1953,46 @@ je_calloc(size_t num, size_t size) { } static void * -irealloc_prof_sample(tsd_t *tsd, extent_t *extent, void *old_ptr, - size_t old_usize, size_t usize, prof_tctx_t *tctx) { +irealloc_prof_sample(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize, + prof_tctx_t *tctx) { void *p; if (tctx == NULL) { return NULL; } if (usize <= SMALL_MAXCLASS) { - p = iralloc(tsd, extent, old_ptr, old_usize, LARGE_MINCLASS, 0, - false); + p = iralloc(tsd, old_ptr, old_usize, LARGE_MINCLASS, 0, false); if (p == NULL) { return NULL; } - arena_prof_promote(tsd_tsdn(tsd), iealloc(tsd_tsdn(tsd), p), p, - usize); + arena_prof_promote(tsd_tsdn(tsd), p, usize); } else { - p = iralloc(tsd, extent, old_ptr, old_usize, usize, 0, false); + p = iralloc(tsd, old_ptr, old_usize, usize, 0, false); } return p; } JEMALLOC_ALWAYS_INLINE_C void * -irealloc_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, - size_t usize) { +irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize) { void *p; - extent_t *extent; bool prof_active; prof_tctx_t *old_tctx, *tctx; prof_active = prof_active_get_unlocked(); - old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_extent, old_ptr); + old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr); tctx = prof_alloc_prep(tsd, usize, prof_active, true); if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { - p = irealloc_prof_sample(tsd, old_extent, old_ptr, old_usize, - usize, tctx); + p = irealloc_prof_sample(tsd, old_ptr, old_usize, usize, tctx); } else { - p = iralloc(tsd, old_extent, old_ptr, old_usize, usize, 0, - false); + p = iralloc(tsd, old_ptr, old_usize, usize, 0, false); } if (unlikely(p == NULL)) { prof_alloc_rollback(tsd, tctx, true); return NULL; } - extent = (p == old_ptr) ? old_extent : iealloc(tsd_tsdn(tsd), p); - prof_realloc(tsd, extent, p, usize, tctx, prof_active, true, old_extent, - old_ptr, old_usize, old_tctx); + prof_realloc(tsd, p, usize, tctx, prof_active, true, old_ptr, old_usize, + old_tctx); return p; } @@ -2016,8 +2007,7 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { size_t usize; if (config_prof && opt_prof) { usize = isalloc(tsd_tsdn(tsd), ptr); - extent_t *extent = iealloc(tsd_tsdn(tsd), ptr); - prof_free(tsd, extent, ptr, usize); + prof_free(tsd, ptr, usize); } else if (config_stats) { usize = isalloc(tsd_tsdn(tsd), ptr); } @@ -2040,8 +2030,7 @@ isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) { assert(malloc_initialized() || IS_INITIALIZER); if (config_prof && opt_prof) { - extent_t *extent = iealloc(tsd_tsdn(tsd), ptr); - prof_free(tsd, extent, ptr, usize); + prof_free(tsd, ptr, usize); } if (config_stats) { *tsd_thread_deallocatedp_get(tsd) += usize; @@ -2077,27 +2066,21 @@ je_realloc(void *ptr, size_t size) { } if (likely(ptr != NULL)) { - tsd_t *tsd; - extent_t *extent; - assert(malloc_initialized() || IS_INITIALIZER); - tsd = tsd_fetch(); + tsd_t *tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); - extent = iealloc(tsd_tsdn(tsd), ptr); old_usize = isalloc(tsd_tsdn(tsd), ptr); if (config_prof && opt_prof) { usize = s2u(size); ret = unlikely(usize == 0 || usize > LARGE_MAXCLASS) ? - NULL : irealloc_prof(tsd, extent, ptr, old_usize, - usize); + NULL : irealloc_prof(tsd, ptr, old_usize, usize); } else { if (config_stats) { usize = s2u(size); } - ret = iralloc(tsd, extent, ptr, old_usize, size, 0, - false); + ret = iralloc(tsd, ptr, old_usize, size, 0, false); } tsdn = tsd_tsdn(tsd); } else { @@ -2314,47 +2297,46 @@ je_mallocx(size_t size, int flags) { } static void * -irallocx_prof_sample(tsdn_t *tsdn, extent_t *extent, void *old_ptr, - size_t old_usize, size_t usize, size_t alignment, bool zero, - tcache_t *tcache, arena_t *arena, prof_tctx_t *tctx) { +irallocx_prof_sample(tsdn_t *tsdn, void *old_ptr, size_t old_usize, + size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena, + prof_tctx_t *tctx) { void *p; if (tctx == NULL) { return NULL; } if (usize <= SMALL_MAXCLASS) { - p = iralloct(tsdn, extent, old_ptr, old_usize, LARGE_MINCLASS, + p = iralloct(tsdn, old_ptr, old_usize, LARGE_MINCLASS, alignment, zero, tcache, arena); if (p == NULL) { return NULL; } - arena_prof_promote(tsdn, iealloc(tsdn, p), p, usize); + arena_prof_promote(tsdn, p, usize); } else { - p = iralloct(tsdn, extent, old_ptr, old_usize, usize, alignment, - zero, tcache, arena); + p = iralloct(tsdn, old_ptr, old_usize, usize, alignment, zero, + tcache, arena); } return p; } JEMALLOC_ALWAYS_INLINE_C void * -irallocx_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, - size_t size, size_t alignment, size_t *usize, bool zero, tcache_t *tcache, +irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size, + size_t alignment, size_t *usize, bool zero, tcache_t *tcache, arena_t *arena) { void *p; - extent_t *extent; bool prof_active; prof_tctx_t *old_tctx, *tctx; prof_active = prof_active_get_unlocked(); - old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_extent, old_ptr); + old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr); tctx = prof_alloc_prep(tsd, *usize, prof_active, false); if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { - p = irallocx_prof_sample(tsd_tsdn(tsd), old_extent, old_ptr, - old_usize, *usize, alignment, zero, tcache, arena, tctx); + p = irallocx_prof_sample(tsd_tsdn(tsd), old_ptr, old_usize, + *usize, alignment, zero, tcache, arena, tctx); } else { - p = iralloct(tsd_tsdn(tsd), old_extent, old_ptr, old_usize, - size, alignment, zero, tcache, arena); + p = iralloct(tsd_tsdn(tsd), old_ptr, old_usize, size, alignment, + zero, tcache, arena); } if (unlikely(p == NULL)) { prof_alloc_rollback(tsd, tctx, false); @@ -2370,13 +2352,10 @@ irallocx_prof(tsd_t *tsd, extent_t *old_extent, void *old_ptr, size_t old_usize, * be the same as the current usize because of in-place large * reallocation. Therefore, query the actual value of usize. */ - extent = old_extent; *usize = isalloc(tsd_tsdn(tsd), p); - } else { - extent = iealloc(tsd_tsdn(tsd), p); } - prof_realloc(tsd, extent, p, *usize, tctx, prof_active, false, - old_extent, old_ptr, old_usize, old_tctx); + prof_realloc(tsd, p, *usize, tctx, prof_active, false, old_ptr, + old_usize, old_tctx); return p; } @@ -2387,7 +2366,6 @@ JEMALLOC_ALLOC_SIZE(2) je_rallocx(void *ptr, size_t size, int flags) { void *p; tsd_t *tsd; - extent_t *extent; size_t usize; size_t old_usize; size_t alignment = MALLOCX_ALIGN_GET(flags); @@ -2400,7 +2378,6 @@ je_rallocx(void *ptr, size_t size, int flags) { assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); - extent = iealloc(tsd_tsdn(tsd), ptr); if (unlikely((flags & MALLOCX_ARENA_MASK) != 0)) { unsigned arena_ind = MALLOCX_ARENA_GET(flags); @@ -2429,14 +2406,14 @@ je_rallocx(void *ptr, size_t size, int flags) { if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { goto label_oom; } - p = irallocx_prof(tsd, extent, ptr, old_usize, size, alignment, - &usize, zero, tcache, arena); + p = irallocx_prof(tsd, ptr, old_usize, size, alignment, &usize, + zero, tcache, arena); if (unlikely(p == NULL)) { goto label_oom; } } else { - p = iralloct(tsd_tsdn(tsd), extent, ptr, old_usize, size, - alignment, zero, tcache, arena); + p = iralloct(tsd_tsdn(tsd), ptr, old_usize, size, alignment, + zero, tcache, arena); if (unlikely(p == NULL)) { goto label_oom; } @@ -2464,12 +2441,11 @@ label_oom: } JEMALLOC_ALWAYS_INLINE_C size_t -ixallocx_helper(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t old_usize, - size_t size, size_t extra, size_t alignment, bool zero) { +ixallocx_helper(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size, + size_t extra, size_t alignment, bool zero) { size_t usize; - if (ixalloc(tsdn, extent, ptr, old_usize, size, extra, alignment, - zero)) { + if (ixalloc(tsdn, ptr, old_usize, size, extra, alignment, zero)) { return old_usize; } usize = isalloc(tsdn, ptr); @@ -2478,29 +2454,28 @@ ixallocx_helper(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t old_usize, } static size_t -ixallocx_prof_sample(tsdn_t *tsdn, extent_t *extent, void *ptr, - size_t old_usize, size_t size, size_t extra, size_t alignment, bool zero, - prof_tctx_t *tctx) { +ixallocx_prof_sample(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size, + size_t extra, size_t alignment, bool zero, prof_tctx_t *tctx) { size_t usize; if (tctx == NULL) { return old_usize; } - usize = ixallocx_helper(tsdn, extent, ptr, old_usize, size, extra, - alignment, zero); + usize = ixallocx_helper(tsdn, ptr, old_usize, size, extra, alignment, + zero); return usize; } JEMALLOC_ALWAYS_INLINE_C size_t -ixallocx_prof(tsd_t *tsd, extent_t *extent, void *ptr, size_t old_usize, - size_t size, size_t extra, size_t alignment, bool zero) { +ixallocx_prof(tsd_t *tsd, void *ptr, size_t old_usize, size_t size, + size_t extra, size_t alignment, bool zero) { size_t usize_max, usize; bool prof_active; prof_tctx_t *old_tctx, *tctx; prof_active = prof_active_get_unlocked(); - old_tctx = prof_tctx_get(tsd_tsdn(tsd), extent, ptr); + old_tctx = prof_tctx_get(tsd_tsdn(tsd), ptr); /* * usize isn't knowable before ixalloc() returns when extra is non-zero. * Therefore, compute its maximum possible value and use that in @@ -2525,18 +2500,18 @@ ixallocx_prof(tsd_t *tsd, extent_t *extent, void *ptr, size_t old_usize, tctx = prof_alloc_prep(tsd, usize_max, prof_active, false); if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { - usize = ixallocx_prof_sample(tsd_tsdn(tsd), extent, ptr, - old_usize, size, extra, alignment, zero, tctx); + usize = ixallocx_prof_sample(tsd_tsdn(tsd), ptr, old_usize, + size, extra, alignment, zero, tctx); } else { - usize = ixallocx_helper(tsd_tsdn(tsd), extent, ptr, old_usize, - size, extra, alignment, zero); + usize = ixallocx_helper(tsd_tsdn(tsd), ptr, old_usize, size, + extra, alignment, zero); } if (usize == old_usize) { prof_alloc_rollback(tsd, tctx, false); return usize; } - prof_realloc(tsd, extent, ptr, usize, tctx, prof_active, false, extent, - ptr, old_usize, old_tctx); + prof_realloc(tsd, ptr, usize, tctx, prof_active, false, ptr, old_usize, + old_tctx); return usize; } @@ -2544,7 +2519,6 @@ ixallocx_prof(tsd_t *tsd, extent_t *extent, void *ptr, size_t old_usize, JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW je_xallocx(void *ptr, size_t size, size_t extra, int flags) { tsd_t *tsd; - extent_t *extent; size_t usize, old_usize; size_t alignment = MALLOCX_ALIGN_GET(flags); bool zero = flags & MALLOCX_ZERO; @@ -2555,7 +2529,6 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) { assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); - extent = iealloc(tsd_tsdn(tsd), ptr); old_usize = isalloc(tsd_tsdn(tsd), ptr); @@ -2577,11 +2550,11 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) { } if (config_prof && opt_prof) { - usize = ixallocx_prof(tsd, extent, ptr, old_usize, size, extra, + usize = ixallocx_prof(tsd, ptr, old_usize, size, extra, alignment, zero); } else { - usize = ixallocx_helper(tsd_tsdn(tsd), extent, ptr, old_usize, - size, extra, alignment, zero); + usize = ixallocx_helper(tsd_tsdn(tsd), ptr, old_usize, size, + extra, alignment, zero); } if (unlikely(usize == old_usize)) { goto label_not_resized; diff --git a/src/prof.c b/src/prof.c index be06555b..b04984b7 100644 --- a/src/prof.c +++ b/src/prof.c @@ -222,9 +222,9 @@ prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated) { } void -prof_malloc_sample_object(tsdn_t *tsdn, extent_t *extent, const void *ptr, - size_t usize, prof_tctx_t *tctx) { - prof_tctx_set(tsdn, extent, ptr, usize, tctx); +prof_malloc_sample_object(tsdn_t *tsdn, const void *ptr, size_t usize, + prof_tctx_t *tctx) { + prof_tctx_set(tsdn, ptr, usize, tctx); malloc_mutex_lock(tsdn, tctx->tdata->lock); tctx->cnts.curobjs++; diff --git a/test/unit/prof_tctx.c b/test/unit/prof_tctx.c index 14510c65..183f7ce0 100644 --- a/test/unit/prof_tctx.c +++ b/test/unit/prof_tctx.c @@ -4,7 +4,6 @@ TEST_BEGIN(test_prof_realloc) { tsdn_t *tsdn; int flags; void *p, *q; - extent_t *extent_p, *extent_q; prof_tctx_t *tctx_p, *tctx_q; uint64_t curobjs_0, curobjs_1, curobjs_2, curobjs_3; @@ -16,9 +15,7 @@ TEST_BEGIN(test_prof_realloc) { prof_cnt_all(&curobjs_0, NULL, NULL, NULL); p = mallocx(1024, flags); assert_ptr_not_null(p, "Unexpected mallocx() failure"); - extent_p = iealloc(tsdn, p); - assert_ptr_not_null(extent_p, "Unexpected iealloc() failure"); - tctx_p = prof_tctx_get(tsdn, extent_p, p); + tctx_p = prof_tctx_get(tsdn, p); assert_ptr_ne(tctx_p, (prof_tctx_t *)(uintptr_t)1U, "Expected valid tctx"); prof_cnt_all(&curobjs_1, NULL, NULL, NULL); @@ -28,9 +25,7 @@ TEST_BEGIN(test_prof_realloc) { q = rallocx(p, 2048, flags); assert_ptr_ne(p, q, "Expected move"); assert_ptr_not_null(p, "Unexpected rmallocx() failure"); - extent_q = iealloc(tsdn, q); - assert_ptr_not_null(extent_q, "Unexpected iealloc() failure"); - tctx_q = prof_tctx_get(tsdn, extent_q, q); + tctx_q = prof_tctx_get(tsdn, q); assert_ptr_ne(tctx_q, (prof_tctx_t *)(uintptr_t)1U, "Expected valid tctx"); prof_cnt_all(&curobjs_2, NULL, NULL, NULL); -- GitLab From 32e7cf51cd879e4f2b0307bba544f913e2d77a7e Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 22 Mar 2017 11:00:40 -0700 Subject: [PATCH 343/544] Further specialize arena_[s]dalloc() tcache fast path. Use tsd_rtree_ctx() rather than tsdn_rtree_ctx() when tcache is non-NULL, in order to avoid an extra branch (and potentially extra stack space) in the fast path. --- include/jemalloc/internal/arena_inlines_b.h | 141 ++++++++++++++---- include/jemalloc/internal/private_symbols.txt | 3 + include/jemalloc/internal/tsd_inlines.h | 30 ++-- 3 files changed, 129 insertions(+), 45 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 3c48ce4f..ea69a688 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -2,20 +2,22 @@ #define JEMALLOC_INTERNAL_ARENA_INLINES_B_H #ifndef JEMALLOC_ENABLE_INLINE -szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin); -prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr); -void arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, +szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin); +prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr); +void arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, prof_tctx_t *tctx); -void arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx); -void arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks); -void arena_decay_tick(tsdn_t *tsdn, arena_t *arena); -void *arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, +void arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx); +void arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks); +void arena_decay_tick(tsdn_t *tsdn, arena_t *arena); +void *arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero, tcache_t *tcache, bool slow_path); -arena_t *arena_aalloc(tsdn_t *tsdn, const void *ptr); +arena_t *arena_aalloc(tsdn_t *tsdn, const void *ptr); size_t arena_salloc(tsdn_t *tsdn, const void *ptr); size_t arena_vsalloc(tsdn_t *tsdn, const void *ptr); -void arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path); -void arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, +void arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr); +void arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path); +void arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size); +void arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, bool slow_path); #endif @@ -162,14 +164,46 @@ arena_vsalloc(tsdn_t *tsdn, const void *ptr) { return index2size(szind); } +JEMALLOC_INLINE void +arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) { + assert(ptr != NULL); + + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + + szind_t szind; + bool slab; + rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, + true, &szind, &slab); + + if (config_debug) { + extent_t *extent = rtree_extent_read(tsdn, &extents_rtree, + rtree_ctx, (uintptr_t)ptr, true); + assert(szind == extent_szind_get(extent)); + assert(szind < NSIZES); + assert(slab == extent_slab_get(extent)); + } + + if (likely(slab)) { + /* Small allocation. */ + arena_dalloc_small(tsdn, ptr); + } else { + extent_t *extent = iealloc(tsdn, ptr); + large_dalloc(tsdn, extent); + } +} + JEMALLOC_ALWAYS_INLINE void arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path) { assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); - rtree_ctx_t rtree_ctx_fallback; - rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + if (unlikely(tcache == NULL)) { + arena_dalloc_no_tcache(tsdn, ptr); + return; + } + rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn)); szind_t szind; bool slab; rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, @@ -179,25 +213,22 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path) { extent_t *extent = rtree_extent_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, true); assert(szind == extent_szind_get(extent)); + assert(szind < NSIZES); assert(slab == extent_slab_get(extent)); } if (likely(slab)) { /* Small allocation. */ - if (likely(tcache != NULL)) { - tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind, - slow_path); - } else { - arena_dalloc_small(tsdn, ptr); - } + tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind, + slow_path); } else { - if (likely(tcache != NULL) && szind < nhbins) { + if (szind < nhbins) { if (config_prof && unlikely(szind < NBINS)) { arena_dalloc_promoted(tsdn, ptr, tcache, slow_path); } else { - tcache_dalloc_large(tsdn_tsd(tsdn), tcache, - ptr, szind, slow_path); + tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, + szind, slow_path); } } else { extent_t *extent = iealloc(tsdn, ptr); @@ -206,11 +237,10 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path) { } } -JEMALLOC_ALWAYS_INLINE void -arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - bool slow_path) { - assert(!tsdn_null(tsdn) || tcache == NULL); +JEMALLOC_INLINE void +arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) { assert(ptr != NULL); + assert(size <= LARGE_MAXCLASS); szind_t szind; bool slab; @@ -244,20 +274,65 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, if (likely(slab)) { /* Small allocation. */ - if (likely(tcache != NULL)) { - tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind, - slow_path); - } else { - arena_dalloc_small(tsdn, ptr); + arena_dalloc_small(tsdn, ptr); + } else { + extent_t *extent = iealloc(tsdn, ptr); + large_dalloc(tsdn, extent); + } +} + +JEMALLOC_ALWAYS_INLINE void +arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, + bool slow_path) { + assert(!tsdn_null(tsdn) || tcache == NULL); + assert(ptr != NULL); + assert(size <= LARGE_MAXCLASS); + + if (unlikely(tcache == NULL)) { + arena_sdalloc_no_tcache(tsdn, ptr, size); + return; + } + + szind_t szind; + bool slab; + if (!config_prof || !opt_prof) { + /* + * There is no risk of being confused by a promoted sampled + * object, so base szind and slab on the given size. + */ + szind = size2index(size); + slab = (szind < NBINS); + } + + if ((config_prof && opt_prof) || config_debug) { + rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn)); + + rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true, &szind, &slab); + + assert(szind == size2index(size)); + assert((config_prof && opt_prof) || slab == (szind < NBINS)); + + if (config_debug) { + extent_t *extent = rtree_extent_read(tsdn, + &extents_rtree, rtree_ctx, (uintptr_t)ptr, true); + assert(szind == extent_szind_get(extent)); + assert(slab == extent_slab_get(extent)); } + } + + if (likely(slab)) { + /* Small allocation. */ + tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr, szind, + slow_path); } else { - if (likely(tcache != NULL) && szind < nhbins) { + if (szind < nhbins) { if (config_prof && unlikely(szind < NBINS)) { arena_dalloc_promoted(tsdn, ptr, tcache, slow_path); } else { - tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, - szind, slow_path); + tcache_dalloc_large(tsdn_tsd(tsdn), + tcache, ptr, szind, slow_path); } } else { extent_t *extent = iealloc(tsdn, ptr); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 35c7028b..e138de0c 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -13,6 +13,7 @@ arena_cleanup arena_dalloc arena_dalloc_bin_junked_locked arena_dalloc_junk_small +arena_dalloc_no_tcache arena_dalloc_promoted arena_dalloc_small arena_decay @@ -69,6 +70,7 @@ arena_ralloc_no_move arena_reset arena_salloc arena_sdalloc +arena_sdalloc_no_tcache arena_set arena_slab_regind arena_stats_init @@ -528,6 +530,7 @@ tsd_nominal tsd_prof_tdata_get tsd_prof_tdata_set tsd_prof_tdatap_get +tsd_rtree_ctx tsd_rtree_ctxp_get tsd_rtree_leaf_elm_witnessesp_get tsd_set diff --git a/include/jemalloc/internal/tsd_inlines.h b/include/jemalloc/internal/tsd_inlines.h index 1457c03e..96de4063 100644 --- a/include/jemalloc/internal/tsd_inlines.h +++ b/include/jemalloc/internal/tsd_inlines.h @@ -4,20 +4,21 @@ #ifndef JEMALLOC_ENABLE_INLINE malloc_tsd_protos(JEMALLOC_ATTR(unused), , tsd_t) -tsd_t *tsd_fetch_impl(bool init); -tsd_t *tsd_fetch(void); -tsdn_t *tsd_tsdn(tsd_t *tsd); -bool tsd_nominal(tsd_t *tsd); +tsd_t *tsd_fetch_impl(bool init); +tsd_t *tsd_fetch(void); +tsdn_t *tsd_tsdn(tsd_t *tsd); +bool tsd_nominal(tsd_t *tsd); #define O(n, t, gs, c) \ -t *tsd_##n##p_get(tsd_t *tsd); \ -t tsd_##n##_get(tsd_t *tsd); \ -void tsd_##n##_set(tsd_t *tsd, t n); +t *tsd_##n##p_get(tsd_t *tsd); \ +t tsd_##n##_get(tsd_t *tsd); \ +void tsd_##n##_set(tsd_t *tsd, t n); MALLOC_TSD #undef O -tsdn_t *tsdn_fetch(void); -bool tsdn_null(const tsdn_t *tsdn); -tsd_t *tsdn_tsd(tsdn_t *tsdn); -rtree_ctx_t *tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback); +tsdn_t *tsdn_fetch(void); +bool tsdn_null(const tsdn_t *tsdn); +tsd_t *tsdn_tsd(tsdn_t *tsdn); +rtree_ctx_t *tsd_rtree_ctx(tsd_t *tsd); +rtree_ctx_t *tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TSD_C_)) @@ -108,6 +109,11 @@ tsdn_tsd(tsdn_t *tsdn) { return &tsdn->tsd; } +JEMALLOC_ALWAYS_INLINE rtree_ctx_t * +tsd_rtree_ctx(tsd_t *tsd) { + return tsd_rtree_ctxp_get(tsd); +} + JEMALLOC_ALWAYS_INLINE rtree_ctx_t * tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback) { /* @@ -119,7 +125,7 @@ tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback) { memcpy(fallback, &rtree_ctx, sizeof(rtree_ctx_t)); return fallback; } - return tsd_rtree_ctxp_get(tsdn_tsd(tsdn)); + return tsd_rtree_ctx(tsdn_tsd(tsdn)); } #endif -- GitLab From 6309df628fa4f11dce084dc53c77ea852408d347 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Thu, 23 Feb 2017 14:18:07 -0800 Subject: [PATCH 344/544] First stage of mutex profiling. Switched to trylock and update counters based on state. --- include/jemalloc/internal/mutex_inlines.h | 51 +++++++++++------------ include/jemalloc/internal/mutex_structs.h | 43 ++++++++++++++++++- include/jemalloc/internal/mutex_types.h | 42 ++++++++++++++++--- include/jemalloc/internal/nstime_types.h | 2 + src/mutex.c | 43 +++++++++++++++++++ 5 files changed, 149 insertions(+), 32 deletions(-) diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index c0c3cfe9..cf0ce23a 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -1,31 +1,42 @@ #ifndef JEMALLOC_INTERNAL_MUTEX_INLINES_H #define JEMALLOC_INTERNAL_MUTEX_INLINES_H +void malloc_mutex_lock_slow(malloc_mutex_t *mutex); + #ifndef JEMALLOC_ENABLE_INLINE void malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex); +bool malloc_mutex_trylock(malloc_mutex_t *mutex); void malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex); void malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); void malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) +JEMALLOC_INLINE void +malloc_mutex_lock_final(malloc_mutex_t *mutex) { + MALLOC_MUTEX_LOCK(mutex); +} + +/* Trylock: return false if the lock is successfully acquired. */ +JEMALLOC_INLINE bool +malloc_mutex_trylock(malloc_mutex_t *mutex) { + return MALLOC_MUTEX_TRYLOCK(mutex); +} + JEMALLOC_INLINE void malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) { witness_assert_not_owner(tsdn, &mutex->witness); if (isthreaded) { -#ifdef _WIN32 -# if _WIN32_WINNT >= 0x0600 - AcquireSRWLockExclusive(&mutex->lock); -# else - EnterCriticalSection(&mutex->lock); -# endif -#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) - os_unfair_lock_lock(&mutex->lock); -#elif (defined(JEMALLOC_OSSPIN)) - OSSpinLockLock(&mutex->lock); -#else - pthread_mutex_lock(&mutex->lock); -#endif + if (malloc_mutex_trylock(mutex)) { + malloc_mutex_lock_slow(mutex); + } + /* We own the lock now. Update a few counters. */ + lock_prof_data_t *data = &mutex->prof_data; + data->n_lock_ops++; + if (data->prev_owner != tsdn) { + data->prev_owner = tsdn; + data->n_owner_switches++; + } } witness_lock(tsdn, &mutex->witness); } @@ -34,19 +45,7 @@ JEMALLOC_INLINE void malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) { witness_unlock(tsdn, &mutex->witness); if (isthreaded) { -#ifdef _WIN32 -# if _WIN32_WINNT >= 0x0600 - ReleaseSRWLockExclusive(&mutex->lock); -# else - LeaveCriticalSection(&mutex->lock); -# endif -#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) - os_unfair_lock_unlock(&mutex->lock); -#elif (defined(JEMALLOC_OSSPIN)) - OSSpinLockUnlock(&mutex->lock); -#else - pthread_mutex_unlock(&mutex->lock); -#endif + MALLOC_MUTEX_UNLOCK(mutex); } } diff --git a/include/jemalloc/internal/mutex_structs.h b/include/jemalloc/internal/mutex_structs.h index c34c1d47..7065c997 100644 --- a/include/jemalloc/internal/mutex_structs.h +++ b/include/jemalloc/internal/mutex_structs.h @@ -1,9 +1,50 @@ #ifndef JEMALLOC_INTERNAL_MUTEX_STRUCTS_H #define JEMALLOC_INTERNAL_MUTEX_STRUCTS_H +struct lock_prof_data_s { + /* + * Counters touched on the slow path, i.e. when there is lock + * contention. We update them once we have the lock. + */ + /* Total time spent waiting on this lock. */ + nstime_t tot_wait_time; + /* Max time spent on a single lock operation. */ + nstime_t max_wait_time; + /* # of times have to wait for this lock (after spinning). */ + uint64_t n_wait_times; + /* # of times acquired the lock through local spinning. */ + uint64_t n_spin_acquired; + /* Max # of threads waiting for the lock at the same time. */ + uint32_t max_n_thds; + /* Current # of threads waiting on the lock. Atomic synced. */ + uint32_t n_waiting_thds; + + /* + * Data touched on the fast path. These are modified right after we + * grab the lock, so it's placed closest to the end (i.e. right before + * the lock) so that we have a higher chance of them being on the same + * cacheline. + */ + /* # of times the new lock holder is different from the previous one. */ + uint64_t n_owner_switches; + /* Previous lock holder, to facilitate n_owner_switches. */ + tsdn_t *prev_owner; + /* # of lock() operations in total. */ + uint64_t n_lock_ops; +}; + struct malloc_mutex_s { union { struct { + /* + * prof_data is defined first to reduce cacheline + * bouncing: the data is not touched by the lock holder + * during unlocking, while might be modified by + * contenders. Having it before the lock itself could + * avoid prefetching a modified cacheline (for the + * unlocking thread). + */ + lock_prof_data_t prof_data; #ifdef _WIN32 # if _WIN32_WINNT >= 0x0600 SRWLOCK lock; @@ -22,7 +63,7 @@ struct malloc_mutex_s { #endif }; /* - * We only touch witness when configured w/ debug. However we + * We only touch witness when configured w/ debug. However we * keep the field in a union when !debug so that we don't have * to pollute the code base with #ifdefs, while avoid paying the * memory cost. diff --git a/include/jemalloc/internal/mutex_types.h b/include/jemalloc/internal/mutex_types.h index b7e3a7a1..d7c7f04f 100644 --- a/include/jemalloc/internal/mutex_types.h +++ b/include/jemalloc/internal/mutex_types.h @@ -1,31 +1,63 @@ #ifndef JEMALLOC_INTERNAL_MUTEX_TYPES_H #define JEMALLOC_INTERNAL_MUTEX_TYPES_H +typedef struct lock_prof_data_s lock_prof_data_t; typedef struct malloc_mutex_s malloc_mutex_t; +#ifdef _WIN32 +# if _WIN32_WINNT >= 0x0600 +# define MALLOC_MUTEX_LOCK(m) AcquireSRWLockExclusive(&(m)->lock) +# define MALLOC_MUTEX_UNLOCK(m) ReleaseSRWLockExclusive(&(m)->lock) +# define MALLOC_MUTEX_TRYLOCK(m) (!TryAcquireSRWLockExclusive(&(m)->lock)) +# else +# define MALLOC_MUTEX_LOCK(m) EnterCriticalSection(&(m)->lock) +# define MALLOC_MUTEX_UNLOCK(m) LeaveCriticalSection(&(m)->lock) +# define MALLOC_MUTEX_TRYLOCK(m) (!TryEnterCriticalSection(&(m)->lock)) +# endif +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) +# define MALLOC_MUTEX_LOCK(m) os_unfair_lock_lock(&(m)->lock) +# define MALLOC_MUTEX_UNLOCK(m) os_unfair_lock_unlock(&(m)->lock) +# define MALLOC_MUTEX_TRYLOCK(m) (!os_unfair_lock_trylock(&(m)->lock)) +#elif (defined(JEMALLOC_OSSPIN)) +# define MALLOC_MUTEX_LOCK(m) OSSpinLockLock(&(m)->lock) +# define MALLOC_MUTEX_UNLOCK(m) OSSpinLockUnlock(&(m)->lock) +# define MALLOC_MUTEX_TRYLOCK(m) (!OSSpinLockTry(&(m)->lock)) +#else +# define MALLOC_MUTEX_LOCK(m) pthread_mutex_lock(&(m)->lock) +# define MALLOC_MUTEX_UNLOCK(m) pthread_mutex_unlock(&(m)->lock) +# define MALLOC_MUTEX_TRYLOCK(m) (pthread_mutex_trylock(&(m)->lock) != 0) +#endif + +#define LOCK_PROF_DATA_INITIALIZER \ + {NSTIME_ZERO_INITIALIZER, NSTIME_ZERO_INITIALIZER, 0, 0, 0, 0, 0, NULL, 0} + #ifdef _WIN32 # define MALLOC_MUTEX_INITIALIZER #elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) # define MALLOC_MUTEX_INITIALIZER \ - {{{OS_UNFAIR_LOCK_INIT}}, WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} + {{{LOCK_PROF_DATA_INITIALIZER, OS_UNFAIR_LOCK_INIT}}, \ + WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} #elif (defined(JEMALLOC_OSSPIN)) # define MALLOC_MUTEX_INITIALIZER \ - {{{0}}, WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} + {{{LOCK_PROF_DATA_INITIALIZER, 0}}, \ + WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} #elif (defined(JEMALLOC_MUTEX_INIT_CB)) # define MALLOC_MUTEX_INITIALIZER \ - {{{PTHREAD_MUTEX_INITIALIZER, NULL}}, \ + {{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, NULL}}, \ WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} #else +/* TODO: get rid of adaptive mutex once we do our own spin. */ # if (defined(JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP) && \ defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP)) # define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_ADAPTIVE_NP # define MALLOC_MUTEX_INITIALIZER \ - {{{PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP}}, \ + {{{LOCK_PROF_DATA_INITIALIZER, \ + PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP}}, \ WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} # else # define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT # define MALLOC_MUTEX_INITIALIZER \ - {{{PTHREAD_MUTEX_INITIALIZER}}, \ + {{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER}}, \ WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} # endif #endif diff --git a/include/jemalloc/internal/nstime_types.h b/include/jemalloc/internal/nstime_types.h index d6039e03..6e7e74cf 100644 --- a/include/jemalloc/internal/nstime_types.h +++ b/include/jemalloc/internal/nstime_types.h @@ -6,4 +6,6 @@ typedef struct nstime_s nstime_t; /* Maximum supported number of seconds (~584 years). */ #define NSTIME_SEC_MAX KQU(18446744072) +#define NSTIME_ZERO_INITIALIZER {0} + #endif /* JEMALLOC_INTERNAL_NSTIME_TYPES_H */ diff --git a/src/mutex.c b/src/mutex.c index f1aa155e..2b80a9d9 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -65,6 +65,49 @@ JEMALLOC_EXPORT int _pthread_mutex_init_calloc_cb(pthread_mutex_t *mutex, void *(calloc_cb)(size_t, size_t)); #endif +void +malloc_mutex_lock_slow(malloc_mutex_t *mutex) { + lock_prof_data_t *data = &mutex->prof_data; + bool spin_success = false; + + {//TODO: a smart spin policy + if (!malloc_mutex_trylock(mutex)) { + spin_success = true; + goto label_locked; + } + } + + nstime_t now, before; + uint32_t n_thds; + nstime_init(&now, 0); + nstime_update(&now); + n_thds = atomic_add_u32(&data->n_waiting_thds, 1); + /* One last try as above two calls may take quite some cycles. */ + if (!malloc_mutex_trylock(mutex)) { + spin_success = true; + atomic_sub_u32(&data->n_waiting_thds, 1); + goto label_locked; + } + nstime_copy(&before, &now); + malloc_mutex_lock_final(mutex); + atomic_sub_u32(&data->n_waiting_thds, 1); + nstime_update(&now); + nstime_subtract(&now, &before); +label_locked: + if (spin_success) { + data->n_spin_acquired++; + } else { + data->n_wait_times++; + nstime_add(&data->tot_wait_time, &now); + if (nstime_compare(&now, &data->max_wait_time)) { + nstime_copy(&data->max_wait_time, &now); + } + if (n_thds > data->max_n_thds) { + data->max_n_thds = n_thds; + } + } +} + bool malloc_mutex_init(malloc_mutex_t *mutex, const char *name, witness_rank_t rank) { -- GitLab From a4f176af57de77d62b4751af876512748c6ce800 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 3 Mar 2017 19:58:43 -0800 Subject: [PATCH 345/544] Output bin lock profiling results to malloc_stats. Two counters are included for the small bins: lock contention rate, and max lock waiting time. --- include/jemalloc/internal/mutex_inlines.h | 35 +++++++ include/jemalloc/internal/nstime_externs.h | 1 + include/jemalloc/internal/private_symbols.txt | 2 + include/jemalloc/internal/stats_structs.h | 2 + src/arena.c | 1 + src/ctl.c | 8 +- src/nstime.c | 6 ++ src/stats.c | 99 ++++++++++++------- 8 files changed, 120 insertions(+), 34 deletions(-) diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index cf0ce23a..8e81fcde 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -9,6 +9,9 @@ bool malloc_mutex_trylock(malloc_mutex_t *mutex); void malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex); void malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); void malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); +void malloc_lock_prof_read(tsdn_t *tsdn, lock_prof_data_t *data, + malloc_mutex_t *mutex); +void malloc_lock_prof_merge(lock_prof_data_t *sum, lock_prof_data_t *data); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) @@ -23,6 +26,24 @@ malloc_mutex_trylock(malloc_mutex_t *mutex) { return MALLOC_MUTEX_TRYLOCK(mutex); } +/* Aggregate lock prof data. */ +JEMALLOC_INLINE void +malloc_lock_prof_merge(lock_prof_data_t *sum, lock_prof_data_t *data) { + nstime_add(&sum->tot_wait_time, &data->tot_wait_time); + if (nstime_compare(&data->max_wait_time, &sum->max_wait_time)) { + nstime_copy(&sum->max_wait_time, &data->max_wait_time); + } + sum->n_wait_times += data->n_wait_times; + sum->n_spin_acquired += data->n_spin_acquired; + + if (sum->max_n_thds < data->max_n_thds) { + sum->max_n_thds = data->max_n_thds; + } + sum->n_waiting_thds += data->n_waiting_thds; + sum->n_owner_switches += data->n_owner_switches; + sum->n_lock_ops += data->n_lock_ops; +} + JEMALLOC_INLINE void malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) { witness_assert_not_owner(tsdn, &mutex->witness); @@ -58,6 +79,20 @@ JEMALLOC_INLINE void malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { witness_assert_not_owner(tsdn, &mutex->witness); } + +/* Copy the prof data from mutex for processing. */ +JEMALLOC_INLINE void +malloc_lock_prof_read(tsdn_t *tsdn, lock_prof_data_t *data, + malloc_mutex_t *mutex) { + lock_prof_data_t *source = &mutex->prof_data; + /* Can only read with the lock. */ + malloc_mutex_assert_owner(tsdn, mutex); + + *data = *source; + /* n_wait_thds is not reported (modified w/o locking). */ + data->n_waiting_thds = 0; +} + #endif #endif /* JEMALLOC_INTERNAL_MUTEX_INLINES_H */ diff --git a/include/jemalloc/internal/nstime_externs.h b/include/jemalloc/internal/nstime_externs.h index cf14ae0c..1abc84d9 100644 --- a/include/jemalloc/internal/nstime_externs.h +++ b/include/jemalloc/internal/nstime_externs.h @@ -5,6 +5,7 @@ void nstime_init(nstime_t *time, uint64_t ns); void nstime_init2(nstime_t *time, uint64_t sec, uint64_t nsec); uint64_t nstime_ns(const nstime_t *time); uint64_t nstime_sec(const nstime_t *time); +uint64_t nstime_msec(const nstime_t *time); uint64_t nstime_nsec(const nstime_t *time); void nstime_copy(nstime_t *time, const nstime_t *source); int nstime_compare(const nstime_t *a, const nstime_t *b); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index e138de0c..14ecdeda 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -273,6 +273,7 @@ malloc_mutex_assert_owner malloc_mutex_boot malloc_mutex_init malloc_mutex_lock +malloc_mutex_lock_slow malloc_mutex_postfork_child malloc_mutex_postfork_parent malloc_mutex_prefork @@ -302,6 +303,7 @@ nstime_imultiply nstime_init nstime_init2 nstime_monotonic +nstime_msec nstime_ns nstime_nsec nstime_sec diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index ffcb3c18..cbc448a3 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -56,6 +56,8 @@ struct malloc_bin_stats_s { /* Current number of slabs in this bin. */ size_t curslabs; + + lock_prof_data_t lock_data; }; struct malloc_large_stats_s { diff --git a/src/arena.c b/src/arena.c index ef7ec37b..832a125e 100644 --- a/src/arena.c +++ b/src/arena.c @@ -299,6 +299,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, arena_bin_t *bin = &arena->bins[i]; malloc_mutex_lock(tsdn, &bin->lock); + malloc_lock_prof_read(tsdn, &bstats[i].lock_data, &bin->lock); bstats[i].nmalloc += bin->stats.nmalloc; bstats[i].ndalloc += bin->stats.ndalloc; bstats[i].nrequests += bin->stats.nrequests; diff --git a/src/ctl.c b/src/ctl.c index ee69be6d..d9f8be60 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -145,6 +145,7 @@ CTL_PROTO(stats_arenas_i_bins_j_nflushes) CTL_PROTO(stats_arenas_i_bins_j_nslabs) CTL_PROTO(stats_arenas_i_bins_j_nreslabs) CTL_PROTO(stats_arenas_i_bins_j_curslabs) +CTL_PROTO(stats_arenas_i_bins_j_lock_data) INDEX_PROTO(stats_arenas_i_bins_j) CTL_PROTO(stats_arenas_i_lextents_j_nmalloc) CTL_PROTO(stats_arenas_i_lextents_j_ndalloc) @@ -357,7 +358,8 @@ static const ctl_named_node_t stats_arenas_i_bins_j_node[] = { {NAME("nflushes"), CTL(stats_arenas_i_bins_j_nflushes)}, {NAME("nslabs"), CTL(stats_arenas_i_bins_j_nslabs)}, {NAME("nreslabs"), CTL(stats_arenas_i_bins_j_nreslabs)}, - {NAME("curslabs"), CTL(stats_arenas_i_bins_j_curslabs)} + {NAME("curslabs"), CTL(stats_arenas_i_bins_j_curslabs)}, + {NAME("lock_data"), CTL(stats_arenas_i_bins_j_lock_data)} }; static const ctl_named_node_t super_stats_arenas_i_bins_j_node[] = { {NAME(""), CHILD(named, stats_arenas_i_bins_j)} @@ -726,6 +728,8 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, } else { assert(astats->bstats[i].curslabs == 0); } + malloc_lock_prof_merge(&sdstats->bstats[i].lock_data, + &astats->bstats[i].lock_data); } for (i = 0; i < NSIZES - NBINS; i++) { @@ -2333,6 +2337,8 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreslabs, arenas_i(mib[2])->astats->bstats[mib[4]].reslabs, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curslabs, arenas_i(mib[2])->astats->bstats[mib[4]].curslabs, size_t) +CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_lock_data, + arenas_i(mib[2])->astats->bstats[mib[4]].lock_data, lock_prof_data_t) static const ctl_named_node_t * stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, diff --git a/src/nstime.c b/src/nstime.c index a3f6c1de..70b2f9d8 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -1,6 +1,7 @@ #include "jemalloc/internal/jemalloc_internal.h" #define BILLION UINT64_C(1000000000) +#define MILLION UINT64_C(1000000) void nstime_init(nstime_t *time, uint64_t ns) { @@ -17,6 +18,11 @@ nstime_ns(const nstime_t *time) { return time->ns; } +uint64_t +nstime_msec(const nstime_t *time) { + return time->ns / MILLION; +} + uint64_t nstime_sec(const nstime_t *time) { return time->ns / BILLION; diff --git a/src/stats.c b/src/stats.c index 58b9a04f..58283f87 100644 --- a/src/stats.c +++ b/src/stats.c @@ -32,6 +32,31 @@ bool opt_stats_print = false; /******************************************************************************/ +/* Calculate x.yyy and output a string (takes a fixed sized char array). */ +static bool +get_rate_str(uint64_t dividend, uint64_t divisor, char str[6]) { + if (divisor == 0 || dividend > divisor) { + /* The rate is not supposed to be greater than 1. */ + return true; + } + if (dividend > 0) { + assert(UINT64_MAX / dividend >= 1000); + } + + unsigned n = (unsigned)((dividend * 1000) / divisor); + if (n < 10) { + malloc_snprintf(str, 6, "0.00%u", n); + } else if (n < 100) { + malloc_snprintf(str, 6, "0.0%u", n); + } else if (n < 1000) { + malloc_snprintf(str, 6, "0.%u", n); + } else { + malloc_snprintf(str, 6, "1"); + } + + return false; +} + static void stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, bool json, bool large, unsigned i) { @@ -51,13 +76,14 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, "bins: size ind allocated nmalloc" " ndalloc nrequests curregs" " curslabs regs pgs util nfills" - " nflushes newslabs reslabs\n"); + " nflushes newslabs reslabs" + " contention max_wait\n"); } else { malloc_cprintf(write_cb, cbopaque, "bins: size ind allocated nmalloc" " ndalloc nrequests curregs" " curslabs regs pgs util newslabs" - " reslabs\n"); + " reslabs contention max_wait\n"); } } for (j = 0, in_gap = false; j < nbins; j++) { @@ -100,6 +126,9 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, uint64_t); CTL_M2_M4_GET("stats.arenas.0.bins.0.curslabs", i, j, &curslabs, size_t); + lock_prof_data_t lock_data; + CTL_M2_M4_GET("stats.arenas.0.bins.0.lock_data", i, j, + &lock_data, lock_prof_data_t); if (json) { malloc_cprintf(write_cb, cbopaque, @@ -127,55 +156,59 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, curslabs, (j + 1 < nbins) ? "," : ""); } else if (!in_gap) { - size_t availregs, milli; - char util[6]; /* "x.yyy". */ - - availregs = nregs * curslabs; - milli = (availregs != 0) ? (1000 * curregs) / availregs - : 1000; - - if (milli > 1000) { - /* - * Race detected: the counters were read in - * separate mallctl calls and concurrent - * operations happened in between. In this case - * no meaningful utilization can be computed. - */ - malloc_snprintf(util, sizeof(util), " race"); - } else if (milli < 10) { - malloc_snprintf(util, sizeof(util), - "0.00%zu", milli); - } else if (milli < 100) { - malloc_snprintf(util, sizeof(util), "0.0%zu", - milli); - } else if (milli < 1000) { - malloc_snprintf(util, sizeof(util), "0.%zu", - milli); - } else { - assert(milli == 1000); - malloc_snprintf(util, sizeof(util), "1"); + size_t availregs = nregs * curslabs; + char util[6]; + if (get_rate_str((uint64_t)curregs, (uint64_t)availregs, + util)) { + if (availregs == 0) { + malloc_snprintf(util, sizeof(util), + "1"); + } else if (curregs > availregs) { + /* + * Race detected: the counters were read + * in separate mallctl calls and + * concurrent operations happened in + * between. In this case no meaningful + * utilization can be computed. + */ + malloc_snprintf(util, sizeof(util), + " race"); + } else { + not_reached(); + } + } + char rate[6]; + if (get_rate_str(lock_data.n_wait_times, + lock_data.n_lock_ops, rate)) { + if (lock_data.n_lock_ops == 0) { + malloc_snprintf(rate, sizeof(rate), + "0"); + } } + uint64_t max_wait = nstime_msec( + &lock_data.max_wait_time); if (config_tcache) { malloc_cprintf(write_cb, cbopaque, "%20zu %3u %12zu %12"FMTu64 " %12"FMTu64" %12"FMTu64" %12zu" " %12zu %4u %3zu %-5s %12"FMTu64 - " %12"FMTu64" %12"FMTu64" %12"FMTu64"\n", + " %12"FMTu64" %12"FMTu64" %12"FMTu64 + " %12s %12"FMTu64"\n", reg_size, j, curregs * reg_size, nmalloc, ndalloc, nrequests, curregs, curslabs, nregs, slab_size / page, util, nfills, - nflushes, nslabs, nreslabs); + nflushes, nslabs, nreslabs, rate, max_wait); } else { malloc_cprintf(write_cb, cbopaque, "%20zu %3u %12zu %12"FMTu64 " %12"FMTu64" %12"FMTu64" %12zu" " %12zu %4u %3zu %-5s %12"FMTu64 - " %12"FMTu64"\n", + " %12"FMTu64" %12s\n", reg_size, j, curregs * reg_size, nmalloc, ndalloc, nrequests, curregs, curslabs, nregs, slab_size / page, util, nslabs, - nreslabs); + nreslabs, rate); } } } -- GitLab From 0fb5c0e853963480196ac413db18d1ad78d87ec9 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 10 Mar 2017 12:14:05 -0800 Subject: [PATCH 346/544] Add arena lock stats output. --- include/jemalloc/internal/ctl_externs.h | 8 ++ include/jemalloc/internal/mutex_inlines.h | 6 +- include/jemalloc/internal/mutex_structs.h | 8 +- include/jemalloc/internal/mutex_types.h | 3 +- include/jemalloc/internal/stats_structs.h | 7 ++ src/arena.c | 18 +++ src/ctl.c | 142 ++++++++++++++++++++-- src/mutex.c | 46 ++++--- src/stats.c | 82 ++++++++++--- 9 files changed, 269 insertions(+), 51 deletions(-) diff --git a/include/jemalloc/internal/ctl_externs.h b/include/jemalloc/internal/ctl_externs.h index 2ef48c66..812ec4fa 100644 --- a/include/jemalloc/internal/ctl_externs.h +++ b/include/jemalloc/internal/ctl_externs.h @@ -1,6 +1,14 @@ #ifndef JEMALLOC_INTERNAL_CTL_EXTERNS_H #define JEMALLOC_INTERNAL_CTL_EXTERNS_H +/* Maximum ctl tree depth. */ +#define CTL_MAX_DEPTH 7 + +#define NUM_ARENA_PROF_LOCKS 6 +#define NUM_LOCK_PROF_COUNTERS 7 +const char *arena_lock_names[NUM_ARENA_PROF_LOCKS]; +const char *lock_counter_names[NUM_LOCK_PROF_COUNTERS]; + int ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen); int ctl_nametomib(tsdn_t *tsdn, const char *name, size_t *mibp, diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index 8e81fcde..1020eefd 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -29,9 +29,9 @@ malloc_mutex_trylock(malloc_mutex_t *mutex) { /* Aggregate lock prof data. */ JEMALLOC_INLINE void malloc_lock_prof_merge(lock_prof_data_t *sum, lock_prof_data_t *data) { - nstime_add(&sum->tot_wait_time, &data->tot_wait_time); - if (nstime_compare(&data->max_wait_time, &sum->max_wait_time)) { - nstime_copy(&sum->max_wait_time, &data->max_wait_time); + sum->tot_wait_time += data->tot_wait_time; + if (data->max_wait_time > sum->max_wait_time) { + sum->max_wait_time = data->max_wait_time; } sum->n_wait_times += data->n_wait_times; sum->n_spin_acquired += data->n_spin_acquired; diff --git a/include/jemalloc/internal/mutex_structs.h b/include/jemalloc/internal/mutex_structs.h index 7065c997..ce80e15d 100644 --- a/include/jemalloc/internal/mutex_structs.h +++ b/include/jemalloc/internal/mutex_structs.h @@ -6,10 +6,10 @@ struct lock_prof_data_s { * Counters touched on the slow path, i.e. when there is lock * contention. We update them once we have the lock. */ - /* Total time spent waiting on this lock. */ - nstime_t tot_wait_time; - /* Max time spent on a single lock operation. */ - nstime_t max_wait_time; + /* Total time (in nano seconds) spent waiting on this lock. */ + uint64_t tot_wait_time; + /* Max time (in nano seconds) spent on a single lock operation. */ + uint64_t max_wait_time; /* # of times have to wait for this lock (after spinning). */ uint64_t n_wait_times; /* # of times acquired the lock through local spinning. */ diff --git a/include/jemalloc/internal/mutex_types.h b/include/jemalloc/internal/mutex_types.h index d7c7f04f..0d93fe87 100644 --- a/include/jemalloc/internal/mutex_types.h +++ b/include/jemalloc/internal/mutex_types.h @@ -28,8 +28,7 @@ typedef struct malloc_mutex_s malloc_mutex_t; # define MALLOC_MUTEX_TRYLOCK(m) (pthread_mutex_trylock(&(m)->lock) != 0) #endif -#define LOCK_PROF_DATA_INITIALIZER \ - {NSTIME_ZERO_INITIALIZER, NSTIME_ZERO_INITIALIZER, 0, 0, 0, 0, 0, NULL, 0} +#define LOCK_PROF_DATA_INITIALIZER {0, 0, 0, 0, 0, 0, 0, NULL, 0} #ifdef _WIN32 # define MALLOC_MUTEX_INITIALIZER diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index cbc448a3..0e33394b 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -124,6 +124,13 @@ struct arena_stats_s { /* Number of bytes cached in tcache associated with this arena. */ atomic_zu_t tcache_bytes; /* Derived. */ + lock_prof_data_t large_mtx_data; + lock_prof_data_t extent_freelist_mtx_data; + lock_prof_data_t extents_cached_mtx_data; + lock_prof_data_t extents_retained_mtx_data; + lock_prof_data_t decay_mtx_data; + lock_prof_data_t tcache_mtx_data; + /* One element for each large size class. */ malloc_large_stats_t lstats[NSIZES - NBINS]; }; diff --git a/src/arena.c b/src/arena.c index 832a125e..0c12004d 100644 --- a/src/arena.c +++ b/src/arena.c @@ -292,9 +292,27 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, tbin->ncached * index2size(i)); } } + malloc_lock_prof_read(tsdn, &astats->tcache_mtx_data, + &arena->tcache_ql_mtx); malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx); } +#define READ_ARENA_MUTEX_PROF_DATA(mtx, data) \ + malloc_mutex_lock(tsdn, &arena->mtx); \ + malloc_lock_prof_read(tsdn, &astats->data, &arena->mtx); \ + malloc_mutex_unlock(tsdn, &arena->mtx); + + /* Gather per arena mutex profiling data. */ + READ_ARENA_MUTEX_PROF_DATA(large_mtx, large_mtx_data) + READ_ARENA_MUTEX_PROF_DATA(extent_freelist_mtx, + extent_freelist_mtx_data) + READ_ARENA_MUTEX_PROF_DATA(extents_cached.mtx, + extents_cached_mtx_data) + READ_ARENA_MUTEX_PROF_DATA(extents_retained.mtx, + extents_retained_mtx_data) + READ_ARENA_MUTEX_PROF_DATA(decay.mtx, decay_mtx_data) +#undef READ_ARENA_MUTEX_PROF_DATA + for (szind_t i = 0; i < NBINS; i++) { arena_bin_t *bin = &arena->bins[i]; diff --git a/src/ctl.c b/src/ctl.c index d9f8be60..016275e5 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -13,6 +13,24 @@ static bool ctl_initialized; static ctl_stats_t *ctl_stats; static ctl_arenas_t *ctl_arenas; +const char *arena_lock_names[NUM_ARENA_PROF_LOCKS] = { + "large", + "extent_freelist", + "extents_cached", + "extents_retained", + "decay", + "tcache" +}; +const char *lock_counter_names[NUM_LOCK_PROF_COUNTERS] = { + "num_ops", + "num_wait", + "num_spin_acq", + "num_owner_switch", + "total_wait_time", + "max_wait_time", + "max_num_thds" +}; + /******************************************************************************/ /* Helpers for named and indexed nodes. */ @@ -145,7 +163,6 @@ CTL_PROTO(stats_arenas_i_bins_j_nflushes) CTL_PROTO(stats_arenas_i_bins_j_nslabs) CTL_PROTO(stats_arenas_i_bins_j_nreslabs) CTL_PROTO(stats_arenas_i_bins_j_curslabs) -CTL_PROTO(stats_arenas_i_bins_j_lock_data) INDEX_PROTO(stats_arenas_i_bins_j) CTL_PROTO(stats_arenas_i_lextents_j_nmalloc) CTL_PROTO(stats_arenas_i_lextents_j_ndalloc) @@ -179,12 +196,30 @@ CTL_PROTO(stats_resident) CTL_PROTO(stats_mapped) CTL_PROTO(stats_retained) +#define STATS_LOCKS_CTL_PROTO_GEN(l, n) \ +CTL_PROTO(stats_arenas_i_##l##_##n##_num_ops) \ +CTL_PROTO(stats_arenas_i_##l##_##n##_num_wait) \ +CTL_PROTO(stats_arenas_i_##l##_##n##_num_spin_acq) \ +CTL_PROTO(stats_arenas_i_##l##_##n##_num_owner_switch) \ +CTL_PROTO(stats_arenas_i_##l##_##n##_total_wait_time) \ +CTL_PROTO(stats_arenas_i_##l##_##n##_max_wait_time) \ +CTL_PROTO(stats_arenas_i_##l##_##n##_max_num_thds) + +#define ARENA_LOCKS_CTL_PROTO_GEN(n) STATS_LOCKS_CTL_PROTO_GEN(locks, n) +ARENA_LOCKS_CTL_PROTO_GEN(large) +ARENA_LOCKS_CTL_PROTO_GEN(extent_freelist) +ARENA_LOCKS_CTL_PROTO_GEN(extents_cached) +ARENA_LOCKS_CTL_PROTO_GEN(extents_retained) +ARENA_LOCKS_CTL_PROTO_GEN(decay) +ARENA_LOCKS_CTL_PROTO_GEN(tcache) +#undef ARENA_LOCKS_CTL_PROTO_GEN + +STATS_LOCKS_CTL_PROTO_GEN(bins_j, lock) +#undef STATS_LOCKS_CTL_PROTO_GEN + /******************************************************************************/ /* mallctl tree. */ -/* Maximum tree depth. */ -#define CTL_MAX_DEPTH 6 - #define NAME(n) {true}, n #define CHILD(t, c) \ sizeof(c##_node) / sizeof(ctl_##t##_node_t), \ @@ -349,6 +384,26 @@ static const ctl_named_node_t stats_arenas_i_large_node[] = { {NAME("nrequests"), CTL(stats_arenas_i_large_nrequests)} }; +#define LOCK_PROF_DATA_NODE(prefix, n) \ +static const ctl_named_node_t prefix##_##n##_node[] = { \ + {NAME("num_ops"), \ + CTL(prefix##_##n##_num_ops)}, \ + {NAME("num_wait"), \ + CTL(prefix##_##n##_num_wait)}, \ + {NAME("num_spin_acq"), \ + CTL(prefix##_##n##_num_spin_acq)}, \ + {NAME("num_owner_switch"), \ + CTL(prefix##_##n##_num_owner_switch)}, \ + {NAME("total_wait_time"), \ + CTL(prefix##_##n##_total_wait_time)}, \ + {NAME("max_wait_time"), \ + CTL(prefix##_##n##_max_wait_time)}, \ + {NAME("max_num_thds"), \ + CTL(prefix##_##n##_max_num_thds)} \ + /* Note that # of current waiting thread not provided. */ \ +}; + +LOCK_PROF_DATA_NODE(stats_arenas_i_bins_j, lock) static const ctl_named_node_t stats_arenas_i_bins_j_node[] = { {NAME("nmalloc"), CTL(stats_arenas_i_bins_j_nmalloc)}, {NAME("ndalloc"), CTL(stats_arenas_i_bins_j_ndalloc)}, @@ -359,8 +414,9 @@ static const ctl_named_node_t stats_arenas_i_bins_j_node[] = { {NAME("nslabs"), CTL(stats_arenas_i_bins_j_nslabs)}, {NAME("nreslabs"), CTL(stats_arenas_i_bins_j_nreslabs)}, {NAME("curslabs"), CTL(stats_arenas_i_bins_j_curslabs)}, - {NAME("lock_data"), CTL(stats_arenas_i_bins_j_lock_data)} + {NAME("lock"), CHILD(named, stats_arenas_i_bins_j_lock)} }; + static const ctl_named_node_t super_stats_arenas_i_bins_j_node[] = { {NAME(""), CHILD(named, stats_arenas_i_bins_j)} }; @@ -383,6 +439,26 @@ static const ctl_indexed_node_t stats_arenas_i_lextents_node[] = { {INDEX(stats_arenas_i_lextents_j)} }; +LOCK_PROF_DATA_NODE(stats_arenas_i_locks, large) +LOCK_PROF_DATA_NODE(stats_arenas_i_locks, extent_freelist) +LOCK_PROF_DATA_NODE(stats_arenas_i_locks, extents_cached) +LOCK_PROF_DATA_NODE(stats_arenas_i_locks, extents_retained) +LOCK_PROF_DATA_NODE(stats_arenas_i_locks, decay) +LOCK_PROF_DATA_NODE(stats_arenas_i_locks, tcache) + +static const ctl_named_node_t stats_arenas_i_locks_node[] = { + {NAME("large"), CHILD(named, stats_arenas_i_locks_large)}, + {NAME("extent_freelist"), + CHILD(named, stats_arenas_i_locks_extent_freelist)}, + {NAME("extents_cached"), + CHILD(named, stats_arenas_i_locks_extents_cached)}, + {NAME("extents_retained"), + CHILD(named, stats_arenas_i_locks_extents_retained)}, + {NAME("decay"), CHILD(named, stats_arenas_i_locks_decay)}, + {NAME("tcache"), CHILD(named, stats_arenas_i_locks_tcache)} +}; +#undef LOCK_PROF_DATA_NODE + static const ctl_named_node_t stats_arenas_i_node[] = { {NAME("nthreads"), CTL(stats_arenas_i_nthreads)}, {NAME("dss"), CTL(stats_arenas_i_dss)}, @@ -406,7 +482,8 @@ static const ctl_named_node_t stats_arenas_i_node[] = { {NAME("small"), CHILD(named, stats_arenas_i_small)}, {NAME("large"), CHILD(named, stats_arenas_i_large)}, {NAME("bins"), CHILD(indexed, stats_arenas_i_bins)}, - {NAME("lextents"), CHILD(indexed, stats_arenas_i_lextents)} + {NAME("lextents"), CHILD(indexed, stats_arenas_i_lextents)}, + {NAME("locks"), CHILD(named, stats_arenas_i_locks)} }; static const ctl_named_node_t super_stats_arenas_i_node[] = { {NAME(""), CHILD(named, stats_arenas_i)} @@ -663,6 +740,22 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, accum_arena_stats_u64(&sdstats->astats.decay_muzzy.purged, &astats->astats.decay_muzzy.purged); + malloc_lock_prof_merge(&(sdstats->astats.large_mtx_data), + &(astats->astats.large_mtx_data)); + malloc_lock_prof_merge( + &(sdstats->astats.extent_freelist_mtx_data), + &(astats->astats.extent_freelist_mtx_data)); + malloc_lock_prof_merge( + &(sdstats->astats.extents_cached_mtx_data), + &(astats->astats.extents_cached_mtx_data)); + malloc_lock_prof_merge( + &(sdstats->astats.extents_retained_mtx_data), + &(astats->astats.extents_retained_mtx_data)); + malloc_lock_prof_merge(&(sdstats->astats.decay_mtx_data), + &(astats->astats.decay_mtx_data)); + malloc_lock_prof_merge(&(sdstats->astats.tcache_mtx_data), + &(astats->astats.tcache_mtx_data)); + if (!destroyed) { accum_atomic_zu(&sdstats->astats.base, &astats->astats.base); @@ -2319,6 +2412,41 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests, arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.nmalloc_large), uint64_t) /* Intentional. */ +/* Lock profiling related APIs below. */ +#define ARENAS_LOCK_CTL_GEN(l, s, d) \ +CTL_RO_CGEN(config_stats, stats_arenas_i_##l##_num_ops, \ + arenas_i(mib[2])->astats->s.d.n_lock_ops, uint64_t) \ +CTL_RO_CGEN(config_stats, stats_arenas_i_##l##_num_wait, \ + arenas_i(mib[2])->astats->s.d.n_wait_times, uint64_t) \ +CTL_RO_CGEN(config_stats, stats_arenas_i_##l##_num_spin_acq, \ + arenas_i(mib[2])->astats->s.d.n_spin_acquired, uint64_t) \ +CTL_RO_CGEN(config_stats, stats_arenas_i_##l##_num_owner_switch, \ + arenas_i(mib[2])->astats->s.d.n_owner_switches, uint64_t) \ +CTL_RO_CGEN(config_stats, stats_arenas_i_##l##_total_wait_time, \ + arenas_i(mib[2])->astats->s.d.tot_wait_time, uint64_t) \ +CTL_RO_CGEN(config_stats, stats_arenas_i_##l##_max_wait_time, \ + arenas_i(mib[2])->astats->s.d.max_wait_time, uint64_t) \ +CTL_RO_CGEN(config_stats, stats_arenas_i_##l##_max_num_thds, \ + arenas_i(mib[2])->astats->s.d.max_n_thds, uint64_t) + +#define ARENAS_ASTATS_LOCK_CTL_GEN(l, d) \ + ARENAS_LOCK_CTL_GEN(locks_##l, astats, d) + +/* arena->large_mtx */ +ARENAS_ASTATS_LOCK_CTL_GEN(large, large_mtx_data) +/* arena->extent_freelist_mtx */ +ARENAS_ASTATS_LOCK_CTL_GEN(extent_freelist, extent_freelist_mtx_data) +/* arena->extents_cached.mtx */ +ARENAS_ASTATS_LOCK_CTL_GEN(extents_cached, extents_cached_mtx_data) +/* arena->extents_retained.mtx */ +ARENAS_ASTATS_LOCK_CTL_GEN(extents_retained, extents_retained_mtx_data) +/* arena->decay.mtx */ +ARENAS_ASTATS_LOCK_CTL_GEN(decay, decay_mtx_data) +/* arena->tcache_ql_mtx */ +ARENAS_ASTATS_LOCK_CTL_GEN(tcache, tcache_mtx_data) +/* arena->bins[j].lock */ +ARENAS_LOCK_CTL_GEN(bins_j_lock, bstats[mib[4]], lock_data) + CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc, arenas_i(mib[2])->astats->bstats[mib[4]].nmalloc, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_ndalloc, @@ -2337,8 +2465,6 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreslabs, arenas_i(mib[2])->astats->bstats[mib[4]].reslabs, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curslabs, arenas_i(mib[2])->astats->bstats[mib[4]].curslabs, size_t) -CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_lock_data, - arenas_i(mib[2])->astats->bstats[mib[4]].lock_data, lock_prof_data_t) static const ctl_named_node_t * stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, diff --git a/src/mutex.c b/src/mutex.c index 2b80a9d9..af6f3c19 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -68,49 +68,55 @@ JEMALLOC_EXPORT int _pthread_mutex_init_calloc_cb(pthread_mutex_t *mutex, void malloc_mutex_lock_slow(malloc_mutex_t *mutex) { lock_prof_data_t *data = &mutex->prof_data; - bool spin_success = false; {//TODO: a smart spin policy if (!malloc_mutex_trylock(mutex)) { - spin_success = true; - goto label_locked; + data->n_spin_acquired++; + return; } } nstime_t now, before; - uint32_t n_thds; nstime_init(&now, 0); nstime_update(&now); - n_thds = atomic_add_u32(&data->n_waiting_thds, 1); + nstime_copy(&before, &now); + + uint32_t n_thds = atomic_add_u32(&data->n_waiting_thds, 1); /* One last try as above two calls may take quite some cycles. */ if (!malloc_mutex_trylock(mutex)) { - spin_success = true; atomic_sub_u32(&data->n_waiting_thds, 1); - goto label_locked; + data->n_spin_acquired++; + return; } - nstime_copy(&before, &now); + + /* True slow path. */ malloc_mutex_lock_final(mutex); atomic_sub_u32(&data->n_waiting_thds, 1); nstime_update(&now); + + /* Update more slow-path only counters. */ nstime_subtract(&now, &before); -label_locked: - if (spin_success) { - data->n_spin_acquired++; - } else { - data->n_wait_times++; - nstime_add(&data->tot_wait_time, &now); - if (nstime_compare(&now, &data->max_wait_time)) { - nstime_copy(&data->max_wait_time, &now); - } - if (n_thds > data->max_n_thds) { - data->max_n_thds = n_thds; - } + uint64_t wait_time = nstime_ns(&now); + data->n_wait_times++; + data->tot_wait_time += wait_time; + if (wait_time > data->max_wait_time) { + data->max_wait_time = wait_time; + } + if (n_thds > data->max_n_thds) { + data->max_n_thds = n_thds; } } +static void +lock_prof_data_init(lock_prof_data_t *data) { + memset(data, 0, sizeof(lock_prof_data_t)); + data->prev_owner = NULL; +} + bool malloc_mutex_init(malloc_mutex_t *mutex, const char *name, witness_rank_t rank) { + lock_prof_data_init(&mutex->prof_data); #ifdef _WIN32 # if _WIN32_WINNT >= 0x0600 InitializeSRWLock(&mutex->lock); diff --git a/src/stats.c b/src/stats.c index 58283f87..7b690e7f 100644 --- a/src/stats.c +++ b/src/stats.c @@ -7,7 +7,7 @@ } while (0) #define CTL_M2_GET(n, i, v, t) do { \ - size_t mib[6]; \ + size_t mib[CTL_MAX_DEPTH]; \ size_t miblen = sizeof(mib) / sizeof(size_t); \ size_t sz = sizeof(t); \ xmallctlnametomib(n, mib, &miblen); \ @@ -16,7 +16,7 @@ } while (0) #define CTL_M2_M4_GET(n, i, j, v, t) do { \ - size_t mib[6]; \ + size_t mib[CTL_MAX_DEPTH]; \ size_t miblen = sizeof(mib) / sizeof(size_t); \ size_t sz = sizeof(t); \ xmallctlnametomib(n, mib, &miblen); \ @@ -77,13 +77,13 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, " ndalloc nrequests curregs" " curslabs regs pgs util nfills" " nflushes newslabs reslabs" - " contention max_wait\n"); + " contention max_wait_ns\n"); } else { malloc_cprintf(write_cb, cbopaque, "bins: size ind allocated nmalloc" " ndalloc nrequests curregs" " curslabs regs pgs util newslabs" - " reslabs contention max_wait\n"); + " reslabs contention max_wait_ns\n"); } } for (j = 0, in_gap = false; j < nbins; j++) { @@ -126,9 +126,14 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, uint64_t); CTL_M2_M4_GET("stats.arenas.0.bins.0.curslabs", i, j, &curslabs, size_t); - lock_prof_data_t lock_data; - CTL_M2_M4_GET("stats.arenas.0.bins.0.lock_data", i, j, - &lock_data, lock_prof_data_t); + + uint64_t num_ops, num_wait, max_wait; + CTL_M2_M4_GET("stats.arenas.0.bins.0.lock.num_wait", i, j, + &num_wait, uint64_t); + CTL_M2_M4_GET("stats.arenas.0.bins.0.lock.max_wait_time", i, j, + &max_wait, uint64_t); + CTL_M2_M4_GET("stats.arenas.0.bins.0.lock.num_ops", i, j, + &num_ops, uint64_t); if (json) { malloc_cprintf(write_cb, cbopaque, @@ -178,15 +183,12 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, } } char rate[6]; - if (get_rate_str(lock_data.n_wait_times, - lock_data.n_lock_ops, rate)) { - if (lock_data.n_lock_ops == 0) { + if (get_rate_str(num_wait, num_ops, rate)) { + if (num_ops == 0) { malloc_snprintf(rate, sizeof(rate), "0"); } } - uint64_t max_wait = nstime_msec( - &lock_data.max_wait_time); if (config_tcache) { malloc_cprintf(write_cb, cbopaque, @@ -204,11 +206,11 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, "%20zu %3u %12zu %12"FMTu64 " %12"FMTu64" %12"FMTu64" %12zu" " %12zu %4u %3zu %-5s %12"FMTu64 - " %12"FMTu64" %12s\n", + " %12"FMTu64" %12s %12"FMTu64"\n", reg_size, j, curregs * reg_size, nmalloc, ndalloc, nrequests, curregs, curslabs, nregs, slab_size / page, util, nslabs, - nreslabs, rate); + nreslabs, rate, max_wait); } } } @@ -287,6 +289,57 @@ stats_arena_lextents_print(void (*write_cb)(void *, const char *), } } +static void +gen_ctl_str(char *str, const char *lock, const char *counter) { + sprintf(str, "stats.arenas.0.locks.%s.%s", lock, counter); +} + +static void read_arena_lock_stats(unsigned arena_ind, + uint64_t results[NUM_ARENA_PROF_LOCKS][NUM_LOCK_PROF_COUNTERS]) { + char cmd[128]; + + unsigned i, j; + for (i = 0; i < NUM_ARENA_PROF_LOCKS; i++) { + for (j = 0; j < NUM_LOCK_PROF_COUNTERS; j++) { + gen_ctl_str(cmd, arena_lock_names[i], + lock_counter_names[j]); + CTL_M2_GET(cmd, arena_ind, &results[i][j], uint64_t); + } + } +} + +static void +stats_arena_locks_print(void (*write_cb)(void *, const char *), + void *cbopaque, bool json, unsigned arena_ind) { + uint64_t lock_stats[NUM_ARENA_PROF_LOCKS][NUM_LOCK_PROF_COUNTERS]; + read_arena_lock_stats(arena_ind, lock_stats); + + /* Output lock stats. */ + if (json) { + //TODO + } else { + malloc_cprintf(write_cb, cbopaque, + " n_lock_ops n_waiting" + " n_spin_acq n_owner_switch total_wait_ns" + " max_wait_ns max_n_wait_thds\n"); + + unsigned i, j; + for (i = 0; i < NUM_ARENA_PROF_LOCKS; i++) { + malloc_cprintf(write_cb, cbopaque, + "%s", arena_lock_names[i]); + malloc_cprintf(write_cb, cbopaque, ":%*c", + (int)(18 - strlen(arena_lock_names[i])), ' '); + + for (j = 0; j < NUM_LOCK_PROF_COUNTERS; j++) { + malloc_cprintf(write_cb, cbopaque, " %15"FMTu64, + lock_stats[i][j]); + } + malloc_cprintf(write_cb, cbopaque, "\n"); + } + } + +} + static void stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, bool json, unsigned i, bool bins, bool large) { @@ -518,6 +571,7 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, "resident: %12zu\n", resident); } + stats_arena_locks_print(write_cb, cbopaque, json, i); if (bins) { stats_arena_bins_print(write_cb, cbopaque, json, large, i); } -- GitLab From ca9074deffe799dafa74a1d71333a103c4c007ce Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Sat, 11 Mar 2017 20:28:31 -0800 Subject: [PATCH 347/544] Added lock profiling and output for global locks (ctl, prof and base). --- include/jemalloc/internal/ctl_externs.h | 11 +- include/jemalloc/internal/ctl_structs.h | 4 + include/jemalloc/internal/ctl_types.h | 5 + include/jemalloc/internal/private_symbols.txt | 1 + include/jemalloc/internal/prof_externs.h | 2 + src/arena.c | 6 +- src/ctl.c | 146 ++++++++++++------ src/prof.c | 3 +- src/stats.c | 74 ++++++--- 9 files changed, 174 insertions(+), 78 deletions(-) diff --git a/include/jemalloc/internal/ctl_externs.h b/include/jemalloc/internal/ctl_externs.h index 812ec4fa..33ca2039 100644 --- a/include/jemalloc/internal/ctl_externs.h +++ b/include/jemalloc/internal/ctl_externs.h @@ -4,10 +4,13 @@ /* Maximum ctl tree depth. */ #define CTL_MAX_DEPTH 7 -#define NUM_ARENA_PROF_LOCKS 6 -#define NUM_LOCK_PROF_COUNTERS 7 -const char *arena_lock_names[NUM_ARENA_PROF_LOCKS]; -const char *lock_counter_names[NUM_LOCK_PROF_COUNTERS]; +#define NUM_GLOBAL_PROF_LOCKS 3 +#define NUM_ARENA_PROF_LOCKS 6 +#define NUM_LOCK_PROF_COUNTERS 7 + +extern const char *arena_lock_names[NUM_ARENA_PROF_LOCKS]; +extern const char *global_lock_names[NUM_GLOBAL_PROF_LOCKS]; +extern const char *lock_counter_names[NUM_LOCK_PROF_COUNTERS]; int ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen); diff --git a/include/jemalloc/internal/ctl_structs.h b/include/jemalloc/internal/ctl_structs.h index 4df43d90..e467a247 100644 --- a/include/jemalloc/internal/ctl_structs.h +++ b/include/jemalloc/internal/ctl_structs.h @@ -41,6 +41,10 @@ struct ctl_stats_s { size_t resident; size_t mapped; size_t retained; + +#define MTX(mutex) lock_prof_data_t mutex##_mtx_data; +GLOBAL_PROF_MUTEXES +#undef MTX }; struct ctl_arena_s { diff --git a/include/jemalloc/internal/ctl_types.h b/include/jemalloc/internal/ctl_types.h index 7853a4b2..562418ca 100644 --- a/include/jemalloc/internal/ctl_types.h +++ b/include/jemalloc/internal/ctl_types.h @@ -1,6 +1,11 @@ #ifndef JEMALLOC_INTERNAL_CTL_TYPES_H #define JEMALLOC_INTERNAL_CTL_TYPES_H +#define GLOBAL_PROF_MUTEXES \ + MTX(base) \ + MTX(ctl) \ + MTX(prof) + typedef struct ctl_node_s ctl_node_t; typedef struct ctl_named_node_s ctl_named_node_t; typedef struct ctl_indexed_node_s ctl_indexed_node_t; diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 14ecdeda..3c5a21b5 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -106,6 +106,7 @@ bootstrap_calloc bootstrap_free bootstrap_malloc bt_init +bt2gctx_mtx buferror ckh_count ckh_delete diff --git a/include/jemalloc/internal/prof_externs.h b/include/jemalloc/internal/prof_externs.h index 985532f6..cbd9795b 100644 --- a/include/jemalloc/internal/prof_externs.h +++ b/include/jemalloc/internal/prof_externs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_PROF_EXTERNS_H #define JEMALLOC_INTERNAL_PROF_EXTERNS_H +extern malloc_mutex_t bt2gctx_mtx; + extern bool opt_prof; extern bool opt_prof_active; extern bool opt_prof_thread_active_init; diff --git a/src/arena.c b/src/arena.c index 0c12004d..266c85fb 100644 --- a/src/arena.c +++ b/src/arena.c @@ -298,9 +298,9 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, } #define READ_ARENA_MUTEX_PROF_DATA(mtx, data) \ - malloc_mutex_lock(tsdn, &arena->mtx); \ - malloc_lock_prof_read(tsdn, &astats->data, &arena->mtx); \ - malloc_mutex_unlock(tsdn, &arena->mtx); + malloc_mutex_lock(tsdn, &arena->mtx); \ + malloc_lock_prof_read(tsdn, &astats->data, &arena->mtx); \ + malloc_mutex_unlock(tsdn, &arena->mtx); /* Gather per arena mutex profiling data. */ READ_ARENA_MUTEX_PROF_DATA(large_mtx, large_mtx_data) diff --git a/src/ctl.c b/src/ctl.c index 016275e5..c5ef70b5 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -13,6 +13,12 @@ static bool ctl_initialized; static ctl_stats_t *ctl_stats; static ctl_arenas_t *ctl_arenas; +const char *global_lock_names[NUM_GLOBAL_PROF_LOCKS] = { + "base", + "prof", + "ctl" +}; + const char *arena_lock_names[NUM_ARENA_PROF_LOCKS] = { "large", "extent_freelist", @@ -21,6 +27,7 @@ const char *arena_lock_names[NUM_ARENA_PROF_LOCKS] = { "decay", "tcache" }; + const char *lock_counter_names[NUM_LOCK_PROF_COUNTERS] = { "num_ops", "num_wait", @@ -196,16 +203,26 @@ CTL_PROTO(stats_resident) CTL_PROTO(stats_mapped) CTL_PROTO(stats_retained) -#define STATS_LOCKS_CTL_PROTO_GEN(l, n) \ -CTL_PROTO(stats_arenas_i_##l##_##n##_num_ops) \ -CTL_PROTO(stats_arenas_i_##l##_##n##_num_wait) \ -CTL_PROTO(stats_arenas_i_##l##_##n##_num_spin_acq) \ -CTL_PROTO(stats_arenas_i_##l##_##n##_num_owner_switch) \ -CTL_PROTO(stats_arenas_i_##l##_##n##_total_wait_time) \ -CTL_PROTO(stats_arenas_i_##l##_##n##_max_wait_time) \ -CTL_PROTO(stats_arenas_i_##l##_##n##_max_num_thds) - -#define ARENA_LOCKS_CTL_PROTO_GEN(n) STATS_LOCKS_CTL_PROTO_GEN(locks, n) +#define LOCK_STATS_CTL_PROTO_GEN(n) \ +CTL_PROTO(stats_##n##_num_ops) \ +CTL_PROTO(stats_##n##_num_wait) \ +CTL_PROTO(stats_##n##_num_spin_acq) \ +CTL_PROTO(stats_##n##_num_owner_switch) \ +CTL_PROTO(stats_##n##_total_wait_time) \ +CTL_PROTO(stats_##n##_max_wait_time) \ +CTL_PROTO(stats_##n##_max_num_thds) + +/* Global locks. */ +LOCK_STATS_CTL_PROTO_GEN(locks_base) +LOCK_STATS_CTL_PROTO_GEN(locks_prof) +LOCK_STATS_CTL_PROTO_GEN(locks_ctl) + +/* Arena bin locks. */ +LOCK_STATS_CTL_PROTO_GEN(arenas_i_bins_j_lock) + +#define ARENA_LOCKS_CTL_PROTO_GEN(n) \ + LOCK_STATS_CTL_PROTO_GEN(arenas_i_locks_##n) +/* Per arena locks. */ ARENA_LOCKS_CTL_PROTO_GEN(large) ARENA_LOCKS_CTL_PROTO_GEN(extent_freelist) ARENA_LOCKS_CTL_PROTO_GEN(extents_cached) @@ -213,9 +230,7 @@ ARENA_LOCKS_CTL_PROTO_GEN(extents_retained) ARENA_LOCKS_CTL_PROTO_GEN(decay) ARENA_LOCKS_CTL_PROTO_GEN(tcache) #undef ARENA_LOCKS_CTL_PROTO_GEN - -STATS_LOCKS_CTL_PROTO_GEN(bins_j, lock) -#undef STATS_LOCKS_CTL_PROTO_GEN +#undef LOCK_STATS_CTL_PROTO_GEN /******************************************************************************/ /* mallctl tree. */ @@ -384,26 +399,27 @@ static const ctl_named_node_t stats_arenas_i_large_node[] = { {NAME("nrequests"), CTL(stats_arenas_i_large_nrequests)} }; -#define LOCK_PROF_DATA_NODE(prefix, n) \ -static const ctl_named_node_t prefix##_##n##_node[] = { \ +#define LOCK_PROF_DATA_NODE(prefix) \ +static const ctl_named_node_t stats_##prefix##_node[] = { \ {NAME("num_ops"), \ - CTL(prefix##_##n##_num_ops)}, \ + CTL(stats_##prefix##_num_ops)}, \ {NAME("num_wait"), \ - CTL(prefix##_##n##_num_wait)}, \ + CTL(stats_##prefix##_num_wait)}, \ {NAME("num_spin_acq"), \ - CTL(prefix##_##n##_num_spin_acq)}, \ + CTL(stats_##prefix##_num_spin_acq)}, \ {NAME("num_owner_switch"), \ - CTL(prefix##_##n##_num_owner_switch)}, \ + CTL(stats_##prefix##_num_owner_switch)}, \ {NAME("total_wait_time"), \ - CTL(prefix##_##n##_total_wait_time)}, \ + CTL(stats_##prefix##_total_wait_time)}, \ {NAME("max_wait_time"), \ - CTL(prefix##_##n##_max_wait_time)}, \ + CTL(stats_##prefix##_max_wait_time)}, \ {NAME("max_num_thds"), \ - CTL(prefix##_##n##_max_num_thds)} \ + CTL(stats_##prefix##_max_num_thds)} \ /* Note that # of current waiting thread not provided. */ \ }; -LOCK_PROF_DATA_NODE(stats_arenas_i_bins_j, lock) +LOCK_PROF_DATA_NODE(arenas_i_bins_j_lock) + static const ctl_named_node_t stats_arenas_i_bins_j_node[] = { {NAME("nmalloc"), CTL(stats_arenas_i_bins_j_nmalloc)}, {NAME("ndalloc"), CTL(stats_arenas_i_bins_j_ndalloc)}, @@ -439,12 +455,14 @@ static const ctl_indexed_node_t stats_arenas_i_lextents_node[] = { {INDEX(stats_arenas_i_lextents_j)} }; -LOCK_PROF_DATA_NODE(stats_arenas_i_locks, large) -LOCK_PROF_DATA_NODE(stats_arenas_i_locks, extent_freelist) -LOCK_PROF_DATA_NODE(stats_arenas_i_locks, extents_cached) -LOCK_PROF_DATA_NODE(stats_arenas_i_locks, extents_retained) -LOCK_PROF_DATA_NODE(stats_arenas_i_locks, decay) -LOCK_PROF_DATA_NODE(stats_arenas_i_locks, tcache) +#define ARENA_LOCK_PROF_DATA_NODE(n) LOCK_PROF_DATA_NODE(arenas_i_locks_##n) + +ARENA_LOCK_PROF_DATA_NODE(large) +ARENA_LOCK_PROF_DATA_NODE(extent_freelist) +ARENA_LOCK_PROF_DATA_NODE(extents_cached) +ARENA_LOCK_PROF_DATA_NODE(extents_retained) +ARENA_LOCK_PROF_DATA_NODE(decay) +ARENA_LOCK_PROF_DATA_NODE(tcache) static const ctl_named_node_t stats_arenas_i_locks_node[] = { {NAME("large"), CHILD(named, stats_arenas_i_locks_large)}, @@ -457,7 +475,6 @@ static const ctl_named_node_t stats_arenas_i_locks_node[] = { {NAME("decay"), CHILD(named, stats_arenas_i_locks_decay)}, {NAME("tcache"), CHILD(named, stats_arenas_i_locks_tcache)} }; -#undef LOCK_PROF_DATA_NODE static const ctl_named_node_t stats_arenas_i_node[] = { {NAME("nthreads"), CTL(stats_arenas_i_nthreads)}, @@ -493,6 +510,15 @@ static const ctl_indexed_node_t stats_arenas_node[] = { {INDEX(stats_arenas_i)} }; +LOCK_PROF_DATA_NODE(locks_base) +LOCK_PROF_DATA_NODE(locks_prof) +LOCK_PROF_DATA_NODE(locks_ctl) +static const ctl_named_node_t stats_locks_node[] = { + {NAME("base"), CHILD(named, stats_locks_base)}, + {NAME("prof"), CHILD(named, stats_locks_prof)}, + {NAME("ctl"), CHILD(named, stats_locks_ctl)} +}; + static const ctl_named_node_t stats_node[] = { {NAME("allocated"), CTL(stats_allocated)}, {NAME("active"), CTL(stats_active)}, @@ -500,8 +526,10 @@ static const ctl_named_node_t stats_node[] = { {NAME("resident"), CTL(stats_resident)}, {NAME("mapped"), CTL(stats_mapped)}, {NAME("retained"), CTL(stats_retained)}, + {NAME("locks"), CHILD(named, stats_locks)}, {NAME("arenas"), CHILD(indexed, stats_arenas)} }; +#undef LOCK_PROF_DATA_NODE static const ctl_named_node_t root_node[] = { {NAME("version"), CTL(version)}, @@ -925,6 +953,17 @@ ctl_refresh(tsdn_t *tsdn) { &ctl_sarena->astats->astats.mapped, ATOMIC_RELAXED); ctl_stats->retained = atomic_load_zu( &ctl_sarena->astats->astats.retained, ATOMIC_RELAXED); + +#define READ_GLOBAL_MUTEX_PROF_DATA(mtx, data) \ + malloc_mutex_lock(tsdn, &mtx); \ + malloc_lock_prof_read(tsdn, &ctl_stats->data, &mtx); \ + malloc_mutex_unlock(tsdn, &mtx); + + READ_GLOBAL_MUTEX_PROF_DATA(b0get()->mtx, base_mtx_data); + READ_GLOBAL_MUTEX_PROF_DATA(bt2gctx_mtx, prof_mtx_data); + /* We own ctl mutex already. */ + malloc_lock_prof_read(tsdn, &ctl_stats->ctl_mtx_data, &ctl_mtx); +#undef READ_GLOBAL_MUTEX_PROF_DATA } ctl_arenas->epoch++; } @@ -2413,25 +2452,34 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests, uint64_t) /* Intentional. */ /* Lock profiling related APIs below. */ -#define ARENAS_LOCK_CTL_GEN(l, s, d) \ -CTL_RO_CGEN(config_stats, stats_arenas_i_##l##_num_ops, \ - arenas_i(mib[2])->astats->s.d.n_lock_ops, uint64_t) \ -CTL_RO_CGEN(config_stats, stats_arenas_i_##l##_num_wait, \ - arenas_i(mib[2])->astats->s.d.n_wait_times, uint64_t) \ -CTL_RO_CGEN(config_stats, stats_arenas_i_##l##_num_spin_acq, \ - arenas_i(mib[2])->astats->s.d.n_spin_acquired, uint64_t) \ -CTL_RO_CGEN(config_stats, stats_arenas_i_##l##_num_owner_switch, \ - arenas_i(mib[2])->astats->s.d.n_owner_switches, uint64_t) \ -CTL_RO_CGEN(config_stats, stats_arenas_i_##l##_total_wait_time, \ - arenas_i(mib[2])->astats->s.d.tot_wait_time, uint64_t) \ -CTL_RO_CGEN(config_stats, stats_arenas_i_##l##_max_wait_time, \ - arenas_i(mib[2])->astats->s.d.max_wait_time, uint64_t) \ -CTL_RO_CGEN(config_stats, stats_arenas_i_##l##_max_num_thds, \ - arenas_i(mib[2])->astats->s.d.max_n_thds, uint64_t) +#define RO_LOCK_CTL_GEN(n, l) \ +CTL_RO_CGEN(config_stats, stats_##n##_num_ops, \ + l.n_lock_ops, uint64_t) \ +CTL_RO_CGEN(config_stats, stats_##n##_num_wait, \ + l.n_wait_times, uint64_t) \ +CTL_RO_CGEN(config_stats, stats_##n##_num_spin_acq, \ + l.n_spin_acquired, uint64_t) \ +CTL_RO_CGEN(config_stats, stats_##n##_num_owner_switch, \ + l.n_owner_switches, uint64_t) \ +CTL_RO_CGEN(config_stats, stats_##n##_total_wait_time, \ + l.tot_wait_time, uint64_t) \ +CTL_RO_CGEN(config_stats, stats_##n##_max_wait_time, \ + l.max_wait_time, uint64_t) \ +CTL_RO_CGEN(config_stats, stats_##n##_max_num_thds, \ + l.max_n_thds, uint64_t) + +/* Global lock. */ +#define MTX(mutex) RO_LOCK_CTL_GEN(locks_##mutex, ctl_stats->mutex##_mtx_data) +GLOBAL_PROF_MUTEXES +#undef MTX -#define ARENAS_ASTATS_LOCK_CTL_GEN(l, d) \ - ARENAS_LOCK_CTL_GEN(locks_##l, astats, d) +/* arena->bins[j].lock */ +RO_LOCK_CTL_GEN(arenas_i_bins_j_lock, + arenas_i(mib[2])->astats->bstats[mib[4]].lock_data) +/* Per arena locks */ +#define ARENAS_ASTATS_LOCK_CTL_GEN(l, d) \ + RO_LOCK_CTL_GEN(arenas_i_locks_##l, arenas_i(mib[2])->astats->astats.d) /* arena->large_mtx */ ARENAS_ASTATS_LOCK_CTL_GEN(large, large_mtx_data) /* arena->extent_freelist_mtx */ @@ -2444,8 +2492,8 @@ ARENAS_ASTATS_LOCK_CTL_GEN(extents_retained, extents_retained_mtx_data) ARENAS_ASTATS_LOCK_CTL_GEN(decay, decay_mtx_data) /* arena->tcache_ql_mtx */ ARENAS_ASTATS_LOCK_CTL_GEN(tcache, tcache_mtx_data) -/* arena->bins[j].lock */ -ARENAS_LOCK_CTL_GEN(bins_j_lock, bstats[mib[4]], lock_data) +#undef ARENAS_ASTATS_LOCK_CTL_GEN +#undef RO_LOCK_CTL_GEN CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc, arenas_i(mib[2])->astats->bstats[mib[4]].nmalloc, uint64_t) diff --git a/src/prof.c b/src/prof.c index b04984b7..4e83ae3f 100644 --- a/src/prof.c +++ b/src/prof.c @@ -78,7 +78,8 @@ static malloc_mutex_t *tdata_locks; * structure that knows about all backtraces currently captured. */ static ckh_t bt2gctx; -static malloc_mutex_t bt2gctx_mtx; +/* Non static to enable profiling. */ +malloc_mutex_t bt2gctx_mtx; /* * Tree of all extant prof_tdata_t structures, regardless of state, diff --git a/src/stats.c b/src/stats.c index 7b690e7f..89ba6693 100644 --- a/src/stats.c +++ b/src/stats.c @@ -127,6 +127,7 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, CTL_M2_M4_GET("stats.arenas.0.bins.0.curslabs", i, j, &curslabs, size_t); + /* Output less info for bin locks to save space. */ uint64_t num_ops, num_wait, max_wait; CTL_M2_M4_GET("stats.arenas.0.bins.0.lock.num_wait", i, j, &num_wait, uint64_t); @@ -290,8 +291,9 @@ stats_arena_lextents_print(void (*write_cb)(void *, const char *), } static void -gen_ctl_str(char *str, const char *lock, const char *counter) { - sprintf(str, "stats.arenas.0.locks.%s.%s", lock, counter); +gen_lock_ctl_str(char *str, const char *prefix, const char *lock, + const char *counter) { + sprintf(str, "stats.%s.%s.%s", prefix, lock, counter); } static void read_arena_lock_stats(unsigned arena_ind, @@ -301,13 +303,34 @@ static void read_arena_lock_stats(unsigned arena_ind, unsigned i, j; for (i = 0; i < NUM_ARENA_PROF_LOCKS; i++) { for (j = 0; j < NUM_LOCK_PROF_COUNTERS; j++) { - gen_ctl_str(cmd, arena_lock_names[i], - lock_counter_names[j]); + gen_lock_ctl_str(cmd, "arenas.0.locks", + arena_lock_names[i], lock_counter_names[j]); CTL_M2_GET(cmd, arena_ind, &results[i][j], uint64_t); } } } +static void lock_stats_output(void (*write_cb)(void *, const char *), + void *cbopaque, const char *name, uint64_t stats[NUM_LOCK_PROF_COUNTERS], + bool first_mutex) { + if (first_mutex) { + /* Print title. */ + malloc_cprintf(write_cb, cbopaque, + " n_lock_ops n_waiting" + " n_spin_acq n_owner_switch total_wait_ns" + " max_wait_ns max_n_wait_thds\n"); + } + + malloc_cprintf(write_cb, cbopaque, "%s", name); + malloc_cprintf(write_cb, cbopaque, ":%*c", + (int)(19 - strlen(name)), ' '); + + for (unsigned i = 0; i < NUM_LOCK_PROF_COUNTERS; i++) { + malloc_cprintf(write_cb, cbopaque, " %16"FMTu64, stats[i]); + } + malloc_cprintf(write_cb, cbopaque, "\n"); +} + static void stats_arena_locks_print(void (*write_cb)(void *, const char *), void *cbopaque, bool json, unsigned arena_ind) { @@ -318,23 +341,9 @@ stats_arena_locks_print(void (*write_cb)(void *, const char *), if (json) { //TODO } else { - malloc_cprintf(write_cb, cbopaque, - " n_lock_ops n_waiting" - " n_spin_acq n_owner_switch total_wait_ns" - " max_wait_ns max_n_wait_thds\n"); - - unsigned i, j; - for (i = 0; i < NUM_ARENA_PROF_LOCKS; i++) { - malloc_cprintf(write_cb, cbopaque, - "%s", arena_lock_names[i]); - malloc_cprintf(write_cb, cbopaque, ":%*c", - (int)(18 - strlen(arena_lock_names[i])), ' '); - - for (j = 0; j < NUM_LOCK_PROF_COUNTERS; j++) { - malloc_cprintf(write_cb, cbopaque, " %15"FMTu64, - lock_stats[i][j]); - } - malloc_cprintf(write_cb, cbopaque, "\n"); + for (unsigned i = 0; i < NUM_ARENA_PROF_LOCKS; i++) { + lock_stats_output(write_cb, cbopaque, + arena_lock_names[i], lock_stats[i], i == 0); } } @@ -930,6 +939,20 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, } } +static void read_global_lock_stats( + uint64_t results[NUM_GLOBAL_PROF_LOCKS][NUM_LOCK_PROF_COUNTERS]) { + char cmd[128]; + + unsigned i, j; + for (i = 0; i < NUM_GLOBAL_PROF_LOCKS; i++) { + for (j = 0; j < NUM_LOCK_PROF_COUNTERS; j++) { + gen_lock_ctl_str(cmd, "locks", global_lock_names[i], + lock_counter_names[j]); + CTL_GET(cmd, &results[i][j], uint64_t); + } + } +} + static void stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, bool json, bool merged, bool destroyed, bool unmerged, bool bins, @@ -942,6 +965,10 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, CTL_GET("stats.resident", &resident, size_t); CTL_GET("stats.mapped", &mapped, size_t); CTL_GET("stats.retained", &retained, size_t); + + uint64_t lock_stats[NUM_GLOBAL_PROF_LOCKS][NUM_LOCK_PROF_COUNTERS]; + read_global_lock_stats(lock_stats); + if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t\"stats\": {\n"); @@ -966,6 +993,11 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, "Allocated: %zu, active: %zu, metadata: %zu," " resident: %zu, mapped: %zu, retained: %zu\n", allocated, active, metadata, resident, mapped, retained); + + for (unsigned i = 0; i < NUM_GLOBAL_PROF_LOCKS; i++) { + lock_stats_output(write_cb, cbopaque, + global_lock_names[i], lock_stats[i], i == 0); + } } if (merged || destroyed || unmerged) { -- GitLab From bd2006a41bc6b7e1ef60994db88b955eb3ab6cbd Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Sun, 12 Mar 2017 01:28:52 -0800 Subject: [PATCH 348/544] Added JSON output for lock stats. Also added option 'x' to malloc_stats() to bypass lock section. --- doc/jemalloc.xml.in | 3 +- src/ctl.c | 4 +- src/stats.c | 154 +++++++++++++++++++++++++++++----------- test/unit/stats_print.c | 7 +- 4 files changed, 124 insertions(+), 44 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 7faa474d..265da86f 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -430,7 +430,8 @@ for (i = 0; i < nbins; i++) { can be specified to omit merged arena, destroyed merged arena, and per arena statistics, respectively; b and l can be specified to omit per size class statistics for bins and large objects, - respectively. Unrecognized characters are silently ignored. Note that + respectively; x can be specified to omit all mutex + statistics. Unrecognized characters are silently ignored. Note that thread caching may prevent some statistics from being completely up to date, since extra locking would be required to merge counters that track thread cache operations. diff --git a/src/ctl.c b/src/ctl.c index c5ef70b5..a880c63a 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -960,7 +960,9 @@ ctl_refresh(tsdn_t *tsdn) { malloc_mutex_unlock(tsdn, &mtx); READ_GLOBAL_MUTEX_PROF_DATA(b0get()->mtx, base_mtx_data); - READ_GLOBAL_MUTEX_PROF_DATA(bt2gctx_mtx, prof_mtx_data); + if (config_prof && opt_prof) { + READ_GLOBAL_MUTEX_PROF_DATA(bt2gctx_mtx, prof_mtx_data); + } /* We own ctl mutex already. */ malloc_lock_prof_read(tsdn, &ctl_stats->ctl_mtx_data, &ctl_mtx); #undef READ_GLOBAL_MUTEX_PROF_DATA diff --git a/src/stats.c b/src/stats.c index 89ba6693..b6f2124a 100644 --- a/src/stats.c +++ b/src/stats.c @@ -57,6 +57,25 @@ get_rate_str(uint64_t dividend, uint64_t divisor, char str[6]) { return false; } +static void +gen_lock_ctl_str(char *str, const char *prefix, const char *lock, + const char *counter) { + sprintf(str, "stats.%s.%s.%s", prefix, lock, counter); +} + +static void +read_arena_bin_lock_stats(unsigned arena_ind, unsigned bin_ind, + uint64_t results[NUM_LOCK_PROF_COUNTERS]) { + char cmd[128]; + + unsigned i; + for (i = 0; i < NUM_LOCK_PROF_COUNTERS; i++) { + gen_lock_ctl_str(cmd, "arenas.0.bins.0","lock", + lock_counter_names[i]); + CTL_M2_M4_GET(cmd, arena_ind, bin_ind, &results[i], uint64_t); + } +} + static void stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, bool json, bool large, unsigned i) { @@ -127,16 +146,10 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, CTL_M2_M4_GET("stats.arenas.0.bins.0.curslabs", i, j, &curslabs, size_t); - /* Output less info for bin locks to save space. */ - uint64_t num_ops, num_wait, max_wait; - CTL_M2_M4_GET("stats.arenas.0.bins.0.lock.num_wait", i, j, - &num_wait, uint64_t); - CTL_M2_M4_GET("stats.arenas.0.bins.0.lock.max_wait_time", i, j, - &max_wait, uint64_t); - CTL_M2_M4_GET("stats.arenas.0.bins.0.lock.num_ops", i, j, - &num_ops, uint64_t); - if (json) { + uint64_t lock_stats[NUM_LOCK_PROF_COUNTERS]; + read_arena_bin_lock_stats(i, j, lock_stats); + malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\t{\n" "\t\t\t\t\t\t\"nmalloc\": %"FMTu64",\n" @@ -156,10 +169,21 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, } malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\t\t\"nreslabs\": %"FMTu64",\n" - "\t\t\t\t\t\t\"curslabs\": %zu\n" - "\t\t\t\t\t}%s\n", + "\t\t\t\t\t\t\"curslabs\": %zu,\n" + "\t\t\t\t\t\t\"lock\": {\n", nreslabs, - curslabs, + curslabs); + + for (unsigned k = 0; k < NUM_LOCK_PROF_COUNTERS; k++) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\t\t\"%s\": %"FMTu64"%s\n", + lock_counter_names[k], lock_stats[k], + k == NUM_LOCK_PROF_COUNTERS - 1 ? "" : ","); + } + + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\t}\n" + "\t\t\t\t\t}%s\n", (j + 1 < nbins) ? "," : ""); } else if (!in_gap) { size_t availregs = nregs * curslabs; @@ -183,6 +207,16 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, not_reached(); } } + /* Output less info for bin locks to save space. */ + uint64_t num_ops, num_wait, max_wait; + CTL_M2_M4_GET("stats.arenas.0.bins.0.lock.num_wait", + i, j, &num_wait, uint64_t); + CTL_M2_M4_GET( + "stats.arenas.0.bins.0.lock.max_wait_time", i, j, + &max_wait, uint64_t); + CTL_M2_M4_GET("stats.arenas.0.bins.0.lock.num_ops", + i, j, &num_ops, uint64_t); + char rate[6]; if (get_rate_str(num_wait, num_ops, rate)) { if (num_ops == 0) { @@ -291,12 +325,7 @@ stats_arena_lextents_print(void (*write_cb)(void *, const char *), } static void -gen_lock_ctl_str(char *str, const char *prefix, const char *lock, - const char *counter) { - sprintf(str, "stats.%s.%s.%s", prefix, lock, counter); -} - -static void read_arena_lock_stats(unsigned arena_ind, +read_arena_lock_stats(unsigned arena_ind, uint64_t results[NUM_ARENA_PROF_LOCKS][NUM_LOCK_PROF_COUNTERS]) { char cmd[128]; @@ -310,8 +339,24 @@ static void read_arena_lock_stats(unsigned arena_ind, } } -static void lock_stats_output(void (*write_cb)(void *, const char *), - void *cbopaque, const char *name, uint64_t stats[NUM_LOCK_PROF_COUNTERS], +static void +lock_stats_output_json(void (*write_cb)(void *, const char *), void *cbopaque, + const char *name, uint64_t stats[NUM_LOCK_PROF_COUNTERS], + const char *json_indent, bool last) { + + malloc_cprintf(write_cb, cbopaque, "%s\"%s\": {\n", json_indent, name); + for (unsigned i = 0; i < NUM_LOCK_PROF_COUNTERS; i++) { + malloc_cprintf(write_cb, cbopaque, "%s\t\"%s\": %"FMTu64"%s\n", + json_indent, lock_counter_names[i], stats[i], + i < (NUM_LOCK_PROF_COUNTERS - 1) ? "," : ""); + } + malloc_cprintf(write_cb, cbopaque, "%s}%s\n", json_indent, + last ? "" : ","); +} + +static void +lock_stats_output(void (*write_cb)(void *, const char *), void *cbopaque, + const char *name, uint64_t stats[NUM_LOCK_PROF_COUNTERS], bool first_mutex) { if (first_mutex) { /* Print title. */ @@ -333,25 +378,31 @@ static void lock_stats_output(void (*write_cb)(void *, const char *), static void stats_arena_locks_print(void (*write_cb)(void *, const char *), - void *cbopaque, bool json, unsigned arena_ind) { + void *cbopaque, bool json, bool json_end, unsigned arena_ind) { uint64_t lock_stats[NUM_ARENA_PROF_LOCKS][NUM_LOCK_PROF_COUNTERS]; read_arena_lock_stats(arena_ind, lock_stats); /* Output lock stats. */ if (json) { - //TODO + malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\"locks\": {\n"); + for (unsigned i = 0; i < NUM_ARENA_PROF_LOCKS; i++) { + lock_stats_output_json(write_cb, cbopaque, + arena_lock_names[i], lock_stats[i], + "\t\t\t\t\t", (i == NUM_ARENA_PROF_LOCKS - 1)); + } + malloc_cprintf(write_cb, cbopaque, "\t\t\t\t}%s\n", + json_end ? "" : ","); } else { for (unsigned i = 0; i < NUM_ARENA_PROF_LOCKS; i++) { lock_stats_output(write_cb, cbopaque, arena_lock_names[i], lock_stats[i], i == 0); } } - } static void stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, - bool json, unsigned i, bool bins, bool large) { + bool json, unsigned i, bool bins, bool large, bool lock) { unsigned nthreads; const char *dss; ssize_t dirty_decay_time, muzzy_decay_time; @@ -573,14 +624,17 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, CTL_M2_GET("stats.arenas.0.resident", i, &resident, size_t); if (json) { malloc_cprintf(write_cb, cbopaque, - "\t\t\t\t\"resident\": %zu%s\n", resident, (bins || large) ? - "," : ""); + "\t\t\t\t\"resident\": %zu%s\n", resident, + (bins || large || lock) ? "," : ""); } else { malloc_cprintf(write_cb, cbopaque, "resident: %12zu\n", resident); } - stats_arena_locks_print(write_cb, cbopaque, json, i); + if (lock) { + stats_arena_locks_print(write_cb, cbopaque, json, + !(bins || large), i); + } if (bins) { stats_arena_bins_print(write_cb, cbopaque, json, large, i); } @@ -956,7 +1010,7 @@ static void read_global_lock_stats( static void stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, bool json, bool merged, bool destroyed, bool unmerged, bool bins, - bool large) { + bool large, bool lock) { size_t allocated, active, metadata, resident, mapped, retained; CTL_GET("stats.allocated", &allocated, size_t); @@ -967,7 +1021,9 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, CTL_GET("stats.retained", &retained, size_t); uint64_t lock_stats[NUM_GLOBAL_PROF_LOCKS][NUM_LOCK_PROF_COUNTERS]; - read_global_lock_stats(lock_stats); + if (lock) { + read_global_lock_stats(lock_stats); + } if (json) { malloc_cprintf(write_cb, cbopaque, @@ -984,19 +1040,31 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "\t\t\t\"mapped\": %zu,\n", mapped); malloc_cprintf(write_cb, cbopaque, - "\t\t\t\"retained\": %zu\n", retained); + "\t\t\t\"retained\": %zu,\n", retained); + if (lock) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"locks\": {\n"); + for (unsigned i = 0; i < NUM_GLOBAL_PROF_LOCKS; i++) { + lock_stats_output_json(write_cb, cbopaque, + global_lock_names[i], lock_stats[i], + "\t\t\t\t", i == NUM_GLOBAL_PROF_LOCKS - 1); + } + malloc_cprintf(write_cb, cbopaque, "\t\t\t}\n"); + } malloc_cprintf(write_cb, cbopaque, - "\t\t}%s\n", (merged || unmerged) ? "," : ""); + "\t\t}%s\n", (merged || unmerged || destroyed) ? "," : ""); } else { malloc_cprintf(write_cb, cbopaque, "Allocated: %zu, active: %zu, metadata: %zu," " resident: %zu, mapped: %zu, retained: %zu\n", allocated, active, metadata, resident, mapped, retained); - - for (unsigned i = 0; i < NUM_GLOBAL_PROF_LOCKS; i++) { - lock_stats_output(write_cb, cbopaque, - global_lock_names[i], lock_stats[i], i == 0); + if (lock) { + for (unsigned i = 0; i < NUM_GLOBAL_PROF_LOCKS; i++) { + lock_stats_output(write_cb, cbopaque, + global_lock_names[i], lock_stats[i], + i == 0); + } } } @@ -1043,7 +1111,7 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, "\nMerged arenas stats:\n"); } stats_arena_print(write_cb, cbopaque, json, - MALLCTL_ARENAS_ALL, bins, large); + MALLCTL_ARENAS_ALL, bins, large, lock); if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t\t}%s\n", @@ -1064,7 +1132,8 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, "\nDestroyed arenas stats:\n"); } stats_arena_print(write_cb, cbopaque, json, - MALLCTL_ARENAS_DESTROYED, bins, large); + MALLCTL_ARENAS_DESTROYED, bins, large, + lock); if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t\t}%s\n", unmerged ? "," : @@ -1090,7 +1159,7 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, } stats_arena_print(write_cb, cbopaque, json, i, bins, - large); + large, lock); if (json) { malloc_cprintf(write_cb, cbopaque, @@ -1123,6 +1192,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, bool unmerged = config_stats; bool bins = true; bool large = true; + bool lock = true; /* * Refresh stats, in case mallctl() was called by the application. @@ -1172,6 +1242,9 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, case 'l': large = false; break; + case 'x': + lock = false; + break; default:; } } @@ -1187,12 +1260,11 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, } if (general) { - bool more = (merged || unmerged); - stats_general_print(write_cb, cbopaque, json, more); + stats_general_print(write_cb, cbopaque, json, config_stats); } if (config_stats) { stats_print_helper(write_cb, cbopaque, json, merged, destroyed, - unmerged, bins, large); + unmerged, bins, large, lock); } if (json) { diff --git a/test/unit/stats_print.c b/test/unit/stats_print.c index f0437891..81778b04 100644 --- a/test/unit/stats_print.c +++ b/test/unit/stats_print.c @@ -938,11 +938,16 @@ TEST_BEGIN(test_stats_print_json) { "Ja", "Jb", "Jl", + "Jx", "Jbl", "Jal", "Jab", "Jabl", - "Jgmdabl", + "Jax", + "Jbx", + "Jlx", + "Jablx", + "Jgmdablx", }; unsigned arena_ind, i; -- GitLab From 64c5f5c17437ea618a2c1a5fe72814c51c46853e Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 13 Mar 2017 17:29:03 -0700 Subject: [PATCH 349/544] Added "stats.mutexes.reset" mallctl to reset all mutex stats. Also switched from the term "lock" to "mutex". --- include/jemalloc/internal/ctl_externs.h | 12 +- include/jemalloc/internal/ctl_structs.h | 4 +- include/jemalloc/internal/mutex_externs.h | 1 + include/jemalloc/internal/mutex_inlines.h | 14 +- include/jemalloc/internal/mutex_structs.h | 20 +- include/jemalloc/internal/mutex_types.h | 2 +- include/jemalloc/internal/private_symbols.txt | 1 + include/jemalloc/internal/stats_structs.h | 14 +- src/arena.c | 6 +- src/ctl.c | 204 +++++++++++------- src/mutex.c | 14 +- src/stats.c | 147 ++++++------- 12 files changed, 250 insertions(+), 189 deletions(-) diff --git a/include/jemalloc/internal/ctl_externs.h b/include/jemalloc/internal/ctl_externs.h index 33ca2039..1b06dd4d 100644 --- a/include/jemalloc/internal/ctl_externs.h +++ b/include/jemalloc/internal/ctl_externs.h @@ -4,13 +4,13 @@ /* Maximum ctl tree depth. */ #define CTL_MAX_DEPTH 7 -#define NUM_GLOBAL_PROF_LOCKS 3 -#define NUM_ARENA_PROF_LOCKS 6 -#define NUM_LOCK_PROF_COUNTERS 7 +#define NUM_GLOBAL_PROF_MUTEXES 3 +#define NUM_ARENA_PROF_MUTEXES 6 +#define NUM_MUTEX_PROF_COUNTERS 7 -extern const char *arena_lock_names[NUM_ARENA_PROF_LOCKS]; -extern const char *global_lock_names[NUM_GLOBAL_PROF_LOCKS]; -extern const char *lock_counter_names[NUM_LOCK_PROF_COUNTERS]; +extern const char *arena_mutex_names[NUM_ARENA_PROF_MUTEXES]; +extern const char *global_mutex_names[NUM_GLOBAL_PROF_MUTEXES]; +extern const char *mutex_counter_names[NUM_MUTEX_PROF_COUNTERS]; int ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen); diff --git a/include/jemalloc/internal/ctl_structs.h b/include/jemalloc/internal/ctl_structs.h index e467a247..b1ee3555 100644 --- a/include/jemalloc/internal/ctl_structs.h +++ b/include/jemalloc/internal/ctl_structs.h @@ -42,8 +42,8 @@ struct ctl_stats_s { size_t mapped; size_t retained; -#define MTX(mutex) lock_prof_data_t mutex##_mtx_data; -GLOBAL_PROF_MUTEXES +#define MTX(mutex) mutex_prof_data_t mutex##_mtx_data; + GLOBAL_PROF_MUTEXES #undef MTX }; diff --git a/include/jemalloc/internal/mutex_externs.h b/include/jemalloc/internal/mutex_externs.h index ba6418ef..5199d3cf 100644 --- a/include/jemalloc/internal/mutex_externs.h +++ b/include/jemalloc/internal/mutex_externs.h @@ -14,5 +14,6 @@ void malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex); void malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex); void malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex); bool malloc_mutex_boot(void); +void malloc_mutex_prof_data_reset(tsdn_t *tsdn, malloc_mutex_t *mutex); #endif /* JEMALLOC_INTERNAL_MUTEX_EXTERNS_H */ diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index 1020eefd..d4703d23 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -9,9 +9,9 @@ bool malloc_mutex_trylock(malloc_mutex_t *mutex); void malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex); void malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); void malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); -void malloc_lock_prof_read(tsdn_t *tsdn, lock_prof_data_t *data, +void malloc_mutex_prof_read(tsdn_t *tsdn, mutex_prof_data_t *data, malloc_mutex_t *mutex); -void malloc_lock_prof_merge(lock_prof_data_t *sum, lock_prof_data_t *data); +void malloc_mutex_prof_merge(mutex_prof_data_t *sum, mutex_prof_data_t *data); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) @@ -28,7 +28,7 @@ malloc_mutex_trylock(malloc_mutex_t *mutex) { /* Aggregate lock prof data. */ JEMALLOC_INLINE void -malloc_lock_prof_merge(lock_prof_data_t *sum, lock_prof_data_t *data) { +malloc_mutex_prof_merge(mutex_prof_data_t *sum, mutex_prof_data_t *data) { sum->tot_wait_time += data->tot_wait_time; if (data->max_wait_time > sum->max_wait_time) { sum->max_wait_time = data->max_wait_time; @@ -52,7 +52,7 @@ malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) { malloc_mutex_lock_slow(mutex); } /* We own the lock now. Update a few counters. */ - lock_prof_data_t *data = &mutex->prof_data; + mutex_prof_data_t *data = &mutex->prof_data; data->n_lock_ops++; if (data->prev_owner != tsdn) { data->prev_owner = tsdn; @@ -82,10 +82,10 @@ malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { /* Copy the prof data from mutex for processing. */ JEMALLOC_INLINE void -malloc_lock_prof_read(tsdn_t *tsdn, lock_prof_data_t *data, +malloc_mutex_prof_read(tsdn_t *tsdn, mutex_prof_data_t *data, malloc_mutex_t *mutex) { - lock_prof_data_t *source = &mutex->prof_data; - /* Can only read with the lock. */ + mutex_prof_data_t *source = &mutex->prof_data; + /* Can only read holding the mutex. */ malloc_mutex_assert_owner(tsdn, mutex); *data = *source; diff --git a/include/jemalloc/internal/mutex_structs.h b/include/jemalloc/internal/mutex_structs.h index ce80e15d..8d6e7eb2 100644 --- a/include/jemalloc/internal/mutex_structs.h +++ b/include/jemalloc/internal/mutex_structs.h @@ -1,20 +1,20 @@ #ifndef JEMALLOC_INTERNAL_MUTEX_STRUCTS_H #define JEMALLOC_INTERNAL_MUTEX_STRUCTS_H -struct lock_prof_data_s { +struct mutex_prof_data_s { /* * Counters touched on the slow path, i.e. when there is lock * contention. We update them once we have the lock. */ - /* Total time (in nano seconds) spent waiting on this lock. */ + /* Total time (in nano seconds) spent waiting on this mutex. */ uint64_t tot_wait_time; /* Max time (in nano seconds) spent on a single lock operation. */ uint64_t max_wait_time; - /* # of times have to wait for this lock (after spinning). */ + /* # of times have to wait for this mutex (after spinning). */ uint64_t n_wait_times; - /* # of times acquired the lock through local spinning. */ + /* # of times acquired the mutex through local spinning. */ uint64_t n_spin_acquired; - /* Max # of threads waiting for the lock at the same time. */ + /* Max # of threads waiting for the mutex at the same time. */ uint32_t max_n_thds; /* Current # of threads waiting on the lock. Atomic synced. */ uint32_t n_waiting_thds; @@ -25,9 +25,9 @@ struct lock_prof_data_s { * the lock) so that we have a higher chance of them being on the same * cacheline. */ - /* # of times the new lock holder is different from the previous one. */ + /* # of times the mutex holder is different than the previous one. */ uint64_t n_owner_switches; - /* Previous lock holder, to facilitate n_owner_switches. */ + /* Previous mutex holder, to facilitate n_owner_switches. */ tsdn_t *prev_owner; /* # of lock() operations in total. */ uint64_t n_lock_ops; @@ -38,13 +38,13 @@ struct malloc_mutex_s { struct { /* * prof_data is defined first to reduce cacheline - * bouncing: the data is not touched by the lock holder + * bouncing: the data is not touched by the mutex holder * during unlocking, while might be modified by - * contenders. Having it before the lock itself could + * contenders. Having it before the mutex itself could * avoid prefetching a modified cacheline (for the * unlocking thread). */ - lock_prof_data_t prof_data; + mutex_prof_data_t prof_data; #ifdef _WIN32 # if _WIN32_WINNT >= 0x0600 SRWLOCK lock; diff --git a/include/jemalloc/internal/mutex_types.h b/include/jemalloc/internal/mutex_types.h index 0d93fe87..257f69ca 100644 --- a/include/jemalloc/internal/mutex_types.h +++ b/include/jemalloc/internal/mutex_types.h @@ -1,7 +1,7 @@ #ifndef JEMALLOC_INTERNAL_MUTEX_TYPES_H #define JEMALLOC_INTERNAL_MUTEX_TYPES_H -typedef struct lock_prof_data_s lock_prof_data_t; +typedef struct mutex_prof_data_s mutex_prof_data_t; typedef struct malloc_mutex_s malloc_mutex_t; #ifdef _WIN32 diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 3c5a21b5..1af1f91b 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -269,6 +269,7 @@ lg_floor lg_prof_sample malloc_cprintf malloc_getcpu +malloc_mutex_prof_data_reset malloc_mutex_assert_not_owner malloc_mutex_assert_owner malloc_mutex_boot diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index 0e33394b..601c8512 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -57,7 +57,7 @@ struct malloc_bin_stats_s { /* Current number of slabs in this bin. */ size_t curslabs; - lock_prof_data_t lock_data; + mutex_prof_data_t mutex_data; }; struct malloc_large_stats_s { @@ -124,12 +124,12 @@ struct arena_stats_s { /* Number of bytes cached in tcache associated with this arena. */ atomic_zu_t tcache_bytes; /* Derived. */ - lock_prof_data_t large_mtx_data; - lock_prof_data_t extent_freelist_mtx_data; - lock_prof_data_t extents_cached_mtx_data; - lock_prof_data_t extents_retained_mtx_data; - lock_prof_data_t decay_mtx_data; - lock_prof_data_t tcache_mtx_data; + mutex_prof_data_t large_mtx_data; + mutex_prof_data_t extent_freelist_mtx_data; + mutex_prof_data_t extents_cached_mtx_data; + mutex_prof_data_t extents_retained_mtx_data; + mutex_prof_data_t decay_mtx_data; + mutex_prof_data_t tcache_mtx_data; /* One element for each large size class. */ malloc_large_stats_t lstats[NSIZES - NBINS]; diff --git a/src/arena.c b/src/arena.c index 266c85fb..57b79c52 100644 --- a/src/arena.c +++ b/src/arena.c @@ -292,14 +292,14 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, tbin->ncached * index2size(i)); } } - malloc_lock_prof_read(tsdn, &astats->tcache_mtx_data, + malloc_mutex_prof_read(tsdn, &astats->tcache_mtx_data, &arena->tcache_ql_mtx); malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx); } #define READ_ARENA_MUTEX_PROF_DATA(mtx, data) \ malloc_mutex_lock(tsdn, &arena->mtx); \ - malloc_lock_prof_read(tsdn, &astats->data, &arena->mtx); \ + malloc_mutex_prof_read(tsdn, &astats->data, &arena->mtx); \ malloc_mutex_unlock(tsdn, &arena->mtx); /* Gather per arena mutex profiling data. */ @@ -317,7 +317,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, arena_bin_t *bin = &arena->bins[i]; malloc_mutex_lock(tsdn, &bin->lock); - malloc_lock_prof_read(tsdn, &bstats[i].lock_data, &bin->lock); + malloc_mutex_prof_read(tsdn, &bstats[i].mutex_data, &bin->lock); bstats[i].nmalloc += bin->stats.nmalloc; bstats[i].ndalloc += bin->stats.ndalloc; bstats[i].nrequests += bin->stats.nrequests; diff --git a/src/ctl.c b/src/ctl.c index a880c63a..b2b9e7d9 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -13,13 +13,13 @@ static bool ctl_initialized; static ctl_stats_t *ctl_stats; static ctl_arenas_t *ctl_arenas; -const char *global_lock_names[NUM_GLOBAL_PROF_LOCKS] = { +const char *global_mutex_names[NUM_GLOBAL_PROF_MUTEXES] = { "base", "prof", "ctl" }; -const char *arena_lock_names[NUM_ARENA_PROF_LOCKS] = { +const char *arena_mutex_names[NUM_ARENA_PROF_MUTEXES] = { "large", "extent_freelist", "extents_cached", @@ -28,7 +28,7 @@ const char *arena_lock_names[NUM_ARENA_PROF_LOCKS] = { "tcache" }; -const char *lock_counter_names[NUM_LOCK_PROF_COUNTERS] = { +const char *mutex_counter_names[NUM_MUTEX_PROF_COUNTERS] = { "num_ops", "num_wait", "num_spin_acq", @@ -203,7 +203,7 @@ CTL_PROTO(stats_resident) CTL_PROTO(stats_mapped) CTL_PROTO(stats_retained) -#define LOCK_STATS_CTL_PROTO_GEN(n) \ +#define MUTEX_STATS_CTL_PROTO_GEN(n) \ CTL_PROTO(stats_##n##_num_ops) \ CTL_PROTO(stats_##n##_num_wait) \ CTL_PROTO(stats_##n##_num_spin_acq) \ @@ -212,25 +212,27 @@ CTL_PROTO(stats_##n##_total_wait_time) \ CTL_PROTO(stats_##n##_max_wait_time) \ CTL_PROTO(stats_##n##_max_num_thds) -/* Global locks. */ -LOCK_STATS_CTL_PROTO_GEN(locks_base) -LOCK_STATS_CTL_PROTO_GEN(locks_prof) -LOCK_STATS_CTL_PROTO_GEN(locks_ctl) - -/* Arena bin locks. */ -LOCK_STATS_CTL_PROTO_GEN(arenas_i_bins_j_lock) - -#define ARENA_LOCKS_CTL_PROTO_GEN(n) \ - LOCK_STATS_CTL_PROTO_GEN(arenas_i_locks_##n) -/* Per arena locks. */ -ARENA_LOCKS_CTL_PROTO_GEN(large) -ARENA_LOCKS_CTL_PROTO_GEN(extent_freelist) -ARENA_LOCKS_CTL_PROTO_GEN(extents_cached) -ARENA_LOCKS_CTL_PROTO_GEN(extents_retained) -ARENA_LOCKS_CTL_PROTO_GEN(decay) -ARENA_LOCKS_CTL_PROTO_GEN(tcache) -#undef ARENA_LOCKS_CTL_PROTO_GEN -#undef LOCK_STATS_CTL_PROTO_GEN +/* Global mutexes. */ +MUTEX_STATS_CTL_PROTO_GEN(mutexes_base) +MUTEX_STATS_CTL_PROTO_GEN(mutexes_prof) +MUTEX_STATS_CTL_PROTO_GEN(mutexes_ctl) + +/* Arena bin mutexes. */ +MUTEX_STATS_CTL_PROTO_GEN(arenas_i_bins_j_mutex) + +#define ARENA_MUTEXES_CTL_PROTO_GEN(n) \ + MUTEX_STATS_CTL_PROTO_GEN(arenas_i_mutexes_##n) +/* Per arena mutexes. */ +ARENA_MUTEXES_CTL_PROTO_GEN(large) +ARENA_MUTEXES_CTL_PROTO_GEN(extent_freelist) +ARENA_MUTEXES_CTL_PROTO_GEN(extents_cached) +ARENA_MUTEXES_CTL_PROTO_GEN(extents_retained) +ARENA_MUTEXES_CTL_PROTO_GEN(decay) +ARENA_MUTEXES_CTL_PROTO_GEN(tcache) +#undef ARENA_MUTEXES_CTL_PROTO_GEN +#undef MUTEX_STATS_CTL_PROTO_GEN + +CTL_PROTO(stats_mutexes_reset) /******************************************************************************/ /* mallctl tree. */ @@ -399,7 +401,7 @@ static const ctl_named_node_t stats_arenas_i_large_node[] = { {NAME("nrequests"), CTL(stats_arenas_i_large_nrequests)} }; -#define LOCK_PROF_DATA_NODE(prefix) \ +#define MUTEX_PROF_DATA_NODE(prefix) \ static const ctl_named_node_t stats_##prefix##_node[] = { \ {NAME("num_ops"), \ CTL(stats_##prefix##_num_ops)}, \ @@ -418,7 +420,7 @@ static const ctl_named_node_t stats_##prefix##_node[] = { \ /* Note that # of current waiting thread not provided. */ \ }; -LOCK_PROF_DATA_NODE(arenas_i_bins_j_lock) +MUTEX_PROF_DATA_NODE(arenas_i_bins_j_mutex) static const ctl_named_node_t stats_arenas_i_bins_j_node[] = { {NAME("nmalloc"), CTL(stats_arenas_i_bins_j_nmalloc)}, @@ -430,7 +432,7 @@ static const ctl_named_node_t stats_arenas_i_bins_j_node[] = { {NAME("nslabs"), CTL(stats_arenas_i_bins_j_nslabs)}, {NAME("nreslabs"), CTL(stats_arenas_i_bins_j_nreslabs)}, {NAME("curslabs"), CTL(stats_arenas_i_bins_j_curslabs)}, - {NAME("lock"), CHILD(named, stats_arenas_i_bins_j_lock)} + {NAME("mutex"), CHILD(named, stats_arenas_i_bins_j_mutex)} }; static const ctl_named_node_t super_stats_arenas_i_bins_j_node[] = { @@ -455,25 +457,25 @@ static const ctl_indexed_node_t stats_arenas_i_lextents_node[] = { {INDEX(stats_arenas_i_lextents_j)} }; -#define ARENA_LOCK_PROF_DATA_NODE(n) LOCK_PROF_DATA_NODE(arenas_i_locks_##n) +#define ARENA_MUTEX_PROF_DATA_NODE(n) MUTEX_PROF_DATA_NODE(arenas_i_mutexes_##n) -ARENA_LOCK_PROF_DATA_NODE(large) -ARENA_LOCK_PROF_DATA_NODE(extent_freelist) -ARENA_LOCK_PROF_DATA_NODE(extents_cached) -ARENA_LOCK_PROF_DATA_NODE(extents_retained) -ARENA_LOCK_PROF_DATA_NODE(decay) -ARENA_LOCK_PROF_DATA_NODE(tcache) +ARENA_MUTEX_PROF_DATA_NODE(large) +ARENA_MUTEX_PROF_DATA_NODE(extent_freelist) +ARENA_MUTEX_PROF_DATA_NODE(extents_cached) +ARENA_MUTEX_PROF_DATA_NODE(extents_retained) +ARENA_MUTEX_PROF_DATA_NODE(decay) +ARENA_MUTEX_PROF_DATA_NODE(tcache) -static const ctl_named_node_t stats_arenas_i_locks_node[] = { - {NAME("large"), CHILD(named, stats_arenas_i_locks_large)}, +static const ctl_named_node_t stats_arenas_i_mutexes_node[] = { + {NAME("large"), CHILD(named, stats_arenas_i_mutexes_large)}, {NAME("extent_freelist"), - CHILD(named, stats_arenas_i_locks_extent_freelist)}, + CHILD(named, stats_arenas_i_mutexes_extent_freelist)}, {NAME("extents_cached"), - CHILD(named, stats_arenas_i_locks_extents_cached)}, + CHILD(named, stats_arenas_i_mutexes_extents_cached)}, {NAME("extents_retained"), - CHILD(named, stats_arenas_i_locks_extents_retained)}, - {NAME("decay"), CHILD(named, stats_arenas_i_locks_decay)}, - {NAME("tcache"), CHILD(named, stats_arenas_i_locks_tcache)} + CHILD(named, stats_arenas_i_mutexes_extents_retained)}, + {NAME("decay"), CHILD(named, stats_arenas_i_mutexes_decay)}, + {NAME("tcache"), CHILD(named, stats_arenas_i_mutexes_tcache)} }; static const ctl_named_node_t stats_arenas_i_node[] = { @@ -500,7 +502,7 @@ static const ctl_named_node_t stats_arenas_i_node[] = { {NAME("large"), CHILD(named, stats_arenas_i_large)}, {NAME("bins"), CHILD(indexed, stats_arenas_i_bins)}, {NAME("lextents"), CHILD(indexed, stats_arenas_i_lextents)}, - {NAME("locks"), CHILD(named, stats_arenas_i_locks)} + {NAME("mutexes"), CHILD(named, stats_arenas_i_mutexes)} }; static const ctl_named_node_t super_stats_arenas_i_node[] = { {NAME(""), CHILD(named, stats_arenas_i)} @@ -510,13 +512,14 @@ static const ctl_indexed_node_t stats_arenas_node[] = { {INDEX(stats_arenas_i)} }; -LOCK_PROF_DATA_NODE(locks_base) -LOCK_PROF_DATA_NODE(locks_prof) -LOCK_PROF_DATA_NODE(locks_ctl) -static const ctl_named_node_t stats_locks_node[] = { - {NAME("base"), CHILD(named, stats_locks_base)}, - {NAME("prof"), CHILD(named, stats_locks_prof)}, - {NAME("ctl"), CHILD(named, stats_locks_ctl)} +MUTEX_PROF_DATA_NODE(mutexes_base) +MUTEX_PROF_DATA_NODE(mutexes_prof) +MUTEX_PROF_DATA_NODE(mutexes_ctl) +static const ctl_named_node_t stats_mutexes_node[] = { + {NAME("base"), CHILD(named, stats_mutexes_base)}, + {NAME("prof"), CHILD(named, stats_mutexes_prof)}, + {NAME("ctl"), CHILD(named, stats_mutexes_ctl)}, + {NAME("reset"), CTL(stats_mutexes_reset)} }; static const ctl_named_node_t stats_node[] = { @@ -526,10 +529,10 @@ static const ctl_named_node_t stats_node[] = { {NAME("resident"), CTL(stats_resident)}, {NAME("mapped"), CTL(stats_mapped)}, {NAME("retained"), CTL(stats_retained)}, - {NAME("locks"), CHILD(named, stats_locks)}, + {NAME("mutexes"), CHILD(named, stats_mutexes)}, {NAME("arenas"), CHILD(indexed, stats_arenas)} }; -#undef LOCK_PROF_DATA_NODE +#undef MUTEX_PROF_DATA_NODE static const ctl_named_node_t root_node[] = { {NAME("version"), CTL(version)}, @@ -768,20 +771,20 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, accum_arena_stats_u64(&sdstats->astats.decay_muzzy.purged, &astats->astats.decay_muzzy.purged); - malloc_lock_prof_merge(&(sdstats->astats.large_mtx_data), + malloc_mutex_prof_merge(&(sdstats->astats.large_mtx_data), &(astats->astats.large_mtx_data)); - malloc_lock_prof_merge( + malloc_mutex_prof_merge( &(sdstats->astats.extent_freelist_mtx_data), &(astats->astats.extent_freelist_mtx_data)); - malloc_lock_prof_merge( + malloc_mutex_prof_merge( &(sdstats->astats.extents_cached_mtx_data), &(astats->astats.extents_cached_mtx_data)); - malloc_lock_prof_merge( + malloc_mutex_prof_merge( &(sdstats->astats.extents_retained_mtx_data), &(astats->astats.extents_retained_mtx_data)); - malloc_lock_prof_merge(&(sdstats->astats.decay_mtx_data), + malloc_mutex_prof_merge(&(sdstats->astats.decay_mtx_data), &(astats->astats.decay_mtx_data)); - malloc_lock_prof_merge(&(sdstats->astats.tcache_mtx_data), + malloc_mutex_prof_merge(&(sdstats->astats.tcache_mtx_data), &(astats->astats.tcache_mtx_data)); if (!destroyed) { @@ -849,8 +852,8 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, } else { assert(astats->bstats[i].curslabs == 0); } - malloc_lock_prof_merge(&sdstats->bstats[i].lock_data, - &astats->bstats[i].lock_data); + malloc_mutex_prof_merge(&sdstats->bstats[i].mutex_data, + &astats->bstats[i].mutex_data); } for (i = 0; i < NSIZES - NBINS; i++) { @@ -956,7 +959,7 @@ ctl_refresh(tsdn_t *tsdn) { #define READ_GLOBAL_MUTEX_PROF_DATA(mtx, data) \ malloc_mutex_lock(tsdn, &mtx); \ - malloc_lock_prof_read(tsdn, &ctl_stats->data, &mtx); \ + malloc_mutex_prof_read(tsdn, &ctl_stats->data, &mtx); \ malloc_mutex_unlock(tsdn, &mtx); READ_GLOBAL_MUTEX_PROF_DATA(b0get()->mtx, base_mtx_data); @@ -964,7 +967,7 @@ ctl_refresh(tsdn_t *tsdn) { READ_GLOBAL_MUTEX_PROF_DATA(bt2gctx_mtx, prof_mtx_data); } /* We own ctl mutex already. */ - malloc_lock_prof_read(tsdn, &ctl_stats->ctl_mtx_data, &ctl_mtx); + malloc_mutex_prof_read(tsdn, &ctl_stats->ctl_mtx_data, &ctl_mtx); #undef READ_GLOBAL_MUTEX_PROF_DATA } ctl_arenas->epoch++; @@ -2454,7 +2457,7 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests, uint64_t) /* Intentional. */ /* Lock profiling related APIs below. */ -#define RO_LOCK_CTL_GEN(n, l) \ +#define RO_MUTEX_CTL_GEN(n, l) \ CTL_RO_CGEN(config_stats, stats_##n##_num_ops, \ l.n_lock_ops, uint64_t) \ CTL_RO_CGEN(config_stats, stats_##n##_num_wait, \ @@ -2470,32 +2473,81 @@ CTL_RO_CGEN(config_stats, stats_##n##_max_wait_time, \ CTL_RO_CGEN(config_stats, stats_##n##_max_num_thds, \ l.max_n_thds, uint64_t) -/* Global lock. */ -#define MTX(mutex) RO_LOCK_CTL_GEN(locks_##mutex, ctl_stats->mutex##_mtx_data) +/* Global mutexes. */ +#define MTX(mutex) \ + RO_MUTEX_CTL_GEN(mutexes_##mutex, ctl_stats->mutex##_mtx_data) GLOBAL_PROF_MUTEXES #undef MTX /* arena->bins[j].lock */ -RO_LOCK_CTL_GEN(arenas_i_bins_j_lock, - arenas_i(mib[2])->astats->bstats[mib[4]].lock_data) +RO_MUTEX_CTL_GEN(arenas_i_bins_j_mutex, + arenas_i(mib[2])->astats->bstats[mib[4]].mutex_data) -/* Per arena locks */ -#define ARENAS_ASTATS_LOCK_CTL_GEN(l, d) \ - RO_LOCK_CTL_GEN(arenas_i_locks_##l, arenas_i(mib[2])->astats->astats.d) +/* Per arena mutexes */ +#define ARENAS_ASTATS_MUTEX_CTL_GEN(l, d) \ + RO_MUTEX_CTL_GEN(arenas_i_mutexes_##l, arenas_i(mib[2])->astats->astats.d) /* arena->large_mtx */ -ARENAS_ASTATS_LOCK_CTL_GEN(large, large_mtx_data) +ARENAS_ASTATS_MUTEX_CTL_GEN(large, large_mtx_data) /* arena->extent_freelist_mtx */ -ARENAS_ASTATS_LOCK_CTL_GEN(extent_freelist, extent_freelist_mtx_data) +ARENAS_ASTATS_MUTEX_CTL_GEN(extent_freelist, extent_freelist_mtx_data) /* arena->extents_cached.mtx */ -ARENAS_ASTATS_LOCK_CTL_GEN(extents_cached, extents_cached_mtx_data) +ARENAS_ASTATS_MUTEX_CTL_GEN(extents_cached, extents_cached_mtx_data) /* arena->extents_retained.mtx */ -ARENAS_ASTATS_LOCK_CTL_GEN(extents_retained, extents_retained_mtx_data) +ARENAS_ASTATS_MUTEX_CTL_GEN(extents_retained, extents_retained_mtx_data) /* arena->decay.mtx */ -ARENAS_ASTATS_LOCK_CTL_GEN(decay, decay_mtx_data) +ARENAS_ASTATS_MUTEX_CTL_GEN(decay, decay_mtx_data) /* arena->tcache_ql_mtx */ -ARENAS_ASTATS_LOCK_CTL_GEN(tcache, tcache_mtx_data) -#undef ARENAS_ASTATS_LOCK_CTL_GEN -#undef RO_LOCK_CTL_GEN +ARENAS_ASTATS_MUTEX_CTL_GEN(tcache, tcache_mtx_data) +#undef ARENAS_ASTATS_MUTEX_CTL_GEN +#undef RO_MUTEX_CTL_GEN + +/* Resets all mutex stats, including global, arena and bin mutexes. */ +static int +stats_mutexes_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, + void *oldp, size_t *oldlenp, void *newp, size_t newlen) { + if (!config_stats) { + return ENOENT; + } + + tsdn_t *tsdn = tsd_tsdn(tsd); + +#define MUTEX_PROF_RESET(mtx) \ + malloc_mutex_lock(tsdn, &mtx); \ + malloc_mutex_prof_data_reset(tsdn, &mtx); \ + malloc_mutex_unlock(tsdn, &mtx); + + /* Global mutexes: base, prof and ctl. */ + MUTEX_PROF_RESET(b0get()->mtx); + if (config_prof && opt_prof) { + MUTEX_PROF_RESET(bt2gctx_mtx); + } + MUTEX_PROF_RESET(ctl_mtx); + + /* Per arena mutexes. */ + unsigned n = narenas_total_get(); + + for (unsigned i = 0; i < n; i++) { + arena_t *arena = arena_get(tsdn, i, false); + if (!arena) { + continue; + } + MUTEX_PROF_RESET(arena->large_mtx); + MUTEX_PROF_RESET(arena->extent_freelist_mtx); + MUTEX_PROF_RESET(arena->extents_cached.mtx); + MUTEX_PROF_RESET(arena->extents_retained.mtx); + MUTEX_PROF_RESET(arena->decay.mtx); + if (config_tcache) { + MUTEX_PROF_RESET(arena->tcache_ql_mtx); + } + + for (szind_t i = 0; i < NBINS; i++) { + arena_bin_t *bin = &arena->bins[i]; + MUTEX_PROF_RESET(bin->lock); + } + } +#undef MUTEX_PROF_RESET + return 0; +} CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc, arenas_i(mib[2])->astats->bstats[mib[4]].nmalloc, uint64_t) diff --git a/src/mutex.c b/src/mutex.c index af6f3c19..82a5fa3e 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -67,7 +67,7 @@ JEMALLOC_EXPORT int _pthread_mutex_init_calloc_cb(pthread_mutex_t *mutex, void malloc_mutex_lock_slow(malloc_mutex_t *mutex) { - lock_prof_data_t *data = &mutex->prof_data; + mutex_prof_data_t *data = &mutex->prof_data; {//TODO: a smart spin policy if (!malloc_mutex_trylock(mutex)) { @@ -108,15 +108,21 @@ malloc_mutex_lock_slow(malloc_mutex_t *mutex) { } static void -lock_prof_data_init(lock_prof_data_t *data) { - memset(data, 0, sizeof(lock_prof_data_t)); +mutex_prof_data_init(mutex_prof_data_t *data) { + memset(data, 0, sizeof(mutex_prof_data_t)); data->prev_owner = NULL; } +void +malloc_mutex_prof_data_reset(tsdn_t *tsdn, malloc_mutex_t *mutex) { + malloc_mutex_assert_owner(tsdn, mutex); + mutex_prof_data_init(&mutex->prof_data); +} + bool malloc_mutex_init(malloc_mutex_t *mutex, const char *name, witness_rank_t rank) { - lock_prof_data_init(&mutex->prof_data); + mutex_prof_data_init(&mutex->prof_data); #ifdef _WIN32 # if _WIN32_WINNT >= 0x0600 InitializeSRWLock(&mutex->lock); diff --git a/src/stats.c b/src/stats.c index b6f2124a..ada95e92 100644 --- a/src/stats.c +++ b/src/stats.c @@ -58,20 +58,20 @@ get_rate_str(uint64_t dividend, uint64_t divisor, char str[6]) { } static void -gen_lock_ctl_str(char *str, const char *prefix, const char *lock, +gen_mutex_ctl_str(char *str, const char *prefix, const char *mutex, const char *counter) { - sprintf(str, "stats.%s.%s.%s", prefix, lock, counter); + malloc_snprintf(str, 128, "stats.%s.%s.%s", prefix, mutex, counter); } static void -read_arena_bin_lock_stats(unsigned arena_ind, unsigned bin_ind, - uint64_t results[NUM_LOCK_PROF_COUNTERS]) { +read_arena_bin_mutex_stats(unsigned arena_ind, unsigned bin_ind, + uint64_t results[NUM_MUTEX_PROF_COUNTERS]) { char cmd[128]; unsigned i; - for (i = 0; i < NUM_LOCK_PROF_COUNTERS; i++) { - gen_lock_ctl_str(cmd, "arenas.0.bins.0","lock", - lock_counter_names[i]); + for (i = 0; i < NUM_MUTEX_PROF_COUNTERS; i++) { + gen_mutex_ctl_str(cmd, "arenas.0.bins.0","mutex", + mutex_counter_names[i]); CTL_M2_M4_GET(cmd, arena_ind, bin_ind, &results[i], uint64_t); } } @@ -147,8 +147,8 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, size_t); if (json) { - uint64_t lock_stats[NUM_LOCK_PROF_COUNTERS]; - read_arena_bin_lock_stats(i, j, lock_stats); + uint64_t mutex_stats[NUM_MUTEX_PROF_COUNTERS]; + read_arena_bin_mutex_stats(i, j, mutex_stats); malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\t{\n" @@ -170,15 +170,15 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\t\t\"nreslabs\": %"FMTu64",\n" "\t\t\t\t\t\t\"curslabs\": %zu,\n" - "\t\t\t\t\t\t\"lock\": {\n", + "\t\t\t\t\t\t\"mutex\": {\n", nreslabs, curslabs); - for (unsigned k = 0; k < NUM_LOCK_PROF_COUNTERS; k++) { + for (unsigned k = 0; k < NUM_MUTEX_PROF_COUNTERS; k++) { malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\t\t\t\"%s\": %"FMTu64"%s\n", - lock_counter_names[k], lock_stats[k], - k == NUM_LOCK_PROF_COUNTERS - 1 ? "" : ","); + mutex_counter_names[k], mutex_stats[k], + k == NUM_MUTEX_PROF_COUNTERS - 1 ? "" : ","); } malloc_cprintf(write_cb, cbopaque, @@ -207,14 +207,14 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, not_reached(); } } - /* Output less info for bin locks to save space. */ + /* Output less info for bin mutexes to save space. */ uint64_t num_ops, num_wait, max_wait; - CTL_M2_M4_GET("stats.arenas.0.bins.0.lock.num_wait", + CTL_M2_M4_GET("stats.arenas.0.bins.0.mutex.num_wait", i, j, &num_wait, uint64_t); CTL_M2_M4_GET( - "stats.arenas.0.bins.0.lock.max_wait_time", i, j, + "stats.arenas.0.bins.0.mutex.max_wait_time", i, j, &max_wait, uint64_t); - CTL_M2_M4_GET("stats.arenas.0.bins.0.lock.num_ops", + CTL_M2_M4_GET("stats.arenas.0.bins.0.mutex.num_ops", i, j, &num_ops, uint64_t); char rate[6]; @@ -325,38 +325,38 @@ stats_arena_lextents_print(void (*write_cb)(void *, const char *), } static void -read_arena_lock_stats(unsigned arena_ind, - uint64_t results[NUM_ARENA_PROF_LOCKS][NUM_LOCK_PROF_COUNTERS]) { +read_arena_mutex_stats(unsigned arena_ind, + uint64_t results[NUM_ARENA_PROF_MUTEXES][NUM_MUTEX_PROF_COUNTERS]) { char cmd[128]; unsigned i, j; - for (i = 0; i < NUM_ARENA_PROF_LOCKS; i++) { - for (j = 0; j < NUM_LOCK_PROF_COUNTERS; j++) { - gen_lock_ctl_str(cmd, "arenas.0.locks", - arena_lock_names[i], lock_counter_names[j]); + for (i = 0; i < NUM_ARENA_PROF_MUTEXES; i++) { + for (j = 0; j < NUM_MUTEX_PROF_COUNTERS; j++) { + gen_mutex_ctl_str(cmd, "arenas.0.mutexes", + arena_mutex_names[i], mutex_counter_names[j]); CTL_M2_GET(cmd, arena_ind, &results[i][j], uint64_t); } } } static void -lock_stats_output_json(void (*write_cb)(void *, const char *), void *cbopaque, - const char *name, uint64_t stats[NUM_LOCK_PROF_COUNTERS], +mutex_stats_output_json(void (*write_cb)(void *, const char *), void *cbopaque, + const char *name, uint64_t stats[NUM_MUTEX_PROF_COUNTERS], const char *json_indent, bool last) { malloc_cprintf(write_cb, cbopaque, "%s\"%s\": {\n", json_indent, name); - for (unsigned i = 0; i < NUM_LOCK_PROF_COUNTERS; i++) { + for (unsigned i = 0; i < NUM_MUTEX_PROF_COUNTERS; i++) { malloc_cprintf(write_cb, cbopaque, "%s\t\"%s\": %"FMTu64"%s\n", - json_indent, lock_counter_names[i], stats[i], - i < (NUM_LOCK_PROF_COUNTERS - 1) ? "," : ""); + json_indent, mutex_counter_names[i], stats[i], + i < (NUM_MUTEX_PROF_COUNTERS - 1) ? "," : ""); } malloc_cprintf(write_cb, cbopaque, "%s}%s\n", json_indent, last ? "" : ","); } static void -lock_stats_output(void (*write_cb)(void *, const char *), void *cbopaque, - const char *name, uint64_t stats[NUM_LOCK_PROF_COUNTERS], +mutex_stats_output(void (*write_cb)(void *, const char *), void *cbopaque, + const char *name, uint64_t stats[NUM_MUTEX_PROF_COUNTERS], bool first_mutex) { if (first_mutex) { /* Print title. */ @@ -370,39 +370,39 @@ lock_stats_output(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, ":%*c", (int)(19 - strlen(name)), ' '); - for (unsigned i = 0; i < NUM_LOCK_PROF_COUNTERS; i++) { + for (unsigned i = 0; i < NUM_MUTEX_PROF_COUNTERS; i++) { malloc_cprintf(write_cb, cbopaque, " %16"FMTu64, stats[i]); } malloc_cprintf(write_cb, cbopaque, "\n"); } static void -stats_arena_locks_print(void (*write_cb)(void *, const char *), +stats_arena_mutexes_print(void (*write_cb)(void *, const char *), void *cbopaque, bool json, bool json_end, unsigned arena_ind) { - uint64_t lock_stats[NUM_ARENA_PROF_LOCKS][NUM_LOCK_PROF_COUNTERS]; - read_arena_lock_stats(arena_ind, lock_stats); + uint64_t mutex_stats[NUM_ARENA_PROF_MUTEXES][NUM_MUTEX_PROF_COUNTERS]; + read_arena_mutex_stats(arena_ind, mutex_stats); - /* Output lock stats. */ + /* Output mutex stats. */ if (json) { - malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\"locks\": {\n"); - for (unsigned i = 0; i < NUM_ARENA_PROF_LOCKS; i++) { - lock_stats_output_json(write_cb, cbopaque, - arena_lock_names[i], lock_stats[i], - "\t\t\t\t\t", (i == NUM_ARENA_PROF_LOCKS - 1)); + malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\"mutexes\": {\n"); + for (unsigned i = 0; i < NUM_ARENA_PROF_MUTEXES; i++) { + mutex_stats_output_json(write_cb, cbopaque, + arena_mutex_names[i], mutex_stats[i], + "\t\t\t\t\t", (i == NUM_ARENA_PROF_MUTEXES - 1)); } malloc_cprintf(write_cb, cbopaque, "\t\t\t\t}%s\n", json_end ? "" : ","); } else { - for (unsigned i = 0; i < NUM_ARENA_PROF_LOCKS; i++) { - lock_stats_output(write_cb, cbopaque, - arena_lock_names[i], lock_stats[i], i == 0); + for (unsigned i = 0; i < NUM_ARENA_PROF_MUTEXES; i++) { + mutex_stats_output(write_cb, cbopaque, + arena_mutex_names[i], mutex_stats[i], i == 0); } } } static void stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, - bool json, unsigned i, bool bins, bool large, bool lock) { + bool json, unsigned i, bool bins, bool large, bool mutex) { unsigned nthreads; const char *dss; ssize_t dirty_decay_time, muzzy_decay_time; @@ -625,14 +625,14 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\"resident\": %zu%s\n", resident, - (bins || large || lock) ? "," : ""); + (bins || large || mutex) ? "," : ""); } else { malloc_cprintf(write_cb, cbopaque, "resident: %12zu\n", resident); } - if (lock) { - stats_arena_locks_print(write_cb, cbopaque, json, + if (mutex) { + stats_arena_mutexes_print(write_cb, cbopaque, json, !(bins || large), i); } if (bins) { @@ -993,15 +993,16 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, } } -static void read_global_lock_stats( - uint64_t results[NUM_GLOBAL_PROF_LOCKS][NUM_LOCK_PROF_COUNTERS]) { +static void +read_global_mutex_stats( + uint64_t results[NUM_GLOBAL_PROF_MUTEXES][NUM_MUTEX_PROF_COUNTERS]) { char cmd[128]; unsigned i, j; - for (i = 0; i < NUM_GLOBAL_PROF_LOCKS; i++) { - for (j = 0; j < NUM_LOCK_PROF_COUNTERS; j++) { - gen_lock_ctl_str(cmd, "locks", global_lock_names[i], - lock_counter_names[j]); + for (i = 0; i < NUM_GLOBAL_PROF_MUTEXES; i++) { + for (j = 0; j < NUM_MUTEX_PROF_COUNTERS; j++) { + gen_mutex_ctl_str(cmd, "mutexes", global_mutex_names[i], + mutex_counter_names[j]); CTL_GET(cmd, &results[i][j], uint64_t); } } @@ -1010,7 +1011,7 @@ static void read_global_lock_stats( static void stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, bool json, bool merged, bool destroyed, bool unmerged, bool bins, - bool large, bool lock) { + bool large, bool mutex) { size_t allocated, active, metadata, resident, mapped, retained; CTL_GET("stats.allocated", &allocated, size_t); @@ -1020,9 +1021,9 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, CTL_GET("stats.mapped", &mapped, size_t); CTL_GET("stats.retained", &retained, size_t); - uint64_t lock_stats[NUM_GLOBAL_PROF_LOCKS][NUM_LOCK_PROF_COUNTERS]; - if (lock) { - read_global_lock_stats(lock_stats); + uint64_t mutex_stats[NUM_GLOBAL_PROF_MUTEXES][NUM_MUTEX_PROF_COUNTERS]; + if (mutex) { + read_global_mutex_stats(mutex_stats); } if (json) { @@ -1041,14 +1042,14 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, "\t\t\t\"mapped\": %zu,\n", mapped); malloc_cprintf(write_cb, cbopaque, "\t\t\t\"retained\": %zu,\n", retained); - if (lock) { + if (mutex) { malloc_cprintf(write_cb, cbopaque, - "\t\t\t\"locks\": {\n"); + "\t\t\t\"mutexes\": {\n"); - for (unsigned i = 0; i < NUM_GLOBAL_PROF_LOCKS; i++) { - lock_stats_output_json(write_cb, cbopaque, - global_lock_names[i], lock_stats[i], - "\t\t\t\t", i == NUM_GLOBAL_PROF_LOCKS - 1); + for (unsigned i = 0; i < NUM_GLOBAL_PROF_MUTEXES; i++) { + mutex_stats_output_json(write_cb, cbopaque, + global_mutex_names[i], mutex_stats[i], + "\t\t\t\t", i == NUM_GLOBAL_PROF_MUTEXES - 1); } malloc_cprintf(write_cb, cbopaque, "\t\t\t}\n"); } @@ -1059,10 +1060,10 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, "Allocated: %zu, active: %zu, metadata: %zu," " resident: %zu, mapped: %zu, retained: %zu\n", allocated, active, metadata, resident, mapped, retained); - if (lock) { - for (unsigned i = 0; i < NUM_GLOBAL_PROF_LOCKS; i++) { - lock_stats_output(write_cb, cbopaque, - global_lock_names[i], lock_stats[i], + if (mutex) { + for (unsigned i = 0; i < NUM_GLOBAL_PROF_MUTEXES; i++) { + mutex_stats_output(write_cb, cbopaque, + global_mutex_names[i], mutex_stats[i], i == 0); } } @@ -1111,7 +1112,7 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, "\nMerged arenas stats:\n"); } stats_arena_print(write_cb, cbopaque, json, - MALLCTL_ARENAS_ALL, bins, large, lock); + MALLCTL_ARENAS_ALL, bins, large, mutex); if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t\t}%s\n", @@ -1133,7 +1134,7 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, } stats_arena_print(write_cb, cbopaque, json, MALLCTL_ARENAS_DESTROYED, bins, large, - lock); + mutex); if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t\t}%s\n", unmerged ? "," : @@ -1159,7 +1160,7 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, } stats_arena_print(write_cb, cbopaque, json, i, bins, - large, lock); + large, mutex); if (json) { malloc_cprintf(write_cb, cbopaque, @@ -1192,7 +1193,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, bool unmerged = config_stats; bool bins = true; bool large = true; - bool lock = true; + bool mutex = true; /* * Refresh stats, in case mallctl() was called by the application. @@ -1243,7 +1244,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, large = false; break; case 'x': - lock = false; + mutex = false; break; default:; } @@ -1264,7 +1265,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, } if (config_stats) { stats_print_helper(write_cb, cbopaque, json, merged, destroyed, - unmerged, bins, large, lock); + unmerged, bins, large, mutex); } if (json) { -- GitLab From 20b8c70e9f0177d3276504ec5e3f631e1b69df87 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 15 Mar 2017 14:00:57 -0700 Subject: [PATCH 350/544] Added extents_dirty / _muzzy mutexes, as well as decay_dirty / _muzzy. --- include/jemalloc/internal/ctl_externs.h | 2 +- include/jemalloc/internal/stats_structs.h | 8 ++- src/arena.c | 11 +-- src/ctl.c | 81 ++++++++++++++--------- 4 files changed, 61 insertions(+), 41 deletions(-) diff --git a/include/jemalloc/internal/ctl_externs.h b/include/jemalloc/internal/ctl_externs.h index 1b06dd4d..3eddba34 100644 --- a/include/jemalloc/internal/ctl_externs.h +++ b/include/jemalloc/internal/ctl_externs.h @@ -5,7 +5,7 @@ #define CTL_MAX_DEPTH 7 #define NUM_GLOBAL_PROF_MUTEXES 3 -#define NUM_ARENA_PROF_MUTEXES 6 +#define NUM_ARENA_PROF_MUTEXES 8 #define NUM_MUTEX_PROF_COUNTERS 7 extern const char *arena_mutex_names[NUM_ARENA_PROF_MUTEXES]; diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index 601c8512..5a9624fb 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -126,10 +126,12 @@ struct arena_stats_s { mutex_prof_data_t large_mtx_data; mutex_prof_data_t extent_freelist_mtx_data; - mutex_prof_data_t extents_cached_mtx_data; + mutex_prof_data_t extents_dirty_mtx_data; + mutex_prof_data_t extents_muzzy_mtx_data; mutex_prof_data_t extents_retained_mtx_data; - mutex_prof_data_t decay_mtx_data; - mutex_prof_data_t tcache_mtx_data; + mutex_prof_data_t decay_dirty_mtx_data; + mutex_prof_data_t decay_muzzy_mtx_data; + mutex_prof_data_t tcache_list_mtx_data; /* One element for each large size class. */ malloc_large_stats_t lstats[NSIZES - NBINS]; diff --git a/src/arena.c b/src/arena.c index 57b79c52..6bb67338 100644 --- a/src/arena.c +++ b/src/arena.c @@ -292,7 +292,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, tbin->ncached * index2size(i)); } } - malloc_mutex_prof_read(tsdn, &astats->tcache_mtx_data, + malloc_mutex_prof_read(tsdn, &astats->tcache_list_mtx_data, &arena->tcache_ql_mtx); malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx); } @@ -306,11 +306,14 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, READ_ARENA_MUTEX_PROF_DATA(large_mtx, large_mtx_data) READ_ARENA_MUTEX_PROF_DATA(extent_freelist_mtx, extent_freelist_mtx_data) - READ_ARENA_MUTEX_PROF_DATA(extents_cached.mtx, - extents_cached_mtx_data) + READ_ARENA_MUTEX_PROF_DATA(extents_dirty.mtx, + extents_dirty_mtx_data) + READ_ARENA_MUTEX_PROF_DATA(extents_muzzy.mtx, + extents_muzzy_mtx_data) READ_ARENA_MUTEX_PROF_DATA(extents_retained.mtx, extents_retained_mtx_data) - READ_ARENA_MUTEX_PROF_DATA(decay.mtx, decay_mtx_data) + READ_ARENA_MUTEX_PROF_DATA(decay_dirty.mtx, decay_dirty_mtx_data) + READ_ARENA_MUTEX_PROF_DATA(decay_muzzy.mtx, decay_muzzy_mtx_data) #undef READ_ARENA_MUTEX_PROF_DATA for (szind_t i = 0; i < NBINS; i++) { diff --git a/src/ctl.c b/src/ctl.c index b2b9e7d9..b6b031c3 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -22,10 +22,12 @@ const char *global_mutex_names[NUM_GLOBAL_PROF_MUTEXES] = { const char *arena_mutex_names[NUM_ARENA_PROF_MUTEXES] = { "large", "extent_freelist", - "extents_cached", + "extents_dirty", + "extents_muzzy", "extents_retained", - "decay", - "tcache" + "decay_dirty", + "decay_muzzy", + "tcache_list" }; const char *mutex_counter_names[NUM_MUTEX_PROF_COUNTERS] = { @@ -225,10 +227,12 @@ MUTEX_STATS_CTL_PROTO_GEN(arenas_i_bins_j_mutex) /* Per arena mutexes. */ ARENA_MUTEXES_CTL_PROTO_GEN(large) ARENA_MUTEXES_CTL_PROTO_GEN(extent_freelist) -ARENA_MUTEXES_CTL_PROTO_GEN(extents_cached) +ARENA_MUTEXES_CTL_PROTO_GEN(extents_dirty) +ARENA_MUTEXES_CTL_PROTO_GEN(extents_muzzy) ARENA_MUTEXES_CTL_PROTO_GEN(extents_retained) -ARENA_MUTEXES_CTL_PROTO_GEN(decay) -ARENA_MUTEXES_CTL_PROTO_GEN(tcache) +ARENA_MUTEXES_CTL_PROTO_GEN(decay_dirty) +ARENA_MUTEXES_CTL_PROTO_GEN(decay_muzzy) +ARENA_MUTEXES_CTL_PROTO_GEN(tcache_list) #undef ARENA_MUTEXES_CTL_PROTO_GEN #undef MUTEX_STATS_CTL_PROTO_GEN @@ -461,21 +465,30 @@ static const ctl_indexed_node_t stats_arenas_i_lextents_node[] = { ARENA_MUTEX_PROF_DATA_NODE(large) ARENA_MUTEX_PROF_DATA_NODE(extent_freelist) -ARENA_MUTEX_PROF_DATA_NODE(extents_cached) +ARENA_MUTEX_PROF_DATA_NODE(extents_dirty) +ARENA_MUTEX_PROF_DATA_NODE(extents_muzzy) ARENA_MUTEX_PROF_DATA_NODE(extents_retained) -ARENA_MUTEX_PROF_DATA_NODE(decay) -ARENA_MUTEX_PROF_DATA_NODE(tcache) +ARENA_MUTEX_PROF_DATA_NODE(decay_dirty) +ARENA_MUTEX_PROF_DATA_NODE(decay_muzzy) +ARENA_MUTEX_PROF_DATA_NODE(tcache_list) static const ctl_named_node_t stats_arenas_i_mutexes_node[] = { - {NAME("large"), CHILD(named, stats_arenas_i_mutexes_large)}, + {NAME("large"), + CHILD(named, stats_arenas_i_mutexes_large)}, {NAME("extent_freelist"), CHILD(named, stats_arenas_i_mutexes_extent_freelist)}, - {NAME("extents_cached"), - CHILD(named, stats_arenas_i_mutexes_extents_cached)}, + {NAME("extents_dirty"), + CHILD(named, stats_arenas_i_mutexes_extents_dirty)}, + {NAME("extents_muzzy"), + CHILD(named, stats_arenas_i_mutexes_extents_muzzy)}, {NAME("extents_retained"), CHILD(named, stats_arenas_i_mutexes_extents_retained)}, - {NAME("decay"), CHILD(named, stats_arenas_i_mutexes_decay)}, - {NAME("tcache"), CHILD(named, stats_arenas_i_mutexes_tcache)} + {NAME("decay_dirty"), + CHILD(named, stats_arenas_i_mutexes_decay_dirty)}, + {NAME("decay_muzzy"), + CHILD(named, stats_arenas_i_mutexes_decay_muzzy)}, + {NAME("tcache_list"), + CHILD(named, stats_arenas_i_mutexes_tcache_list)} }; static const ctl_named_node_t stats_arenas_i_node[] = { @@ -777,15 +790,20 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, &(sdstats->astats.extent_freelist_mtx_data), &(astats->astats.extent_freelist_mtx_data)); malloc_mutex_prof_merge( - &(sdstats->astats.extents_cached_mtx_data), - &(astats->astats.extents_cached_mtx_data)); + &(sdstats->astats.extents_dirty_mtx_data), + &(astats->astats.extents_dirty_mtx_data)); + malloc_mutex_prof_merge( + &(sdstats->astats.extents_muzzy_mtx_data), + &(astats->astats.extents_muzzy_mtx_data)); malloc_mutex_prof_merge( &(sdstats->astats.extents_retained_mtx_data), &(astats->astats.extents_retained_mtx_data)); - malloc_mutex_prof_merge(&(sdstats->astats.decay_mtx_data), - &(astats->astats.decay_mtx_data)); - malloc_mutex_prof_merge(&(sdstats->astats.tcache_mtx_data), - &(astats->astats.tcache_mtx_data)); + malloc_mutex_prof_merge(&(sdstats->astats.decay_dirty_mtx_data), + &(astats->astats.decay_dirty_mtx_data)); + malloc_mutex_prof_merge(&(sdstats->astats.decay_muzzy_mtx_data), + &(astats->astats.decay_muzzy_mtx_data)); + malloc_mutex_prof_merge(&(sdstats->astats.tcache_list_mtx_data), + &(astats->astats.tcache_list_mtx_data)); if (!destroyed) { accum_atomic_zu(&sdstats->astats.base, @@ -2479,25 +2497,20 @@ CTL_RO_CGEN(config_stats, stats_##n##_max_num_thds, \ GLOBAL_PROF_MUTEXES #undef MTX -/* arena->bins[j].lock */ +/* tcache bin mutex */ RO_MUTEX_CTL_GEN(arenas_i_bins_j_mutex, arenas_i(mib[2])->astats->bstats[mib[4]].mutex_data) - /* Per arena mutexes */ #define ARENAS_ASTATS_MUTEX_CTL_GEN(l, d) \ RO_MUTEX_CTL_GEN(arenas_i_mutexes_##l, arenas_i(mib[2])->astats->astats.d) -/* arena->large_mtx */ ARENAS_ASTATS_MUTEX_CTL_GEN(large, large_mtx_data) -/* arena->extent_freelist_mtx */ ARENAS_ASTATS_MUTEX_CTL_GEN(extent_freelist, extent_freelist_mtx_data) -/* arena->extents_cached.mtx */ -ARENAS_ASTATS_MUTEX_CTL_GEN(extents_cached, extents_cached_mtx_data) -/* arena->extents_retained.mtx */ +ARENAS_ASTATS_MUTEX_CTL_GEN(extents_dirty, extents_dirty_mtx_data) +ARENAS_ASTATS_MUTEX_CTL_GEN(extents_muzzy, extents_muzzy_mtx_data) ARENAS_ASTATS_MUTEX_CTL_GEN(extents_retained, extents_retained_mtx_data) -/* arena->decay.mtx */ -ARENAS_ASTATS_MUTEX_CTL_GEN(decay, decay_mtx_data) -/* arena->tcache_ql_mtx */ -ARENAS_ASTATS_MUTEX_CTL_GEN(tcache, tcache_mtx_data) +ARENAS_ASTATS_MUTEX_CTL_GEN(decay_dirty, decay_dirty_mtx_data) +ARENAS_ASTATS_MUTEX_CTL_GEN(decay_muzzy, decay_muzzy_mtx_data) +ARENAS_ASTATS_MUTEX_CTL_GEN(tcache_list, tcache_list_mtx_data) #undef ARENAS_ASTATS_MUTEX_CTL_GEN #undef RO_MUTEX_CTL_GEN @@ -2533,9 +2546,11 @@ stats_mutexes_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, } MUTEX_PROF_RESET(arena->large_mtx); MUTEX_PROF_RESET(arena->extent_freelist_mtx); - MUTEX_PROF_RESET(arena->extents_cached.mtx); + MUTEX_PROF_RESET(arena->extents_dirty.mtx); + MUTEX_PROF_RESET(arena->extents_muzzy.mtx); MUTEX_PROF_RESET(arena->extents_retained.mtx); - MUTEX_PROF_RESET(arena->decay.mtx); + MUTEX_PROF_RESET(arena->decay_dirty.mtx); + MUTEX_PROF_RESET(arena->decay_muzzy.mtx); if (config_tcache) { MUTEX_PROF_RESET(arena->tcache_ql_mtx); } -- GitLab From 74f78cafdaa0adc885f9670066d3ecf13aee1ba5 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 15 Mar 2017 15:31:37 -0700 Subject: [PATCH 351/544] Added custom mutex spin. A fixed max spin count is used -- with benchmark results showing it solves almost all problems. As the benchmark used was rather intense, the upper bound could be a little bit high. However it should offer a good tradeoff between spinning and blocking. --- include/jemalloc/internal/mutex_inlines.h | 12 +++++++----- include/jemalloc/internal/mutex_types.h | 16 ++++++---------- src/mutex.c | 16 ++++++++++++++-- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index d4703d23..7adcff4e 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -52,11 +52,13 @@ malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) { malloc_mutex_lock_slow(mutex); } /* We own the lock now. Update a few counters. */ - mutex_prof_data_t *data = &mutex->prof_data; - data->n_lock_ops++; - if (data->prev_owner != tsdn) { - data->prev_owner = tsdn; - data->n_owner_switches++; + if (config_stats) { + mutex_prof_data_t *data = &mutex->prof_data; + data->n_lock_ops++; + if (data->prev_owner != tsdn) { + data->prev_owner = tsdn; + data->n_owner_switches++; + } } } witness_lock(tsdn, &mutex->witness); diff --git a/include/jemalloc/internal/mutex_types.h b/include/jemalloc/internal/mutex_types.h index 257f69ca..3cc7bc2b 100644 --- a/include/jemalloc/internal/mutex_types.h +++ b/include/jemalloc/internal/mutex_types.h @@ -4,6 +4,12 @@ typedef struct mutex_prof_data_s mutex_prof_data_t; typedef struct malloc_mutex_s malloc_mutex_t; +/* + * Based on benchmark results, a fixed spin with this amount of retries works + * well for our critical sections. + */ +#define MALLOC_MUTEX_MAX_SPIN 250 + #ifdef _WIN32 # if _WIN32_WINNT >= 0x0600 # define MALLOC_MUTEX_LOCK(m) AcquireSRWLockExclusive(&(m)->lock) @@ -45,20 +51,10 @@ typedef struct malloc_mutex_s malloc_mutex_t; {{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, NULL}}, \ WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} #else -/* TODO: get rid of adaptive mutex once we do our own spin. */ -# if (defined(JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP) && \ - defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP)) -# define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_ADAPTIVE_NP -# define MALLOC_MUTEX_INITIALIZER \ - {{{LOCK_PROF_DATA_INITIALIZER, \ - PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP}}, \ - WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} -# else # define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT # define MALLOC_MUTEX_INITIALIZER \ {{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER}}, \ WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} -# endif #endif #endif /* JEMALLOC_INTERNAL_MUTEX_TYPES_H */ diff --git a/src/mutex.c b/src/mutex.c index 82a5fa3e..06ccd42c 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -69,14 +69,26 @@ void malloc_mutex_lock_slow(malloc_mutex_t *mutex) { mutex_prof_data_t *data = &mutex->prof_data; - {//TODO: a smart spin policy + if (ncpus == 1) { + goto label_spin_done; + } + + int cnt = 0, max_cnt = MALLOC_MUTEX_MAX_SPIN; + do { + CPU_SPINWAIT; if (!malloc_mutex_trylock(mutex)) { data->n_spin_acquired++; return; } - } + } while (cnt++ < max_cnt); + if (!config_stats) { + /* Only spin is useful when stats is off. */ + malloc_mutex_lock_final(mutex); + return; + } nstime_t now, before; +label_spin_done: nstime_init(&now, 0); nstime_update(&now); nstime_copy(&before, &now); -- GitLab From f6698ec1e6752e40be9adf43ebf42ab832255afc Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 17 Mar 2017 17:42:10 -0700 Subject: [PATCH 352/544] Switch to nstime_t for the time related fields in mutex profiling. --- include/jemalloc/internal/mutex_inlines.h | 7 +++--- include/jemalloc/internal/mutex_structs.h | 4 ++-- include/jemalloc/internal/mutex_types.h | 3 ++- src/ctl.c | 4 ++-- src/mutex.c | 26 ++++++++++++----------- 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index 7adcff4e..3a12a722 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -29,10 +29,11 @@ malloc_mutex_trylock(malloc_mutex_t *mutex) { /* Aggregate lock prof data. */ JEMALLOC_INLINE void malloc_mutex_prof_merge(mutex_prof_data_t *sum, mutex_prof_data_t *data) { - sum->tot_wait_time += data->tot_wait_time; - if (data->max_wait_time > sum->max_wait_time) { - sum->max_wait_time = data->max_wait_time; + nstime_add(&sum->tot_wait_time, &data->tot_wait_time); + if (nstime_compare(&sum->max_wait_time, &data->max_wait_time) < 0) { + nstime_copy(&sum->max_wait_time, &data->max_wait_time); } + sum->n_wait_times += data->n_wait_times; sum->n_spin_acquired += data->n_spin_acquired; diff --git a/include/jemalloc/internal/mutex_structs.h b/include/jemalloc/internal/mutex_structs.h index 8d6e7eb2..5dddb846 100644 --- a/include/jemalloc/internal/mutex_structs.h +++ b/include/jemalloc/internal/mutex_structs.h @@ -7,9 +7,9 @@ struct mutex_prof_data_s { * contention. We update them once we have the lock. */ /* Total time (in nano seconds) spent waiting on this mutex. */ - uint64_t tot_wait_time; + nstime_t tot_wait_time; /* Max time (in nano seconds) spent on a single lock operation. */ - uint64_t max_wait_time; + nstime_t max_wait_time; /* # of times have to wait for this mutex (after spinning). */ uint64_t n_wait_times; /* # of times acquired the mutex through local spinning. */ diff --git a/include/jemalloc/internal/mutex_types.h b/include/jemalloc/internal/mutex_types.h index 3cc7bc2b..bd261490 100644 --- a/include/jemalloc/internal/mutex_types.h +++ b/include/jemalloc/internal/mutex_types.h @@ -34,7 +34,8 @@ typedef struct malloc_mutex_s malloc_mutex_t; # define MALLOC_MUTEX_TRYLOCK(m) (pthread_mutex_trylock(&(m)->lock) != 0) #endif -#define LOCK_PROF_DATA_INITIALIZER {0, 0, 0, 0, 0, 0, 0, NULL, 0} +#define LOCK_PROF_DATA_INITIALIZER \ + {NSTIME_ZERO_INITIALIZER, NSTIME_ZERO_INITIALIZER, 0, 0, 0, 0, 0, NULL, 0} #ifdef _WIN32 # define MALLOC_MUTEX_INITIALIZER diff --git a/src/ctl.c b/src/ctl.c index b6b031c3..360c6bdc 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -2485,9 +2485,9 @@ CTL_RO_CGEN(config_stats, stats_##n##_num_spin_acq, \ CTL_RO_CGEN(config_stats, stats_##n##_num_owner_switch, \ l.n_owner_switches, uint64_t) \ CTL_RO_CGEN(config_stats, stats_##n##_total_wait_time, \ - l.tot_wait_time, uint64_t) \ + nstime_ns(&l.tot_wait_time), uint64_t) \ CTL_RO_CGEN(config_stats, stats_##n##_max_wait_time, \ - l.max_wait_time, uint64_t) \ + nstime_ns(&l.max_wait_time), uint64_t) \ CTL_RO_CGEN(config_stats, stats_##n##_max_num_thds, \ l.max_n_thds, uint64_t) diff --git a/src/mutex.c b/src/mutex.c index 06ccd42c..fa2770a3 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -68,6 +68,7 @@ JEMALLOC_EXPORT int _pthread_mutex_init_calloc_cb(pthread_mutex_t *mutex, void malloc_mutex_lock_slow(malloc_mutex_t *mutex) { mutex_prof_data_t *data = &mutex->prof_data; + UNUSED nstime_t before = NSTIME_ZERO_INITIALIZER; if (ncpus == 1) { goto label_spin_done; @@ -87,12 +88,11 @@ malloc_mutex_lock_slow(malloc_mutex_t *mutex) { malloc_mutex_lock_final(mutex); return; } - nstime_t now, before; label_spin_done: - nstime_init(&now, 0); - nstime_update(&now); - nstime_copy(&before, &now); - + nstime_update(&before); + /* Copy before to after to avoid clock skews. */ + nstime_t after; + nstime_copy(&after, &before); uint32_t n_thds = atomic_add_u32(&data->n_waiting_thds, 1); /* One last try as above two calls may take quite some cycles. */ if (!malloc_mutex_trylock(mutex)) { @@ -103,16 +103,18 @@ label_spin_done: /* True slow path. */ malloc_mutex_lock_final(mutex); + /* Update more slow-path only counters. */ atomic_sub_u32(&data->n_waiting_thds, 1); - nstime_update(&now); + nstime_update(&after); + + nstime_t delta; + nstime_copy(&delta, &after); + nstime_subtract(&delta, &before); - /* Update more slow-path only counters. */ - nstime_subtract(&now, &before); - uint64_t wait_time = nstime_ns(&now); data->n_wait_times++; - data->tot_wait_time += wait_time; - if (wait_time > data->max_wait_time) { - data->max_wait_time = wait_time; + nstime_add(&data->tot_wait_time, &delta); + if (nstime_compare(&data->max_wait_time, &delta) < 0) { + nstime_copy(&data->max_wait_time, &delta); } if (n_thds > data->max_n_thds) { data->max_n_thds = n_thds; -- GitLab From d3fde1c12459f43e653bb842269b082b5635ccc6 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 21 Mar 2017 11:56:38 -0700 Subject: [PATCH 353/544] Refactor mutex profiling code with x-macros. --- include/jemalloc/internal/ctl_externs.h | 8 - include/jemalloc/internal/ctl_structs.h | 4 +- include/jemalloc/internal/ctl_types.h | 46 ++++- include/jemalloc/internal/stats_structs.h | 9 +- src/arena.c | 24 +-- src/ctl.c | 167 ++++++------------ src/stats.c | 199 +++++++++++++--------- 7 files changed, 225 insertions(+), 232 deletions(-) diff --git a/include/jemalloc/internal/ctl_externs.h b/include/jemalloc/internal/ctl_externs.h index 3eddba34..17bbba06 100644 --- a/include/jemalloc/internal/ctl_externs.h +++ b/include/jemalloc/internal/ctl_externs.h @@ -4,14 +4,6 @@ /* Maximum ctl tree depth. */ #define CTL_MAX_DEPTH 7 -#define NUM_GLOBAL_PROF_MUTEXES 3 -#define NUM_ARENA_PROF_MUTEXES 8 -#define NUM_MUTEX_PROF_COUNTERS 7 - -extern const char *arena_mutex_names[NUM_ARENA_PROF_MUTEXES]; -extern const char *global_mutex_names[NUM_GLOBAL_PROF_MUTEXES]; -extern const char *mutex_counter_names[NUM_MUTEX_PROF_COUNTERS]; - int ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen); int ctl_nametomib(tsdn_t *tsdn, const char *name, size_t *mibp, diff --git a/include/jemalloc/internal/ctl_structs.h b/include/jemalloc/internal/ctl_structs.h index b1ee3555..af0f78b9 100644 --- a/include/jemalloc/internal/ctl_structs.h +++ b/include/jemalloc/internal/ctl_structs.h @@ -42,9 +42,7 @@ struct ctl_stats_s { size_t mapped; size_t retained; -#define MTX(mutex) mutex_prof_data_t mutex##_mtx_data; - GLOBAL_PROF_MUTEXES -#undef MTX + mutex_prof_data_t mutex_prof_data[num_global_prof_mutexes]; }; struct ctl_arena_s { diff --git a/include/jemalloc/internal/ctl_types.h b/include/jemalloc/internal/ctl_types.h index 562418ca..1b5c76f9 100644 --- a/include/jemalloc/internal/ctl_types.h +++ b/include/jemalloc/internal/ctl_types.h @@ -2,9 +2,49 @@ #define JEMALLOC_INTERNAL_CTL_TYPES_H #define GLOBAL_PROF_MUTEXES \ - MTX(base) \ - MTX(ctl) \ - MTX(prof) + OP(base) \ + OP(ctl) \ + OP(prof) + +typedef enum { +#define OP(mtx) global_prof_mutex_##mtx, + GLOBAL_PROF_MUTEXES +#undef OP + num_global_prof_mutexes +} global_prof_mutex_ind_t; + +#define ARENA_PROF_MUTEXES \ + OP(large) \ + OP(extent_freelist) \ + OP(extents_dirty) \ + OP(extents_muzzy) \ + OP(extents_retained) \ + OP(decay_dirty) \ + OP(decay_muzzy) \ + OP(tcache_list) + +typedef enum { +#define OP(mtx) arena_prof_mutex_##mtx, + ARENA_PROF_MUTEXES +#undef OP + num_arena_prof_mutexes +} arena_prof_mutex_ind_t; + +#define MUTEX_PROF_COUNTERS \ + OP(num_ops, uint64_t) \ + OP(num_wait, uint64_t) \ + OP(num_spin_acq, uint64_t) \ + OP(num_owner_switch, uint64_t) \ + OP(total_wait_time, uint64_t) \ + OP(max_wait_time, uint64_t) \ + OP(max_num_thds, uint32_t) + +typedef enum { +#define OP(counter, type) mutex_counter_##counter, + MUTEX_PROF_COUNTERS +#undef OP + num_mutex_prof_counters +} mutex_prof_counter_ind_t; typedef struct ctl_node_s ctl_node_t; typedef struct ctl_named_node_s ctl_named_node_t; diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index 5a9624fb..75a4a783 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -124,14 +124,7 @@ struct arena_stats_s { /* Number of bytes cached in tcache associated with this arena. */ atomic_zu_t tcache_bytes; /* Derived. */ - mutex_prof_data_t large_mtx_data; - mutex_prof_data_t extent_freelist_mtx_data; - mutex_prof_data_t extents_dirty_mtx_data; - mutex_prof_data_t extents_muzzy_mtx_data; - mutex_prof_data_t extents_retained_mtx_data; - mutex_prof_data_t decay_dirty_mtx_data; - mutex_prof_data_t decay_muzzy_mtx_data; - mutex_prof_data_t tcache_list_mtx_data; + mutex_prof_data_t mutex_prof_data[num_arena_prof_mutexes]; /* One element for each large size class. */ malloc_large_stats_t lstats[NSIZES - NBINS]; diff --git a/src/arena.c b/src/arena.c index 6bb67338..3383a3b8 100644 --- a/src/arena.c +++ b/src/arena.c @@ -292,28 +292,32 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, tbin->ncached * index2size(i)); } } - malloc_mutex_prof_read(tsdn, &astats->tcache_list_mtx_data, + malloc_mutex_prof_read(tsdn, + &astats->mutex_prof_data[arena_prof_mutex_tcache_list], &arena->tcache_ql_mtx); malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx); } -#define READ_ARENA_MUTEX_PROF_DATA(mtx, data) \ +#define READ_ARENA_MUTEX_PROF_DATA(mtx, ind) \ malloc_mutex_lock(tsdn, &arena->mtx); \ - malloc_mutex_prof_read(tsdn, &astats->data, &arena->mtx); \ + malloc_mutex_prof_read(tsdn, &astats->mutex_prof_data[ind], \ + &arena->mtx); \ malloc_mutex_unlock(tsdn, &arena->mtx); /* Gather per arena mutex profiling data. */ - READ_ARENA_MUTEX_PROF_DATA(large_mtx, large_mtx_data) + READ_ARENA_MUTEX_PROF_DATA(large_mtx, arena_prof_mutex_large); READ_ARENA_MUTEX_PROF_DATA(extent_freelist_mtx, - extent_freelist_mtx_data) + arena_prof_mutex_extent_freelist) READ_ARENA_MUTEX_PROF_DATA(extents_dirty.mtx, - extents_dirty_mtx_data) + arena_prof_mutex_extents_dirty) READ_ARENA_MUTEX_PROF_DATA(extents_muzzy.mtx, - extents_muzzy_mtx_data) + arena_prof_mutex_extents_muzzy) READ_ARENA_MUTEX_PROF_DATA(extents_retained.mtx, - extents_retained_mtx_data) - READ_ARENA_MUTEX_PROF_DATA(decay_dirty.mtx, decay_dirty_mtx_data) - READ_ARENA_MUTEX_PROF_DATA(decay_muzzy.mtx, decay_muzzy_mtx_data) + arena_prof_mutex_extents_retained) + READ_ARENA_MUTEX_PROF_DATA(decay_dirty.mtx, + arena_prof_mutex_decay_dirty) + READ_ARENA_MUTEX_PROF_DATA(decay_muzzy.mtx, + arena_prof_mutex_decay_muzzy) #undef READ_ARENA_MUTEX_PROF_DATA for (szind_t i = 0; i < NBINS; i++) { diff --git a/src/ctl.c b/src/ctl.c index 360c6bdc..e2ee36a6 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -13,33 +13,6 @@ static bool ctl_initialized; static ctl_stats_t *ctl_stats; static ctl_arenas_t *ctl_arenas; -const char *global_mutex_names[NUM_GLOBAL_PROF_MUTEXES] = { - "base", - "prof", - "ctl" -}; - -const char *arena_mutex_names[NUM_ARENA_PROF_MUTEXES] = { - "large", - "extent_freelist", - "extents_dirty", - "extents_muzzy", - "extents_retained", - "decay_dirty", - "decay_muzzy", - "tcache_list" -}; - -const char *mutex_counter_names[NUM_MUTEX_PROF_COUNTERS] = { - "num_ops", - "num_wait", - "num_spin_acq", - "num_owner_switch", - "total_wait_time", - "max_wait_time", - "max_num_thds" -}; - /******************************************************************************/ /* Helpers for named and indexed nodes. */ @@ -215,25 +188,17 @@ CTL_PROTO(stats_##n##_max_wait_time) \ CTL_PROTO(stats_##n##_max_num_thds) /* Global mutexes. */ -MUTEX_STATS_CTL_PROTO_GEN(mutexes_base) -MUTEX_STATS_CTL_PROTO_GEN(mutexes_prof) -MUTEX_STATS_CTL_PROTO_GEN(mutexes_ctl) +#define OP(mtx) MUTEX_STATS_CTL_PROTO_GEN(mutexes_##mtx) +GLOBAL_PROF_MUTEXES +#undef OP + +/* Per arena mutexes. */ +#define OP(mtx) MUTEX_STATS_CTL_PROTO_GEN(arenas_i_mutexes_##mtx) +ARENA_PROF_MUTEXES +#undef OP /* Arena bin mutexes. */ MUTEX_STATS_CTL_PROTO_GEN(arenas_i_bins_j_mutex) - -#define ARENA_MUTEXES_CTL_PROTO_GEN(n) \ - MUTEX_STATS_CTL_PROTO_GEN(arenas_i_mutexes_##n) -/* Per arena mutexes. */ -ARENA_MUTEXES_CTL_PROTO_GEN(large) -ARENA_MUTEXES_CTL_PROTO_GEN(extent_freelist) -ARENA_MUTEXES_CTL_PROTO_GEN(extents_dirty) -ARENA_MUTEXES_CTL_PROTO_GEN(extents_muzzy) -ARENA_MUTEXES_CTL_PROTO_GEN(extents_retained) -ARENA_MUTEXES_CTL_PROTO_GEN(decay_dirty) -ARENA_MUTEXES_CTL_PROTO_GEN(decay_muzzy) -ARENA_MUTEXES_CTL_PROTO_GEN(tcache_list) -#undef ARENA_MUTEXES_CTL_PROTO_GEN #undef MUTEX_STATS_CTL_PROTO_GEN CTL_PROTO(stats_mutexes_reset) @@ -461,34 +426,14 @@ static const ctl_indexed_node_t stats_arenas_i_lextents_node[] = { {INDEX(stats_arenas_i_lextents_j)} }; -#define ARENA_MUTEX_PROF_DATA_NODE(n) MUTEX_PROF_DATA_NODE(arenas_i_mutexes_##n) - -ARENA_MUTEX_PROF_DATA_NODE(large) -ARENA_MUTEX_PROF_DATA_NODE(extent_freelist) -ARENA_MUTEX_PROF_DATA_NODE(extents_dirty) -ARENA_MUTEX_PROF_DATA_NODE(extents_muzzy) -ARENA_MUTEX_PROF_DATA_NODE(extents_retained) -ARENA_MUTEX_PROF_DATA_NODE(decay_dirty) -ARENA_MUTEX_PROF_DATA_NODE(decay_muzzy) -ARENA_MUTEX_PROF_DATA_NODE(tcache_list) +#define OP(mtx) MUTEX_PROF_DATA_NODE(arenas_i_mutexes_##mtx) +ARENA_PROF_MUTEXES +#undef OP static const ctl_named_node_t stats_arenas_i_mutexes_node[] = { - {NAME("large"), - CHILD(named, stats_arenas_i_mutexes_large)}, - {NAME("extent_freelist"), - CHILD(named, stats_arenas_i_mutexes_extent_freelist)}, - {NAME("extents_dirty"), - CHILD(named, stats_arenas_i_mutexes_extents_dirty)}, - {NAME("extents_muzzy"), - CHILD(named, stats_arenas_i_mutexes_extents_muzzy)}, - {NAME("extents_retained"), - CHILD(named, stats_arenas_i_mutexes_extents_retained)}, - {NAME("decay_dirty"), - CHILD(named, stats_arenas_i_mutexes_decay_dirty)}, - {NAME("decay_muzzy"), - CHILD(named, stats_arenas_i_mutexes_decay_muzzy)}, - {NAME("tcache_list"), - CHILD(named, stats_arenas_i_mutexes_tcache_list)} +#define OP(mtx) {NAME(#mtx), CHILD(named, stats_arenas_i_mutexes_##mtx)}, +ARENA_PROF_MUTEXES +#undef OP }; static const ctl_named_node_t stats_arenas_i_node[] = { @@ -525,15 +470,17 @@ static const ctl_indexed_node_t stats_arenas_node[] = { {INDEX(stats_arenas_i)} }; -MUTEX_PROF_DATA_NODE(mutexes_base) -MUTEX_PROF_DATA_NODE(mutexes_prof) -MUTEX_PROF_DATA_NODE(mutexes_ctl) +#define OP(mtx) MUTEX_PROF_DATA_NODE(mutexes_##mtx) +GLOBAL_PROF_MUTEXES +#undef OP + static const ctl_named_node_t stats_mutexes_node[] = { - {NAME("base"), CHILD(named, stats_mutexes_base)}, - {NAME("prof"), CHILD(named, stats_mutexes_prof)}, - {NAME("ctl"), CHILD(named, stats_mutexes_ctl)}, +#define OP(mtx) {NAME(#mtx), CHILD(named, stats_mutexes_##mtx)}, +GLOBAL_PROF_MUTEXES +#undef OP {NAME("reset"), CTL(stats_mutexes_reset)} }; +#undef MUTEX_PROF_DATA_NODE static const ctl_named_node_t stats_node[] = { {NAME("allocated"), CTL(stats_allocated)}, @@ -545,7 +492,6 @@ static const ctl_named_node_t stats_node[] = { {NAME("mutexes"), CHILD(named, stats_mutexes)}, {NAME("arenas"), CHILD(indexed, stats_arenas)} }; -#undef MUTEX_PROF_DATA_NODE static const ctl_named_node_t root_node[] = { {NAME("version"), CTL(version)}, @@ -784,27 +730,13 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, accum_arena_stats_u64(&sdstats->astats.decay_muzzy.purged, &astats->astats.decay_muzzy.purged); - malloc_mutex_prof_merge(&(sdstats->astats.large_mtx_data), - &(astats->astats.large_mtx_data)); - malloc_mutex_prof_merge( - &(sdstats->astats.extent_freelist_mtx_data), - &(astats->astats.extent_freelist_mtx_data)); - malloc_mutex_prof_merge( - &(sdstats->astats.extents_dirty_mtx_data), - &(astats->astats.extents_dirty_mtx_data)); - malloc_mutex_prof_merge( - &(sdstats->astats.extents_muzzy_mtx_data), - &(astats->astats.extents_muzzy_mtx_data)); - malloc_mutex_prof_merge( - &(sdstats->astats.extents_retained_mtx_data), - &(astats->astats.extents_retained_mtx_data)); - malloc_mutex_prof_merge(&(sdstats->astats.decay_dirty_mtx_data), - &(astats->astats.decay_dirty_mtx_data)); - malloc_mutex_prof_merge(&(sdstats->astats.decay_muzzy_mtx_data), - &(astats->astats.decay_muzzy_mtx_data)); - malloc_mutex_prof_merge(&(sdstats->astats.tcache_list_mtx_data), - &(astats->astats.tcache_list_mtx_data)); - +#define OP(mtx) malloc_mutex_prof_merge( \ + &(sdstats->astats.mutex_prof_data[ \ + arena_prof_mutex_##mtx]), \ + &(astats->astats.mutex_prof_data[ \ + arena_prof_mutex_##mtx])); +ARENA_PROF_MUTEXES +#undef OP if (!destroyed) { accum_atomic_zu(&sdstats->astats.base, &astats->astats.base); @@ -975,17 +907,21 @@ ctl_refresh(tsdn_t *tsdn) { ctl_stats->retained = atomic_load_zu( &ctl_sarena->astats->astats.retained, ATOMIC_RELAXED); -#define READ_GLOBAL_MUTEX_PROF_DATA(mtx, data) \ +#define READ_GLOBAL_MUTEX_PROF_DATA(i, mtx) \ malloc_mutex_lock(tsdn, &mtx); \ - malloc_mutex_prof_read(tsdn, &ctl_stats->data, &mtx); \ + malloc_mutex_prof_read(tsdn, &ctl_stats->mutex_prof_data[i], &mtx); \ malloc_mutex_unlock(tsdn, &mtx); - READ_GLOBAL_MUTEX_PROF_DATA(b0get()->mtx, base_mtx_data); + READ_GLOBAL_MUTEX_PROF_DATA(global_prof_mutex_base, + b0get()->mtx); if (config_prof && opt_prof) { - READ_GLOBAL_MUTEX_PROF_DATA(bt2gctx_mtx, prof_mtx_data); + READ_GLOBAL_MUTEX_PROF_DATA(global_prof_mutex_prof, + bt2gctx_mtx); } /* We own ctl mutex already. */ - malloc_mutex_prof_read(tsdn, &ctl_stats->ctl_mtx_data, &ctl_mtx); + malloc_mutex_prof_read(tsdn, + &ctl_stats->mutex_prof_data[global_prof_mutex_ctl], + &ctl_mtx); #undef READ_GLOBAL_MUTEX_PROF_DATA } ctl_arenas->epoch++; @@ -2489,29 +2425,24 @@ CTL_RO_CGEN(config_stats, stats_##n##_total_wait_time, \ CTL_RO_CGEN(config_stats, stats_##n##_max_wait_time, \ nstime_ns(&l.max_wait_time), uint64_t) \ CTL_RO_CGEN(config_stats, stats_##n##_max_num_thds, \ - l.max_n_thds, uint64_t) + l.max_n_thds, uint32_t) /* Global mutexes. */ -#define MTX(mutex) \ - RO_MUTEX_CTL_GEN(mutexes_##mutex, ctl_stats->mutex##_mtx_data) +#define OP(mtx) \ + RO_MUTEX_CTL_GEN(mutexes_##mtx, \ + ctl_stats->mutex_prof_data[global_prof_mutex_##mtx]) GLOBAL_PROF_MUTEXES -#undef MTX +#undef OP + +/* Per arena mutexes */ +#define OP(mtx) RO_MUTEX_CTL_GEN(arenas_i_mutexes_##mtx, \ + arenas_i(mib[2])->astats->astats.mutex_prof_data[arena_prof_mutex_##mtx]) +ARENA_PROF_MUTEXES +#undef OP /* tcache bin mutex */ RO_MUTEX_CTL_GEN(arenas_i_bins_j_mutex, arenas_i(mib[2])->astats->bstats[mib[4]].mutex_data) -/* Per arena mutexes */ -#define ARENAS_ASTATS_MUTEX_CTL_GEN(l, d) \ - RO_MUTEX_CTL_GEN(arenas_i_mutexes_##l, arenas_i(mib[2])->astats->astats.d) -ARENAS_ASTATS_MUTEX_CTL_GEN(large, large_mtx_data) -ARENAS_ASTATS_MUTEX_CTL_GEN(extent_freelist, extent_freelist_mtx_data) -ARENAS_ASTATS_MUTEX_CTL_GEN(extents_dirty, extents_dirty_mtx_data) -ARENAS_ASTATS_MUTEX_CTL_GEN(extents_muzzy, extents_muzzy_mtx_data) -ARENAS_ASTATS_MUTEX_CTL_GEN(extents_retained, extents_retained_mtx_data) -ARENAS_ASTATS_MUTEX_CTL_GEN(decay_dirty, decay_dirty_mtx_data) -ARENAS_ASTATS_MUTEX_CTL_GEN(decay_muzzy, decay_muzzy_mtx_data) -ARENAS_ASTATS_MUTEX_CTL_GEN(tcache_list, tcache_list_mtx_data) -#undef ARENAS_ASTATS_MUTEX_CTL_GEN #undef RO_MUTEX_CTL_GEN /* Resets all mutex stats, including global, arena and bin mutexes. */ diff --git a/src/stats.c b/src/stats.c index ada95e92..aa7ca507 100644 --- a/src/stats.c +++ b/src/stats.c @@ -1,6 +1,18 @@ #define JEMALLOC_STATS_C_ #include "jemalloc/internal/jemalloc_internal.h" +const char *global_mutex_names[num_global_prof_mutexes] = { +#define OP(mtx) #mtx, + GLOBAL_PROF_MUTEXES +#undef OP +}; + +const char *arena_mutex_names[num_arena_prof_mutexes] = { +#define OP(mtx) #mtx, + ARENA_PROF_MUTEXES +#undef OP +}; + #define CTL_GET(n, v, t) do { \ size_t sz = sizeof(t); \ xmallctl(n, (void *)v, &sz, NULL, 0); \ @@ -57,28 +69,49 @@ get_rate_str(uint64_t dividend, uint64_t divisor, char str[6]) { return false; } +#define MUTEX_CTL_STR_MAX_LENGTH 128 static void -gen_mutex_ctl_str(char *str, const char *prefix, const char *mutex, - const char *counter) { - malloc_snprintf(str, 128, "stats.%s.%s.%s", prefix, mutex, counter); +gen_mutex_ctl_str(char *str, size_t buf_len, const char *prefix, + const char *mutex, const char *counter) { + malloc_snprintf(str, buf_len, "stats.%s.%s.%s", prefix, mutex, counter); } static void read_arena_bin_mutex_stats(unsigned arena_ind, unsigned bin_ind, - uint64_t results[NUM_MUTEX_PROF_COUNTERS]) { - char cmd[128]; - - unsigned i; - for (i = 0; i < NUM_MUTEX_PROF_COUNTERS; i++) { - gen_mutex_ctl_str(cmd, "arenas.0.bins.0","mutex", - mutex_counter_names[i]); - CTL_M2_M4_GET(cmd, arena_ind, bin_ind, &results[i], uint64_t); - } + uint64_t results[num_mutex_prof_counters]) { + char cmd[MUTEX_CTL_STR_MAX_LENGTH]; +#define OP(c, t) \ + gen_mutex_ctl_str(cmd, MUTEX_CTL_STR_MAX_LENGTH, \ + "arenas.0.bins.0","mutex", #c); \ + CTL_M2_M4_GET(cmd, arena_ind, bin_ind, \ + (t *)&results[mutex_counter_##c], t); +MUTEX_PROF_COUNTERS +#undef OP +} + +static void +mutex_stats_output_json(void (*write_cb)(void *, const char *), void *cbopaque, + const char *name, uint64_t stats[num_mutex_prof_counters], + const char *json_indent, bool last) { + malloc_cprintf(write_cb, cbopaque, "%s\"%s\": {\n", json_indent, name); + + mutex_prof_counter_ind_t k = 0; + char *fmt_str[2] = {"%s\t\"%s\": %"FMTu32"%s\n", + "%s\t\"%s\": %"FMTu64"%s\n"}; +#define OP(c, t) \ + malloc_cprintf(write_cb, cbopaque, \ + fmt_str[sizeof(t) / sizeof(uint32_t) - 1], \ + json_indent, #c, (t)stats[mutex_counter_##c], \ + (++k == num_mutex_prof_counters) ? "" : ","); +MUTEX_PROF_COUNTERS +#undef OP + malloc_cprintf(write_cb, cbopaque, "%s}%s\n", json_indent, + last ? "" : ","); } static void stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, - bool json, bool large, unsigned i) { + bool json, bool large, bool mutex, unsigned i) { size_t page; bool in_gap, in_gap_prev; unsigned nbins, j; @@ -147,9 +180,6 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, size_t); if (json) { - uint64_t mutex_stats[NUM_MUTEX_PROF_COUNTERS]; - read_arena_bin_mutex_stats(i, j, mutex_stats); - malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\t{\n" "\t\t\t\t\t\t\"nmalloc\": %"FMTu64",\n" @@ -169,20 +199,16 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, } malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\t\t\"nreslabs\": %"FMTu64",\n" - "\t\t\t\t\t\t\"curslabs\": %zu,\n" - "\t\t\t\t\t\t\"mutex\": {\n", - nreslabs, - curslabs); + "\t\t\t\t\t\t\"curslabs\": %zu%s\n", + nreslabs, curslabs, mutex ? "," : ""); - for (unsigned k = 0; k < NUM_MUTEX_PROF_COUNTERS; k++) { - malloc_cprintf(write_cb, cbopaque, - "\t\t\t\t\t\t\t\"%s\": %"FMTu64"%s\n", - mutex_counter_names[k], mutex_stats[k], - k == NUM_MUTEX_PROF_COUNTERS - 1 ? "" : ","); + if (mutex) { + uint64_t mutex_stats[num_mutex_prof_counters]; + read_arena_bin_mutex_stats(i, j, mutex_stats); + mutex_stats_output_json(write_cb, cbopaque, + "mutex", mutex_stats, "\t\t\t\t\t\t", true); } - malloc_cprintf(write_cb, cbopaque, - "\t\t\t\t\t\t}\n" "\t\t\t\t\t}%s\n", (j + 1 < nbins) ? "," : ""); } else if (!in_gap) { @@ -326,74 +352,79 @@ stats_arena_lextents_print(void (*write_cb)(void *, const char *), static void read_arena_mutex_stats(unsigned arena_ind, - uint64_t results[NUM_ARENA_PROF_MUTEXES][NUM_MUTEX_PROF_COUNTERS]) { - char cmd[128]; - - unsigned i, j; - for (i = 0; i < NUM_ARENA_PROF_MUTEXES; i++) { - for (j = 0; j < NUM_MUTEX_PROF_COUNTERS; j++) { - gen_mutex_ctl_str(cmd, "arenas.0.mutexes", - arena_mutex_names[i], mutex_counter_names[j]); - CTL_M2_GET(cmd, arena_ind, &results[i][j], uint64_t); - } + uint64_t results[num_arena_prof_mutexes][num_mutex_prof_counters]) { + char cmd[MUTEX_CTL_STR_MAX_LENGTH]; + + arena_prof_mutex_ind_t i; + for (i = 0; i < num_arena_prof_mutexes; i++) { +#define OP(c, t) \ + gen_mutex_ctl_str(cmd, MUTEX_CTL_STR_MAX_LENGTH, \ + "arenas.0.mutexes", arena_mutex_names[i], #c); \ + CTL_M2_GET(cmd, arena_ind, \ + (t *)&results[i][mutex_counter_##c], t); +MUTEX_PROF_COUNTERS +#undef OP } } -static void -mutex_stats_output_json(void (*write_cb)(void *, const char *), void *cbopaque, - const char *name, uint64_t stats[NUM_MUTEX_PROF_COUNTERS], - const char *json_indent, bool last) { - - malloc_cprintf(write_cb, cbopaque, "%s\"%s\": {\n", json_indent, name); - for (unsigned i = 0; i < NUM_MUTEX_PROF_COUNTERS; i++) { - malloc_cprintf(write_cb, cbopaque, "%s\t\"%s\": %"FMTu64"%s\n", - json_indent, mutex_counter_names[i], stats[i], - i < (NUM_MUTEX_PROF_COUNTERS - 1) ? "," : ""); - } - malloc_cprintf(write_cb, cbopaque, "%s}%s\n", json_indent, - last ? "" : ","); -} - static void mutex_stats_output(void (*write_cb)(void *, const char *), void *cbopaque, - const char *name, uint64_t stats[NUM_MUTEX_PROF_COUNTERS], + const char *name, uint64_t stats[num_mutex_prof_counters], bool first_mutex) { if (first_mutex) { /* Print title. */ malloc_cprintf(write_cb, cbopaque, - " n_lock_ops n_waiting" - " n_spin_acq n_owner_switch total_wait_ns" - " max_wait_ns max_n_wait_thds\n"); + " n_lock_ops n_waiting" + " n_spin_acq n_owner_switch total_wait_ns" + " max_wait_ns max_n_thds\n"); } malloc_cprintf(write_cb, cbopaque, "%s", name); malloc_cprintf(write_cb, cbopaque, ":%*c", - (int)(19 - strlen(name)), ' '); - - for (unsigned i = 0; i < NUM_MUTEX_PROF_COUNTERS; i++) { - malloc_cprintf(write_cb, cbopaque, " %16"FMTu64, stats[i]); - } + (int)(20 - strlen(name)), ' '); + + char *fmt_str[2] = {"%12"FMTu32, "%16"FMTu64}; +#define OP(c, t) \ + malloc_cprintf(write_cb, cbopaque, \ + fmt_str[sizeof(t) / sizeof(uint32_t) - 1], \ + (t)stats[mutex_counter_##c]); +MUTEX_PROF_COUNTERS +#undef OP malloc_cprintf(write_cb, cbopaque, "\n"); } static void stats_arena_mutexes_print(void (*write_cb)(void *, const char *), void *cbopaque, bool json, bool json_end, unsigned arena_ind) { - uint64_t mutex_stats[NUM_ARENA_PROF_MUTEXES][NUM_MUTEX_PROF_COUNTERS]; + uint64_t mutex_stats[num_arena_prof_mutexes][num_mutex_prof_counters]; read_arena_mutex_stats(arena_ind, mutex_stats); /* Output mutex stats. */ if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\"mutexes\": {\n"); - for (unsigned i = 0; i < NUM_ARENA_PROF_MUTEXES; i++) { + arena_prof_mutex_ind_t i, last_mutex; + last_mutex = num_arena_prof_mutexes - 1; + if (!config_tcache) { + last_mutex--; + } + for (i = 0; i < num_arena_prof_mutexes; i++) { + if (!config_tcache && + i == arena_prof_mutex_tcache_list) { + continue; + } mutex_stats_output_json(write_cb, cbopaque, arena_mutex_names[i], mutex_stats[i], - "\t\t\t\t\t", (i == NUM_ARENA_PROF_MUTEXES - 1)); + "\t\t\t\t\t", (i == last_mutex)); } malloc_cprintf(write_cb, cbopaque, "\t\t\t\t}%s\n", json_end ? "" : ","); } else { - for (unsigned i = 0; i < NUM_ARENA_PROF_MUTEXES; i++) { + arena_prof_mutex_ind_t i; + for (i = 0; i < num_arena_prof_mutexes; i++) { + if (!config_tcache && + i == arena_prof_mutex_tcache_list) { + continue; + } mutex_stats_output(write_cb, cbopaque, arena_mutex_names[i], mutex_stats[i], i == 0); } @@ -636,7 +667,8 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, !(bins || large), i); } if (bins) { - stats_arena_bins_print(write_cb, cbopaque, json, large, i); + stats_arena_bins_print(write_cb, cbopaque, json, large, mutex, + i); } if (large) { stats_arena_lextents_print(write_cb, cbopaque, json, i); @@ -995,16 +1027,17 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, static void read_global_mutex_stats( - uint64_t results[NUM_GLOBAL_PROF_MUTEXES][NUM_MUTEX_PROF_COUNTERS]) { - char cmd[128]; - - unsigned i, j; - for (i = 0; i < NUM_GLOBAL_PROF_MUTEXES; i++) { - for (j = 0; j < NUM_MUTEX_PROF_COUNTERS; j++) { - gen_mutex_ctl_str(cmd, "mutexes", global_mutex_names[i], - mutex_counter_names[j]); - CTL_GET(cmd, &results[i][j], uint64_t); - } + uint64_t results[num_global_prof_mutexes][num_mutex_prof_counters]) { + char cmd[MUTEX_CTL_STR_MAX_LENGTH]; + + global_prof_mutex_ind_t i; + for (i = 0; i < num_global_prof_mutexes; i++) { +#define OP(c, t) \ + gen_mutex_ctl_str(cmd, MUTEX_CTL_STR_MAX_LENGTH, \ + "mutexes", global_mutex_names[i], #c); \ + CTL_GET(cmd, (t *)&results[i][mutex_counter_##c], t); +MUTEX_PROF_COUNTERS +#undef OP } } @@ -1021,7 +1054,7 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, CTL_GET("stats.mapped", &mapped, size_t); CTL_GET("stats.retained", &retained, size_t); - uint64_t mutex_stats[NUM_GLOBAL_PROF_MUTEXES][NUM_MUTEX_PROF_COUNTERS]; + uint64_t mutex_stats[num_global_prof_mutexes][num_mutex_prof_counters]; if (mutex) { read_global_mutex_stats(mutex_stats); } @@ -1041,15 +1074,16 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "\t\t\t\"mapped\": %zu,\n", mapped); malloc_cprintf(write_cb, cbopaque, - "\t\t\t\"retained\": %zu,\n", retained); + "\t\t\t\"retained\": %zu%s\n", retained, mutex ? "," : ""); if (mutex) { malloc_cprintf(write_cb, cbopaque, "\t\t\t\"mutexes\": {\n"); - - for (unsigned i = 0; i < NUM_GLOBAL_PROF_MUTEXES; i++) { + global_prof_mutex_ind_t i; + for (i = 0; i < num_global_prof_mutexes; i++) { mutex_stats_output_json(write_cb, cbopaque, global_mutex_names[i], mutex_stats[i], - "\t\t\t\t", i == NUM_GLOBAL_PROF_MUTEXES - 1); + "\t\t\t\t", + i == num_global_prof_mutexes - 1); } malloc_cprintf(write_cb, cbopaque, "\t\t\t}\n"); } @@ -1061,7 +1095,8 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, " resident: %zu, mapped: %zu, retained: %zu\n", allocated, active, metadata, resident, mapped, retained); if (mutex) { - for (unsigned i = 0; i < NUM_GLOBAL_PROF_MUTEXES; i++) { + global_prof_mutex_ind_t i; + for (i = 0; i < num_global_prof_mutexes; i++) { mutex_stats_output(write_cb, cbopaque, global_mutex_names[i], mutex_stats[i], i == 0); -- GitLab From 362e356675b244fceebb5fe9e2585e77dd47189d Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 22 Mar 2017 01:49:56 -0700 Subject: [PATCH 354/544] Profile per arena base mutex, instead of just a0. --- include/jemalloc/internal/ctl_types.h | 2 +- src/arena.c | 2 ++ src/ctl.c | 9 ++++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/jemalloc/internal/ctl_types.h b/include/jemalloc/internal/ctl_types.h index 1b5c76f9..065ccda5 100644 --- a/include/jemalloc/internal/ctl_types.h +++ b/include/jemalloc/internal/ctl_types.h @@ -2,7 +2,6 @@ #define JEMALLOC_INTERNAL_CTL_TYPES_H #define GLOBAL_PROF_MUTEXES \ - OP(base) \ OP(ctl) \ OP(prof) @@ -21,6 +20,7 @@ typedef enum { OP(extents_retained) \ OP(decay_dirty) \ OP(decay_muzzy) \ + OP(base) \ OP(tcache_list) typedef enum { diff --git a/src/arena.c b/src/arena.c index 3383a3b8..519111e5 100644 --- a/src/arena.c +++ b/src/arena.c @@ -318,6 +318,8 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, arena_prof_mutex_decay_dirty) READ_ARENA_MUTEX_PROF_DATA(decay_muzzy.mtx, arena_prof_mutex_decay_muzzy) + READ_ARENA_MUTEX_PROF_DATA(base->mtx, + arena_prof_mutex_base) #undef READ_ARENA_MUTEX_PROF_DATA for (szind_t i = 0; i < NBINS; i++) { diff --git a/src/ctl.c b/src/ctl.c index e2ee36a6..36f5634d 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -912,8 +912,6 @@ ctl_refresh(tsdn_t *tsdn) { malloc_mutex_prof_read(tsdn, &ctl_stats->mutex_prof_data[i], &mtx); \ malloc_mutex_unlock(tsdn, &mtx); - READ_GLOBAL_MUTEX_PROF_DATA(global_prof_mutex_base, - b0get()->mtx); if (config_prof && opt_prof) { READ_GLOBAL_MUTEX_PROF_DATA(global_prof_mutex_prof, bt2gctx_mtx); @@ -2460,12 +2458,12 @@ stats_mutexes_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, malloc_mutex_prof_data_reset(tsdn, &mtx); \ malloc_mutex_unlock(tsdn, &mtx); - /* Global mutexes: base, prof and ctl. */ - MUTEX_PROF_RESET(b0get()->mtx); + /* Global mutexes: ctl and prof. */ + MUTEX_PROF_RESET(ctl_mtx); if (config_prof && opt_prof) { MUTEX_PROF_RESET(bt2gctx_mtx); } - MUTEX_PROF_RESET(ctl_mtx); + /* Per arena mutexes. */ unsigned n = narenas_total_get(); @@ -2485,6 +2483,7 @@ stats_mutexes_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, if (config_tcache) { MUTEX_PROF_RESET(arena->tcache_ql_mtx); } + MUTEX_PROF_RESET(arena->base->mtx); for (szind_t i = 0; i < NBINS; i++) { arena_bin_t *bin = &arena->bins[i]; -- GitLab From bbc16a50f975d84ba43d831666b95d8b38e01656 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 22 Mar 2017 16:59:14 -0700 Subject: [PATCH 355/544] Added documentation for mutex profiling related mallctls. --- doc/jemalloc.xml.in | 206 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 265da86f..91127a03 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -2153,6 +2153,80 @@ struct extent_hooks_s { + + + stats.mutexes.ctl.{counter}; + (counter specific type) + r- + [] + + Statistics on ctl mutex (global + scope; mallctl related). {counter} is one of the + counters below: + + num_ops (uint64_t): + Total number of lock acquisition operations on this mutex. + + num_spin_acq (uint64_t): Number + of times the mutex was spin-acquired. When the mutex is currently + locked and cannot be acquired immediately, a short period of + spin-retry within jemalloc will be performed. Acquired through spin + generally means the contention was lightweight and not causing context + switches. + + num_wait (uint64_t): Number of + times the mutex was wait-acquired, which means the mutex contention + was not solved by spin-retry, and blocking operation was likely + involved in order to acquire the mutex. This event generally implies + higher cost / longer delay, and should be investigated if it happens + often. + + max_wait_time (uint64_t): + Maximum length of time in nanoseconds spent on a single wait-acquired + lock operation. Note that to avoid profiling overhead on the common + path, this does not consider spin-acquired cases. + + total_wait_time (uint64_t): + Cumulative time in nanoseconds spent on wait-acquired lock operations. + Similarly, spin-acquired cases are not considered. + + max_num_thds (uint32_t): Maximum + number of threads waiting on this mutex simultaneously. Similarly, + spin-acquired cases are not considered. + + num_owner_switch (uint64_t): + Number of times the current mutex owner is different from the previous + one. This event does not generally imply an issue; rather it is an + indicator of how often the protected data are accessed by different + threads. + + + + + + + + + stats.mutexes.prof.{counter} + (counter specific type) r- + [] + + Statistics on prof mutex (global + scope; profiling related). {counter} is one of the + counters in mutex profiling + counters. + + + + + stats.mutexes.reset + (void) -- + [] + + Reset all mutex profile statistics, including global + mutexes, arena mutexes and bin mutexes. + + stats.arenas.<i>.dss @@ -2547,6 +2621,19 @@ struct extent_hooks_s { Current number of slabs. + + + stats.arenas.<i>.bins.<j>.mutex.{counter} + (counter specific type) r- + [] + + Statistics on + arena.<i>.bins.<j> mutex (arena bin + scope; bin operation related). {counter} is one of + the counters in mutex profiling + counters. + + stats.arenas.<i>.lextents.<j>.nmalloc @@ -2590,6 +2677,125 @@ struct extent_hooks_s { Current number of large allocations for this size class. + + + + stats.arenas.<i>.mutexes.large.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.large + mutex (arena scope; large allocation related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.extent_freelist.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.extent_freelist + mutex (arena scope; extent freelist related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.extents_dirty.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.extents_dirty + mutex (arena scope; dirty extents related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.extents_muzzy.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.extents_muzzy + mutex (arena scope; muzzy extents related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.extents_retained.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.extents_retained + mutex (arena scope; retained extents related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.decay_dirty.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.decay_dirty + mutex (arena scope; decay for dirty pages related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.decay_muzzy.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.decay_muzzy + mutex (arena scope; decay for muzzy pages related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.base.{counter} + (counter specific type) r- + [] + + Statistics on arena.<i>.base + mutex (arena scope; base allocator related). + {counter} is one of the counters in mutex profiling + counters. + + + + + stats.arenas.<i>.mutexes.tcache_list.{counter} + (counter specific type) r- + [] + + Statistics on + arena.<i>.tcache_list mutex (arena scope; + tcache to arena association related). This mutex is expected to be + accessed less often. {counter} is one of the + counters in mutex profiling + counters. + + -- GitLab From a832ebaee905522fafa1be438dbf3fb5066f1e00 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 22 Mar 2017 20:06:25 -0700 Subject: [PATCH 356/544] Use first fit layout policy instead of best fit. For extents which do not delay coalescing, use first fit layout policy rather than first-best fit layout policy. This packs extents toward older virtual memory mappings, but at the cost of higher search overhead in the common case. This resolves #711. --- src/extent.c | 54 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/src/extent.c b/src/extent.c index f1b513e4..f04fd01a 100644 --- a/src/extent.c +++ b/src/extent.c @@ -256,21 +256,13 @@ extents_remove_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent, cur_extents_npages - (size >> LG_PAGE), ATOMIC_RELAXED); } -/* - * Do {first,any}-best-fit extent selection, i.e. select the oldest/lowest or - * any extent that best fits, where {first,any} corresponds to - * extents->delay_coalesce={false,true}. - */ +/* Do any-best-fit extent selection, i.e. select any extent that best fits. */ static extent_t * extents_best_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, size_t size) { - malloc_mutex_assert_owner(tsdn, &extents->mtx); - pszind_t pind = psz2ind(extent_size_quantize_ceil(size)); for (pszind_t i = pind; i < NPSIZES+1; i++) { - extent_t *extent = extents->delay_coalesce ? - extent_heap_any(&extents->heaps[i]) : - extent_heap_first(&extents->heaps[i]); + extent_t *extent = extent_heap_any(&extents->heaps[i]); if (extent != NULL) { assert(extent_size_get(extent) >= size); return extent; @@ -280,6 +272,45 @@ extents_best_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, return NULL; } +/* + * Do first-fit extent selection, i.e. select the oldest/lowest extent that is + * large enough. + */ +static extent_t * +extents_first_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, + size_t size) { + extent_t *ret = NULL; + + pszind_t pind = psz2ind(extent_size_quantize_ceil(size)); + for (pszind_t i = pind; i < NPSIZES+1; i++) { + extent_t *extent = extent_heap_first(&extents->heaps[i]); + if (extent != NULL) { + assert(extent_size_get(extent) >= size); + if (ret == NULL || extent_snad_comp(extent, ret) < 0) { + ret = extent; + } + } + } + + return ret; +} + +/* + * Do {best,first}-fit extent selection, where the selection policy choice is + * based on extents->delay_coalesce. Best-fit selection requires less + * searching, but its layout policy is less stable and may cause higher virtual + * memory fragmentation as a side effect. + */ +static extent_t * +extents_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, + size_t size) { + malloc_mutex_assert_owner(tsdn, &extents->mtx); + + return extents->delay_coalesce ? extents_best_fit_locked(tsdn, arena, + extents, size) : extents_first_fit_locked(tsdn, arena, extents, + size); +} + static bool extent_try_delayed_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, @@ -675,8 +706,7 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, extent = NULL; } } else { - extent = extents_best_fit_locked(tsdn, arena, extents, - alloc_size); + extent = extents_fit_locked(tsdn, arena, extents, alloc_size); } if (extent == NULL) { if (!locked) { -- GitLab From c8021d01f6efe14dc1bd200021a815638063cb5f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 23 Mar 2017 17:59:47 -0700 Subject: [PATCH 357/544] Implement bitmap_ffu(), which finds the first unset bit. --- include/jemalloc/internal/bitmap_externs.h | 2 +- include/jemalloc/internal/bitmap_inlines.h | 70 +++++++++++++++++-- include/jemalloc/internal/private_symbols.txt | 1 + src/arena.c | 2 +- src/bitmap.c | 27 +++++-- test/unit/bitmap.c | 59 ++++++++++++---- 6 files changed, 136 insertions(+), 25 deletions(-) diff --git a/include/jemalloc/internal/bitmap_externs.h b/include/jemalloc/internal/bitmap_externs.h index 4df63eba..034a4e6b 100644 --- a/include/jemalloc/internal/bitmap_externs.h +++ b/include/jemalloc/internal/bitmap_externs.h @@ -2,7 +2,7 @@ #define JEMALLOC_INTERNAL_BITMAP_EXTERNS_H void bitmap_info_init(bitmap_info_t *binfo, size_t nbits); -void bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo); +void bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo, bool fill); size_t bitmap_size(const bitmap_info_t *binfo); #endif /* JEMALLOC_INTERNAL_BITMAP_EXTERNS_H */ diff --git a/include/jemalloc/internal/bitmap_inlines.h b/include/jemalloc/internal/bitmap_inlines.h index df582bbe..07166ba5 100644 --- a/include/jemalloc/internal/bitmap_inlines.h +++ b/include/jemalloc/internal/bitmap_inlines.h @@ -2,11 +2,13 @@ #define JEMALLOC_INTERNAL_BITMAP_INLINES_H #ifndef JEMALLOC_ENABLE_INLINE -bool bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo); -bool bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); -void bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); -size_t bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo); -void bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); +bool bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo); +bool bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); +void bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); +size_t bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, + size_t min_bit); +size_t bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo); +void bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BITMAP_C_)) @@ -75,6 +77,64 @@ bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { #endif } +/* ffu: find first unset >= bit. */ +JEMALLOC_INLINE size_t +bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) { + assert(min_bit < binfo->nbits); + +#ifdef BITMAP_USE_TREE + unsigned level = binfo->nlevels - 1; + size_t lg_bits_per_group = (LG_BITMAP_GROUP_NBITS * (level+1)); + size_t bits_per_group = 1LU << lg_bits_per_group; + size_t bits_per_group_mask = bits_per_group - 1; + unsigned group_nmask = (min_bit & bits_per_group_mask) >> (level * + LG_BITMAP_GROUP_NBITS); + bitmap_t group_mask = ~((1LU << group_nmask) - 1); + bitmap_t group = bitmap[binfo->levels[level].group_offset] & group_mask; + if (group == 0LU) { + return binfo->nbits; + } + size_t bit = ffs_lu(group) - 1; + + while (level > 0) { + level--; + + lg_bits_per_group = (LG_BITMAP_GROUP_NBITS * (level+1)); + bits_per_group = 1LU << lg_bits_per_group; + bits_per_group_mask = bits_per_group - 1; + + group = bitmap[binfo->levels[level].group_offset + bit]; + size_t cur_base = bit << lg_bits_per_group; + if (cur_base < min_bit) { + group_nmask = (min_bit & bits_per_group_mask) >> (level + * LG_BITMAP_GROUP_NBITS); + group_mask = ~((1LU << group_nmask) - 1); + group &= group_mask; + } + if (group == 0LU) { + return binfo->nbits; + } + bit = (bit << LG_BITMAP_GROUP_NBITS) + (ffs_lu(group) - 1); + } + assert(bit < binfo->nbits); + return bit; +#else + size_t i = min_bit >> LG_BITMAP_GROUP_NBITS; + bitmap_t g = bitmap[i] & ~((1LU << (min_bit & BITMAP_GROUP_NBITS_MASK)) + - 1); + size_t bit; + do { + bit = ffs_lu(g); + if (bit != 0) { + return (i << LG_BITMAP_GROUP_NBITS) + (bit - 1); + } + i++; + g = bitmap[i]; + } while (i < binfo->ngroups); + return binfo->nbits; +#endif +} + /* sfu: set first unset. */ JEMALLOC_INLINE size_t bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) { diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 1af1f91b..d22cd874 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -94,6 +94,7 @@ base_postfork_child base_postfork_parent base_prefork base_stats_get +bitmap_ffu bitmap_full bitmap_get bitmap_info_init diff --git a/src/arena.c b/src/arena.c index 519111e5..b0913c35 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1210,7 +1210,7 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, /* Initialize slab internals. */ arena_slab_data_t *slab_data = extent_slab_data_get(slab); slab_data->nfree = bin_info->nregs; - bitmap_init(slab_data->bitmap, &bin_info->bitmap_info); + bitmap_init(slab_data->bitmap, &bin_info->bitmap_info, false); arena_nactive_add(arena, extent_size_get(slab) >> LG_PAGE); diff --git a/src/bitmap.c b/src/bitmap.c index 17efb73c..81d2a6da 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -39,16 +39,26 @@ bitmap_info_ngroups(const bitmap_info_t *binfo) { } void -bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo) { +bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo, bool fill) { size_t extra; unsigned i; /* * Bits are actually inverted with regard to the external bitmap - * interface, so the bitmap starts out with all 1 bits, except for - * trailing unused bits (if any). Note that each group uses bit 0 to - * correspond to the first logical bit in the group, so extra bits - * are the most significant bits of the last group. + * interface. + */ + + if (fill) { + /* The "filled" bitmap starts out with all 0 bits. */ + memset(bitmap, 0, bitmap_size(binfo)); + return; + } + + /* + * The "empty" bitmap starts out with all 1 bits, except for trailing + * unused bits (if any). Note that each group uses bit 0 to correspond + * to the first logical bit in the group, so extra bits are the most + * significant bits of the last group. */ memset(bitmap, 0xffU, bitmap_size(binfo)); extra = (BITMAP_GROUP_NBITS - (binfo->nbits & BITMAP_GROUP_NBITS_MASK)) @@ -84,9 +94,14 @@ bitmap_info_ngroups(const bitmap_info_t *binfo) { } void -bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo) { +bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo, bool fill) { size_t extra; + if (fill) { + memset(bitmap, 0, bitmap_size(binfo)); + return; + } + memset(bitmap, 0xffU, bitmap_size(binfo)); extra = (BITMAP_GROUP_NBITS - (binfo->nbits & BITMAP_GROUP_NBITS_MASK)) & BITMAP_GROUP_NBITS_MASK; diff --git a/test/unit/bitmap.c b/test/unit/bitmap.c index ca657608..92a07dec 100644 --- a/test/unit/bitmap.c +++ b/test/unit/bitmap.c @@ -171,12 +171,18 @@ test_bitmap_init_body(const bitmap_info_t *binfo, size_t nbits) { size_t i; bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo)); assert_ptr_not_null(bitmap, "Unexpected malloc() failure"); - bitmap_init(bitmap, binfo); + bitmap_init(bitmap, binfo, false); for (i = 0; i < nbits; i++) { assert_false(bitmap_get(bitmap, binfo, i), "Bit should be unset"); } + + bitmap_init(bitmap, binfo, true); + for (i = 0; i < nbits; i++) { + assert_true(bitmap_get(bitmap, binfo, i), "Bit should be set"); + } + free(bitmap); } @@ -202,7 +208,7 @@ test_bitmap_set_body(const bitmap_info_t *binfo, size_t nbits) { size_t i; bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo)); assert_ptr_not_null(bitmap, "Unexpected malloc() failure"); - bitmap_init(bitmap, binfo); + bitmap_init(bitmap, binfo, false); for (i = 0; i < nbits; i++) { bitmap_set(bitmap, binfo, i); @@ -233,7 +239,7 @@ test_bitmap_unset_body(const bitmap_info_t *binfo, size_t nbits) { size_t i; bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo)); assert_ptr_not_null(bitmap, "Unexpected malloc() failure"); - bitmap_init(bitmap, binfo); + bitmap_init(bitmap, binfo, false); for (i = 0; i < nbits; i++) { bitmap_set(bitmap, binfo, i); @@ -268,14 +274,22 @@ TEST_END static void test_bitmap_sfu_body(const bitmap_info_t *binfo, size_t nbits) { - size_t i; bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo)); assert_ptr_not_null(bitmap, "Unexpected malloc() failure"); - bitmap_init(bitmap, binfo); + bitmap_init(bitmap, binfo, false); /* Iteratively set bits starting at the beginning. */ - for (i = 0; i < nbits; i++) { - assert_zd_eq(bitmap_sfu(bitmap, binfo), i, + for (size_t i = 0; i < nbits; i++) { + assert_zu_eq(bitmap_ffu(bitmap, binfo, 0), i, + "First unset bit should be just after previous first unset " + "bit"); + assert_zu_eq(bitmap_ffu(bitmap, binfo, (i > 0) ? i-1 : i), i, + "First unset bit should be just after previous first unset " + "bit"); + assert_zu_eq(bitmap_ffu(bitmap, binfo, i), i, + "First unset bit should be just after previous first unset " + "bit"); + assert_zu_eq(bitmap_sfu(bitmap, binfo), i, "First unset bit should be just after previous first unset " "bit"); } @@ -285,9 +299,15 @@ test_bitmap_sfu_body(const bitmap_info_t *binfo, size_t nbits) { * Iteratively unset bits starting at the end, and verify that * bitmap_sfu() reaches the unset bits. */ - for (i = nbits - 1; i < nbits; i--) { /* (nbits..0] */ + for (size_t i = nbits - 1; i < nbits; i--) { /* (nbits..0] */ bitmap_unset(bitmap, binfo, i); - assert_zd_eq(bitmap_sfu(bitmap, binfo), i, + assert_zu_eq(bitmap_ffu(bitmap, binfo, 0), i, + "First unset bit should the bit previously unset"); + assert_zu_eq(bitmap_ffu(bitmap, binfo, (i > 0) ? i-1 : i), i, + "First unset bit should the bit previously unset"); + assert_zu_eq(bitmap_ffu(bitmap, binfo, i), i, + "First unset bit should the bit previously unset"); + assert_zu_eq(bitmap_sfu(bitmap, binfo), i, "First unset bit should the bit previously unset"); bitmap_unset(bitmap, binfo, i); } @@ -297,14 +317,29 @@ test_bitmap_sfu_body(const bitmap_info_t *binfo, size_t nbits) { * Iteratively set bits starting at the beginning, and verify that * bitmap_sfu() looks past them. */ - for (i = 1; i < nbits; i++) { + for (size_t i = 1; i < nbits; i++) { bitmap_set(bitmap, binfo, i - 1); - assert_zd_eq(bitmap_sfu(bitmap, binfo), i, + assert_zu_eq(bitmap_ffu(bitmap, binfo, 0), i, + "First unset bit should be just after the bit previously " + "set"); + assert_zu_eq(bitmap_ffu(bitmap, binfo, (i > 0) ? i-1 : i), i, + "First unset bit should be just after the bit previously " + "set"); + assert_zu_eq(bitmap_ffu(bitmap, binfo, i), i, + "First unset bit should be just after the bit previously " + "set"); + assert_zu_eq(bitmap_sfu(bitmap, binfo), i, "First unset bit should be just after the bit previously " "set"); bitmap_unset(bitmap, binfo, i); } - assert_zd_eq(bitmap_sfu(bitmap, binfo), nbits - 1, + assert_zu_eq(bitmap_ffu(bitmap, binfo, 0), nbits - 1, + "First unset bit should be the last bit"); + assert_zu_eq(bitmap_ffu(bitmap, binfo, (nbits > 1) ? nbits-2 : nbits-1), + nbits - 1, "First unset bit should be the last bit"); + assert_zu_eq(bitmap_ffu(bitmap, binfo, nbits - 1), nbits - 1, + "First unset bit should be the last bit"); + assert_zu_eq(bitmap_sfu(bitmap, binfo), nbits - 1, "First unset bit should be the last bit"); assert_true(bitmap_full(bitmap, binfo), "All bits should be set"); free(bitmap); -- GitLab From 57e353163f0ec099aed8feee2083e95c9d4b472b Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 24 Mar 2017 01:12:42 -0700 Subject: [PATCH 358/544] Implement BITMAP_GROUPS(). --- include/jemalloc/internal/bitmap_types.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/jemalloc/internal/bitmap_types.h b/include/jemalloc/internal/bitmap_types.h index ec8a6dc9..d0de2f05 100644 --- a/include/jemalloc/internal/bitmap_types.h +++ b/include/jemalloc/internal/bitmap_types.h @@ -65,14 +65,19 @@ typedef unsigned long bitmap_t; #ifdef BITMAP_USE_TREE #if LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_1_LEVEL(nbits) # define BITMAP_GROUPS_MAX BITMAP_GROUPS_1_LEVEL(BITMAP_MAXBITS) #elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 2 +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_2_LEVEL(nbits) # define BITMAP_GROUPS_MAX BITMAP_GROUPS_2_LEVEL(BITMAP_MAXBITS) #elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 3 +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_3_LEVEL(nbits) # define BITMAP_GROUPS_MAX BITMAP_GROUPS_3_LEVEL(BITMAP_MAXBITS) #elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 4 +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_4_LEVEL(nbits) # define BITMAP_GROUPS_MAX BITMAP_GROUPS_4_LEVEL(BITMAP_MAXBITS) #elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 5 +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_5_LEVEL(nbits) # define BITMAP_GROUPS_MAX BITMAP_GROUPS_5_LEVEL(BITMAP_MAXBITS) #else # error "Unsupported bitmap size" @@ -119,6 +124,7 @@ typedef unsigned long bitmap_t; #else /* BITMAP_USE_TREE */ +#define BITMAP_GROUPS(nbits) BITMAP_BITS2GROUPS(nbits) #define BITMAP_GROUPS_MAX BITMAP_BITS2GROUPS(BITMAP_MAXBITS) #define BITMAP_INFO_INITIALIZER(nbits) { \ -- GitLab From 5d33233a5e6601902df7cddd8cc8aa0b135c77b2 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 23 Mar 2017 23:45:11 -0700 Subject: [PATCH 359/544] Use a bitmap in extents_t to speed up search. Rather than iteratively checking all sufficiently large heaps during search, maintain and use a bitmap in order to skip empty heaps. --- include/jemalloc/internal/bitmap_types.h | 8 ++++- include/jemalloc/internal/extent_structs.h | 7 ++++ src/extent.c | 41 ++++++++++++++++------ 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/include/jemalloc/internal/bitmap_types.h b/include/jemalloc/internal/bitmap_types.h index d0de2f05..b334769f 100644 --- a/include/jemalloc/internal/bitmap_types.h +++ b/include/jemalloc/internal/bitmap_types.h @@ -2,7 +2,13 @@ #define JEMALLOC_INTERNAL_BITMAP_TYPES_H /* Maximum bitmap bit count is 2^LG_BITMAP_MAXBITS. */ -#define LG_BITMAP_MAXBITS LG_SLAB_MAXREGS +#if LG_SLAB_MAXREGS > LG_CEIL_NSIZES +/* Maximum bitmap bit count is determined by maximum regions per slab. */ +# define LG_BITMAP_MAXBITS LG_SLAB_MAXREGS +#else +/* Maximum bitmap bit count is determined by number of extent size classes. */ +# define LG_BITMAP_MAXBITS LG_CEIL_NSIZES +#endif #define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS) typedef struct bitmap_level_s bitmap_level_t; diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 82cfa58a..5cf3c9b2 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -102,6 +102,13 @@ struct extents_s { */ extent_heap_t heaps[NPSIZES+1]; + /* + * Bitmap for which set bits correspond to non-empty heaps. + * + * Synchronization: mtx. + */ + bitmap_t bitmap[BITMAP_GROUPS(NPSIZES+1)]; + /* * LRU of all extents in heaps. * diff --git a/src/extent.c b/src/extent.c index f04fd01a..3f4f5f1b 100644 --- a/src/extent.c +++ b/src/extent.c @@ -6,6 +6,9 @@ rtree_t extents_rtree; +static const bitmap_info_t extents_bitmap_info = + BITMAP_INFO_INITIALIZER(NPSIZES+1); + static void *extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit, unsigned arena_ind); @@ -189,6 +192,7 @@ extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state, for (unsigned i = 0; i < NPSIZES+1; i++) { extent_heap_new(&extents->heaps[i]); } + bitmap_init(extents->bitmap, &extents_bitmap_info, true); extent_list_init(&extents->lru); atomic_store_zu(&extents->npages, 0, ATOMIC_RELAXED); extents->state = state; @@ -215,6 +219,10 @@ extents_insert_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent, size_t size = extent_size_get(extent); size_t psz = extent_size_quantize_floor(size); pszind_t pind = psz2ind(psz); + if (extent_heap_empty(&extents->heaps[pind])) { + bitmap_unset(extents->bitmap, &extents_bitmap_info, + (size_t)pind); + } extent_heap_insert(&extents->heaps[pind], extent); if (!preserve_lru) { extent_list_append(&extents->lru, extent); @@ -241,6 +249,10 @@ extents_remove_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent, size_t psz = extent_size_quantize_floor(size); pszind_t pind = psz2ind(psz); extent_heap_remove(&extents->heaps[pind], extent); + if (extent_heap_empty(&extents->heaps[pind])) { + bitmap_set(extents->bitmap, &extents_bitmap_info, + (size_t)pind); + } if (!preserve_lru) { extent_list_remove(&extents->lru, extent); } @@ -261,12 +273,13 @@ static extent_t * extents_best_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, size_t size) { pszind_t pind = psz2ind(extent_size_quantize_ceil(size)); - for (pszind_t i = pind; i < NPSIZES+1; i++) { + pszind_t i = (pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info, + (size_t)pind); + if (i < NPSIZES+1) { + assert(!extent_heap_empty(&extents->heaps[i])); extent_t *extent = extent_heap_any(&extents->heaps[i]); - if (extent != NULL) { - assert(extent_size_get(extent) >= size); - return extent; - } + assert(extent_size_get(extent) >= size); + return extent; } return NULL; @@ -282,14 +295,20 @@ extents_first_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, extent_t *ret = NULL; pszind_t pind = psz2ind(extent_size_quantize_ceil(size)); - for (pszind_t i = pind; i < NPSIZES+1; i++) { + for (pszind_t i = (pszind_t)bitmap_ffu(extents->bitmap, + &extents_bitmap_info, (size_t)pind); i < NPSIZES+1; i = + (pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info, + (size_t)i+1)) { + assert(!extent_heap_empty(&extents->heaps[i])); extent_t *extent = extent_heap_first(&extents->heaps[i]); - if (extent != NULL) { - assert(extent_size_get(extent) >= size); - if (ret == NULL || extent_snad_comp(extent, ret) < 0) { - ret = extent; - } + assert(extent_size_get(extent) >= size); + if (ret == NULL || extent_snad_comp(extent, ret) < 0) { + ret = extent; + } + if (i == NPSIZES) { + break; } + assert(i < NPSIZES); } return ret; -- GitLab From e6b074472e4515a74b1e8062bd94683cc8f5b3ba Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 24 Mar 2017 17:21:38 -0700 Subject: [PATCH 360/544] Force inline ifree to avoid function call costs on fast path. Without ALWAYS_INLINE, sometimes ifree() gets compiled into its own function, which adds overhead on the fast path. --- src/jemalloc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index d8688bdd..ab047c24 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1997,7 +1997,7 @@ irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize) { return p; } -JEMALLOC_INLINE_C void +JEMALLOC_ALWAYS_INLINE_C void ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { witness_assert_lockless(tsd_tsdn(tsd)); @@ -2022,7 +2022,7 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { } } -JEMALLOC_INLINE_C void +JEMALLOC_ALWAYS_INLINE_C void isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) { witness_assert_lockless(tsd_tsdn(tsd)); -- GitLab From 5e12223925e3cbd1f7c314e9d0224e1fa597ccc7 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 24 Mar 2017 22:46:56 -0700 Subject: [PATCH 361/544] Fix BITMAP_USE_TREE version of bitmap_ffu(). This fixes an extent searching regression on 32-bit systems, caused by the initial bitmap_ffu() implementation in c8021d01f6efe14dc1bd200021a815638063cb5f (Implement bitmap_ffu(), which finds the first unset bit.), as first used in 5d33233a5e6601902df7cddd8cc8aa0b135c77b2 (Use a bitmap in extents_t to speed up search.). --- include/jemalloc/internal/bitmap_inlines.h | 13 +++++++ test/unit/bitmap.c | 40 +++++++++++++++++++--- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/include/jemalloc/internal/bitmap_inlines.h b/include/jemalloc/internal/bitmap_inlines.h index 07166ba5..b4a5ca00 100644 --- a/include/jemalloc/internal/bitmap_inlines.h +++ b/include/jemalloc/internal/bitmap_inlines.h @@ -112,6 +112,19 @@ bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) { group &= group_mask; } if (group == 0LU) { + /* + * If min_bit is not the first bit in its group, try + * again starting at the first bit of the next group. + * This will only recurse at most once, since on + * recursion, min_bit will be the first bit in its + * group. + */ + size_t ceil_min_bit = (min_bit + + BITMAP_GROUP_NBITS_MASK) & ~BITMAP_GROUP_NBITS_MASK; + if (ceil_min_bit != min_bit && ceil_min_bit < + binfo->nbits) { + return bitmap_ffu(bitmap, binfo, ceil_min_bit); + } return binfo->nbits; } bit = (bit << LG_BITMAP_GROUP_NBITS) + (ffs_lu(group) - 1); diff --git a/test/unit/bitmap.c b/test/unit/bitmap.c index 92a07dec..22d2871e 100644 --- a/test/unit/bitmap.c +++ b/test/unit/bitmap.c @@ -273,7 +273,7 @@ TEST_BEGIN(test_bitmap_unset) { TEST_END static void -test_bitmap_sfu_body(const bitmap_info_t *binfo, size_t nbits) { +test_bitmap_xfu_body(const bitmap_info_t *binfo, size_t nbits) { bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo)); assert_ptr_not_null(bitmap, "Unexpected malloc() failure"); bitmap_init(bitmap, binfo, false); @@ -342,20 +342,50 @@ test_bitmap_sfu_body(const bitmap_info_t *binfo, size_t nbits) { assert_zu_eq(bitmap_sfu(bitmap, binfo), nbits - 1, "First unset bit should be the last bit"); assert_true(bitmap_full(bitmap, binfo), "All bits should be set"); + + /* + * Bubble a "usu" pattern through the bitmap and verify that + * bitmap_ffu() finds the correct bit for all five min_bit cases. + */ + if (nbits >= 3) { + for (size_t i = 0; i < nbits-2; i++) { + bitmap_unset(bitmap, binfo, i); + bitmap_unset(bitmap, binfo, i+2); + if (i > 0) { + assert_zu_eq(bitmap_ffu(bitmap, binfo, i-1), i, + "Unexpected first unset bit"); + } + assert_zu_eq(bitmap_ffu(bitmap, binfo, i), i, + "Unexpected first unset bit"); + assert_zu_eq(bitmap_ffu(bitmap, binfo, i+1), i+2, + "Unexpected first unset bit"); + assert_zu_eq(bitmap_ffu(bitmap, binfo, i+2), i+2, + "Unexpected first unset bit"); + if (i + 3 < nbits) { + assert_zu_eq(bitmap_ffu(bitmap, binfo, i+3), + nbits, "Unexpected first unset bit"); + } + assert_zu_eq(bitmap_sfu(bitmap, binfo), i, + "Unexpected first unset bit"); + assert_zu_eq(bitmap_sfu(bitmap, binfo), i+2, + "Unexpected first unset bit"); + } + } + free(bitmap); } -TEST_BEGIN(test_bitmap_sfu) { +TEST_BEGIN(test_bitmap_xfu) { size_t nbits; for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) { bitmap_info_t binfo; bitmap_info_init(&binfo, nbits); - test_bitmap_sfu_body(&binfo, nbits); + test_bitmap_xfu_body(&binfo, nbits); } #define NB(nbits) { \ bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \ - test_bitmap_sfu_body(&binfo, nbits); \ + test_bitmap_xfu_body(&binfo, nbits); \ } NBITS_TAB #undef NB @@ -370,5 +400,5 @@ main(void) { test_bitmap_init, test_bitmap_set, test_bitmap_unset, - test_bitmap_sfu); + test_bitmap_xfu); } -- GitLab From 0591c204b468e7b273c2f3f94f488cffbe8d7a74 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 24 Mar 2017 11:25:43 -0700 Subject: [PATCH 362/544] Store arena index rather than (arena_t *) in extent_t. --- include/jemalloc/internal/extent_inlines.h | 4 ++-- include/jemalloc/internal/extent_structs.h | 4 ++-- include/jemalloc/internal/jemalloc_internal.h.in | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index 56f306df..f86822de 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -49,7 +49,7 @@ int extent_snad_comp(const extent_t *a, const extent_t *b); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_)) JEMALLOC_INLINE arena_t * extent_arena_get(const extent_t *extent) { - return extent->e_arena; + return arenas[extent->e_arena_ind]; } JEMALLOC_INLINE void * @@ -151,7 +151,7 @@ extent_prof_tctx_get(const extent_t *extent) { JEMALLOC_INLINE void extent_arena_set(extent_t *extent, arena_t *arena) { - extent->e_arena = arena; + extent->e_arena_ind = (arena != NULL) ? arena_ind_get(arena) : UINT_MAX; } JEMALLOC_INLINE void diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 5cf3c9b2..1b2b4bc7 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -10,8 +10,8 @@ typedef enum { /* Extent (span of pages). Use accessor functions for e_* fields. */ struct extent_s { - /* Arena from which this extent came, if any. */ - arena_t *e_arena; + /* Arena from which this extent came, or UINT_MAX if unassociated. */ + unsigned e_arena_ind; /* Pointer to the extent that this structure is responsible for. */ void *e_addr; diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 2fe21018..4255b639 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -932,7 +932,6 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) { } #endif -#include "jemalloc/internal/extent_inlines.h" #include "jemalloc/internal/rtree_inlines.h" #include "jemalloc/internal/base_inlines.h" #include "jemalloc/internal/bitmap_inlines.h" @@ -942,6 +941,7 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) { */ #include "jemalloc/internal/prof_inlines_a.h" #include "jemalloc/internal/arena_inlines_a.h" +#include "jemalloc/internal/extent_inlines.h" #ifndef JEMALLOC_ENABLE_INLINE extent_t *iealloc(tsdn_t *tsdn, const void *ptr); -- GitLab From 735ad8210c93185b36a36ec4740985681004ce25 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 24 Mar 2017 15:22:26 -0700 Subject: [PATCH 363/544] Pack various extent_t fields into a bitfield. This reduces sizeof(extent_t) from 160 to 136 on x64. --- include/jemalloc/internal/extent_inlines.h | 144 ++++++++++++--------- include/jemalloc/internal/extent_structs.h | 115 +++++++++------- 2 files changed, 155 insertions(+), 104 deletions(-) diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index f86822de..22229b50 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -3,20 +3,20 @@ #ifndef JEMALLOC_ENABLE_INLINE arena_t *extent_arena_get(const extent_t *extent); -void *extent_base_get(const extent_t *extent); -void *extent_addr_get(const extent_t *extent); -size_t extent_size_get(const extent_t *extent); szind_t extent_szind_get_maybe_invalid(const extent_t *extent); szind_t extent_szind_get(const extent_t *extent); size_t extent_usize_get(const extent_t *extent); -void *extent_before_get(const extent_t *extent); -void *extent_last_get(const extent_t *extent); -void *extent_past_get(const extent_t *extent); size_t extent_sn_get(const extent_t *extent); extent_state_t extent_state_get(const extent_t *extent); bool extent_zeroed_get(const extent_t *extent); bool extent_committed_get(const extent_t *extent); bool extent_slab_get(const extent_t *extent); +void *extent_base_get(const extent_t *extent); +void *extent_addr_get(const extent_t *extent); +size_t extent_size_get(const extent_t *extent); +void *extent_before_get(const extent_t *extent); +void *extent_last_get(const extent_t *extent); +void *extent_past_get(const extent_t *extent); arena_slab_data_t *extent_slab_data_get(extent_t *extent); const arena_slab_data_t *extent_slab_data_get_const(const extent_t *extent); prof_tctx_t *extent_prof_tctx_get(const extent_t *extent); @@ -49,32 +49,25 @@ int extent_snad_comp(const extent_t *a, const extent_t *b); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_)) JEMALLOC_INLINE arena_t * extent_arena_get(const extent_t *extent) { - return arenas[extent->e_arena_ind]; -} - -JEMALLOC_INLINE void * -extent_base_get(const extent_t *extent) { - assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || - !extent->e_slab); - return PAGE_ADDR2BASE(extent->e_addr); -} - -JEMALLOC_INLINE void * -extent_addr_get(const extent_t *extent) { - assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || - !extent->e_slab); - return extent->e_addr; -} - -JEMALLOC_INLINE size_t -extent_size_get(const extent_t *extent) { - return extent->e_size; + unsigned arena_ind = (unsigned)((extent->e_bits & + EXTENT_BITS_ARENA_MASK) >> EXTENT_BITS_ARENA_SHIFT); + /* + * The following check is omitted because we should never actually read + * a NULL arena pointer. + */ + if (false && arena_ind > MALLOCX_ARENA_MAX) { + return NULL; + } + assert(arena_ind <= MALLOCX_ARENA_MAX); + return arenas[arena_ind]; } JEMALLOC_INLINE szind_t extent_szind_get_maybe_invalid(const extent_t *extent) { - assert(extent->e_szind <= NSIZES); - return extent->e_szind; + szind_t szind = (szind_t)((extent->e_bits & EXTENT_BITS_SZIND_MASK) >> + EXTENT_BITS_SZIND_SHIFT); + assert(szind <= NSIZES); + return szind; } JEMALLOC_INLINE szind_t @@ -89,57 +82,81 @@ extent_usize_get(const extent_t *extent) { return index2size(extent_szind_get(extent)); } -JEMALLOC_INLINE void * -extent_before_get(const extent_t *extent) { - return (void *)((uintptr_t)extent_base_get(extent) - PAGE); -} - -JEMALLOC_INLINE void * -extent_last_get(const extent_t *extent) { - return (void *)((uintptr_t)extent_base_get(extent) + - extent_size_get(extent) - PAGE); -} - -JEMALLOC_INLINE void * -extent_past_get(const extent_t *extent) { - return (void *)((uintptr_t)extent_base_get(extent) + - extent_size_get(extent)); -} - JEMALLOC_INLINE size_t extent_sn_get(const extent_t *extent) { - return extent->e_sn; + return (size_t)((extent->e_bits & EXTENT_BITS_SN_MASK) >> + EXTENT_BITS_SN_SHIFT); } JEMALLOC_INLINE extent_state_t extent_state_get(const extent_t *extent) { - return extent->e_state; + return (extent_state_t)((extent->e_bits & EXTENT_BITS_STATE_MASK) >> + EXTENT_BITS_STATE_SHIFT); } JEMALLOC_INLINE bool extent_zeroed_get(const extent_t *extent) { - return extent->e_zeroed; + return (bool)((extent->e_bits & EXTENT_BITS_ZEROED_MASK) >> + EXTENT_BITS_ZEROED_SHIFT); } JEMALLOC_INLINE bool extent_committed_get(const extent_t *extent) { - return extent->e_committed; + return (bool)((extent->e_bits & EXTENT_BITS_COMMITTED_MASK) >> + EXTENT_BITS_COMMITTED_SHIFT); } JEMALLOC_INLINE bool extent_slab_get(const extent_t *extent) { - return extent->e_slab; + return (bool)((extent->e_bits & EXTENT_BITS_SLAB_MASK) >> + EXTENT_BITS_SLAB_SHIFT); +} + +JEMALLOC_INLINE void * +extent_base_get(const extent_t *extent) { + assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || + !extent_slab_get(extent)); + return PAGE_ADDR2BASE(extent->e_addr); +} + +JEMALLOC_INLINE void * +extent_addr_get(const extent_t *extent) { + assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || + !extent_slab_get(extent)); + return extent->e_addr; +} + +JEMALLOC_INLINE size_t +extent_size_get(const extent_t *extent) { + return extent->e_size; +} + +JEMALLOC_INLINE void * +extent_before_get(const extent_t *extent) { + return (void *)((uintptr_t)extent_base_get(extent) - PAGE); +} + +JEMALLOC_INLINE void * +extent_last_get(const extent_t *extent) { + return (void *)((uintptr_t)extent_base_get(extent) + + extent_size_get(extent) - PAGE); +} + +JEMALLOC_INLINE void * +extent_past_get(const extent_t *extent) { + return (void *)((uintptr_t)extent_base_get(extent) + + extent_size_get(extent)); } JEMALLOC_INLINE arena_slab_data_t * extent_slab_data_get(extent_t *extent) { - assert(extent->e_slab); + assert(extent_slab_get(extent)); return &extent->e_slab_data; } JEMALLOC_INLINE const arena_slab_data_t * extent_slab_data_get_const(const extent_t *extent) { - assert(extent->e_slab); + assert(extent_slab_get(extent)); return &extent->e_slab_data; } @@ -151,7 +168,10 @@ extent_prof_tctx_get(const extent_t *extent) { JEMALLOC_INLINE void extent_arena_set(extent_t *extent, arena_t *arena) { - extent->e_arena_ind = (arena != NULL) ? arena_ind_get(arena) : UINT_MAX; + unsigned arena_ind = (arena != NULL) ? arena_ind_get(arena) : ((1U << + MALLOCX_ARENA_BITS) - 1); + extent->e_bits = (extent->e_bits & ~EXTENT_BITS_ARENA_MASK) | + ((uint64_t)arena_ind << EXTENT_BITS_ARENA_SHIFT); } JEMALLOC_INLINE void @@ -186,32 +206,38 @@ extent_size_set(extent_t *extent, size_t size) { JEMALLOC_INLINE void extent_szind_set(extent_t *extent, szind_t szind) { assert(szind <= NSIZES); /* NSIZES means "invalid". */ - extent->e_szind = szind; + extent->e_bits = (extent->e_bits & ~EXTENT_BITS_SZIND_MASK) | + ((uint64_t)szind << EXTENT_BITS_SZIND_SHIFT); } JEMALLOC_INLINE void extent_sn_set(extent_t *extent, size_t sn) { - extent->e_sn = sn; + extent->e_bits = (extent->e_bits & ~EXTENT_BITS_SN_MASK) | + ((uint64_t)sn << EXTENT_BITS_SN_SHIFT); } JEMALLOC_INLINE void extent_state_set(extent_t *extent, extent_state_t state) { - extent->e_state = state; + extent->e_bits = (extent->e_bits & ~EXTENT_BITS_STATE_MASK) | + ((uint64_t)state << EXTENT_BITS_STATE_SHIFT); } JEMALLOC_INLINE void extent_zeroed_set(extent_t *extent, bool zeroed) { - extent->e_zeroed = zeroed; + extent->e_bits = (extent->e_bits & ~EXTENT_BITS_ZEROED_MASK) | + ((uint64_t)zeroed << EXTENT_BITS_ZEROED_SHIFT); } JEMALLOC_INLINE void extent_committed_set(extent_t *extent, bool committed) { - extent->e_committed = committed; + extent->e_bits = (extent->e_bits & ~EXTENT_BITS_COMMITTED_MASK) | + ((uint64_t)committed << EXTENT_BITS_COMMITTED_SHIFT); } JEMALLOC_INLINE void extent_slab_set(extent_t *extent, bool slab) { - extent->e_slab = slab; + extent->e_bits = (extent->e_bits & ~EXTENT_BITS_SLAB_MASK) | + ((uint64_t)slab << EXTENT_BITS_SLAB_SHIFT); } JEMALLOC_INLINE void diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 1b2b4bc7..ddc04087 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -10,59 +10,84 @@ typedef enum { /* Extent (span of pages). Use accessor functions for e_* fields. */ struct extent_s { - /* Arena from which this extent came, or UINT_MAX if unassociated. */ - unsigned e_arena_ind; - - /* Pointer to the extent that this structure is responsible for. */ - void *e_addr; - - /* Extent size. */ - size_t e_size; - /* - * Usable size class index for allocations residing in this extent, - * regardless of whether the extent is a slab. Extent size and usable - * size often differ even for non-slabs, either due to large_pad or - * promotion of sampled small regions. - */ - szind_t e_szind; - - /* - * Serial number (potentially non-unique). + * Bitfield containing several fields: + * + * a: arena_ind + * b: slab + * c: committed + * z: zeroed + * t: state + * i: szind + * n: sn + * + * nnnnnnnn ... nnnnnnni iiiiiiit tzcbaaaa aaaaaaaa + * + * arena_ind: Arena from which this extent came, or all 1 bits if + * unassociated. + * + * slab: The slab flag indicates whether the extent is used for a slab + * of small regions. This helps differentiate small size classes, + * and it indicates whether interior pointers can be looked up via + * iealloc(). + * + * committed: The committed flag indicates whether physical memory is + * committed to the extent, whether explicitly or implicitly + * as on a system that overcommits and satisfies physical + * memory needs on demand via soft page faults. + * + * zeroed: The zeroed flag is used by extent recycling code to track + * whether memory is zero-filled. + * + * state: The state flag is an extent_state_t. * - * In principle serial numbers can wrap around on 32-bit systems if - * JEMALLOC_MUNMAP is defined, but as long as comparison functions fall - * back on address comparison for equal serial numbers, stable (if - * imperfect) ordering is maintained. + * szind: The szind flag indicates usable size class index for + * allocations residing in this extent, regardless of whether the + * extent is a slab. Extent size and usable size often differ + * even for non-slabs, either due to large_pad or promotion of + * sampled small regions. * - * Serial numbers may not be unique even in the absence of wrap-around, - * e.g. when splitting an extent and assigning the same serial number to - * both resulting adjacent extents. + * sn: Serial number (potentially non-unique). + * + * Serial numbers may wrap around if JEMALLOC_MUNMAP is defined, but + * as long as comparison functions fall back on address comparison + * for equal serial numbers, stable (if imperfect) ordering is + * maintained. + * + * Serial numbers may not be unique even in the absence of + * wrap-around, e.g. when splitting an extent and assigning the same + * serial number to both resulting adjacent extents. */ - size_t e_sn; + uint64_t e_bits; +#define EXTENT_BITS_ARENA_SHIFT 0 +#define EXTENT_BITS_ARENA_MASK \ + (((1U << MALLOCX_ARENA_BITS) - 1) << EXTENT_BITS_ARENA_SHIFT) - /* Extent state. */ - extent_state_t e_state; +#define EXTENT_BITS_SLAB_SHIFT MALLOCX_ARENA_BITS +#define EXTENT_BITS_SLAB_MASK (0x1U << EXTENT_BITS_SLAB_SHIFT) - /* - * The zeroed flag is used by extent recycling code to track whether - * memory is zero-filled. - */ - bool e_zeroed; +#define EXTENT_BITS_COMMITTED_SHIFT (MALLOCX_ARENA_BITS + 1) +#define EXTENT_BITS_COMMITTED_MASK (0x1U << EXTENT_BITS_COMMITTED_SHIFT) - /* - * True if physical memory is committed to the extent, whether - * explicitly or implicitly as on a system that overcommits and - * satisfies physical memory needs on demand via soft page faults. - */ - bool e_committed; +#define EXTENT_BITS_ZEROED_SHIFT (MALLOCX_ARENA_BITS + 2) +#define EXTENT_BITS_ZEROED_MASK (0x1U << EXTENT_BITS_ZEROED_SHIFT) - /* - * The slab flag indicates whether the extent is used for a slab of - * small regions. This helps differentiate small size classes, and it - * indicates whether interior pointers can be looked up via iealloc(). - */ - bool e_slab; +#define EXTENT_BITS_STATE_SHIFT (MALLOCX_ARENA_BITS + 3) +#define EXTENT_BITS_STATE_MASK (0x3U << EXTENT_BITS_STATE_SHIFT) + +#define EXTENT_BITS_SZIND_SHIFT (MALLOCX_ARENA_BITS + 5) +#define EXTENT_BITS_SZIND_MASK \ + (((1U << LG_CEIL_NSIZES) - 1) << EXTENT_BITS_SZIND_SHIFT) + +#define EXTENT_BITS_SN_SHIFT \ + (MALLOCX_ARENA_BITS + 5 + LG_CEIL_NSIZES) +#define EXTENT_BITS_SN_MASK (UINT64_MAX << EXTENT_BITS_SN_SHIFT) + + /* Pointer to the extent that this structure is responsible for. */ + void *e_addr; + + /* Extent size. */ + size_t e_size; union { /* Small region slab metadata. */ -- GitLab From 6258176c87cd3632dcdd8df14842734b46e2e916 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 27 Mar 2017 01:52:20 -0700 Subject: [PATCH 364/544] Fix bitmap_ffu() to work with 3+ levels. --- include/jemalloc/internal/bitmap_inlines.h | 70 +++++++++------------- test/unit/bitmap.c | 27 +++++++++ 2 files changed, 56 insertions(+), 41 deletions(-) diff --git a/include/jemalloc/internal/bitmap_inlines.h b/include/jemalloc/internal/bitmap_inlines.h index b4a5ca00..84f43a87 100644 --- a/include/jemalloc/internal/bitmap_inlines.h +++ b/include/jemalloc/internal/bitmap_inlines.h @@ -83,52 +83,40 @@ bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) { assert(min_bit < binfo->nbits); #ifdef BITMAP_USE_TREE - unsigned level = binfo->nlevels - 1; - size_t lg_bits_per_group = (LG_BITMAP_GROUP_NBITS * (level+1)); - size_t bits_per_group = 1LU << lg_bits_per_group; - size_t bits_per_group_mask = bits_per_group - 1; - unsigned group_nmask = (min_bit & bits_per_group_mask) >> (level * - LG_BITMAP_GROUP_NBITS); - bitmap_t group_mask = ~((1LU << group_nmask) - 1); - bitmap_t group = bitmap[binfo->levels[level].group_offset] & group_mask; - if (group == 0LU) { - return binfo->nbits; - } - size_t bit = ffs_lu(group) - 1; - - while (level > 0) { - level--; - - lg_bits_per_group = (LG_BITMAP_GROUP_NBITS * (level+1)); - bits_per_group = 1LU << lg_bits_per_group; - bits_per_group_mask = bits_per_group - 1; - - group = bitmap[binfo->levels[level].group_offset + bit]; - size_t cur_base = bit << lg_bits_per_group; - if (cur_base < min_bit) { - group_nmask = (min_bit & bits_per_group_mask) >> (level - * LG_BITMAP_GROUP_NBITS); - group_mask = ~((1LU << group_nmask) - 1); - group &= group_mask; - } - if (group == 0LU) { + size_t bit = 0; + for (unsigned level = binfo->nlevels; level--;) { + size_t lg_bits_per_group = (LG_BITMAP_GROUP_NBITS * (level + + 1)); + bitmap_t group = bitmap[binfo->levels[level].group_offset + (bit + >> lg_bits_per_group)]; + unsigned group_nmask = ((min_bit > bit) ? (min_bit - bit) : 0) + >> (lg_bits_per_group - LG_BITMAP_GROUP_NBITS); + assert(group_nmask <= BITMAP_GROUP_NBITS); + bitmap_t group_mask = ~((1LU << group_nmask) - 1); + bitmap_t group_masked = group & group_mask; + if (group_masked == 0LU) { + if (group == 0LU) { + return binfo->nbits; + } /* - * If min_bit is not the first bit in its group, try - * again starting at the first bit of the next group. - * This will only recurse at most once, since on - * recursion, min_bit will be the first bit in its - * group. + * min_bit was preceded by one or more unset bits in + * this group, but there are no other unset bits in this + * group. Try again starting at the first bit of the + * next sibling. This will recurse at most once per + * non-root level. */ - size_t ceil_min_bit = (min_bit + - BITMAP_GROUP_NBITS_MASK) & ~BITMAP_GROUP_NBITS_MASK; - if (ceil_min_bit != min_bit && ceil_min_bit < - binfo->nbits) { - return bitmap_ffu(bitmap, binfo, ceil_min_bit); + size_t sib_base = bit + (1U << lg_bits_per_group); + assert(sib_base > min_bit); + assert(sib_base > bit); + if (sib_base >= binfo->nbits) { + return binfo->nbits; } - return binfo->nbits; + return bitmap_ffu(bitmap, binfo, sib_base); } - bit = (bit << LG_BITMAP_GROUP_NBITS) + (ffs_lu(group) - 1); + bit += (ffs_lu(group_masked) - 1) << (lg_bits_per_group - + LG_BITMAP_GROUP_NBITS); } + assert(bit >= min_bit); assert(bit < binfo->nbits); return bit; #else diff --git a/test/unit/bitmap.c b/test/unit/bitmap.c index 22d2871e..cafb2039 100644 --- a/test/unit/bitmap.c +++ b/test/unit/bitmap.c @@ -372,6 +372,33 @@ test_bitmap_xfu_body(const bitmap_info_t *binfo, size_t nbits) { } } + /* + * Unset the last bit, bubble another unset bit through the bitmap, and + * verify that bitmap_ffu() finds the correct bit for all four min_bit + * cases. + */ + if (nbits >= 3) { + bitmap_unset(bitmap, binfo, nbits-1); + for (size_t i = 0; i < nbits-1; i++) { + bitmap_unset(bitmap, binfo, i); + if (i > 0) { + assert_zu_eq(bitmap_ffu(bitmap, binfo, i-1), i, + "Unexpected first unset bit"); + } + assert_zu_eq(bitmap_ffu(bitmap, binfo, i), i, + "Unexpected first unset bit"); + assert_zu_eq(bitmap_ffu(bitmap, binfo, i+1), nbits-1, + "Unexpected first unset bit"); + assert_zu_eq(bitmap_ffu(bitmap, binfo, nbits-1), + nbits-1, "Unexpected first unset bit"); + + assert_zu_eq(bitmap_sfu(bitmap, binfo), i, + "Unexpected first unset bit"); + } + assert_zu_eq(bitmap_sfu(bitmap, binfo), nbits-1, + "Unexpected first unset bit"); + } + free(bitmap); } -- GitLab From 7c00f04ff40a34627e31488d02ff1081c749c7ba Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 27 Mar 2017 01:58:09 -0700 Subject: [PATCH 365/544] Remove BITMAP_USE_TREE. Remove tree-structured bitmap support, in order to reduce complexity and ease maintenance. No bitmaps larger than 512 bits have been necessary since before 4.0.0, and there is no current plan that would increase maximum bitmap size. Although tree-structured bitmaps were used on 32-bit platforms prior to this change, the overall benefits were questionable (higher metadata overhead, higher bitmap modification cost, marginally lower search cost). --- include/jemalloc/internal/bitmap_inlines.h | 95 ------------------ include/jemalloc/internal/bitmap_structs.h | 11 --- include/jemalloc/internal/bitmap_types.h | 107 --------------------- src/bitmap.c | 78 --------------- test/unit/bitmap.c | 16 --- 5 files changed, 307 deletions(-) diff --git a/include/jemalloc/internal/bitmap_inlines.h b/include/jemalloc/internal/bitmap_inlines.h index 84f43a87..506d5269 100644 --- a/include/jemalloc/internal/bitmap_inlines.h +++ b/include/jemalloc/internal/bitmap_inlines.h @@ -14,12 +14,6 @@ void bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BITMAP_C_)) JEMALLOC_INLINE bool bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) { -#ifdef BITMAP_USE_TREE - size_t rgoff = binfo->levels[binfo->nlevels].group_offset - 1; - bitmap_t rg = bitmap[rgoff]; - /* The bitmap is full iff the root group is 0. */ - return (rg == 0); -#else size_t i; for (i = 0; i < binfo->ngroups; i++) { @@ -28,7 +22,6 @@ bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) { } } return true; -#endif } JEMALLOC_INLINE bool @@ -57,24 +50,6 @@ bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); *gp = g; assert(bitmap_get(bitmap, binfo, bit)); -#ifdef BITMAP_USE_TREE - /* Propagate group state transitions up the tree. */ - if (g == 0) { - unsigned i; - for (i = 1; i < binfo->nlevels; i++) { - bit = goff; - goff = bit >> LG_BITMAP_GROUP_NBITS; - gp = &bitmap[binfo->levels[i].group_offset + goff]; - g = *gp; - assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); - g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); - *gp = g; - if (g != 0) { - break; - } - } - } -#endif } /* ffu: find first unset >= bit. */ @@ -82,44 +57,6 @@ JEMALLOC_INLINE size_t bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) { assert(min_bit < binfo->nbits); -#ifdef BITMAP_USE_TREE - size_t bit = 0; - for (unsigned level = binfo->nlevels; level--;) { - size_t lg_bits_per_group = (LG_BITMAP_GROUP_NBITS * (level + - 1)); - bitmap_t group = bitmap[binfo->levels[level].group_offset + (bit - >> lg_bits_per_group)]; - unsigned group_nmask = ((min_bit > bit) ? (min_bit - bit) : 0) - >> (lg_bits_per_group - LG_BITMAP_GROUP_NBITS); - assert(group_nmask <= BITMAP_GROUP_NBITS); - bitmap_t group_mask = ~((1LU << group_nmask) - 1); - bitmap_t group_masked = group & group_mask; - if (group_masked == 0LU) { - if (group == 0LU) { - return binfo->nbits; - } - /* - * min_bit was preceded by one or more unset bits in - * this group, but there are no other unset bits in this - * group. Try again starting at the first bit of the - * next sibling. This will recurse at most once per - * non-root level. - */ - size_t sib_base = bit + (1U << lg_bits_per_group); - assert(sib_base > min_bit); - assert(sib_base > bit); - if (sib_base >= binfo->nbits) { - return binfo->nbits; - } - return bitmap_ffu(bitmap, binfo, sib_base); - } - bit += (ffs_lu(group_masked) - 1) << (lg_bits_per_group - - LG_BITMAP_GROUP_NBITS); - } - assert(bit >= min_bit); - assert(bit < binfo->nbits); - return bit; -#else size_t i = min_bit >> LG_BITMAP_GROUP_NBITS; bitmap_t g = bitmap[i] & ~((1LU << (min_bit & BITMAP_GROUP_NBITS_MASK)) - 1); @@ -133,7 +70,6 @@ bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) { g = bitmap[i]; } while (i < binfo->ngroups); return binfo->nbits; -#endif } /* sfu: set first unset. */ @@ -145,16 +81,6 @@ bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) { assert(!bitmap_full(bitmap, binfo)); -#ifdef BITMAP_USE_TREE - i = binfo->nlevels - 1; - g = bitmap[binfo->levels[i].group_offset]; - bit = ffs_lu(g) - 1; - while (i > 0) { - i--; - g = bitmap[binfo->levels[i].group_offset + bit]; - bit = (bit << LG_BITMAP_GROUP_NBITS) + (ffs_lu(g) - 1); - } -#else i = 0; g = bitmap[0]; while ((bit = ffs_lu(g)) == 0) { @@ -162,7 +88,6 @@ bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) { g = bitmap[i]; } bit = (i << LG_BITMAP_GROUP_NBITS) + (bit - 1); -#endif bitmap_set(bitmap, binfo, bit); return bit; } @@ -184,26 +109,6 @@ bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); *gp = g; assert(!bitmap_get(bitmap, binfo, bit)); -#ifdef BITMAP_USE_TREE - /* Propagate group state transitions up the tree. */ - if (propagate) { - unsigned i; - for (i = 1; i < binfo->nlevels; i++) { - bit = goff; - goff = bit >> LG_BITMAP_GROUP_NBITS; - gp = &bitmap[binfo->levels[i].group_offset + goff]; - g = *gp; - propagate = (g == 0); - assert((g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))) - == 0); - g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); - *gp = g; - if (!propagate) { - break; - } - } - } -#endif /* BITMAP_USE_TREE */ } #endif diff --git a/include/jemalloc/internal/bitmap_structs.h b/include/jemalloc/internal/bitmap_structs.h index 297ae669..dde15328 100644 --- a/include/jemalloc/internal/bitmap_structs.h +++ b/include/jemalloc/internal/bitmap_structs.h @@ -10,19 +10,8 @@ struct bitmap_info_s { /* Logical number of bits in bitmap (stored at bottom level). */ size_t nbits; -#ifdef BITMAP_USE_TREE - /* Number of levels necessary for nbits. */ - unsigned nlevels; - - /* - * Only the first (nlevels+1) elements are used, and levels are ordered - * bottom to top (e.g. the bottom level is stored in levels[0]). - */ - bitmap_level_t levels[BITMAP_MAX_LEVELS+1]; -#else /* BITMAP_USE_TREE */ /* Number of groups necessary for nbits. */ size_t ngroups; -#endif /* BITMAP_USE_TREE */ }; #endif /* JEMALLOC_INTERNAL_BITMAP_STRUCTS_H */ diff --git a/include/jemalloc/internal/bitmap_types.h b/include/jemalloc/internal/bitmap_types.h index b334769f..091ccead 100644 --- a/include/jemalloc/internal/bitmap_types.h +++ b/include/jemalloc/internal/bitmap_types.h @@ -21,115 +21,10 @@ typedef unsigned long bitmap_t; #define BITMAP_GROUP_NBITS (1U << LG_BITMAP_GROUP_NBITS) #define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1) -/* - * Do some analysis on how big the bitmap is before we use a tree. For a brute - * force linear search, if we would have to call ffs_lu() more than 2^3 times, - * use a tree instead. - */ -#if LG_BITMAP_MAXBITS - LG_BITMAP_GROUP_NBITS > 3 -# define BITMAP_USE_TREE -#endif - /* Number of groups required to store a given number of bits. */ #define BITMAP_BITS2GROUPS(nbits) \ (((nbits) + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS) -/* - * Number of groups required at a particular level for a given number of bits. - */ -#define BITMAP_GROUPS_L0(nbits) \ - BITMAP_BITS2GROUPS(nbits) -#define BITMAP_GROUPS_L1(nbits) \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits)) -#define BITMAP_GROUPS_L2(nbits) \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))) -#define BITMAP_GROUPS_L3(nbits) \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ - BITMAP_BITS2GROUPS((nbits))))) -#define BITMAP_GROUPS_L4(nbits) \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))))) - -/* - * Assuming the number of levels, number of groups required for a given number - * of bits. - */ -#define BITMAP_GROUPS_1_LEVEL(nbits) \ - BITMAP_GROUPS_L0(nbits) -#define BITMAP_GROUPS_2_LEVEL(nbits) \ - (BITMAP_GROUPS_1_LEVEL(nbits) + BITMAP_GROUPS_L1(nbits)) -#define BITMAP_GROUPS_3_LEVEL(nbits) \ - (BITMAP_GROUPS_2_LEVEL(nbits) + BITMAP_GROUPS_L2(nbits)) -#define BITMAP_GROUPS_4_LEVEL(nbits) \ - (BITMAP_GROUPS_3_LEVEL(nbits) + BITMAP_GROUPS_L3(nbits)) -#define BITMAP_GROUPS_5_LEVEL(nbits) \ - (BITMAP_GROUPS_4_LEVEL(nbits) + BITMAP_GROUPS_L4(nbits)) - -/* - * Maximum number of groups required to support LG_BITMAP_MAXBITS. - */ -#ifdef BITMAP_USE_TREE - -#if LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS -# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_1_LEVEL(nbits) -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_1_LEVEL(BITMAP_MAXBITS) -#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 2 -# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_2_LEVEL(nbits) -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_2_LEVEL(BITMAP_MAXBITS) -#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 3 -# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_3_LEVEL(nbits) -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_3_LEVEL(BITMAP_MAXBITS) -#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 4 -# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_4_LEVEL(nbits) -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_4_LEVEL(BITMAP_MAXBITS) -#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 5 -# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_5_LEVEL(nbits) -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_5_LEVEL(BITMAP_MAXBITS) -#else -# error "Unsupported bitmap size" -#endif - -/* - * Maximum number of levels possible. This could be statically computed based - * on LG_BITMAP_MAXBITS: - * - * #define BITMAP_MAX_LEVELS \ - * (LG_BITMAP_MAXBITS / LG_SIZEOF_BITMAP) \ - * + !!(LG_BITMAP_MAXBITS % LG_SIZEOF_BITMAP) - * - * However, that would not allow the generic BITMAP_INFO_INITIALIZER() macro, so - * instead hardcode BITMAP_MAX_LEVELS to the largest number supported by the - * various cascading macros. The only additional cost this incurs is some - * unused trailing entries in bitmap_info_t structures; the bitmaps themselves - * are not impacted. - */ -#define BITMAP_MAX_LEVELS 5 - -#define BITMAP_INFO_INITIALIZER(nbits) { \ - /* nbits. */ \ - nbits, \ - /* nlevels. */ \ - (BITMAP_GROUPS_L0(nbits) > BITMAP_GROUPS_L1(nbits)) + \ - (BITMAP_GROUPS_L1(nbits) > BITMAP_GROUPS_L2(nbits)) + \ - (BITMAP_GROUPS_L2(nbits) > BITMAP_GROUPS_L3(nbits)) + \ - (BITMAP_GROUPS_L3(nbits) > BITMAP_GROUPS_L4(nbits)) + 1, \ - /* levels. */ \ - { \ - {0}, \ - {BITMAP_GROUPS_L0(nbits)}, \ - {BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \ - {BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) + \ - BITMAP_GROUPS_L0(nbits)}, \ - {BITMAP_GROUPS_L3(nbits) + BITMAP_GROUPS_L2(nbits) + \ - BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \ - {BITMAP_GROUPS_L4(nbits) + BITMAP_GROUPS_L3(nbits) + \ - BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) \ - + BITMAP_GROUPS_L0(nbits)} \ - } \ -} - -#else /* BITMAP_USE_TREE */ - #define BITMAP_GROUPS(nbits) BITMAP_BITS2GROUPS(nbits) #define BITMAP_GROUPS_MAX BITMAP_BITS2GROUPS(BITMAP_MAXBITS) @@ -140,6 +35,4 @@ typedef unsigned long bitmap_t; BITMAP_BITS2GROUPS(nbits) \ } -#endif /* BITMAP_USE_TREE */ - #endif /* JEMALLOC_INTERNAL_BITMAP_TYPES_H */ diff --git a/src/bitmap.c b/src/bitmap.c index 81d2a6da..a629aca6 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -3,82 +3,6 @@ /******************************************************************************/ -#ifdef BITMAP_USE_TREE - -void -bitmap_info_init(bitmap_info_t *binfo, size_t nbits) { - unsigned i; - size_t group_count; - - assert(nbits > 0); - assert(nbits <= (ZU(1) << LG_BITMAP_MAXBITS)); - - /* - * Compute the number of groups necessary to store nbits bits, and - * progressively work upward through the levels until reaching a level - * that requires only one group. - */ - binfo->levels[0].group_offset = 0; - group_count = BITMAP_BITS2GROUPS(nbits); - for (i = 1; group_count > 1; i++) { - assert(i < BITMAP_MAX_LEVELS); - binfo->levels[i].group_offset = binfo->levels[i-1].group_offset - + group_count; - group_count = BITMAP_BITS2GROUPS(group_count); - } - binfo->levels[i].group_offset = binfo->levels[i-1].group_offset - + group_count; - assert(binfo->levels[i].group_offset <= BITMAP_GROUPS_MAX); - binfo->nlevels = i; - binfo->nbits = nbits; -} - -static size_t -bitmap_info_ngroups(const bitmap_info_t *binfo) { - return binfo->levels[binfo->nlevels].group_offset; -} - -void -bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo, bool fill) { - size_t extra; - unsigned i; - - /* - * Bits are actually inverted with regard to the external bitmap - * interface. - */ - - if (fill) { - /* The "filled" bitmap starts out with all 0 bits. */ - memset(bitmap, 0, bitmap_size(binfo)); - return; - } - - /* - * The "empty" bitmap starts out with all 1 bits, except for trailing - * unused bits (if any). Note that each group uses bit 0 to correspond - * to the first logical bit in the group, so extra bits are the most - * significant bits of the last group. - */ - memset(bitmap, 0xffU, bitmap_size(binfo)); - extra = (BITMAP_GROUP_NBITS - (binfo->nbits & BITMAP_GROUP_NBITS_MASK)) - & BITMAP_GROUP_NBITS_MASK; - if (extra != 0) { - bitmap[binfo->levels[1].group_offset - 1] >>= extra; - } - for (i = 1; i < binfo->nlevels; i++) { - size_t group_count = binfo->levels[i].group_offset - - binfo->levels[i-1].group_offset; - extra = (BITMAP_GROUP_NBITS - (group_count & - BITMAP_GROUP_NBITS_MASK)) & BITMAP_GROUP_NBITS_MASK; - if (extra != 0) { - bitmap[binfo->levels[i+1].group_offset - 1] >>= extra; - } - } -} - -#else /* BITMAP_USE_TREE */ - void bitmap_info_init(bitmap_info_t *binfo, size_t nbits) { assert(nbits > 0); @@ -110,8 +34,6 @@ bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo, bool fill) { } } -#endif /* BITMAP_USE_TREE */ - size_t bitmap_size(const bitmap_info_t *binfo) { return (bitmap_info_ngroups(binfo) << LG_SIZEOF_BITMAP); diff --git a/test/unit/bitmap.c b/test/unit/bitmap.c index cafb2039..f65ed53e 100644 --- a/test/unit/bitmap.c +++ b/test/unit/bitmap.c @@ -103,24 +103,8 @@ test_bitmap_initializer_body(const bitmap_info_t *binfo, size_t nbits) { assert_zu_eq(binfo->nbits, binfo_dyn.nbits, "Unexpected difference between static and dynamic initialization, " "nbits=%zu", nbits); -#ifdef BITMAP_USE_TREE - assert_u_eq(binfo->nlevels, binfo_dyn.nlevels, - "Unexpected difference between static and dynamic initialization, " - "nbits=%zu", nbits); - { - unsigned i; - - for (i = 0; i < binfo->nlevels; i++) { - assert_zu_eq(binfo->levels[i].group_offset, - binfo_dyn.levels[i].group_offset, - "Unexpected difference between static and dynamic " - "initialization, nbits=%zu, level=%u", nbits, i); - } - } -#else assert_zu_eq(binfo->ngroups, binfo_dyn.ngroups, "Unexpected difference between static and dynamic initialization"); -#endif } TEST_BEGIN(test_bitmap_initializer) { -- GitLab From 4020523f677fbbdac2d00de3fa7d29c395814a2d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 27 Mar 2017 04:08:51 -0700 Subject: [PATCH 366/544] Fix a race in rtree_szind_slab_update() for RTREE_LEAF_COMPACT. --- include/jemalloc/internal/private_symbols.txt | 1 + include/jemalloc/internal/rtree_inlines.h | 65 +++++++++++++++---- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index d22cd874..64151c1b 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -439,6 +439,7 @@ rtree_leaf_elm_release rtree_leaf_elm_slab_read rtree_leaf_elm_slab_write rtree_leaf_elm_szind_read +rtree_leaf_elm_szind_slab_update rtree_leaf_elm_szind_write rtree_leaf_elm_witness_access rtree_leaf_elm_witness_acquire diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 6f92df94..d3799cb3 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -26,6 +26,8 @@ void rtree_leaf_elm_slab_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, bool acquired, bool slab); void rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, bool acquired, extent_t *extent, szind_t szind, bool slab); +void rtree_leaf_elm_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, + rtree_leaf_elm_t *elm, szind_t szind, bool slab); rtree_leaf_elm_t *rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, @@ -41,12 +43,12 @@ bool rtree_extent_szind_read(tsdn_t *tsdn, rtree_t *rtree, szind_t *r_szind); bool rtree_szind_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, szind_t *r_szind, bool *r_slab); -void rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, - rtree_ctx_t *rtree_ctx, uintptr_t key, szind_t szind, bool slab); rtree_leaf_elm_t *rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); void rtree_leaf_elm_release(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm); +void rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, + rtree_ctx_t *rtree_ctx, uintptr_t key, szind_t szind, bool slab); void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key); #endif @@ -251,12 +253,12 @@ rtree_leaf_elm_slab_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, JEMALLOC_INLINE void rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, bool acquired, extent_t *extent, szind_t szind, bool slab) { -#ifdef RTREE_LEAF_COMPACT if (config_debug && acquired) { rtree_leaf_elm_witness_access(tsdn, rtree, elm); } assert(!slab || szind < NBINS); +#ifdef RTREE_LEAF_COMPACT uintptr_t bits = ((uintptr_t)szind << LG_VADDR) | ((uintptr_t)extent & (((uintptr_t)0x1 << LG_VADDR) - 1)) | ((uintptr_t)slab << 1) | @@ -274,6 +276,44 @@ rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, #endif } +JEMALLOC_INLINE void +rtree_leaf_elm_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, + rtree_leaf_elm_t *elm, szind_t szind, bool slab) { + assert(!slab || szind < NBINS); + + /* + * The caller implicitly assures that it is the only writer to the szind + * and slab fields, and that the extent field cannot currently change. + */ +#ifdef RTREE_LEAF_COMPACT + /* + * Another thread may concurrently acquire the elm, which means that + * even though the szind and slab fields will not be concurrently + * modified by another thread, the fact that the lock is embedded in the + * same word requires that a CAS operation be used here. + */ + uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, false, + true) & ~((uintptr_t)0x1); /* Mask lock bit. */ + uintptr_t bits = ((uintptr_t)szind << LG_VADDR) | + ((uintptr_t)rtree_leaf_elm_bits_extent_get(old_bits) & + (((uintptr_t)0x1 << LG_VADDR) - 1)) | + ((uintptr_t)slab << 1); + spin_t spinner = SPIN_INITIALIZER; + while (true) { + if (likely(atomic_compare_exchange_strong_p(&elm->le_bits, + (void **)&old_bits, (void *)bits, ATOMIC_ACQUIRE, + ATOMIC_RELAXED))) { + break; + } + spin_adaptive(&spinner); + } +#else + /* No need to lock. */ + rtree_leaf_elm_slab_write(tsdn, rtree, elm, false, slab); + rtree_leaf_elm_szind_write(tsdn, rtree, elm, false, szind); +#endif +} + JEMALLOC_ALWAYS_INLINE rtree_leaf_elm_t * rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing) { @@ -404,16 +444,6 @@ rtree_szind_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, return false; } -JEMALLOC_INLINE void -rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, - uintptr_t key, szind_t szind, bool slab) { - assert(!slab || szind < NBINS); - - rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true); - rtree_leaf_elm_slab_write(tsdn, rtree, elm, false, slab); - rtree_leaf_elm_szind_write(tsdn, rtree, elm, false, szind); -} - JEMALLOC_INLINE rtree_leaf_elm_t * rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing) { @@ -464,6 +494,15 @@ rtree_leaf_elm_release(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm) { } } +JEMALLOC_INLINE void +rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, + uintptr_t key, szind_t szind, bool slab) { + assert(!slab || szind < NBINS); + + rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true); + rtree_leaf_elm_szind_slab_update(tsdn, rtree, elm, szind, slab); +} + JEMALLOC_INLINE void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key) { -- GitLab From c6d1819e483ca226e27ca4cf81f7d850e4d4dc79 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 27 Mar 2017 04:10:11 -0700 Subject: [PATCH 367/544] Simplify rtree_clear() to avoid locking. --- include/jemalloc/internal/rtree_inlines.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index d3799cb3..4b530dff 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -506,10 +506,10 @@ rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, JEMALLOC_INLINE void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key) { - rtree_leaf_elm_t *elm = rtree_leaf_elm_acquire(tsdn, rtree, rtree_ctx, - key, true, false); - rtree_leaf_elm_write(tsdn, rtree, elm, true, NULL, NSIZES, false); - rtree_leaf_elm_release(tsdn, rtree, elm); + rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true); + assert(rtree_leaf_elm_extent_read(tsdn, rtree, elm, false, false) != + NULL); + rtree_leaf_elm_write(tsdn, rtree, elm, false, NULL, NSIZES, false); } #endif -- GitLab From af3d737a9aafae8b27a837edaf1f54c14d45a727 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 27 Mar 2017 11:48:39 -0700 Subject: [PATCH 368/544] Simplify rtree cache replacement policy. To avoid memmove on free() fast path, simplify the cache replacement policy to only bubble up the cache hit element by 1. --- include/jemalloc/internal/rtree_inlines.h | 25 ++++++++++------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 4b530dff..3e619b3f 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -325,30 +325,27 @@ rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, if (likely(rtree_ctx->cache[i].leafkey == leafkey)) { \ rtree_leaf_elm_t *leaf = rtree_ctx->cache[i].leaf; \ if (likely(leaf != NULL)) { \ - /* Reorder. */ \ - memmove(&rtree_ctx->cache[1], \ - &rtree_ctx->cache[0], \ - sizeof(rtree_ctx_cache_elm_t) * i); \ - rtree_ctx->cache[0].leafkey = leafkey; \ - rtree_ctx->cache[0].leaf = leaf; \ - \ + /* Bubble up by one. */ \ + if (i > 0) { \ + rtree_ctx->cache[i] = \ + rtree_ctx->cache[i - 1]; \ + rtree_ctx->cache[i - 1].leafkey = \ + leafkey; \ + rtree_ctx->cache[i - 1].leaf = leaf; \ + } \ uintptr_t subkey = rtree_subkey(key, \ RTREE_HEIGHT-1); \ return &leaf[subkey]; \ } \ } \ } while (0) - /* Check the MRU cache entry. */ + /* Check the first cache entry. */ RTREE_CACHE_CHECK(0); /* * Search the remaining cache elements, and on success move the matching - * element to the front. Unroll the first iteration to avoid calling - * memmove() (the compiler typically optimizes it into raw moves). + * element up by one slot. */ - if (RTREE_CTX_NCACHE > 1) { - RTREE_CACHE_CHECK(1); - } - for (unsigned i = 2; i < RTREE_CTX_NCACHE; i++) { + for (unsigned i = 1; i < RTREE_CTX_NCACHE; i++) { RTREE_CACHE_CHECK(i); } #undef RTREE_CACHE_CHECK -- GitLab From 07f4f93434b8fca5aabedbbaa122fa8f6eb681a6 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 27 Mar 2017 16:41:47 -0700 Subject: [PATCH 369/544] Move arena_slab_data_t's nfree into extent_t's e_bits. Compact extent_t to 128 bytes on 64-bit systems by moving arena_slab_data_t's nfree into extent_t's e_bits. Cacheline-align extent_t structures so that they always cross the minimum number of cacheline boundaries. Re-order extent_t fields such that all fields except the slab bitmap (and overlaid heap profiling context pointer) are in the first cacheline. This resolves #461. --- include/jemalloc/internal/arena_structs_a.h | 3 -- include/jemalloc/internal/extent_inlines.h | 32 +++++++++++- include/jemalloc/internal/extent_structs.h | 50 ++++++++++++------- include/jemalloc/internal/private_symbols.txt | 4 ++ src/arena.c | 37 +++++++------- src/extent.c | 3 +- 6 files changed, 86 insertions(+), 43 deletions(-) diff --git a/include/jemalloc/internal/arena_structs_a.h b/include/jemalloc/internal/arena_structs_a.h index ed265b20..07013a06 100644 --- a/include/jemalloc/internal/arena_structs_a.h +++ b/include/jemalloc/internal/arena_structs_a.h @@ -2,9 +2,6 @@ #define JEMALLOC_INTERNAL_ARENA_STRUCTS_A_H struct arena_slab_data_s { - /* Number of free regions in slab. */ - unsigned nfree; - /* Per region allocated/deallocated bitmap. */ bitmap_t bitmap[BITMAP_GROUPS_MAX]; }; diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index 22229b50..99fa67c7 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -11,6 +11,7 @@ extent_state_t extent_state_get(const extent_t *extent); bool extent_zeroed_get(const extent_t *extent); bool extent_committed_get(const extent_t *extent); bool extent_slab_get(const extent_t *extent); +unsigned extent_nfree_get(const extent_t *extent); void *extent_base_get(const extent_t *extent); void *extent_addr_get(const extent_t *extent); size_t extent_size_get(const extent_t *extent); @@ -25,6 +26,9 @@ void extent_addr_set(extent_t *extent, void *addr); void extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment); void extent_size_set(extent_t *extent, size_t size); void extent_szind_set(extent_t *extent, szind_t szind); +void extent_nfree_set(extent_t *extent, unsigned nfree); +void extent_nfree_inc(extent_t *extent); +void extent_nfree_dec(extent_t *extent); void extent_sn_set(extent_t *extent, size_t sn); void extent_state_set(extent_t *extent, extent_state_t state); void extent_zeroed_set(extent_t *extent, bool zeroed); @@ -112,6 +116,13 @@ extent_slab_get(const extent_t *extent) { EXTENT_BITS_SLAB_SHIFT); } +JEMALLOC_INLINE unsigned +extent_nfree_get(const extent_t *extent) { + assert(extent_slab_get(extent)); + return (unsigned)((extent->e_bits & EXTENT_BITS_NFREE_MASK) >> + EXTENT_BITS_NFREE_SHIFT); +} + JEMALLOC_INLINE void * extent_base_get(const extent_t *extent) { assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || @@ -210,6 +221,25 @@ extent_szind_set(extent_t *extent, szind_t szind) { ((uint64_t)szind << EXTENT_BITS_SZIND_SHIFT); } +JEMALLOC_INLINE void +extent_nfree_set(extent_t *extent, unsigned nfree) { + assert(extent_slab_get(extent)); + extent->e_bits = (extent->e_bits & ~EXTENT_BITS_NFREE_MASK) | + ((uint64_t)nfree << EXTENT_BITS_NFREE_SHIFT); +} + +JEMALLOC_INLINE void +extent_nfree_inc(extent_t *extent) { + assert(extent_slab_get(extent)); + extent->e_bits += ((uint64_t)1U << EXTENT_BITS_NFREE_SHIFT); +} + +JEMALLOC_INLINE void +extent_nfree_dec(extent_t *extent) { + assert(extent_slab_get(extent)); + extent->e_bits -= ((uint64_t)1U << EXTENT_BITS_NFREE_SHIFT); +} + JEMALLOC_INLINE void extent_sn_set(extent_t *extent, size_t sn) { extent->e_bits = (extent->e_bits & ~EXTENT_BITS_SN_MASK) | @@ -260,10 +290,10 @@ extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, extent_state_set(extent, state); extent_zeroed_set(extent, zeroed); extent_committed_set(extent, committed); + ql_elm_new(extent, ql_link); if (config_prof) { extent_prof_tctx_set(extent, NULL); } - ql_elm_new(extent, ql_link); } JEMALLOC_INLINE void diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index ddc04087..1527acb9 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -20,8 +20,9 @@ struct extent_s { * t: state * i: szind * n: sn + * f: nfree * - * nnnnnnnn ... nnnnnnni iiiiiiit tzcbaaaa aaaaaaaa + * nnnnnnnn ... nnnnnfff fffffffi iiiiiiit tzcbaaaa aaaaaaaa * * arena_ind: Arena from which this extent came, or all 1 bits if * unassociated. @@ -47,6 +48,8 @@ struct extent_s { * even for non-slabs, either due to large_pad or promotion of * sampled small regions. * + * nfree: Number of free regions in slab. + * * sn: Serial number (potentially non-unique). * * Serial numbers may wrap around if JEMALLOC_MUNMAP is defined, but @@ -61,26 +64,35 @@ struct extent_s { uint64_t e_bits; #define EXTENT_BITS_ARENA_SHIFT 0 #define EXTENT_BITS_ARENA_MASK \ - (((1U << MALLOCX_ARENA_BITS) - 1) << EXTENT_BITS_ARENA_SHIFT) + (((uint64_t)(1U << MALLOCX_ARENA_BITS) - 1) << EXTENT_BITS_ARENA_SHIFT) #define EXTENT_BITS_SLAB_SHIFT MALLOCX_ARENA_BITS -#define EXTENT_BITS_SLAB_MASK (0x1U << EXTENT_BITS_SLAB_SHIFT) +#define EXTENT_BITS_SLAB_MASK \ + ((uint64_t)0x1U << EXTENT_BITS_SLAB_SHIFT) #define EXTENT_BITS_COMMITTED_SHIFT (MALLOCX_ARENA_BITS + 1) -#define EXTENT_BITS_COMMITTED_MASK (0x1U << EXTENT_BITS_COMMITTED_SHIFT) +#define EXTENT_BITS_COMMITTED_MASK \ + ((uint64_t)0x1U << EXTENT_BITS_COMMITTED_SHIFT) #define EXTENT_BITS_ZEROED_SHIFT (MALLOCX_ARENA_BITS + 2) -#define EXTENT_BITS_ZEROED_MASK (0x1U << EXTENT_BITS_ZEROED_SHIFT) +#define EXTENT_BITS_ZEROED_MASK \ + ((uint64_t)0x1U << EXTENT_BITS_ZEROED_SHIFT) #define EXTENT_BITS_STATE_SHIFT (MALLOCX_ARENA_BITS + 3) -#define EXTENT_BITS_STATE_MASK (0x3U << EXTENT_BITS_STATE_SHIFT) +#define EXTENT_BITS_STATE_MASK \ + ((uint64_t)0x3U << EXTENT_BITS_STATE_SHIFT) #define EXTENT_BITS_SZIND_SHIFT (MALLOCX_ARENA_BITS + 5) #define EXTENT_BITS_SZIND_MASK \ - (((1U << LG_CEIL_NSIZES) - 1) << EXTENT_BITS_SZIND_SHIFT) + (((uint64_t)(1U << LG_CEIL_NSIZES) - 1) << EXTENT_BITS_SZIND_SHIFT) -#define EXTENT_BITS_SN_SHIFT \ +#define EXTENT_BITS_NFREE_SHIFT \ (MALLOCX_ARENA_BITS + 5 + LG_CEIL_NSIZES) +#define EXTENT_BITS_NFREE_MASK \ + ((uint64_t)((1U << (LG_SLAB_MAXREGS + 1)) - 1) << EXTENT_BITS_NFREE_SHIFT) + +#define EXTENT_BITS_SN_SHIFT \ + (MALLOCX_ARENA_BITS + 5 + LG_CEIL_NSIZES + (LG_SLAB_MAXREGS + 1)) #define EXTENT_BITS_SN_MASK (UINT64_MAX << EXTENT_BITS_SN_SHIFT) /* Pointer to the extent that this structure is responsible for. */ @@ -89,17 +101,6 @@ struct extent_s { /* Extent size. */ size_t e_size; - union { - /* Small region slab metadata. */ - arena_slab_data_t e_slab_data; - - /* Profile counters, used for large objects. */ - union { - void *e_prof_tctx_pun; - prof_tctx_t *e_prof_tctx; - }; - }; - /* * List linkage, used by a variety of lists: * - arena_bin_t's slabs_full @@ -112,6 +113,17 @@ struct extent_s { /* Linkage for per size class sn/address-ordered heaps. */ phn(extent_t) ph_link; + + union { + /* Small region slab metadata. */ + arena_slab_data_t e_slab_data; + + /* Profile counters, used for large objects. */ + union { + void *e_prof_tctx_pun; + prof_tctx_t *e_prof_tctx; + }; + }; }; typedef ql_head(extent_t) extent_list_t; typedef ph(extent_t) extent_heap_t; diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 64151c1b..5d03f5d0 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -175,6 +175,10 @@ extent_list_last extent_list_remove extent_list_replace extent_merge_wrapper +extent_nfree_dec +extent_nfree_get +extent_nfree_inc +extent_nfree_set extent_past_get extent_prof_tctx_get extent_prof_tctx_set diff --git a/src/arena.c b/src/arena.c index b0913c35..b8ef4731 100644 --- a/src/arena.c +++ b/src/arena.c @@ -361,13 +361,13 @@ arena_slab_reg_alloc(tsdn_t *tsdn, extent_t *slab, arena_slab_data_t *slab_data = extent_slab_data_get(slab); size_t regind; - assert(slab_data->nfree > 0); + assert(extent_nfree_get(slab) > 0); assert(!bitmap_full(slab_data->bitmap, &bin_info->bitmap_info)); regind = bitmap_sfu(slab_data->bitmap, &bin_info->bitmap_info); ret = (void *)((uintptr_t)extent_addr_get(slab) + (uintptr_t)(bin_info->reg_size * regind)); - slab_data->nfree--; + extent_nfree_dec(slab); return ret; } @@ -416,12 +416,12 @@ arena_slab_reg_dalloc(tsdn_t *tsdn, extent_t *slab, const arena_bin_info_t *bin_info = &arena_bin_info[binind]; size_t regind = arena_slab_regind(slab, binind, ptr); - assert(slab_data->nfree < bin_info->nregs); + assert(extent_nfree_get(slab) < bin_info->nregs); /* Freeing an unallocated pointer can cause assertion failure. */ assert(bitmap_get(slab_data->bitmap, &bin_info->bitmap_info, regind)); bitmap_unset(slab_data->bitmap, &bin_info->bitmap_info, regind); - slab_data->nfree++; + extent_nfree_inc(slab); } static void @@ -999,7 +999,7 @@ arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *slab) { static void arena_bin_slabs_nonfull_insert(arena_bin_t *bin, extent_t *slab) { - assert(extent_slab_data_get(slab)->nfree > 0); + assert(extent_nfree_get(slab) > 0); extent_heap_insert(&bin->slabs_nonfull, slab); } @@ -1022,7 +1022,7 @@ arena_bin_slabs_nonfull_tryget(arena_bin_t *bin) { static void arena_bin_slabs_full_insert(arena_bin_t *bin, extent_t *slab) { - assert(extent_slab_data_get(slab)->nfree == 0); + assert(extent_nfree_get(slab) == 0); extent_list_append(&bin->slabs_full, slab); } @@ -1209,7 +1209,7 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, /* Initialize slab internals. */ arena_slab_data_t *slab_data = extent_slab_data_get(slab); - slab_data->nfree = bin_info->nregs; + extent_nfree_set(slab, bin_info->nregs); bitmap_init(slab_data->bitmap, &bin_info->bitmap_info, false); arena_nactive_add(arena, extent_size_get(slab) >> LG_PAGE); @@ -1277,7 +1277,7 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, * Another thread updated slabcur while this one ran without the * bin lock in arena_bin_nonfull_slab_get(). */ - if (extent_slab_data_get(bin->slabcur)->nfree > 0) { + if (extent_nfree_get(bin->slabcur) > 0) { void *ret = arena_slab_reg_alloc(tsdn, bin->slabcur, bin_info); if (slab != NULL) { @@ -1290,8 +1290,7 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, * arena_bin_lower_slab() must be called, as if * a region were just deallocated from the slab. */ - if (extent_slab_data_get(slab)->nfree == - bin_info->nregs) { + if (extent_nfree_get(slab) == bin_info->nregs) { arena_dalloc_bin_slab(tsdn, arena, slab, bin); } else { @@ -1311,7 +1310,7 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, } bin->slabcur = slab; - assert(extent_slab_data_get(bin->slabcur)->nfree > 0); + assert(extent_nfree_get(bin->slabcur) > 0); return arena_slab_reg_alloc(tsdn, slab, bin_info); } @@ -1333,8 +1332,8 @@ arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_bin_t *tbin, tbin->lg_fill_div); i < nfill; i++) { extent_t *slab; void *ptr; - if ((slab = bin->slabcur) != NULL && - extent_slab_data_get(slab)->nfree > 0) { + if ((slab = bin->slabcur) != NULL && extent_nfree_get(slab) > + 0) { ptr = arena_slab_reg_alloc(tsdn, slab, &arena_bin_info[binind]); } else { @@ -1405,8 +1404,7 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) { usize = index2size(binind); malloc_mutex_lock(tsdn, &bin->lock); - if ((slab = bin->slabcur) != NULL && extent_slab_data_get(slab)->nfree > - 0) { + if ((slab = bin->slabcur) != NULL && extent_nfree_get(slab) > 0) { ret = arena_slab_reg_alloc(tsdn, slab, &arena_bin_info[binind]); } else { ret = arena_bin_malloc_hard(tsdn, arena, bin, binind); @@ -1582,7 +1580,7 @@ arena_dalloc_bin_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, arena_bin_t *bin) { - assert(extent_slab_data_get(slab)->nfree > 0); + assert(extent_nfree_get(slab) > 0); /* * Make sure that if bin->slabcur is non-NULL, it refers to the @@ -1592,7 +1590,7 @@ arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, */ if (bin->slabcur != NULL && extent_snad_comp(bin->slabcur, slab) > 0) { /* Switch slabcur. */ - if (extent_slab_data_get(bin->slabcur)->nfree > 0) { + if (extent_nfree_get(bin->slabcur) > 0) { arena_bin_slabs_nonfull_insert(bin, bin->slabcur); } else { arena_bin_slabs_full_insert(bin, bin->slabcur); @@ -1619,10 +1617,11 @@ arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, extent_t *slab, } arena_slab_reg_dalloc(tsdn, slab, slab_data, ptr); - if (slab_data->nfree == bin_info->nregs) { + unsigned nfree = extent_nfree_get(slab); + if (nfree == bin_info->nregs) { arena_dissociate_bin_slab(slab, bin); arena_dalloc_bin_slab(tsdn, arena, slab, bin); - } else if (slab_data->nfree == 1 && slab != bin->slabcur) { + } else if (nfree == 1 && slab != bin->slabcur) { arena_bin_slabs_full_remove(bin, slab); arena_bin_lower_slab(tsdn, arena, slab, bin); } diff --git a/src/extent.c b/src/extent.c index 3f4f5f1b..8bd8eb79 100644 --- a/src/extent.c +++ b/src/extent.c @@ -94,7 +94,8 @@ extent_alloc(tsdn_t *tsdn, arena_t *arena) { extent = extent_list_last(&arena->extent_freelist); if (extent == NULL) { malloc_mutex_unlock(tsdn, &arena->extent_freelist_mtx); - return base_alloc(tsdn, arena->base, sizeof(extent_t), QUANTUM); + return base_alloc(tsdn, arena->base, sizeof(extent_t), + CACHELINE); } extent_list_remove(&arena->extent_freelist, extent); malloc_mutex_unlock(tsdn, &arena->extent_freelist_mtx); -- GitLab From d4e98bc0b27b2ed660002e1603fa353d5c89eb91 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 27 Mar 2017 17:22:01 -0700 Subject: [PATCH 370/544] Lookup extent once per time during tcache_flush_small / _large. Caching the extents on stack to avoid redundant looking up overhead. --- src/tcache.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/tcache.c b/src/tcache.c index 9c99c8b3..6057c890 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -91,19 +91,23 @@ tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, void tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, szind_t binind, unsigned rem) { - arena_t *arena; - void *ptr; - unsigned i, nflush, ndeferred; bool merged_stats = false; assert(binind < NBINS); assert(rem <= tbin->ncached); - arena = tcache->arena; + arena_t *arena = tcache->arena; assert(arena != NULL); - for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) { + unsigned nflush = tbin->ncached - rem; + VARIABLE_ARRAY(extent_t *, item_extent, nflush); + /* Look up extent once per item. */ + for (unsigned i = 0 ; i < nflush; i++) { + item_extent[i] = iealloc(tsd_tsdn(tsd), *(tbin->avail - 1 - i)); + } + + while (nflush > 0) { /* Lock the arena bin associated with the first object. */ - extent_t *extent = iealloc(tsd_tsdn(tsd), *(tbin->avail - 1)); + extent_t *extent = item_extent[0]; arena_t *bin_arena = extent_arena_get(extent); arena_bin_t *bin = &bin_arena->bins[binind]; @@ -123,12 +127,12 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, bin->stats.nrequests += tbin->tstats.nrequests; tbin->tstats.nrequests = 0; } - ndeferred = 0; - for (i = 0; i < nflush; i++) { - ptr = *(tbin->avail - 1 - i); - assert(ptr != NULL); + unsigned ndeferred = 0; + for (unsigned i = 0; i < nflush; i++) { + void *ptr = *(tbin->avail - 1 - i); + extent = item_extent[i]; + assert(ptr != NULL && extent != NULL); - extent = iealloc(tsd_tsdn(tsd), ptr); if (extent_arena_get(extent) == bin_arena) { arena_dalloc_bin_junked_locked(tsd_tsdn(tsd), bin_arena, extent, ptr); @@ -140,11 +144,13 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, * handled in a future pass. */ *(tbin->avail - 1 - ndeferred) = ptr; + item_extent[ndeferred] = extent; ndeferred++; } } malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); arena_decay_ticks(tsd_tsdn(tsd), bin_arena, nflush - ndeferred); + nflush = ndeferred; } if (config_stats && !merged_stats) { /* @@ -178,9 +184,15 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, arena_t *arena = tcache->arena; assert(arena != NULL); unsigned nflush = tbin->ncached - rem; + VARIABLE_ARRAY(extent_t *, item_extent, nflush); + /* Look up extent once per item. */ + for (unsigned i = 0 ; i < nflush; i++) { + item_extent[i] = iealloc(tsd_tsdn(tsd), *(tbin->avail - 1 - i)); + } + while (nflush > 0) { /* Lock the arena associated with the first object. */ - extent_t *extent = iealloc(tsd_tsdn(tsd), *(tbin->avail - 1)); + extent_t *extent = item_extent[0]; arena_t *locked_arena = extent_arena_get(extent); UNUSED bool idump; @@ -217,8 +229,9 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, unsigned ndeferred = 0; for (unsigned i = 0; i < nflush; i++) { void *ptr = *(tbin->avail - 1 - i); - assert(ptr != NULL); - extent = iealloc(tsd_tsdn(tsd), ptr); + extent = item_extent[i]; + assert(ptr != NULL && extent != NULL); + if (extent_arena_get(extent) == locked_arena) { large_dalloc_finish(tsd_tsdn(tsd), extent); } else { @@ -229,6 +242,7 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, * in a future pass. */ *(tbin->avail - 1 - ndeferred) = ptr; + item_extent[ndeferred] = extent; ndeferred++; } } -- GitLab From 5bf800a54247c5752053831e15f7b132bf9fddbf Mon Sep 17 00:00:00 2001 From: Aliaksey Kandratsenka Date: Sat, 14 Dec 2013 12:03:02 -0800 Subject: [PATCH 371/544] issue-586: detect main executable even if PIE is active Previous logic of detecting main program addresses is to assume that main executable is at least addressess. With PIE (active by default on Ubuntus) it doesn't work. In order to deal with that, we're attempting to find main executable mapping in /proc/[pid]/maps. And old logic is preserved too just in case. --- bin/jeprof.in | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/bin/jeprof.in b/bin/jeprof.in index 42087fce..baa80a54 100644 --- a/bin/jeprof.in +++ b/bin/jeprof.in @@ -71,6 +71,7 @@ use strict; use warnings; use Getopt::Long; +use Cwd; my $JEPROF_VERSION = "@jemalloc_version@"; my $PPROF_VERSION = "2.0"; @@ -4570,7 +4571,7 @@ sub ParseTextSectionHeader { # Split /proc/pid/maps dump into a list of libraries sub ParseLibraries { return if $main::use_symbol_page; # We don't need libraries info. - my $prog = shift; + my $prog = Cwd::abs_path(shift); my $map = shift; my $pcs = shift; @@ -4603,6 +4604,16 @@ sub ParseLibraries { $finish = HexExtend($2); $offset = $zero_offset; $lib = $3; + } elsif (($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+)$/i) && ($4 eq $prog)) { + # PIEs and address space randomization do not play well with our + # default assumption that main executable is at lowest + # addresses. So we're detecting main executable in + # /proc/self/maps as well. + $start = HexExtend($1); + $finish = HexExtend($2); + $offset = HexExtend($3); + $lib = $4; + $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths } # FreeBSD 10.0 virtual memory map /proc/curproc/map as defined in # function procfs_doprocmap (sys/fs/procfs/procfs_map.c) -- GitLab From 9ed84b0d458a22e1d98f071f8fb5efb2de24998e Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 29 Mar 2017 13:18:02 -0700 Subject: [PATCH 372/544] Add init function support to tsd members. This will facilitate embedding tcache into tsd, which will require proper initialization cannot be done via the static initializer. Make tsd->rtree_ctx to be initialized via rtree_ctx_data_init(). --- include/jemalloc/internal/private_symbols.txt | 2 ++ include/jemalloc/internal/rtree_externs.h | 1 + include/jemalloc/internal/rtree_types.h | 14 +++++--- include/jemalloc/internal/tsd_externs.h | 1 + include/jemalloc/internal/tsd_inlines.h | 9 ++--- include/jemalloc/internal/tsd_structs.h | 34 +++++++++---------- src/rtree.c | 11 ++++++ src/tsd.c | 19 ++++++++++- test/unit/rtree.c | 16 +++++---- 9 files changed, 74 insertions(+), 33 deletions(-) diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 5d03f5d0..1cced603 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -424,6 +424,7 @@ prof_thread_name_set psz2ind psz2u rtree_clear +rtree_ctx_data_init rtree_delete rtree_extent_read rtree_extent_szind_read @@ -520,6 +521,7 @@ tsd_booted tsd_booted_get tsd_cleanup tsd_cleanup_wrapper +tsd_data_init tsd_fetch tsd_fetch_impl tsd_get diff --git a/include/jemalloc/internal/rtree_externs.h b/include/jemalloc/internal/rtree_externs.h index 5145c12c..482f6ba3 100644 --- a/include/jemalloc/internal/rtree_externs.h +++ b/include/jemalloc/internal/rtree_externs.h @@ -43,5 +43,6 @@ void rtree_leaf_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, const rtree_leaf_elm_t *elm); void rtree_leaf_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, const rtree_leaf_elm_t *elm); +bool rtree_ctx_data_init(rtree_ctx_t *ctx); #endif /* JEMALLOC_INTERNAL_RTREE_EXTERNS_H */ diff --git a/include/jemalloc/internal/rtree_types.h b/include/jemalloc/internal/rtree_types.h index de3893be..e6041560 100644 --- a/include/jemalloc/internal/rtree_types.h +++ b/include/jemalloc/internal/rtree_types.h @@ -38,6 +38,9 @@ typedef struct rtree_s rtree_t; # define RTREE_LEAF_COMPACT #endif +/* Needed for initialization only. */ +#define RTREE_LEAFKEY_INVALID ((uintptr_t)1) + /* * Number of leafkey/leaf pairs to cache. Each entry supports an entire leaf, * so the cache hit rate is typically high even with a small number of entries. @@ -51,12 +54,13 @@ typedef struct rtree_s rtree_t; * the tree nodes, and the cache will itself suffer cache misses if made overly * large, not to mention the cost of linear search. */ -#define RTREE_CTX_NCACHE 8 +#define RTREE_CTX_NCACHE 8 -/* Static initializer for rtree_ctx_t. */ -#define RTREE_CTX_INITIALIZER { \ - {{0, NULL} /* C initializes all trailing elements to NULL. */} \ -} +/* + * Zero initializer required for tsd initialization only. Proper initialization + * done via rtree_ctx_data_init(). + */ +#define RTREE_CTX_ZERO_INITIALIZER {{{0}}} /* * Maximum number of concurrently acquired elements per thread. This controls diff --git a/include/jemalloc/internal/tsd_externs.h b/include/jemalloc/internal/tsd_externs.h index 87ebaf2d..9b88a567 100644 --- a/include/jemalloc/internal/tsd_externs.h +++ b/include/jemalloc/internal/tsd_externs.h @@ -14,5 +14,6 @@ void *tsd_init_check_recursion(tsd_init_head_t *head, void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block); #endif void tsd_cleanup(void *arg); +bool tsd_data_init(void *arg); #endif /* JEMALLOC_INTERNAL_TSD_EXTERNS_H */ diff --git a/include/jemalloc/internal/tsd_inlines.h b/include/jemalloc/internal/tsd_inlines.h index 96de4063..7d57b7dd 100644 --- a/include/jemalloc/internal/tsd_inlines.h +++ b/include/jemalloc/internal/tsd_inlines.h @@ -8,7 +8,7 @@ tsd_t *tsd_fetch_impl(bool init); tsd_t *tsd_fetch(void); tsdn_t *tsd_tsdn(tsd_t *tsd); bool tsd_nominal(tsd_t *tsd); -#define O(n, t, gs, c) \ +#define O(n, t, gs, i, c) \ t *tsd_##n##p_get(tsd_t *tsd); \ t tsd_##n##_get(tsd_t *tsd); \ void tsd_##n##_set(tsd_t *tsd, t n); @@ -39,9 +39,11 @@ tsd_fetch_impl(bool init) { tsd->state = tsd_state_nominal; /* Trigger cleanup handler registration. */ tsd_set(tsd); + tsd_data_init(tsd); } else if (tsd->state == tsd_state_purgatory) { tsd->state = tsd_state_reincarnated; tsd_set(tsd); + tsd_data_init(tsd); } else { assert(tsd->state == tsd_state_reincarnated); } @@ -76,7 +78,7 @@ tsd_##n##_set(tsd_t *tsd, t n) { \ tsd->n = n; \ } #define MALLOC_TSD_getset_no(n, t) -#define O(n, t, gs, c) \ +#define O(n, t, gs, i, c) \ JEMALLOC_ALWAYS_INLINE t * \ tsd_##n##p_get(tsd_t *tsd) { \ return &tsd->n; \ @@ -121,8 +123,7 @@ tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback) { * return a pointer to it. */ if (unlikely(tsdn_null(tsdn))) { - static const rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; - memcpy(fallback, &rtree_ctx, sizeof(rtree_ctx_t)); + rtree_ctx_data_init(fallback); return fallback; } return tsd_rtree_ctx(tsdn_tsd(tsdn)); diff --git a/include/jemalloc/internal/tsd_structs.h b/include/jemalloc/internal/tsd_structs.h index 722b9669..b4ac09fd 100644 --- a/include/jemalloc/internal/tsd_structs.h +++ b/include/jemalloc/internal/tsd_structs.h @@ -15,23 +15,23 @@ struct tsd_init_head_s { #endif #define MALLOC_TSD \ -/* O(name, type, [gs]et, cleanup) */ \ - O(tcache, tcache_t *, yes, yes) \ - O(thread_allocated, uint64_t, yes, no) \ - O(thread_deallocated, uint64_t, yes, no) \ - O(prof_tdata, prof_tdata_t *, yes, yes) \ - O(iarena, arena_t *, yes, yes) \ - O(arena, arena_t *, yes, yes) \ - O(arenas_tdata, arena_tdata_t *,yes, yes) \ - O(narenas_tdata, unsigned, yes, no) \ - O(arenas_tdata_bypass, bool, no, no) \ +/* O(name, type, [gs]et, init, cleanup) */ \ + O(tcache, tcache_t *, yes, no, yes) \ + O(thread_allocated, uint64_t, yes, no, no) \ + O(thread_deallocated, uint64_t, yes, no, no) \ + O(prof_tdata, prof_tdata_t *, yes, no, yes) \ + O(iarena, arena_t *, yes, no, yes) \ + O(arena, arena_t *, yes, no, yes) \ + O(arenas_tdata, arena_tdata_t *,yes, no, yes) \ + O(narenas_tdata, unsigned, yes, no, no) \ + O(arenas_tdata_bypass, bool, no, no, no) \ O(tcache_enabled, tcache_enabled_t, \ - yes, no) \ - O(rtree_ctx, rtree_ctx_t, no, no) \ - O(witnesses, witness_list_t, no, yes) \ + yes, no, no) \ + O(rtree_ctx, rtree_ctx_t, no, yes, no) \ + O(witnesses, witness_list_t, no, no, yes) \ O(rtree_leaf_elm_witnesses, rtree_leaf_elm_witness_tsd_t, \ - no, no) \ - O(witness_fork, bool, yes, no) \ + no, no, no) \ + O(witness_fork, bool, yes, no, no) #define TSD_INITIALIZER { \ tsd_state_uninitialized, \ @@ -45,7 +45,7 @@ struct tsd_init_head_s { 0, \ false, \ tcache_enabled_default, \ - RTREE_CTX_INITIALIZER, \ + RTREE_CTX_ZERO_INITIALIZER, \ ql_head_initializer(witnesses), \ RTREE_ELM_WITNESS_TSD_INITIALIZER, \ false \ @@ -53,7 +53,7 @@ struct tsd_init_head_s { struct tsd_s { tsd_state_t state; -#define O(n, t, gs, c) \ +#define O(n, t, gs, i, c) \ t n; MALLOC_TSD #undef O diff --git a/src/rtree.c b/src/rtree.c index a07380f3..b2c6824f 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -424,3 +424,14 @@ rtree_leaf_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, witness_unlock(tsdn, witness); rtree_leaf_elm_witness_dalloc(tsdn_tsd(tsdn), witness, elm); } + +bool +rtree_ctx_data_init(rtree_ctx_t *ctx) { + for (unsigned i = 0; i < RTREE_CTX_NCACHE; i++) { + rtree_ctx_cache_elm_t *cache = &ctx->cache[i]; + cache->leafkey = RTREE_LEAFKEY_INVALID; + cache->leaf = NULL; + } + + return false; +} diff --git a/src/tsd.c b/src/tsd.c index 9614dd9a..970d5baa 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -60,6 +60,23 @@ malloc_tsd_cleanup_register(bool (*f)(void)) { ncleanups++; } +bool +tsd_data_init(void *arg) { + tsd_t *tsd = (tsd_t *)arg; +#define MALLOC_TSD_init_yes(n, t) \ + if (n##_data_init(&tsd->n)) { \ + return true; \ + } +#define MALLOC_TSD_init_no(n, t) +#define O(n, t, gs, i, c) \ + MALLOC_TSD_init_##i(n, t) +MALLOC_TSD +#undef MALLOC_TSD_init_yes +#undef MALLOC_TSD_init_no +#undef O + return false; +} + void tsd_cleanup(void *arg) { tsd_t *tsd = (tsd_t *)arg; @@ -72,7 +89,7 @@ tsd_cleanup(void *arg) { #define MALLOC_TSD_cleanup_yes(n, t) \ n##_cleanup(tsd); #define MALLOC_TSD_cleanup_no(n, t) -#define O(n, t, gs, c) \ +#define O(n, t, gs, i, c) \ MALLOC_TSD_cleanup_##c(n, t) MALLOC_TSD #undef MALLOC_TSD_cleanup_yes diff --git a/test/unit/rtree.c b/test/unit/rtree.c index 7a25c47d..3c5b2df4 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -68,7 +68,8 @@ TEST_BEGIN(test_rtree_read_empty) { tsdn = tsdn_fetch(); rtree_t *rtree = &test_rtree; - rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; + rtree_ctx_t rtree_ctx; + rtree_ctx_data_init(&rtree_ctx); assert_false(rtree_new(rtree, false), "Unexpected rtree_new() failure"); assert_ptr_null(rtree_extent_read(tsdn, rtree, &rtree_ctx, PAGE, false), "rtree_extent_read() should return NULL for empty tree"); @@ -89,7 +90,8 @@ typedef struct { static void * thd_start(void *varg) { thd_start_arg_t *arg = (thd_start_arg_t *)varg; - rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; + rtree_ctx_t rtree_ctx; + rtree_ctx_data_init(&rtree_ctx); sfmt_t *sfmt; extent_t *extent; tsdn_t *tsdn; @@ -173,7 +175,8 @@ TEST_BEGIN(test_rtree_extrema) { tsdn_t *tsdn = tsdn_fetch(); rtree_t *rtree = &test_rtree; - rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; + rtree_ctx_t rtree_ctx; + rtree_ctx_data_init(&rtree_ctx); assert_false(rtree_new(rtree, false), "Unexpected rtree_new() failure"); assert_false(rtree_write(tsdn, rtree, &rtree_ctx, PAGE, &extent_a, @@ -207,8 +210,8 @@ TEST_BEGIN(test_rtree_bits) { extent_state_active, false, false); rtree_t *rtree = &test_rtree; - rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; - + rtree_ctx_t rtree_ctx; + rtree_ctx_data_init(&rtree_ctx); assert_false(rtree_new(rtree, false), "Unexpected rtree_new() failure"); for (unsigned i = 0; i < sizeof(keys)/sizeof(uintptr_t); i++) { @@ -240,7 +243,8 @@ TEST_BEGIN(test_rtree_random) { tsdn_t *tsdn = tsdn_fetch(); uintptr_t keys[NSET]; rtree_t *rtree = &test_rtree; - rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER; + rtree_ctx_t rtree_ctx; + rtree_ctx_data_init(&rtree_ctx); extent_t extent; extent_init(&extent, NULL, NULL, 0, false, NSIZES, 0, -- GitLab From 51d368295032910577d4f34b9ff99b3ed41544b9 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 28 Mar 2017 17:14:43 -0700 Subject: [PATCH 373/544] Remove the leafkey NULL check in leaf_elm_lookup. --- include/jemalloc/internal/rtree_inlines.h | 18 +++++++----------- include/jemalloc/internal/rtree_types.h | 6 +++--- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 3e619b3f..bebe49e0 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -324,19 +324,15 @@ rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, #define RTREE_CACHE_CHECK(i) do { \ if (likely(rtree_ctx->cache[i].leafkey == leafkey)) { \ rtree_leaf_elm_t *leaf = rtree_ctx->cache[i].leaf; \ - if (likely(leaf != NULL)) { \ + assert(leaf != NULL); \ + if (i > 0) { \ /* Bubble up by one. */ \ - if (i > 0) { \ - rtree_ctx->cache[i] = \ - rtree_ctx->cache[i - 1]; \ - rtree_ctx->cache[i - 1].leafkey = \ - leafkey; \ - rtree_ctx->cache[i - 1].leaf = leaf; \ - } \ - uintptr_t subkey = rtree_subkey(key, \ - RTREE_HEIGHT-1); \ - return &leaf[subkey]; \ + rtree_ctx->cache[i] = rtree_ctx->cache[i - 1]; \ + rtree_ctx->cache[i - 1].leafkey = leafkey; \ + rtree_ctx->cache[i - 1].leaf = leaf; \ } \ + uintptr_t subkey = rtree_subkey(key, RTREE_HEIGHT-1); \ + return &leaf[subkey]; \ } \ } while (0) /* Check the first cache entry. */ diff --git a/include/jemalloc/internal/rtree_types.h b/include/jemalloc/internal/rtree_types.h index e6041560..e480542d 100644 --- a/include/jemalloc/internal/rtree_types.h +++ b/include/jemalloc/internal/rtree_types.h @@ -39,7 +39,7 @@ typedef struct rtree_s rtree_t; #endif /* Needed for initialization only. */ -#define RTREE_LEAFKEY_INVALID ((uintptr_t)1) +#define RTREE_LEAFKEY_INVALID ((uintptr_t)1) /* * Number of leafkey/leaf pairs to cache. Each entry supports an entire leaf, @@ -54,7 +54,7 @@ typedef struct rtree_s rtree_t; * the tree nodes, and the cache will itself suffer cache misses if made overly * large, not to mention the cost of linear search. */ -#define RTREE_CTX_NCACHE 8 +#define RTREE_CTX_NCACHE 8 /* * Zero initializer required for tsd initialization only. Proper initialization @@ -68,7 +68,7 @@ typedef struct rtree_s rtree_t; * would have a witness_t directly embedded, but that would dramatically bloat * the tree. This must contain enough entries to e.g. coalesce two extents. */ -#define RTREE_ELM_ACQUIRE_MAX 4 +#define RTREE_ELM_ACQUIRE_MAX 4 /* Initializers for rtree_leaf_elm_witness_tsd_t. */ #define RTREE_ELM_WITNESS_INITIALIZER { \ -- GitLab From d3cda3423cd7ae47630833e4a888bdaf6a7bf8d9 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 29 Mar 2017 17:00:52 -0700 Subject: [PATCH 374/544] Do proper cleanup for tsd_state_reincarnated. Also enable arena_bind under non-nominal state, as the cleanup will be handled correctly now. --- include/jemalloc/internal/tsd_inlines.h | 3 +- src/jemalloc.c | 9 ++---- src/tsd.c | 15 ++++----- test/unit/tsd.c | 41 ++++++++++++++++++++++++- 4 files changed, 50 insertions(+), 18 deletions(-) diff --git a/include/jemalloc/internal/tsd_inlines.h b/include/jemalloc/internal/tsd_inlines.h index 7d57b7dd..7c3fba5f 100644 --- a/include/jemalloc/internal/tsd_inlines.h +++ b/include/jemalloc/internal/tsd_inlines.h @@ -74,7 +74,8 @@ tsd_##n##_get(tsd_t *tsd) { \ } \ JEMALLOC_ALWAYS_INLINE void \ tsd_##n##_set(tsd_t *tsd, t n) { \ - assert(tsd->state == tsd_state_nominal); \ + assert(tsd->state == tsd_state_nominal || \ + tsd->state == tsd_state_reincarnated); \ tsd->n = n; \ } #define MALLOC_TSD_getset_no(n, t) diff --git a/src/jemalloc.c b/src/jemalloc.c index ab047c24..7c8fe9c9 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -422,13 +422,7 @@ arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { static void arena_bind(tsd_t *tsd, unsigned ind, bool internal) { - arena_t *arena; - - if (!tsd_nominal(tsd)) { - return; - } - - arena = arena_get(tsd_tsdn(tsd), ind, false); + arena_t *arena = arena_get(tsd_tsdn(tsd), ind, false); arena_nthreads_inc(arena, internal); if (internal) { @@ -455,6 +449,7 @@ arena_unbind(tsd_t *tsd, unsigned ind, bool internal) { arena = arena_get(tsd_tsdn(tsd), ind, false); arena_nthreads_dec(arena, internal); + if (internal) { tsd_iarena_set(tsd, NULL); } else { diff --git a/src/tsd.c b/src/tsd.c index 970d5baa..6b68c001 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -86,6 +86,12 @@ tsd_cleanup(void *arg) { /* Do nothing. */ break; case tsd_state_nominal: + case tsd_state_reincarnated: + /* + * Reincarnated means another destructor deallocated memory + * after this destructor was called. Reset state to + * tsd_state_purgatory and request another callback. + */ #define MALLOC_TSD_cleanup_yes(n, t) \ n##_cleanup(tsd); #define MALLOC_TSD_cleanup_no(n, t) @@ -106,15 +112,6 @@ MALLOC_TSD * nothing, and do not request another callback. */ break; - case tsd_state_reincarnated: - /* - * Another destructor deallocated memory after this destructor - * was called. Reset state to tsd_state_purgatory and request - * another callback. - */ - tsd->state = tsd_state_purgatory; - tsd_set(tsd); - break; default: not_reached(); } diff --git a/test/unit/tsd.c b/test/unit/tsd.c index ae47d23e..e033bb76 100644 --- a/test/unit/tsd.c +++ b/test/unit/tsd.c @@ -90,6 +90,44 @@ TEST_BEGIN(test_tsd_sub_thread) { } TEST_END +static void * +thd_start_reincarnated(void *arg) { + tsd_t *tsd = tsd_fetch(); + assert(tsd); + + void *p = malloc(1); + assert_ptr_not_null(p, "Unexpected malloc() failure"); + + /* Manually trigger reincarnation. */ + assert_ptr_not_null(tsd->arena, "Should have tsd arena set."); + tsd_cleanup((void *)tsd); + assert_ptr_null(tsd->arena, "TSD arena should have been cleared."); + assert_u_eq(tsd->state, tsd_state_purgatory, + "TSD state should be purgatory\n"); + + free(p); + assert_u_eq(tsd->state, tsd_state_reincarnated, + "TSD state should be reincarnated\n"); + p = mallocx(1, MALLOCX_TCACHE_NONE); + assert_ptr_not_null(p, "Unexpected malloc() failure"); + assert_ptr_not_null(tsd->arena, + "Should have tsd arena set after reincarnation."); + + free(p); + tsd_cleanup((void *)tsd); + assert_ptr_null(tsd->arena, + "TSD arena should have been cleared after 2nd cleanup."); + + return NULL; +} + +TEST_BEGIN(test_tsd_reincarnation) { + thd_t thd; + thd_create(&thd, thd_start_reincarnated, NULL); + thd_join(thd, NULL); +} +TEST_END + int main(void) { /* Core tsd bootstrapping must happen prior to data_tsd_boot(). */ @@ -101,5 +139,6 @@ main(void) { return test( test_tsd_main_thread, - test_tsd_sub_thread); + test_tsd_sub_thread, + test_tsd_reincarnation); } -- GitLab From 492e9f301eeb980e880d307214fd441264986324 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 4 Apr 2017 11:09:45 -0700 Subject: [PATCH 375/544] Make the tsd member init functions to take tsd_t * type. --- include/jemalloc/internal/rtree_externs.h | 3 ++- src/rtree.c | 7 ++++++- src/tsd.c | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/jemalloc/internal/rtree_externs.h b/include/jemalloc/internal/rtree_externs.h index 482f6ba3..c8d1c376 100644 --- a/include/jemalloc/internal/rtree_externs.h +++ b/include/jemalloc/internal/rtree_externs.h @@ -43,6 +43,7 @@ void rtree_leaf_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, const rtree_leaf_elm_t *elm); void rtree_leaf_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, const rtree_leaf_elm_t *elm); -bool rtree_ctx_data_init(rtree_ctx_t *ctx); +void rtree_ctx_data_init(rtree_ctx_t *ctx); +bool tsd_rtree_ctx_data_init(tsd_t *tsd); #endif /* JEMALLOC_INTERNAL_RTREE_EXTERNS_H */ diff --git a/src/rtree.c b/src/rtree.c index b2c6824f..de4990bd 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -425,13 +425,18 @@ rtree_leaf_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, rtree_leaf_elm_witness_dalloc(tsdn_tsd(tsdn), witness, elm); } -bool +void rtree_ctx_data_init(rtree_ctx_t *ctx) { for (unsigned i = 0; i < RTREE_CTX_NCACHE; i++) { rtree_ctx_cache_elm_t *cache = &ctx->cache[i]; cache->leafkey = RTREE_LEAFKEY_INVALID; cache->leaf = NULL; } +} + +bool +tsd_rtree_ctx_data_init(tsd_t *tsd) { + rtree_ctx_data_init(&tsd->rtree_ctx); return false; } diff --git a/src/tsd.c b/src/tsd.c index 6b68c001..86502116 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -64,7 +64,7 @@ bool tsd_data_init(void *arg) { tsd_t *tsd = (tsd_t *)arg; #define MALLOC_TSD_init_yes(n, t) \ - if (n##_data_init(&tsd->n)) { \ + if (tsd_##n##_data_init(tsd)) { \ return true; \ } #define MALLOC_TSD_init_no(n, t) -- GitLab From 7da04a6b091eb2e3a9fa69bb5f58c18dc10f8e2d Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 3 Apr 2017 18:18:40 -0700 Subject: [PATCH 376/544] Convert prng module to use C11-style atomics --- include/jemalloc/internal/arena_structs_b.h | 2 +- include/jemalloc/internal/prng_inlines.h | 45 +++++++++++---------- src/arena.c | 4 +- test/unit/prng.c | 38 ++++++++--------- 4 files changed, 46 insertions(+), 43 deletions(-) diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index a5191d16..fe4e4eed 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -166,7 +166,7 @@ struct arena_s { * * Synchronization: atomic. */ - size_t offset_state; + atomic_zu_t offset_state; /* * Extent serial number generator state. diff --git a/include/jemalloc/internal/prng_inlines.h b/include/jemalloc/internal/prng_inlines.h index 646e07b7..3f06ccd4 100644 --- a/include/jemalloc/internal/prng_inlines.h +++ b/include/jemalloc/internal/prng_inlines.h @@ -6,14 +6,15 @@ uint32_t prng_state_next_u32(uint32_t state); uint64_t prng_state_next_u64(uint64_t state); size_t prng_state_next_zu(size_t state); -uint32_t prng_lg_range_u32(uint32_t *state, unsigned lg_range, +uint32_t prng_lg_range_u32(atomic_u32_t *state, unsigned lg_range, bool atomic); uint64_t prng_lg_range_u64(uint64_t *state, unsigned lg_range); -size_t prng_lg_range_zu(size_t *state, unsigned lg_range, bool atomic); +size_t prng_lg_range_zu(atomic_zu_t *state, unsigned lg_range, bool atomic); -uint32_t prng_range_u32(uint32_t *state, uint32_t range, bool atomic); +uint32_t prng_range_u32(atomic_u32_t *state, uint32_t range, + bool atomic); uint64_t prng_range_u64(uint64_t *state, uint64_t range); -size_t prng_range_zu(size_t *state, size_t range, bool atomic); +size_t prng_range_zu(atomic_zu_t *state, size_t range, bool atomic); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PRNG_C_)) @@ -39,22 +40,22 @@ prng_state_next_zu(size_t state) { } JEMALLOC_ALWAYS_INLINE uint32_t -prng_lg_range_u32(uint32_t *state, unsigned lg_range, bool atomic) { - uint32_t ret, state1; +prng_lg_range_u32(atomic_u32_t *state, unsigned lg_range, bool atomic) { + uint32_t ret, state0, state1; assert(lg_range > 0); assert(lg_range <= 32); - if (atomic) { - uint32_t state0; + state0 = atomic_load_u32(state, ATOMIC_RELAXED); + if (atomic) { do { - state0 = atomic_read_u32(state); state1 = prng_state_next_u32(state0); - } while (atomic_cas_u32(state, state0, state1)); + } while (!atomic_compare_exchange_weak_u32(state, &state0, + state1, ATOMIC_RELAXED, ATOMIC_RELAXED)); } else { - state1 = prng_state_next_u32(*state); - *state = state1; + state1 = prng_state_next_u32(state0); + atomic_store_u32(state, state1, ATOMIC_RELAXED); } ret = state1 >> (32 - lg_range); @@ -77,22 +78,22 @@ prng_lg_range_u64(uint64_t *state, unsigned lg_range) { } JEMALLOC_ALWAYS_INLINE size_t -prng_lg_range_zu(size_t *state, unsigned lg_range, bool atomic) { - size_t ret, state1; +prng_lg_range_zu(atomic_zu_t *state, unsigned lg_range, bool atomic) { + size_t ret, state0, state1; assert(lg_range > 0); assert(lg_range <= ZU(1) << (3 + LG_SIZEOF_PTR)); - if (atomic) { - size_t state0; + state0 = atomic_load_zu(state, ATOMIC_RELAXED); + if (atomic) { do { - state0 = atomic_read_zu(state); state1 = prng_state_next_zu(state0); - } while (atomic_cas_zu(state, state0, state1)); + } while (atomic_compare_exchange_weak_zu(state, &state0, + state1, ATOMIC_RELAXED, ATOMIC_RELAXED)); } else { - state1 = prng_state_next_zu(*state); - *state = state1; + state1 = prng_state_next_zu(state0); + atomic_store_zu(state, state1, ATOMIC_RELAXED); } ret = state1 >> ((ZU(1) << (3 + LG_SIZEOF_PTR)) - lg_range); @@ -100,7 +101,7 @@ prng_lg_range_zu(size_t *state, unsigned lg_range, bool atomic) { } JEMALLOC_ALWAYS_INLINE uint32_t -prng_range_u32(uint32_t *state, uint32_t range, bool atomic) { +prng_range_u32(atomic_u32_t *state, uint32_t range, bool atomic) { uint32_t ret; unsigned lg_range; @@ -136,7 +137,7 @@ prng_range_u64(uint64_t *state, uint64_t range) { } JEMALLOC_ALWAYS_INLINE size_t -prng_range_zu(size_t *state, size_t range, bool atomic) { +prng_range_zu(atomic_zu_t *state, size_t range, bool atomic) { size_t ret; unsigned lg_range; diff --git a/src/arena.c b/src/arena.c index b8ef4731..53bef36e 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1863,8 +1863,8 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { * cost of test repeatability. For debug builds, instead use a * deterministic seed. */ - arena->offset_state = config_debug ? ind : - (size_t)(uintptr_t)arena; + atomic_store_zu(&arena->offset_state, config_debug ? ind : + (size_t)(uintptr_t)arena, ATOMIC_RELAXED); } arena->extent_sn_next = 0; diff --git a/test/unit/prng.c b/test/unit/prng.c index 74d9cf73..b5795c2f 100644 --- a/test/unit/prng.c +++ b/test/unit/prng.c @@ -2,31 +2,32 @@ static void test_prng_lg_range_u32(bool atomic) { - uint32_t sa, sb, ra, rb; + atomic_u32_t sa, sb; + uint32_t ra, rb; unsigned lg_range; - sa = 42; + atomic_store_u32(&sa, 42, ATOMIC_RELAXED); ra = prng_lg_range_u32(&sa, 32, atomic); - sa = 42; + atomic_store_u32(&sa, 42, ATOMIC_RELAXED); rb = prng_lg_range_u32(&sa, 32, atomic); assert_u32_eq(ra, rb, "Repeated generation should produce repeated results"); - sb = 42; + atomic_store_u32(&sb, 42, ATOMIC_RELAXED); rb = prng_lg_range_u32(&sb, 32, atomic); assert_u32_eq(ra, rb, "Equivalent generation should produce equivalent results"); - sa = 42; + atomic_store_u32(&sa, 42, ATOMIC_RELAXED); ra = prng_lg_range_u32(&sa, 32, atomic); rb = prng_lg_range_u32(&sa, 32, atomic); assert_u32_ne(ra, rb, "Full-width results must not immediately repeat"); - sa = 42; + atomic_store_u32(&sa, 42, ATOMIC_RELAXED); ra = prng_lg_range_u32(&sa, 32, atomic); for (lg_range = 31; lg_range > 0; lg_range--) { - sb = 42; + atomic_store_u32(&sb, 42, ATOMIC_RELAXED); rb = prng_lg_range_u32(&sb, lg_range, atomic); assert_u32_eq((rb & (UINT32_C(0xffffffff) << lg_range)), 0, "High order bits should be 0, lg_range=%u", lg_range); @@ -74,32 +75,33 @@ test_prng_lg_range_u64(void) { static void test_prng_lg_range_zu(bool atomic) { - size_t sa, sb, ra, rb; + atomic_zu_t sa, sb; + size_t ra, rb; unsigned lg_range; - sa = 42; + atomic_store_zu(&sa, 42, ATOMIC_RELAXED); ra = prng_lg_range_zu(&sa, ZU(1) << (3 + LG_SIZEOF_PTR), atomic); - sa = 42; + atomic_store_zu(&sa, 42, ATOMIC_RELAXED); rb = prng_lg_range_zu(&sa, ZU(1) << (3 + LG_SIZEOF_PTR), atomic); assert_zu_eq(ra, rb, "Repeated generation should produce repeated results"); - sb = 42; + atomic_store_zu(&sb, 42, ATOMIC_RELAXED); rb = prng_lg_range_zu(&sb, ZU(1) << (3 + LG_SIZEOF_PTR), atomic); assert_zu_eq(ra, rb, "Equivalent generation should produce equivalent results"); - sa = 42; + atomic_store_zu(&sa, 42, ATOMIC_RELAXED); ra = prng_lg_range_zu(&sa, ZU(1) << (3 + LG_SIZEOF_PTR), atomic); rb = prng_lg_range_zu(&sa, ZU(1) << (3 + LG_SIZEOF_PTR), atomic); assert_zu_ne(ra, rb, "Full-width results must not immediately repeat"); - sa = 42; + atomic_store_zu(&sa, 42, ATOMIC_RELAXED); ra = prng_lg_range_zu(&sa, ZU(1) << (3 + LG_SIZEOF_PTR), atomic); for (lg_range = (ZU(1) << (3 + LG_SIZEOF_PTR)) - 1; lg_range > 0; lg_range--) { - sb = 42; + atomic_store_zu(&sb, 42, ATOMIC_RELAXED); rb = prng_lg_range_zu(&sb, lg_range, atomic); assert_zu_eq((rb & (SIZE_T_MAX << lg_range)), 0, "High order bits should be 0, lg_range=%u", lg_range); @@ -142,10 +144,10 @@ test_prng_range_u32(bool atomic) { #define NREPS 10 for (range = 2; range < MAX_RANGE; range += RANGE_STEP) { - uint32_t s; + atomic_u32_t s; unsigned rep; - s = range; + atomic_store_u32(&s, range, ATOMIC_RELAXED); for (rep = 0; rep < NREPS; rep++) { uint32_t r = prng_range_u32(&s, range, atomic); @@ -182,10 +184,10 @@ test_prng_range_zu(bool atomic) { #define NREPS 10 for (range = 2; range < MAX_RANGE; range += RANGE_STEP) { - size_t s; + atomic_zu_t s; unsigned rep; - s = range; + atomic_store_zu(&s, range, ATOMIC_RELAXED); for (rep = 0; rep < NREPS; rep++) { size_t r = prng_range_zu(&s, range, atomic); -- GitLab From 864adb7f4219dc9b920ead049478946f0a42428d Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 4 Apr 2017 14:33:25 -0700 Subject: [PATCH 377/544] Transition e_prof_tctx in struct extent to C11 atomics --- include/jemalloc/internal/extent_inlines.h | 6 +++--- include/jemalloc/internal/extent_structs.h | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index 99fa67c7..e6e447cf 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -173,8 +173,8 @@ extent_slab_data_get_const(const extent_t *extent) { JEMALLOC_INLINE prof_tctx_t * extent_prof_tctx_get(const extent_t *extent) { - return (prof_tctx_t *)atomic_read_p( - &((extent_t *)extent)->e_prof_tctx_pun); + return (prof_tctx_t *)atomic_load_p(&extent->e_prof_tctx, + ATOMIC_ACQUIRE); } JEMALLOC_INLINE void @@ -272,7 +272,7 @@ extent_slab_set(extent_t *extent, bool slab) { JEMALLOC_INLINE void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) { - atomic_write_p(&extent->e_prof_tctx_pun, tctx); + atomic_store_p(&extent->e_prof_tctx, tctx, ATOMIC_RELEASE); } JEMALLOC_INLINE void diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 1527acb9..5d41bb81 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -118,11 +118,11 @@ struct extent_s { /* Small region slab metadata. */ arena_slab_data_t e_slab_data; - /* Profile counters, used for large objects. */ - union { - void *e_prof_tctx_pun; - prof_tctx_t *e_prof_tctx; - }; + /* + * Profile counters, used for large objects. Points to a + * prof_tctx_t. + */ + atomic_p_t e_prof_tctx; }; }; typedef ql_head(extent_t) extent_list_t; -- GitLab From bc32ec3503433fae4c737c7ffe6b3822ce98d5d8 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 4 Apr 2017 15:12:24 -0700 Subject: [PATCH 378/544] Move arena-tracking atomics in jemalloc.c to C11-style --- include/jemalloc/internal/extent_inlines.h | 2 +- include/jemalloc/internal/jemalloc_internal.h.in | 7 +++---- src/jemalloc.c | 14 ++++++++------ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index e6e447cf..f1b94776 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -63,7 +63,7 @@ extent_arena_get(const extent_t *extent) { return NULL; } assert(arena_ind <= MALLOCX_ARENA_MAX); - return arenas[arena_ind]; + return (arena_t *)atomic_load_p(&arenas[arena_ind], ATOMIC_ACQUIRE); } JEMALLOC_INLINE szind_t diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 4255b639..04f91c07 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -469,7 +469,7 @@ extern unsigned narenas_auto; * Arenas that are used to service external requests. Not all elements of the * arenas array are necessarily used; arenas are created lazily as needed. */ -extern arena_t *arenas[]; +extern atomic_p_t arenas[]; /* * pind2sz_tab encodes the same information as could be computed by @@ -909,10 +909,9 @@ arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing) { assert(ind <= MALLOCX_ARENA_MAX); - ret = arenas[ind]; + ret = (arena_t *)atomic_load_p(&arenas[ind], ATOMIC_ACQUIRE); if (unlikely(ret == NULL)) { - ret = (arena_t *)atomic_read_p((void **)&arenas[ind]); - if (init_if_missing && unlikely(ret == NULL)) { + if (init_if_missing) { ret = arena_init(tsdn, ind, (extent_hooks_t *)&extent_hooks_default); } diff --git a/src/jemalloc.c b/src/jemalloc.c index 7c8fe9c9..94ae030c 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -55,10 +55,12 @@ static malloc_mutex_t arenas_lock; * arenas[0..narenas_auto) are used for automatic multiplexing of threads and * arenas. arenas[narenas_auto..narenas_total) are only used if the application * takes some action to create them and allocate from them. + * + * Points to an arena_t. */ JEMALLOC_ALIGNED(CACHELINE) -arena_t *arenas[MALLOCX_ARENA_MAX + 1]; -static unsigned narenas_total; /* Use narenas_total_*(). */ +atomic_p_t arenas[MALLOCX_ARENA_MAX + 1]; +static atomic_u_t narenas_total; /* Use narenas_total_*(). */ static arena_t *a0; /* arenas[0]; read-only after initialization. */ unsigned narenas_auto; /* Read-only after initialization. */ @@ -363,22 +365,22 @@ bootstrap_free(void *ptr) { void arena_set(unsigned ind, arena_t *arena) { - atomic_write_p((void **)&arenas[ind], arena); + atomic_store_p(&arenas[ind], arena, ATOMIC_RELEASE); } static void narenas_total_set(unsigned narenas) { - atomic_write_u(&narenas_total, narenas); + atomic_store_u(&narenas_total, narenas, ATOMIC_RELEASE); } static void narenas_total_inc(void) { - atomic_add_u(&narenas_total, 1); + atomic_fetch_add_u(&narenas_total, 1, ATOMIC_RELEASE); } unsigned narenas_total_get(void) { - return atomic_read_u(&narenas_total); + return atomic_load_u(&narenas_total, ATOMIC_ACQUIRE); } /* Create a new arena and insert it into the arenas array at index ind. */ -- GitLab From 56b72c7b1781ef75c2450a08e08079fe164bb2df Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 4 Apr 2017 17:22:24 -0700 Subject: [PATCH 379/544] Transition arena struct fields to C11 atomics --- include/jemalloc/internal/arena_structs_b.h | 16 +++--- src/arena.c | 56 +++++++++++---------- src/extent.c | 15 +++--- 3 files changed, 48 insertions(+), 39 deletions(-) diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index fe4e4eed..00e0d0c8 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -134,7 +134,7 @@ struct arena_s { * * Synchronization: atomic. */ - unsigned nthreads[2]; + atomic_u_t nthreads[2]; /* * When percpu_arena is enabled, to amortize the cost of reading / @@ -173,17 +173,21 @@ struct arena_s { * * Synchronization: atomic. */ - size_t extent_sn_next; + atomic_zu_t extent_sn_next; - /* Synchronization: atomic. */ - dss_prec_t dss_prec; + /* + * Represents a dss_prec_t, but atomically. + * + * Synchronization: atomic. + */ + atomic_u_t dss_prec; /* * Number of pages in active extents. * * Synchronization: atomic. */ - size_t nactive; + atomic_zu_t nactive; /* * Extant large allocations. @@ -222,7 +226,7 @@ struct arena_s { * * Synchronization: atomic. */ - pszind_t extent_grow_next; + atomic_u_t extent_grow_next; /* * Freelist of extent structures that were allocated via base_alloc(). diff --git a/src/arena.c b/src/arena.c index 53bef36e..feb1f760 100644 --- a/src/arena.c +++ b/src/arena.c @@ -13,10 +13,11 @@ const char *percpu_arena_mode_names[] = { const char *opt_percpu_arena = OPT_PERCPU_ARENA_DEFAULT; percpu_arena_mode_t percpu_arena_mode = PERCPU_ARENA_MODE_DEFAULT; -ssize_t opt_dirty_decay_time = DIRTY_DECAY_TIME_DEFAULT; -ssize_t opt_muzzy_decay_time = MUZZY_DECAY_TIME_DEFAULT; -static ssize_t dirty_decay_time_default; -static ssize_t muzzy_decay_time_default; +ssize_t opt_dirty_decay_time = DIRTY_DECAY_TIME_DEFAULT; +ssize_t opt_muzzy_decay_time = MUZZY_DECAY_TIME_DEFAULT; + +static atomic_zd_t dirty_decay_time_default; +static atomic_zd_t muzzy_decay_time_default; const arena_bin_info_t arena_bin_info[NBINS] = { #define BIN_INFO_bin_yes(reg_size, slab_size, nregs) \ @@ -197,7 +198,7 @@ arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, *dss = dss_prec_names[arena_dss_prec_get(arena)]; *dirty_decay_time = arena_dirty_decay_time_get(arena); *muzzy_decay_time = arena_muzzy_decay_time_get(arena); - *nactive += atomic_read_zu(&arena->nactive); + *nactive += atomic_load_zu(&arena->nactive, ATOMIC_RELAXED); *ndirty += extents_npages_get(&arena->extents_dirty); *nmuzzy += extents_npages_get(&arena->extents_muzzy); } @@ -246,7 +247,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, arena_stats_accum_zu(&astats->base, base_allocated); arena_stats_accum_zu(&astats->internal, arena_internal_get(arena)); arena_stats_accum_zu(&astats->resident, base_resident + - (((atomic_read_zu(&arena->nactive) + + (((atomic_load_zu(&arena->nactive, ATOMIC_RELAXED) + extents_npages_get(&arena->extents_dirty) + extents_npages_get(&arena->extents_muzzy)) << LG_PAGE))); @@ -426,13 +427,13 @@ arena_slab_reg_dalloc(tsdn_t *tsdn, extent_t *slab, static void arena_nactive_add(arena_t *arena, size_t add_pages) { - atomic_add_zu(&arena->nactive, add_pages); + atomic_fetch_add_zu(&arena->nactive, add_pages, ATOMIC_RELAXED); } static void arena_nactive_sub(arena_t *arena, size_t sub_pages) { - assert(atomic_read_zu(&arena->nactive) >= sub_pages); - atomic_sub_zu(&arena->nactive, sub_pages); + assert(atomic_load_zu(&arena->nactive, ATOMIC_RELAXED) >= sub_pages); + atomic_fetch_sub_zu(&arena->nactive, sub_pages, ATOMIC_RELAXED); } static void @@ -1100,7 +1101,7 @@ arena_reset(tsd_t *tsd, arena_t *arena) { malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); } - atomic_write_zu(&arena->nactive, 0); + atomic_store_zu(&arena->nactive, 0, ATOMIC_RELAXED); } static void @@ -1750,7 +1751,7 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, dss_prec_t arena_dss_prec_get(arena_t *arena) { - return (dss_prec_t)atomic_read_u((unsigned *)&arena->dss_prec); + return (dss_prec_t)atomic_load_u(&arena->dss_prec, ATOMIC_ACQUIRE); } bool @@ -1758,13 +1759,13 @@ arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec) { if (!have_dss) { return (dss_prec != dss_prec_disabled); } - atomic_write_u((unsigned *)&arena->dss_prec, dss_prec); + atomic_store_u(&arena->dss_prec, (unsigned)dss_prec, ATOMIC_RELEASE); return false; } ssize_t arena_dirty_decay_time_default_get(void) { - return (ssize_t)atomic_read_zu((size_t *)&dirty_decay_time_default); + return atomic_load_zd(&dirty_decay_time_default, ATOMIC_RELAXED); } bool @@ -1772,14 +1773,13 @@ arena_dirty_decay_time_default_set(ssize_t decay_time) { if (!arena_decay_time_valid(decay_time)) { return true; } - atomic_write_zu((size_t *)&dirty_decay_time_default, - (size_t)decay_time); + atomic_store_zd(&dirty_decay_time_default, decay_time, ATOMIC_RELAXED); return false; } ssize_t arena_muzzy_decay_time_default_get(void) { - return (ssize_t)atomic_read_zu((size_t *)&muzzy_decay_time_default); + return atomic_load_zd(&muzzy_decay_time_default, ATOMIC_RELAXED); } bool @@ -1787,29 +1787,28 @@ arena_muzzy_decay_time_default_set(ssize_t decay_time) { if (!arena_decay_time_valid(decay_time)) { return true; } - atomic_write_zu((size_t *)&muzzy_decay_time_default, - (size_t)decay_time); + atomic_store_zd(&muzzy_decay_time_default, decay_time, ATOMIC_RELAXED); return false; } unsigned arena_nthreads_get(arena_t *arena, bool internal) { - return atomic_read_u(&arena->nthreads[internal]); + return atomic_load_u(&arena->nthreads[internal], ATOMIC_RELAXED); } void arena_nthreads_inc(arena_t *arena, bool internal) { - atomic_add_u(&arena->nthreads[internal], 1); + atomic_fetch_add_u(&arena->nthreads[internal], 1, ATOMIC_RELAXED); } void arena_nthreads_dec(arena_t *arena, bool internal) { - atomic_sub_u(&arena->nthreads[internal], 1); + atomic_fetch_sub_u(&arena->nthreads[internal], 1, ATOMIC_RELAXED); } size_t arena_extent_sn_next(arena_t *arena) { - return atomic_add_zu(&arena->extent_sn_next, 1) - 1; + return atomic_fetch_add_zu(&arena->extent_sn_next, 1, ATOMIC_RELAXED); } arena_t * @@ -1832,7 +1831,8 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { goto label_error; } - arena->nthreads[0] = arena->nthreads[1] = 0; + atomic_store_u(&arena->nthreads[0], 0, ATOMIC_RELAXED); + atomic_store_u(&arena->nthreads[1], 0, ATOMIC_RELAXED); arena->last_thd = NULL; if (config_stats) { @@ -1867,11 +1867,12 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { (size_t)(uintptr_t)arena, ATOMIC_RELAXED); } - arena->extent_sn_next = 0; + atomic_store_zu(&arena->extent_sn_next, 0, ATOMIC_RELAXED); - arena->dss_prec = extent_dss_prec_get(); + atomic_store_u(&arena->dss_prec, (unsigned)extent_dss_prec_get(), + ATOMIC_RELAXED); - atomic_write_zu(&arena->nactive, 0); + atomic_store_zu(&arena->nactive, 0, ATOMIC_RELAXED); extent_list_init(&arena->large); if (malloc_mutex_init(&arena->large_mtx, "arena_large", @@ -1918,7 +1919,8 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { } if (!config_munmap) { - arena->extent_grow_next = psz2ind(HUGEPAGE); + atomic_store_u(&arena->extent_grow_next, psz2ind(HUGEPAGE), + ATOMIC_RELAXED); } extent_list_init(&arena->extent_freelist); diff --git a/src/extent.c b/src/extent.c index 8bd8eb79..a75016af 100644 --- a/src/extent.c +++ b/src/extent.c @@ -913,7 +913,8 @@ extent_alloc_default_impl(tsdn_t *tsdn, arena_t *arena, void *new_addr, void *ret; ret = extent_alloc_core(tsdn, arena, new_addr, size, alignment, zero, - commit, arena->dss_prec); + commit, (dss_prec_t)atomic_load_u(&arena->dss_prec, + ATOMIC_RELAXED)); return ret; } @@ -956,7 +957,8 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, * extent creation as a side effect. */ size_t esize = size + pad; - size_t alloc_size = pind2sz(atomic_read_u(&arena->extent_grow_next)); + size_t alloc_size = pind2sz(atomic_load_u(&arena->extent_grow_next, + ATOMIC_RELAXED)); size_t alloc_size_min = esize + PAGE_CEILING(alignment) - PAGE; /* Beware size_t wrap-around. */ if (alloc_size_min < esize) { @@ -972,7 +974,8 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, bool zeroed = false; bool committed = false; void *ptr = extent_alloc_core(tsdn, arena, new_addr, alloc_size, PAGE, - &zeroed, &committed, arena->dss_prec); + &zeroed, &committed, (dss_prec_t)atomic_load_u(&arena->dss_prec, + ATOMIC_RELAXED)); extent_init(extent, arena, ptr, alloc_size, false, NSIZES, arena_extent_sn_next(arena), extent_state_active, zeroed, committed); @@ -1078,14 +1081,14 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, * Increment extent_grow_next, but take care to do so atomically and * bail out if the increment would exceed the legal range. */ + pszind_t egn = atomic_load_u(&arena->extent_grow_next, ATOMIC_RELAXED); while (true) { - pszind_t egn = atomic_read_u(&arena->extent_grow_next); - if (egn + 1 == NPSIZES) { break; } assert(egn + 1 < NPSIZES); - if (!atomic_cas_u(&arena->extent_grow_next, egn, egn + 1)) { + if (atomic_compare_exchange_weak_u(&arena->extent_grow_next, + &egn, egn + 1, ATOMIC_RELAXED, ATOMIC_RELAXED)) { break; } } -- GitLab From 92aafb0efe47dbca23fb5b54c33fd4504601ae76 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 4 Apr 2017 17:32:21 -0700 Subject: [PATCH 380/544] Make base_t's extent_hooks field C11-atomic --- include/jemalloc/internal/base_structs.h | 10 +++++----- src/base.c | 14 ++++---------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/include/jemalloc/internal/base_structs.h b/include/jemalloc/internal/base_structs.h index bad37c06..13d5bd46 100644 --- a/include/jemalloc/internal/base_structs.h +++ b/include/jemalloc/internal/base_structs.h @@ -17,11 +17,11 @@ struct base_s { /* Associated arena's index within the arenas array. */ unsigned ind; - /* User-configurable extent hook functions. */ - union { - extent_hooks_t *extent_hooks; - void *extent_hooks_pun; - }; + /* + * User-configurable extent hook functions. Points to an + * extent_hooks_t. + */ + atomic_p_t extent_hooks; /* Protects base_alloc() and base_stats_get() operations. */ malloc_mutex_t mtx; diff --git a/src/base.c b/src/base.c index b1a4ae37..4275259e 100644 --- a/src/base.c +++ b/src/base.c @@ -227,7 +227,7 @@ base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { base = (base_t *)base_extent_bump_alloc_helper(&block->extent, &gap_size, base_size, base_alignment); base->ind = ind; - base->extent_hooks = extent_hooks; + atomic_store_p(&base->extent_hooks, extent_hooks, ATOMIC_RELAXED); if (malloc_mutex_init(&base->mtx, "base", WITNESS_RANK_BASE)) { base_unmap(extent_hooks, ind, block, block->size); return NULL; @@ -264,20 +264,14 @@ base_delete(base_t *base) { extent_hooks_t * base_extent_hooks_get(base_t *base) { - return (extent_hooks_t *)atomic_read_p(&base->extent_hooks_pun); + return (extent_hooks_t *)atomic_load_p(&base->extent_hooks, + ATOMIC_ACQUIRE); } extent_hooks_t * base_extent_hooks_set(base_t *base, extent_hooks_t *extent_hooks) { extent_hooks_t *old_extent_hooks = base_extent_hooks_get(base); - union { - extent_hooks_t **h; - void **v; - } u; - - u.h = &base->extent_hooks; - atomic_write_p(u.v, extent_hooks); - + atomic_store_p(&base->extent_hooks, extent_hooks, ATOMIC_RELEASE); return old_extent_hooks; } -- GitLab From 55d992c48c0ca9c5d823bd717f854c2c8939d1f3 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 4 Apr 2017 17:58:06 -0700 Subject: [PATCH 381/544] Make extent_dss use C11-style atomics --- src/extent_dss.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/extent_dss.c b/src/extent_dss.c index 5074594e..99919090 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -18,14 +18,15 @@ const char *dss_prec_names[] = { * guarantee that sizeof(dss_prec_t) is the same as sizeof(unsigned), and we use * atomic operations to synchronize the setting. */ -static unsigned dss_prec_default = (unsigned)DSS_PREC_DEFAULT; +static atomic_u_t dss_prec_default = ATOMIC_INIT( + (unsigned)DSS_PREC_DEFAULT); /* Base address of the DSS. */ static void *dss_base; /* Atomic boolean indicating whether the DSS is exhausted. */ -static unsigned dss_exhausted; +static atomic_b_t dss_exhausted; /* Atomic current upper limit on DSS addresses. */ -static void *dss_max; +static atomic_p_t dss_max; /******************************************************************************/ @@ -46,7 +47,7 @@ extent_dss_prec_get(void) { if (!have_dss) { return dss_prec_disabled; } - ret = (dss_prec_t)atomic_read_u(&dss_prec_default); + ret = (dss_prec_t)atomic_load_u(&dss_prec_default, ATOMIC_ACQUIRE); return ret; } @@ -55,7 +56,7 @@ extent_dss_prec_set(dss_prec_t dss_prec) { if (!have_dss) { return (dss_prec != dss_prec_disabled); } - atomic_write_u(&dss_prec_default, (unsigned)dss_prec); + atomic_store_u(&dss_prec_default, (unsigned)dss_prec, ATOMIC_RELEASE); return false; } @@ -69,7 +70,7 @@ extent_dss_max_update(void *new_addr) { */ spin_t spinner = SPIN_INITIALIZER; while (true) { - void *max_prev = atomic_read_p(&dss_max); + void *max_prev = atomic_load_p(&dss_max, ATOMIC_RELAXED); max_cur = extent_dss_sbrk(0); if ((uintptr_t)max_prev > (uintptr_t)max_cur) { @@ -80,7 +81,8 @@ extent_dss_max_update(void *new_addr) { spin_adaptive(&spinner); continue; } - if (!atomic_cas_p(&dss_max, max_prev, max_cur)) { + if (atomic_compare_exchange_weak_p(&dss_max, &max_prev, + max_cur, ATOMIC_ACQ_REL, ATOMIC_RELAXED)) { break; } } @@ -114,7 +116,7 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, return NULL; } - if (!atomic_read_u(&dss_exhausted)) { + if (!atomic_load_b(&dss_exhausted, ATOMIC_ACQUIRE)) { /* * The loop is necessary to recover from races with other * threads that are using the DSS for something other than @@ -167,7 +169,8 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, * DSS while dss_max is greater than the current DSS * max reported by sbrk(0). */ - if (atomic_cas_p(&dss_max, max_cur, dss_next)) { + if (!atomic_compare_exchange_weak_p(&dss_max, &max_cur, + dss_next, ATOMIC_ACQ_REL, ATOMIC_RELAXED)) { continue; } @@ -207,10 +210,12 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, * succeeded since this invocation started, in which * case rollback is not necessary. */ - atomic_cas_p(&dss_max, dss_next, max_cur); + atomic_compare_exchange_strong_p(&dss_max, &dss_next, + max_cur, ATOMIC_ACQ_REL, ATOMIC_RELAXED); if (dss_prev == (void *)-1) { /* OOM. */ - atomic_write_u(&dss_exhausted, (unsigned)true); + atomic_store_b(&dss_exhausted, true, + ATOMIC_RELEASE); goto label_oom; } } @@ -230,7 +235,8 @@ bool extent_in_dss(void *addr) { cassert(have_dss); - return extent_in_dss_helper(addr, atomic_read_p(&dss_max)); + return extent_in_dss_helper(addr, atomic_load_p(&dss_max, + ATOMIC_ACQUIRE)); } bool @@ -244,7 +250,7 @@ extent_dss_mergeable(void *addr_a, void *addr_b) { return true; } - max = atomic_read_p(&dss_max); + max = atomic_load_p(&dss_max, ATOMIC_ACQUIRE); return (extent_in_dss_helper(addr_a, max) == extent_in_dss_helper(addr_b, max)); } @@ -254,8 +260,8 @@ extent_dss_boot(void) { cassert(have_dss); dss_base = extent_dss_sbrk(0); - dss_exhausted = (unsigned)(dss_base == (void *)-1); - dss_max = dss_base; + atomic_store_b(&dss_exhausted, dss_base == (void *)-1, ATOMIC_RELAXED); + atomic_store_p(&dss_max, dss_base, ATOMIC_RELAXED); } /******************************************************************************/ -- GitLab From 30d74db08ef2617236cbff219b5f40c9ff0aa0fc Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 4 Apr 2017 18:08:58 -0700 Subject: [PATCH 382/544] Convert accumbytes in prof_accum_t to C11 atomics, when possible --- include/jemalloc/internal/prof_inlines_a.h | 10 ++++++---- include/jemalloc/internal/prof_structs.h | 4 +++- src/prof.c | 4 +++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/include/jemalloc/internal/prof_inlines_a.h b/include/jemalloc/internal/prof_inlines_a.h index d77635a8..d0d29685 100644 --- a/include/jemalloc/internal/prof_inlines_a.h +++ b/include/jemalloc/internal/prof_inlines_a.h @@ -22,15 +22,16 @@ prof_accum_add(tsdn_t *tsdn, prof_accum_t *prof_accum, uint64_t accumbytes) { * avoids rate-limiting allocation. */ #ifdef JEMALLOC_ATOMIC_U64 + a0 = atomic_load_u64(&prof_accum->accumbytes, ATOMIC_RELAXED); do { - a0 = atomic_read_u64(&prof_accum->accumbytes); a1 = a0 + accumbytes; assert(a1 >= a0); overflow = (a1 >= prof_interval); if (overflow) { a1 %= prof_interval; } - } while (atomic_cas_u64(&prof_accum->accumbytes, a0, a1)); + } while (!atomic_compare_exchange_weak_u64(&prof_accum->accumbytes, &a0, + a1, ATOMIC_RELAXED, ATOMIC_RELAXED)); #else malloc_mutex_lock(tsdn, &prof_accum->mtx); a0 = prof_accum->accumbytes; @@ -57,11 +58,12 @@ prof_accum_cancel(tsdn_t *tsdn, prof_accum_t *prof_accum, size_t usize) { */ uint64_t a0, a1; #ifdef JEMALLOC_ATOMIC_U64 + a0 = atomic_load_u64(&prof_accum->accumbytes, ATOMIC_RELAXED); do { - a0 = atomic_read_u64(&prof_accum->accumbytes); a1 = (a0 >= LARGE_MINCLASS - usize) ? a0 - (LARGE_MINCLASS - usize) : 0; - } while (atomic_cas_u64(&prof_accum->accumbytes, a0, a1)); + } while (!atomic_compare_exchange_weak_u64(&prof_accum->accumbytes, &a0, + a1, ATOMIC_RELAXED, ATOMIC_RELAXED)); #else malloc_mutex_lock(tsdn, &prof_accum->mtx); a0 = prof_accum->accumbytes; diff --git a/include/jemalloc/internal/prof_structs.h b/include/jemalloc/internal/prof_structs.h index afff6aa5..fba8c295 100644 --- a/include/jemalloc/internal/prof_structs.h +++ b/include/jemalloc/internal/prof_structs.h @@ -18,8 +18,10 @@ typedef struct { struct prof_accum_s { #ifndef JEMALLOC_ATOMIC_U64 malloc_mutex_t mtx; -#endif uint64_t accumbytes; +#else + atomic_u64_t accumbytes; +#endif }; struct prof_cnt_s { diff --git a/src/prof.c b/src/prof.c index 4e83ae3f..ce02d99c 100644 --- a/src/prof.c +++ b/src/prof.c @@ -1758,8 +1758,10 @@ prof_accum_init(tsdn_t *tsdn, prof_accum_t *prof_accum) { WITNESS_RANK_PROF_ACCUM)) { return true; } -#endif prof_accum->accumbytes = 0; +#else + atomic_store_u64(&prof_accum->accumbytes, 0, ATOMIC_RELAXED); +#endif return false; } -- GitLab From 492a941f493f77f60062039b60040f426aa7ee45 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 4 Apr 2017 18:20:42 -0700 Subject: [PATCH 383/544] Convert extent module to use C11-style atomcis --- src/extent.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/extent.c b/src/extent.c index a75016af..e080773b 100644 --- a/src/extent.c +++ b/src/extent.c @@ -62,8 +62,8 @@ const extent_hooks_t extent_hooks_default = { }; /* Used exclusively for gdump triggering. */ -static size_t curpages; -static size_t highpages; +static atomic_zu_t curpages; +static atomic_zu_t highpages; /******************************************************************************/ /* @@ -566,14 +566,16 @@ extent_gdump_add(tsdn_t *tsdn, const extent_t *extent) { if (opt_prof && extent_state_get(extent) == extent_state_active) { size_t nadd = extent_size_get(extent) >> LG_PAGE; - size_t cur = atomic_add_zu(&curpages, nadd); - size_t high = atomic_read_zu(&highpages); - while (cur > high && atomic_cas_zu(&highpages, high, cur)) { + size_t cur = atomic_fetch_add_zu(&curpages, nadd, + ATOMIC_RELAXED) + nadd; + size_t high = atomic_load_zu(&highpages, ATOMIC_RELAXED); + while (cur > high && !atomic_compare_exchange_weak_zu( + &highpages, &high, cur, ATOMIC_RELAXED, ATOMIC_RELAXED)) { /* * Don't refresh cur, because it may have decreased * since this thread lost the highpages update race. + * Note that high is updated in case of CAS failure. */ - high = atomic_read_zu(&highpages); } if (cur > high && prof_gdump_get_unlocked()) { prof_gdump(tsdn); @@ -587,8 +589,8 @@ extent_gdump_sub(tsdn_t *tsdn, const extent_t *extent) { if (opt_prof && extent_state_get(extent) == extent_state_active) { size_t nsub = extent_size_get(extent) >> LG_PAGE; - assert(atomic_read_zu(&curpages) >= nsub); - atomic_sub_zu(&curpages, nsub); + assert(atomic_load_zu(&curpages, ATOMIC_RELAXED) >= nsub); + atomic_fetch_sub_zu(&curpages, nsub, ATOMIC_RELAXED); } } -- GitLab From 5dcc13b342b3ffb38a1215ab2584b8cb12c46030 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 4 Apr 2017 18:34:01 -0700 Subject: [PATCH 384/544] Make the mutex n_waiting_thds field a C11-style atomic --- include/jemalloc/internal/mutex_inlines.h | 14 ++++++++++++-- include/jemalloc/internal/mutex_structs.h | 2 +- include/jemalloc/internal/mutex_types.h | 3 ++- src/mutex.c | 7 ++++--- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index 3a12a722..0552e190 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -40,7 +40,12 @@ malloc_mutex_prof_merge(mutex_prof_data_t *sum, mutex_prof_data_t *data) { if (sum->max_n_thds < data->max_n_thds) { sum->max_n_thds = data->max_n_thds; } - sum->n_waiting_thds += data->n_waiting_thds; + uint32_t cur_n_waiting_thds = atomic_load_u32(&sum->n_waiting_thds, + ATOMIC_RELAXED); + uint32_t new_n_waiting_thds = cur_n_waiting_thds + atomic_load_u32( + &data->n_waiting_thds, ATOMIC_RELAXED); + atomic_store_u32(&sum->n_waiting_thds, new_n_waiting_thds, + ATOMIC_RELAXED); sum->n_owner_switches += data->n_owner_switches; sum->n_lock_ops += data->n_lock_ops; } @@ -91,9 +96,14 @@ malloc_mutex_prof_read(tsdn_t *tsdn, mutex_prof_data_t *data, /* Can only read holding the mutex. */ malloc_mutex_assert_owner(tsdn, mutex); + /* + * Not *really* allowed (we shouldn't be doing non-atomic loads of + * atomic data), but the mutex protection makes this safe, and writing + * a member-for-member copy is tedious for this situation. + */ *data = *source; /* n_wait_thds is not reported (modified w/o locking). */ - data->n_waiting_thds = 0; + atomic_store_u32(&data->n_waiting_thds, 0, ATOMIC_RELAXED); } #endif diff --git a/include/jemalloc/internal/mutex_structs.h b/include/jemalloc/internal/mutex_structs.h index 5dddb846..ff090b22 100644 --- a/include/jemalloc/internal/mutex_structs.h +++ b/include/jemalloc/internal/mutex_structs.h @@ -17,7 +17,7 @@ struct mutex_prof_data_s { /* Max # of threads waiting for the mutex at the same time. */ uint32_t max_n_thds; /* Current # of threads waiting on the lock. Atomic synced. */ - uint32_t n_waiting_thds; + atomic_u32_t n_waiting_thds; /* * Data touched on the fast path. These are modified right after we diff --git a/include/jemalloc/internal/mutex_types.h b/include/jemalloc/internal/mutex_types.h index bd261490..e6589374 100644 --- a/include/jemalloc/internal/mutex_types.h +++ b/include/jemalloc/internal/mutex_types.h @@ -35,7 +35,8 @@ typedef struct malloc_mutex_s malloc_mutex_t; #endif #define LOCK_PROF_DATA_INITIALIZER \ - {NSTIME_ZERO_INITIALIZER, NSTIME_ZERO_INITIALIZER, 0, 0, 0, 0, 0, NULL, 0} + {NSTIME_ZERO_INITIALIZER, NSTIME_ZERO_INITIALIZER, 0, 0, 0, \ + ATOMIC_INIT(0), 0, NULL, 0} #ifdef _WIN32 # define MALLOC_MUTEX_INITIALIZER diff --git a/src/mutex.c b/src/mutex.c index fa2770a3..8c593101 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -93,10 +93,11 @@ label_spin_done: /* Copy before to after to avoid clock skews. */ nstime_t after; nstime_copy(&after, &before); - uint32_t n_thds = atomic_add_u32(&data->n_waiting_thds, 1); + uint32_t n_thds = atomic_fetch_add_u32(&data->n_waiting_thds, 1, + ATOMIC_RELAXED) + 1; /* One last try as above two calls may take quite some cycles. */ if (!malloc_mutex_trylock(mutex)) { - atomic_sub_u32(&data->n_waiting_thds, 1); + atomic_fetch_sub_u32(&data->n_waiting_thds, 1, ATOMIC_RELAXED); data->n_spin_acquired++; return; } @@ -104,7 +105,7 @@ label_spin_done: /* True slow path. */ malloc_mutex_lock_final(mutex); /* Update more slow-path only counters. */ - atomic_sub_u32(&data->n_waiting_thds, 1); + atomic_fetch_sub_u32(&data->n_waiting_thds, 1, ATOMIC_RELAXED); nstime_update(&after); nstime_t delta; -- GitLab From 074f2256caecee17b168fe6d7d243a0c6e69a130 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 4 Apr 2017 18:36:45 -0700 Subject: [PATCH 385/544] Make prof's cum_gctx a C11-style atomic --- src/prof.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/prof.c b/src/prof.c index ce02d99c..a0290b8f 100644 --- a/src/prof.c +++ b/src/prof.c @@ -63,7 +63,7 @@ size_t lg_prof_sample; * creating/destroying mutexes. */ static malloc_mutex_t *gctx_locks; -static unsigned cum_gctxs; /* Atomic counter. */ +static atomic_u_t cum_gctxs; /* Atomic counter. */ /* * Table of mutexes that are shared among tdata's. No operations require @@ -524,7 +524,7 @@ prof_backtrace(prof_bt_t *bt) { static malloc_mutex_t * prof_gctx_mutex_choose(void) { - unsigned ngctxs = atomic_add_u(&cum_gctxs, 1); + unsigned ngctxs = atomic_fetch_add_u(&cum_gctxs, 1, ATOMIC_RELAXED); return &gctx_locks[(ngctxs - 1) % PROF_NCTX_LOCKS]; } -- GitLab From eeabdd246693fbf7c54e03ff8957889e63dc9a0c Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 4 Apr 2017 18:40:37 -0700 Subject: [PATCH 386/544] Remove the pre-C11-atomics API, which is now unused --- include/jemalloc/internal/atomic.h | 45 ------------------------------ test/unit/atomic.c | 45 ------------------------------ 2 files changed, 90 deletions(-) diff --git a/include/jemalloc/internal/atomic.h b/include/jemalloc/internal/atomic.h index b68440c4..adadb1a3 100644 --- a/include/jemalloc/internal/atomic.h +++ b/include/jemalloc/internal/atomic.h @@ -52,69 +52,24 @@ # define JEMALLOC_ATOMIC_U64 #endif -/* - * In order to let us transition atomics usage piecemeal (and reason locally - * about memory orders), we'll support the previous API for a while. - */ -#define JEMALLOC_GENERATE_COMPATABILITY_ATOMICS(type, short_type) \ -ATOMIC_INLINE type \ -atomic_read_##short_type(type *p) { \ - return atomic_load_##short_type ((atomic_##short_type##_t *)p, \ - ATOMIC_SEQ_CST); \ -} \ - \ -ATOMIC_INLINE void \ -atomic_write_##short_type(type *p, const type val) { \ - atomic_store_##short_type((atomic_##short_type##_t *)p, \ - (type)val, ATOMIC_SEQ_CST); \ -} \ -ATOMIC_INLINE bool \ -atomic_cas_##short_type(type *p, type c, type s) { \ - /* Note the '!' -- atomic_cas inverts the usual semantics. */ \ - return !atomic_compare_exchange_strong_##short_type( \ - (atomic_##short_type##_t *)p, &c, s, ATOMIC_SEQ_CST, \ - ATOMIC_SEQ_CST); \ -} - -#define JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(type, short_type) \ -JEMALLOC_GENERATE_COMPATABILITY_ATOMICS(type, short_type) \ - \ -ATOMIC_INLINE type \ -atomic_add_##short_type(type *p, type x) { \ - return atomic_fetch_add_##short_type( \ - (atomic_##short_type##_t *)p, x, ATOMIC_SEQ_CST) + x; \ -} \ -ATOMIC_INLINE type \ -atomic_sub_##short_type(type *p, type x) { \ - return atomic_fetch_sub_##short_type( \ - (atomic_##short_type##_t *)p, x, ATOMIC_SEQ_CST) - x; \ -} - JEMALLOC_GENERATE_ATOMICS(void *, p, LG_SIZEOF_PTR) -JEMALLOC_GENERATE_COMPATABILITY_ATOMICS(void *, p) /* * There's no actual guarantee that sizeof(bool) == 1, but it's true on the only * platform that actually needs to know the size, MSVC. */ JEMALLOC_GENERATE_ATOMICS(bool, b, 0) -JEMALLOC_GENERATE_COMPATABILITY_ATOMICS(bool, b) JEMALLOC_GENERATE_INT_ATOMICS(unsigned, u, LG_SIZEOF_INT) -JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(unsigned, u) JEMALLOC_GENERATE_INT_ATOMICS(size_t, zu, LG_SIZEOF_PTR) -JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(size_t, zu) JEMALLOC_GENERATE_INT_ATOMICS(ssize_t, zd, LG_SIZEOF_PTR) -JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(ssize_t, zd) JEMALLOC_GENERATE_INT_ATOMICS(uint32_t, u32, 2) -JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(uint32_t, u32) #ifdef JEMALLOC_ATOMIC_U64 JEMALLOC_GENERATE_INT_ATOMICS(uint64_t, u64, 3) -JEMALLOC_GENERATE_COMPATABILITY_INT_ATOMICS(uint64_t, u64) #endif #undef ATOMIC_INLINE diff --git a/test/unit/atomic.c b/test/unit/atomic.c index fa24415a..572d8d23 100644 --- a/test/unit/atomic.c +++ b/test/unit/atomic.c @@ -17,7 +17,6 @@ #define DO_TESTS(t, ta, val1, val2, val3) do { \ t val; \ - t raw_atomic; \ t expected; \ bool success; \ /* This (along with the load below) also tests ATOMIC_LOAD. */ \ @@ -81,37 +80,11 @@ } \ \ \ - /* Previous atomics API. */ \ - \ - /* Read. */ \ - raw_atomic = val1; \ - val = atomic_read_##ta(&raw_atomic); \ - assert_##ta##_eq(val1, val, "Read failed"); \ - \ - /* Write. */ \ - raw_atomic = val1; \ - atomic_write_##ta(&raw_atomic, val2); \ - assert_##ta##_eq(val2, raw_atomic, "Write failed"); \ - \ - /* CAS. */ \ - raw_atomic = val1; \ - success = !atomic_cas_##ta(&raw_atomic, val2, val3); \ - assert_b_eq(val1 == val2, success, \ - "CAS did the wrong state update"); \ - val = raw_atomic; \ - if (success) { \ - assert_##ta##_eq(val3, val, \ - "Successful CAS should update atomic"); \ - } else { \ - assert_##ta##_eq(val1, val, \ - "Unsuccessful CAS should not update atomic"); \ - } \ } while (0) #define DO_INTEGER_TESTS(t, ta, val1, val2) do { \ atomic_##ta##_t atom; \ t val; \ - t raw_atomic; \ \ /* Fetch-add. */ \ atomic_store_##ta(&atom, val1, ATOMIC_RELAXED); \ @@ -157,24 +130,6 @@ val = atomic_load_##ta(&atom, ATOMIC_RELAXED); \ assert_##ta##_eq(val1 ^ val2, val, \ "Fetch-xor should update atomic"); \ - \ - /* Previous atomics API. */ \ - \ - /* Add. */ \ - raw_atomic = val1; \ - val = atomic_add_##ta(&raw_atomic, val2); \ - assert_##ta##_eq(val1 + val2, val, \ - "atomic_add should return new value"); \ - assert_##ta##_eq(val1 + val2, raw_atomic, \ - "atomic_add should update atomic"); \ - \ - /* Sub. */ \ - raw_atomic = val1; \ - val = atomic_sub_##ta(&raw_atomic, val2); \ - assert_##ta##_eq(val1 - val2, val, \ - "atomic_sub should return new value"); \ - assert_##ta##_eq(val1 - val2, raw_atomic, \ - "atomic_add should update atomic"); \ } while (0) #define TEST_STRUCT(t, ta) \ -- GitLab From fde3e20cc04db459f3c76134bc6dfb0ee5c422bb Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 27 Mar 2017 21:50:38 -0700 Subject: [PATCH 387/544] Integrate auto tcache into TSD. The embedded tcache is initialized upon tsd initialization. The avail arrays for the tbins will be allocated / deallocated accordingly during init / cleanup. With this change, the pointer to the auto tcache will always be available, as long as we have access to the TSD. tcache_available() (called in tcache_get()) is provided to check if we should use tcache. --- include/jemalloc/internal/arena_inlines_a.h | 10 +- .../jemalloc/internal/jemalloc_internal.h.in | 96 ++++++-- include/jemalloc/internal/private_symbols.txt | 8 +- include/jemalloc/internal/rtree_inlines.h | 7 +- include/jemalloc/internal/tcache_externs.h | 7 +- include/jemalloc/internal/tcache_inlines.h | 65 ++---- include/jemalloc/internal/tcache_structs.h | 6 +- include/jemalloc/internal/tcache_types.h | 3 + include/jemalloc/internal/tsd_externs.h | 5 +- include/jemalloc/internal/tsd_structs.h | 7 +- include/jemalloc/internal/tsd_types.h | 12 +- src/ctl.c | 6 +- src/jemalloc.c | 16 +- src/tcache.c | 207 +++++++++++++----- src/tsd.c | 5 - test/unit/tsd.c | 6 + 16 files changed, 294 insertions(+), 172 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_a.h b/include/jemalloc/internal/arena_inlines_a.h index e1c47652..cf92342b 100644 --- a/include/jemalloc/internal/arena_inlines_a.h +++ b/include/jemalloc/internal/arena_inlines_a.h @@ -57,12 +57,10 @@ percpu_arena_update(tsd_t *tsd, unsigned cpu) { /* Set new arena/tcache associations. */ arena_migrate(tsd, oldind, newind); - if (config_tcache) { - tcache_t *tcache = tsd_tcache_get(tsd); - if (tcache) { - tcache_arena_reassociate(tsd_tsdn(tsd), tcache, - newarena); - } + tcache_t *tcache = tcache_get(tsd); + if (config_tcache && tcache) { + tcache_arena_reassociate(tsd_tsdn(tsd), tcache, + newarena); } } } diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 04f91c07..449a4ab8 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -488,23 +488,24 @@ extern size_t const index2size_tab[NSIZES]; */ extern uint8_t const size2index_tab[]; -void *a0malloc(size_t size); -void a0dalloc(void *ptr); -void *bootstrap_malloc(size_t size); -void *bootstrap_calloc(size_t num, size_t size); -void bootstrap_free(void *ptr); -void arena_set(unsigned ind, arena_t *arena); -unsigned narenas_total_get(void); -arena_t *arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); -arena_tdata_t *arena_tdata_get_hard(tsd_t *tsd, unsigned ind); -arena_t *arena_choose_hard(tsd_t *tsd, bool internal); -void arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind); -void iarena_cleanup(tsd_t *tsd); -void arena_cleanup(tsd_t *tsd); -void arenas_tdata_cleanup(tsd_t *tsd); -void jemalloc_prefork(void); -void jemalloc_postfork_parent(void); -void jemalloc_postfork_child(void); +void *a0malloc(size_t size); +void a0dalloc(void *ptr); +void *bootstrap_malloc(size_t size); +void *bootstrap_calloc(size_t num, size_t size); +void bootstrap_free(void *ptr); +void arena_set(unsigned ind, arena_t *arena); +unsigned narenas_total_get(void); +arena_t *arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); +arena_tdata_t *arena_tdata_get_hard(tsd_t *tsd, unsigned ind); +arena_t *arena_choose_hard(tsd_t *tsd, bool internal); +void arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind); +void iarena_cleanup(tsd_t *tsd); +void arena_cleanup(tsd_t *tsd); +void arenas_tdata_cleanup(tsd_t *tsd); +void jemalloc_prefork(void); +void jemalloc_postfork_parent(void); +void jemalloc_postfork_child(void); +bool malloc_initialized(void); #include "jemalloc/internal/nstime_externs.h" #include "jemalloc/internal/ckh_externs.h" @@ -559,6 +560,8 @@ arena_tdata_t *arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing); arena_t *arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing); ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind); +bool tcache_available(tsd_t *tsd); +tcache_t *tcache_get(tsd_t *tsd); malloc_cpuid_t malloc_getcpu(void); unsigned percpu_arena_choose(void); unsigned percpu_arena_ind_limit(void); @@ -929,6 +932,38 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) { } return &tdata->decay_ticker; } + +JEMALLOC_ALWAYS_INLINE bool +tcache_available(tsd_t *tsd) { + cassert(config_tcache); + + /* + * Thread specific auto tcache might be unavailable if: 1) during tcache + * initialization, or 2) disabled through thread.tcache.enabled mallctl + * or config options. This check covers all cases. + */ + if (likely(tsd_tcache_enabled_get(tsd) == tcache_enabled_true)) { + /* Associated arena == null implies tcache init in progress. */ + if (tsd_tcachep_get(tsd)->arena != NULL) { + assert(tsd_tcachep_get(tsd)->tbins[0].avail != NULL); + } + return true; + } + + return false; +} + +JEMALLOC_ALWAYS_INLINE tcache_t * +tcache_get(tsd_t *tsd) { + if (!config_tcache) { + return NULL; + } + if (!tcache_available(tsd)) { + return NULL; + } + + return tsd_tcachep_get(tsd); +} #endif #include "jemalloc/internal/rtree_inlines.h" @@ -959,9 +994,24 @@ arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { ret = internal ? tsd_iarena_get(tsd) : tsd_arena_get(tsd); if (unlikely(ret == NULL)) { ret = arena_choose_hard(tsd, internal); + assert(ret); + if (config_tcache && tcache_available(tsd)) { + tcache_t *tcache = tcache_get(tsd); + if (tcache->arena != NULL) { + /* See comments in tcache_data_init().*/ + assert(tcache->arena == + arena_get(tsd_tsdn(tsd), 0, false)); + if (tcache->arena != ret) { + tcache_arena_reassociate(tsd_tsdn(tsd), + tcache, ret); + } + } else { + tcache_arena_associate(tsd_tsdn(tsd), tcache, + ret); + } + } } - assert(ret != NULL); /* * Note that for percpu arena, if the current arena is outside of the * auto percpu arena range, (i.e. thread is assigned to a manually @@ -1069,8 +1119,8 @@ iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, JEMALLOC_ALWAYS_INLINE void * ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, bool slow_path) { - return iallocztm(tsd_tsdn(tsd), size, ind, zero, tcache_get(tsd, true), - false, NULL, slow_path); + return iallocztm(tsd_tsdn(tsd), size, ind, zero, tcache_get(tsd), false, + NULL, slow_path); } JEMALLOC_ALWAYS_INLINE void * @@ -1102,7 +1152,7 @@ ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, JEMALLOC_ALWAYS_INLINE void * ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero) { return ipallocztm(tsd_tsdn(tsd), usize, alignment, zero, - tcache_get(tsd, true), false, NULL); + tcache_get(tsd), false, NULL); } JEMALLOC_ALWAYS_INLINE size_t @@ -1127,7 +1177,7 @@ idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool is_internal, JEMALLOC_ALWAYS_INLINE void idalloc(tsd_t *tsd, void *ptr) { - idalloctm(tsd_tsdn(tsd), ptr, tcache_get(tsd, false), false, true); + idalloctm(tsd_tsdn(tsd), ptr, tcache_get(tsd), false, true); } JEMALLOC_ALWAYS_INLINE void @@ -1199,7 +1249,7 @@ JEMALLOC_ALWAYS_INLINE void * iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero) { return iralloct(tsd_tsdn(tsd), ptr, oldsize, size, alignment, zero, - tcache_get(tsd, true), NULL); + tcache_get(tsd), NULL); } JEMALLOC_ALWAYS_INLINE bool diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 1cced603..e2bb0592 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -274,6 +274,7 @@ lg_floor lg_prof_sample malloc_cprintf malloc_getcpu +malloc_initialized malloc_mutex_prof_data_reset malloc_mutex_assert_not_owner malloc_mutex_assert_owner @@ -293,7 +294,6 @@ malloc_tsd_boot1 malloc_tsd_cleanup_register malloc_tsd_dalloc malloc_tsd_malloc -malloc_tsd_no_cleanup malloc_vcprintf malloc_vsnprintf malloc_write @@ -475,22 +475,23 @@ tcache_alloc_easy tcache_alloc_large tcache_alloc_small tcache_alloc_small_hard +tcache_arena_associate tcache_arena_reassociate tcache_bin_flush_large tcache_bin_flush_small tcache_bin_info tcache_boot tcache_cleanup -tcache_create +tcache_create_explicit tcache_dalloc_large tcache_dalloc_small +tcache_data_init tcache_enabled_get tcache_enabled_set tcache_event tcache_event_hard tcache_flush tcache_get -tcache_get_hard tcache_maxclass tcache_prefork tcache_postfork_child @@ -521,7 +522,6 @@ tsd_booted tsd_booted_get tsd_cleanup tsd_cleanup_wrapper -tsd_data_init tsd_fetch tsd_fetch_impl tsd_get diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index bebe49e0..ce03c578 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -321,13 +321,18 @@ rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, assert(!dependent || !init_missing); uintptr_t leafkey = rtree_leafkey(key); + assert(leafkey != RTREE_LEAFKEY_INVALID); + #define RTREE_CACHE_CHECK(i) do { \ if (likely(rtree_ctx->cache[i].leafkey == leafkey)) { \ rtree_leaf_elm_t *leaf = rtree_ctx->cache[i].leaf; \ assert(leaf != NULL); \ if (i > 0) { \ /* Bubble up by one. */ \ - rtree_ctx->cache[i] = rtree_ctx->cache[i - 1]; \ + rtree_ctx->cache[i].leafkey = \ + rtree_ctx->cache[i - 1].leafkey; \ + rtree_ctx->cache[i].leaf = \ + rtree_ctx->cache[i - 1].leaf; \ rtree_ctx->cache[i - 1].leafkey = leafkey; \ rtree_ctx->cache[i - 1].leaf = leaf; \ } \ diff --git a/include/jemalloc/internal/tcache_externs.h b/include/jemalloc/internal/tcache_externs.h index 83643033..75ff3214 100644 --- a/include/jemalloc/internal/tcache_externs.h +++ b/include/jemalloc/internal/tcache_externs.h @@ -35,16 +35,19 @@ void tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, unsigned rem, tcache_t *tcache); void tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); -tcache_t *tcache_get_hard(tsd_t *tsd); -tcache_t *tcache_create(tsdn_t *tsdn, arena_t *arena); +tcache_t *tcache_create_explicit(tsd_t *tsd); void tcache_cleanup(tsd_t *tsd); void tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); bool tcaches_create(tsd_t *tsd, unsigned *r_ind); void tcaches_flush(tsd_t *tsd, unsigned ind); void tcaches_destroy(tsd_t *tsd, unsigned ind); bool tcache_boot(tsdn_t *tsdn); +void tcache_arena_associate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); void tcache_prefork(tsdn_t *tsdn); void tcache_postfork_parent(tsdn_t *tsdn); void tcache_postfork_child(tsdn_t *tsdn); +void tcache_flush(void); +bool tsd_tcache_data_init(tsd_t *tsd); +bool tsd_tcache_enabled_data_init(tsd_t *tsd); #endif /* JEMALLOC_INTERNAL_TCACHE_EXTERNS_H */ diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index fd7e1764..c3660963 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -4,9 +4,9 @@ #ifndef JEMALLOC_ENABLE_INLINE void tcache_event(tsd_t *tsd, tcache_t *tcache); void tcache_flush(void); -bool tcache_enabled_get(void); -tcache_t *tcache_get(tsd_t *tsd, bool create); -void tcache_enabled_set(bool enabled); +bool tcache_enabled_get(tsd_t *tsd); +tcache_t *tcache_get(tsd_t *tsd); +void tcache_enabled_set(tsd_t *tsd, bool enabled); void *tcache_alloc_easy(tcache_bin_t *tbin, bool *tcache_success); void *tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, szind_t ind, bool zero, bool slow_path); @@ -20,68 +20,32 @@ tcache_t *tcaches_get(tsd_t *tsd, unsigned ind); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TCACHE_C_)) -JEMALLOC_INLINE void -tcache_flush(void) { - tsd_t *tsd; - - cassert(config_tcache); - - tsd = tsd_fetch(); - tcache_cleanup(tsd); -} - JEMALLOC_INLINE bool -tcache_enabled_get(void) { - tsd_t *tsd; +tcache_enabled_get(tsd_t *tsd) { tcache_enabled_t tcache_enabled; cassert(config_tcache); - tsd = tsd_fetch(); tcache_enabled = tsd_tcache_enabled_get(tsd); - if (tcache_enabled == tcache_enabled_default) { - tcache_enabled = (tcache_enabled_t)opt_tcache; - tsd_tcache_enabled_set(tsd, tcache_enabled); - } + assert(tcache_enabled != tcache_enabled_default); return (bool)tcache_enabled; } JEMALLOC_INLINE void -tcache_enabled_set(bool enabled) { - tsd_t *tsd; - tcache_enabled_t tcache_enabled; - +tcache_enabled_set(tsd_t *tsd, bool enabled) { cassert(config_tcache); - tsd = tsd_fetch(); - - tcache_enabled = (tcache_enabled_t)enabled; - tsd_tcache_enabled_set(tsd, tcache_enabled); + tcache_enabled_t old = tsd_tcache_enabled_get(tsd); - if (!enabled) { + if ((old != tcache_enabled_true) && enabled) { + tsd_tcache_data_init(tsd); + } else if ((old == tcache_enabled_true) && !enabled) { tcache_cleanup(tsd); } -} - -JEMALLOC_ALWAYS_INLINE tcache_t * -tcache_get(tsd_t *tsd, bool create) { - tcache_t *tcache; - - if (!config_tcache) { - return NULL; - } - - tcache = tsd_tcache_get(tsd); - if (!create) { - return tcache; - } - if (unlikely(tcache == NULL) && tsd_nominal(tsd)) { - tcache = tcache_get_hard(tsd); - tsd_tcache_set(tsd, tcache); - } - - return tcache; + /* Commit the state last. Above calls check current state. */ + tcache_enabled_t tcache_enabled = (tcache_enabled_t)enabled; + tsd_tcache_enabled_set(tsd, tcache_enabled); } JEMALLOC_ALWAYS_INLINE void @@ -300,8 +264,7 @@ JEMALLOC_ALWAYS_INLINE tcache_t * tcaches_get(tsd_t *tsd, unsigned ind) { tcaches_t *elm = &tcaches[ind]; if (unlikely(elm->tcache == NULL)) { - elm->tcache = tcache_create(tsd_tsdn(tsd), arena_choose(tsd, - NULL)); + elm->tcache = tcache_create_explicit(tsd); } return elm->tcache; } diff --git a/include/jemalloc/internal/tcache_structs.h b/include/jemalloc/internal/tcache_structs.h index a9b70312..c9c05cd2 100644 --- a/include/jemalloc/internal/tcache_structs.h +++ b/include/jemalloc/internal/tcache_structs.h @@ -36,13 +36,17 @@ struct tcache_s { ticker_t gc_ticker; /* Drives incremental GC. */ szind_t next_gc_bin; /* Next bin to GC. */ arena_t *arena; /* Associated arena. */ - tcache_bin_t tbins[1]; /* Dynamically sized. */ /* * The pointer stacks associated with tbins follow as a contiguous * array. During tcache initialization, the avail pointer in each * element of tbins is initialized to point to the proper offset within * this array. */ +#ifdef JEMALLOC_TCACHE + tcache_bin_t tbins[NSIZES]; +#else + tcache_bin_t tbins[0]; +#endif }; /* Linkage for list of available (previously used) explicit tcache IDs. */ diff --git a/include/jemalloc/internal/tcache_types.h b/include/jemalloc/internal/tcache_types.h index 2d396bf6..8624ac2f 100644 --- a/include/jemalloc/internal/tcache_types.h +++ b/include/jemalloc/internal/tcache_types.h @@ -47,4 +47,7 @@ typedef struct tcaches_s tcaches_t; #define TCACHE_GC_INCR \ ((TCACHE_GC_SWEEP / NBINS) + ((TCACHE_GC_SWEEP / NBINS == 0) ? 0 : 1)) +/* Used in TSD static initializer only. Real init in tcache_data_init(). */ +#define TCACHE_ZERO_INITIALIZER {{NULL}} + #endif /* JEMALLOC_INTERNAL_TCACHE_TYPES_H */ diff --git a/include/jemalloc/internal/tsd_externs.h b/include/jemalloc/internal/tsd_externs.h index 9b88a567..d15fd591 100644 --- a/include/jemalloc/internal/tsd_externs.h +++ b/include/jemalloc/internal/tsd_externs.h @@ -3,7 +3,6 @@ void *malloc_tsd_malloc(size_t size); void malloc_tsd_dalloc(void *wrapper); -void malloc_tsd_no_cleanup(void *arg); void malloc_tsd_cleanup_register(bool (*f)(void)); tsd_t *malloc_tsd_boot0(void); void malloc_tsd_boot1(void); @@ -13,7 +12,7 @@ void *tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block); void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block); #endif -void tsd_cleanup(void *arg); -bool tsd_data_init(void *arg); +bool tsd_data_init(void *arg); +void tsd_cleanup(void *arg); #endif /* JEMALLOC_INTERNAL_TSD_EXTERNS_H */ diff --git a/include/jemalloc/internal/tsd_structs.h b/include/jemalloc/internal/tsd_structs.h index b4ac09fd..d399563c 100644 --- a/include/jemalloc/internal/tsd_structs.h +++ b/include/jemalloc/internal/tsd_structs.h @@ -16,7 +16,7 @@ struct tsd_init_head_s { #define MALLOC_TSD \ /* O(name, type, [gs]et, init, cleanup) */ \ - O(tcache, tcache_t *, yes, no, yes) \ + O(tcache, tcache_t, yes, no, yes) \ O(thread_allocated, uint64_t, yes, no, no) \ O(thread_deallocated, uint64_t, yes, no, no) \ O(prof_tdata, prof_tdata_t *, yes, no, yes) \ @@ -26,7 +26,7 @@ struct tsd_init_head_s { O(narenas_tdata, unsigned, yes, no, no) \ O(arenas_tdata_bypass, bool, no, no, no) \ O(tcache_enabled, tcache_enabled_t, \ - yes, no, no) \ + yes, yes, no) \ O(rtree_ctx, rtree_ctx_t, no, yes, no) \ O(witnesses, witness_list_t, no, no, yes) \ O(rtree_leaf_elm_witnesses, rtree_leaf_elm_witness_tsd_t, \ @@ -35,7 +35,7 @@ struct tsd_init_head_s { #define TSD_INITIALIZER { \ tsd_state_uninitialized, \ - NULL, \ + TCACHE_ZERO_INITIALIZER, \ 0, \ 0, \ NULL, \ @@ -69,6 +69,7 @@ struct tsdn_s { }; static const tsd_t tsd_initializer = TSD_INITIALIZER; +UNUSED static const void *malloc_tsd_no_cleanup = (void *)0; malloc_tsd_types(, tsd_t) diff --git a/include/jemalloc/internal/tsd_types.h b/include/jemalloc/internal/tsd_types.h index 195b6493..29c6378a 100644 --- a/include/jemalloc/internal/tsd_types.h +++ b/include/jemalloc/internal/tsd_types.h @@ -357,8 +357,10 @@ a_name##tsd_boot1(void) { \ " TSD for "#a_name"\n"); \ abort(); \ } \ - memcpy(wrapper, &a_name##tsd_boot_wrapper, \ - sizeof(a_name##tsd_wrapper_t)); \ + a_name##tsd_boot_wrapper.initialized = false; \ + a_cleanup(&a_name##tsd_boot_wrapper.val); \ + wrapper->initialized = false; \ + wrapper->val = a_initializer; \ a_name##tsd_wrapper_set(wrapper); \ } \ a_attr bool \ @@ -487,8 +489,10 @@ a_name##tsd_boot1(void) { \ " TSD for "#a_name"\n"); \ abort(); \ } \ - memcpy(wrapper, &a_name##tsd_boot_wrapper, \ - sizeof(a_name##tsd_wrapper_t)); \ + a_name##tsd_boot_wrapper.initialized = false; \ + a_cleanup(&a_name##tsd_boot_wrapper.val); \ + wrapper->initialized = false; \ + wrapper->val = a_initializer; \ a_name##tsd_wrapper_set(wrapper); \ } \ a_attr bool \ diff --git a/src/ctl.c b/src/ctl.c index 36f5634d..a59a741f 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1532,7 +1532,7 @@ thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, /* Set new arena/tcache associations. */ arena_migrate(tsd, oldind, newind); if (config_tcache) { - tcache_t *tcache = tsd_tcache_get(tsd); + tcache_t *tcache = tsd_tcachep_get(tsd); if (tcache != NULL) { tcache_arena_reassociate(tsd_tsdn(tsd), tcache, newarena); @@ -1564,13 +1564,13 @@ thread_tcache_enabled_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, return ENOENT; } - oldval = tcache_enabled_get(); + oldval = tcache_enabled_get(tsd); if (newp != NULL) { if (newlen != sizeof(bool)) { ret = EINVAL; goto label_return; } - tcache_enabled_set(*(bool *)newp); + tcache_enabled_set(tsd, *(bool *)newp); } READ(oldval, bool); diff --git a/src/jemalloc.c b/src/jemalloc.c index 94ae030c..9d66f7f6 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -275,7 +275,7 @@ static bool malloc_init_hard(void); * Begin miscellaneous support functions. */ -JEMALLOC_ALWAYS_INLINE_C bool +bool malloc_initialized(void) { return (malloc_init_state == malloc_init_initialized); } @@ -1536,7 +1536,7 @@ imalloc_no_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd, /* Fill in the tcache. */ if (dopts->tcache_ind == TCACHE_IND_AUTOMATIC) { - tcache = tcache_get(tsd, true); + tcache = tcache_get(tsd); } else if (dopts->tcache_ind == TCACHE_IND_NONE) { tcache = NULL; } else { @@ -2056,7 +2056,7 @@ je_realloc(void *ptr, size_t size) { /* realloc(ptr, 0) is equivalent to free(ptr). */ UTRACE(ptr, 0, 0); tsd = tsd_fetch(); - ifree(tsd, ptr, tcache_get(tsd, false), true); + ifree(tsd, ptr, tcache_get(tsd), true); return NULL; } size = 1; @@ -2113,9 +2113,9 @@ je_free(void *ptr) { tsd_t *tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); if (likely(!malloc_slow)) { - ifree(tsd, ptr, tcache_get(tsd, false), false); + ifree(tsd, ptr, tcache_get(tsd), false); } else { - ifree(tsd, ptr, tcache_get(tsd, false), true); + ifree(tsd, ptr, tcache_get(tsd), true); } witness_assert_lockless(tsd_tsdn(tsd)); } @@ -2393,7 +2393,7 @@ je_rallocx(void *ptr, size_t size, int flags) { tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags)); } } else { - tcache = tcache_get(tsd, true); + tcache = tcache_get(tsd); } old_usize = isalloc(tsd_tsdn(tsd), ptr); @@ -2605,7 +2605,7 @@ je_dallocx(void *ptr, int flags) { tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags)); } } else { - tcache = tcache_get(tsd, false); + tcache = tcache_get(tsd); } UTRACE(ptr, 0, 0); @@ -2652,7 +2652,7 @@ je_sdallocx(void *ptr, size_t size, int flags) { tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags)); } } else { - tcache = tcache_get(tsd, false); + tcache = tcache_get(tsd); } UTRACE(ptr, 0, 0); diff --git a/src/tcache.c b/src/tcache.c index 6057c890..aa2917b2 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -4,7 +4,13 @@ /******************************************************************************/ /* Data. */ -bool opt_tcache = true; +bool opt_tcache = +#ifdef JEMALLOC_TCACHE + true +#else + false +#endif + ; ssize_t opt_lg_tcache_max = LG_TCACHE_MAXCLASS_DEFAULT; tcache_bin_info_t *tcache_bin_info; @@ -78,6 +84,7 @@ tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, tcache_bin_t *tbin, szind_t binind, bool *tcache_success) { void *ret; + assert(tcache->arena); arena_tcache_fill_small(tsdn, arena, tbin, binind, config_prof ? tcache->prof_accumbytes : 0); if (config_prof) { @@ -271,9 +278,11 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, } } -static void +void tcache_arena_associate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { + assert(tcache->arena == NULL); tcache->arena = arena; + if (config_stats) { /* Link into list of extant tcaches. */ malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx); @@ -286,6 +295,7 @@ tcache_arena_associate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { static void tcache_arena_dissociate(tsdn_t *tsdn, tcache_t *tcache) { arena_t *arena = tcache->arena; + assert(arena); if (config_stats) { /* Unlink from list of extant tcaches. */ malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx); @@ -304,6 +314,7 @@ tcache_arena_dissociate(tsdn_t *tsdn, tcache_t *tcache) { tcache_stats_merge(tsdn, tcache, arena); malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx); } + tcache->arena = NULL; } void @@ -312,30 +323,101 @@ tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { tcache_arena_associate(tsdn, tcache, arena); } -tcache_t * -tcache_get_hard(tsd_t *tsd) { - arena_t *arena; +bool +tsd_tcache_enabled_data_init(tsd_t *tsd) { + /* Called upon tsd initialization. */ + tsd_tcache_enabled_set(tsd, (tcache_enabled_t)opt_tcache); + if (opt_tcache) { + /* Trigger tcache init. */ + tsd_tcache_data_init(tsd); + } - if (!tcache_enabled_get()) { - if (tsd_nominal(tsd)) { - tcache_enabled_set(false); /* Memoize. */ - } - return NULL; + return false; +} + +/* Initialize auto tcache (embedded in TSD). */ +static void +tcache_init(tsd_t *tsd, tcache_t *tcache, void *avail_stack) { + memset(&tcache->link, 0, sizeof(ql_elm(tcache_t))); + tcache->prof_accumbytes = 0; + tcache->next_gc_bin = 0; + tcache->arena = NULL; + + ticker_init(&tcache->gc_ticker, TCACHE_GC_INCR); + + size_t stack_offset = 0; + assert((TCACHE_NSLOTS_SMALL_MAX & 1U) == 0); + memset(tcache->tbins, 0, sizeof(tcache_bin_t) * nhbins); + for (unsigned i = 0; i < nhbins; i++) { + tcache->tbins[i].lg_fill_div = 1; + stack_offset += tcache_bin_info[i].ncached_max * sizeof(void *); + /* + * avail points past the available space. Allocations will + * access the slots toward higher addresses (for the benefit of + * prefetch). + */ + tcache->tbins[i].avail = (void **)((uintptr_t)avail_stack + + (uintptr_t)stack_offset); } - arena = arena_choose(tsd, NULL); - if (unlikely(arena == NULL)) { - return NULL; + assert(stack_offset == stack_nelms * sizeof(void *)); +} + +/* Initialize auto tcache (embedded in TSD). */ +bool +tsd_tcache_data_init(tsd_t *tsd) { + if (!config_tcache) { + return false; + } + + tcache_t *tcache = &tsd->tcache; + assert(tcache->tbins[0].avail == NULL); + size_t size = stack_nelms * sizeof(void *); + /* Avoid false cacheline sharing. */ + size = sa2u(size, CACHELINE); + + /* Manually initialize rcache as we may need it for allocation. */ + tsd_rtree_ctx_data_init(tsd); + + void *avail_array = ipallocztm(tsd_tsdn(tsd), size, CACHELINE, true, + NULL, true, arena_get(TSDN_NULL, 0, true)); + if (avail_array == NULL) { + return true; } - return tcache_create(tsd_tsdn(tsd), arena); + + tcache_init(tsd, tcache, avail_array); + /* + * Initialization is a bit tricky here. After malloc init is done, all + * threads can rely on arena_choose and associate tcache accordingly. + * However, the thread that does actual malloc bootstrapping relies on + * functional tsd, and it can only rely on a0. In that case, we + * associate its tcache to a0 temporarily, and later on + * arena_choose_hard() will re-associate properly. + */ + tcache->arena = NULL; + arena_t *arena; + if (!malloc_initialized()) { + /* If in initialization, assign to a0. */ + arena = arena_get(tsd_tsdn(tsd), 0, false); + tcache_arena_associate(tsd_tsdn(tsd), tcache, arena); + } else { + arena = arena_choose(tsd, NULL); + /* This may happen if thread.tcache.enabled is used. */ + if (tcache->arena == NULL) { + tcache_arena_associate(tsd_tsdn(tsd), tcache, arena); + } + } + assert(arena == tcache->arena); + + return false; } +/* Created manual tcache for tcache.create mallctl. */ tcache_t * -tcache_create(tsdn_t *tsdn, arena_t *arena) { +tcache_create_explicit(tsd_t *tsd) { tcache_t *tcache; size_t size, stack_offset; - unsigned i; - size = offsetof(tcache_t, tbins) + (sizeof(tcache_bin_t) * nhbins); + size = sizeof(tcache_t); /* Naturally align the pointer stacks. */ size = PTR_CEILING(size); stack_offset = size; @@ -343,34 +425,21 @@ tcache_create(tsdn_t *tsdn, arena_t *arena) { /* Avoid false cacheline sharing. */ size = sa2u(size, CACHELINE); - tcache = ipallocztm(tsdn, size, CACHELINE, true, NULL, true, + tcache = ipallocztm(tsd_tsdn(tsd), size, CACHELINE, true, NULL, true, arena_get(TSDN_NULL, 0, true)); if (tcache == NULL) { return NULL; } - tcache_arena_associate(tsdn, tcache, arena); - - ticker_init(&tcache->gc_ticker, TCACHE_GC_INCR); - - assert((TCACHE_NSLOTS_SMALL_MAX & 1U) == 0); - for (i = 0; i < nhbins; i++) { - tcache->tbins[i].lg_fill_div = 1; - stack_offset += tcache_bin_info[i].ncached_max * sizeof(void *); - /* - * avail points past the available space. Allocations will - * access the slots toward higher addresses (for the benefit of - * prefetch). - */ - tcache->tbins[i].avail = (void **)((uintptr_t)tcache + - (uintptr_t)stack_offset); - } + tcache_init(tsd, tcache, + (void *)((uintptr_t)tcache + (uintptr_t)stack_offset)); + tcache_arena_associate(tsd_tsdn(tsd), tcache, arena_ichoose(tsd, NULL)); return tcache; } static void -tcache_destroy(tsd_t *tsd, tcache_t *tcache) { +tcache_flush_cache(tsd_t *tsd, tcache_t *tcache) { unsigned i; for (i = 0; i < NBINS; i++) { @@ -381,7 +450,6 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache) { assert(tbin->tstats.nrequests == 0); } } - for (; i < nhbins; i++) { tcache_bin_t *tbin = &tcache->tbins[i]; tcache_bin_flush_large(tsd, tbin, i, 0, tcache); @@ -391,32 +459,60 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache) { } } - /* - * Get arena after flushing -- when using percpu arena, the associated - * arena could change during flush. - */ - arena_t *arena = arena_choose(tsd, NULL); - tcache_arena_dissociate(tsd_tsdn(tsd), tcache); - - if (config_prof && tcache->prof_accumbytes > 0 && + arena_t *arena = tcache->arena; + if (config_prof && arena && tcache->prof_accumbytes > 0 && arena_prof_accum(tsd_tsdn(tsd), arena, tcache->prof_accumbytes)) { prof_idump(tsd_tsdn(tsd)); } +} + +void +tcache_flush(void) { + tsd_t *tsd; - idalloctm(tsd_tsdn(tsd), tcache, NULL, true, true); + cassert(config_tcache); + + tsd = tsd_fetch(); + tcache_flush_cache(tsd, tsd_tcachep_get(tsd)); +} + +static void +tcache_destroy(tsd_t *tsd, tcache_t *tcache, bool tsd_tcache) { + tcache_flush_cache(tsd, tcache); + tcache_arena_dissociate(tsd_tsdn(tsd), tcache); + + if (tsd_tcache) { + /* Release the avail array for the TSD embedded auto tcache. */ + void *avail_array = (void *)((uintptr_t)tcache->tbins[0].avail - + (uintptr_t)tcache_bin_info[0].ncached_max * sizeof(void *)); + idalloctm(tsd_tsdn(tsd), avail_array, NULL, true, true); + } else { + /* Release both the tcache struct and avail array. */ + idalloctm(tsd_tsdn(tsd), tcache, NULL, true, true); + } } +/* For auto tcache (embedded in TSD) only. */ void tcache_cleanup(tsd_t *tsd) { - tcache_t *tcache; - if (!config_tcache) { return; } - if ((tcache = tsd_tcache_get(tsd)) != NULL) { - tcache_destroy(tsd, tcache); - tsd_tcache_set(tsd, NULL); + tcache_t *tcache = tsd_tcachep_get(tsd); + if (!tcache_available(tsd)) { + assert(tsd_tcache_enabled_get(tsd) == tcache_enabled_false); + if (config_debug) { + assert(tcache->tbins[0].avail == NULL); + } + return; + } + assert(tsd_tcache_enabled_get(tsd) == tcache_enabled_true); + assert(tcache->tbins[0].avail != NULL); + + tcache_destroy(tsd, tcache, true); + if (config_debug) { + tcache->tbins[0].avail = NULL; } } @@ -481,12 +577,7 @@ tcaches_create(tsd_t *tsd, unsigned *r_ind) { goto label_return; } - arena_t *arena = arena_ichoose(tsd, NULL); - if (unlikely(arena == NULL)) { - err = true; - goto label_return; - } - tcache_t *tcache = tcache_create(tsd_tsdn(tsd), arena); + tcache_t *tcache = tcache_create_explicit(tsd); if (tcache == NULL) { err = true; goto label_return; @@ -531,7 +622,7 @@ tcaches_flush(tsd_t *tsd, unsigned ind) { tcache_t *tcache = tcaches_elm_remove(tsd, &tcaches[ind]); malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx); if (tcache != NULL) { - tcache_destroy(tsd, tcache); + tcache_destroy(tsd, tcache, false); } } @@ -544,7 +635,7 @@ tcaches_destroy(tsd_t *tsd, unsigned ind) { tcaches_avail = elm; malloc_mutex_unlock(tsd_tsdn(tsd), &tcaches_mtx); if (tcache != NULL) { - tcache_destroy(tsd, tcache); + tcache_destroy(tsd, tcache, false); } } diff --git a/src/tsd.c b/src/tsd.c index 86502116..8b54770e 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -21,11 +21,6 @@ malloc_tsd_dalloc(void *wrapper) { a0dalloc(wrapper); } -void -malloc_tsd_no_cleanup(void *arg) { - not_reached(); -} - #if defined(JEMALLOC_MALLOC_THREAD_CLEANUP) || defined(_WIN32) #ifndef _WIN32 JEMALLOC_EXPORT diff --git a/test/unit/tsd.c b/test/unit/tsd.c index e033bb76..5bfcdf49 100644 --- a/test/unit/tsd.c +++ b/test/unit/tsd.c @@ -5,6 +5,7 @@ typedef unsigned int data_t; static bool data_cleanup_executed; +static bool data_test_started; malloc_tsd_types(data_, data_t) malloc_tsd_protos(, data_, data_t) @@ -13,6 +14,9 @@ void data_cleanup(void *arg) { data_t *data = (data_t *)arg; + if (!data_test_started) { + return; + } if (!data_cleanup_executed) { assert_x_eq(*data, THREAD_DATA, "Argument passed into cleanup function should match tsd " @@ -135,7 +139,9 @@ main(void) { malloc_printf("Initialization error"); return test_status_fail; } + data_test_started = false; data_tsd_boot(); + data_test_started = true; return test( test_tsd_main_thread, -- GitLab From 0fba57e579e688d0ccda5a615c91ab66cd4ba54a Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 5 Apr 2017 19:23:41 -0700 Subject: [PATCH 388/544] Get rid of tcache_enabled_t as we have runtime init support. --- include/jemalloc/internal/jemalloc_internal.h.in | 2 +- include/jemalloc/internal/tcache_inlines.h | 16 +++++----------- include/jemalloc/internal/tcache_structs.h | 6 ------ include/jemalloc/internal/tcache_types.h | 3 +++ include/jemalloc/internal/tsd_structs.h | 5 ++--- src/tcache.c | 6 +++--- 6 files changed, 14 insertions(+), 24 deletions(-) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 449a4ab8..3b137fcb 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -942,7 +942,7 @@ tcache_available(tsd_t *tsd) { * initialization, or 2) disabled through thread.tcache.enabled mallctl * or config options. This check covers all cases. */ - if (likely(tsd_tcache_enabled_get(tsd) == tcache_enabled_true)) { + if (likely(tsd_tcache_enabled_get(tsd) == true)) { /* Associated arena == null implies tcache init in progress. */ if (tsd_tcachep_get(tsd)->arena != NULL) { assert(tsd_tcachep_get(tsd)->tbins[0].avail != NULL); diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index c3660963..929d8a7e 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -22,30 +22,24 @@ tcache_t *tcaches_get(tsd_t *tsd, unsigned ind); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TCACHE_C_)) JEMALLOC_INLINE bool tcache_enabled_get(tsd_t *tsd) { - tcache_enabled_t tcache_enabled; - cassert(config_tcache); - tcache_enabled = tsd_tcache_enabled_get(tsd); - assert(tcache_enabled != tcache_enabled_default); - - return (bool)tcache_enabled; + return tsd_tcache_enabled_get(tsd); } JEMALLOC_INLINE void tcache_enabled_set(tsd_t *tsd, bool enabled) { cassert(config_tcache); - tcache_enabled_t old = tsd_tcache_enabled_get(tsd); + bool was_enabled = tsd_tcache_enabled_get(tsd); - if ((old != tcache_enabled_true) && enabled) { + if (!was_enabled && enabled) { tsd_tcache_data_init(tsd); - } else if ((old == tcache_enabled_true) && !enabled) { + } else if (was_enabled && !enabled) { tcache_cleanup(tsd); } /* Commit the state last. Above calls check current state. */ - tcache_enabled_t tcache_enabled = (tcache_enabled_t)enabled; - tsd_tcache_enabled_set(tsd, tcache_enabled); + tsd_tcache_enabled_set(tsd, enabled); } JEMALLOC_ALWAYS_INLINE void diff --git a/include/jemalloc/internal/tcache_structs.h b/include/jemalloc/internal/tcache_structs.h index c9c05cd2..d7ec4b69 100644 --- a/include/jemalloc/internal/tcache_structs.h +++ b/include/jemalloc/internal/tcache_structs.h @@ -1,12 +1,6 @@ #ifndef JEMALLOC_INTERNAL_TCACHE_STRUCTS_H #define JEMALLOC_INTERNAL_TCACHE_STRUCTS_H -typedef enum { - tcache_enabled_false = 0, /* Enable cast to/from bool. */ - tcache_enabled_true = 1, - tcache_enabled_default = 2 -} tcache_enabled_t; - /* * Read-only information associated with each element of tcache_t's tbins array * is stored separately, mainly to reduce memory usage. diff --git a/include/jemalloc/internal/tcache_types.h b/include/jemalloc/internal/tcache_types.h index 8624ac2f..70f89608 100644 --- a/include/jemalloc/internal/tcache_types.h +++ b/include/jemalloc/internal/tcache_types.h @@ -50,4 +50,7 @@ typedef struct tcaches_s tcaches_t; /* Used in TSD static initializer only. Real init in tcache_data_init(). */ #define TCACHE_ZERO_INITIALIZER {{NULL}} +/* Used in TSD static initializer only. Will be initialized to opt_tcache. */ +#define TCACHE_ENABLED_DEFAULT false + #endif /* JEMALLOC_INTERNAL_TCACHE_TYPES_H */ diff --git a/include/jemalloc/internal/tsd_structs.h b/include/jemalloc/internal/tsd_structs.h index d399563c..f327c769 100644 --- a/include/jemalloc/internal/tsd_structs.h +++ b/include/jemalloc/internal/tsd_structs.h @@ -25,8 +25,7 @@ struct tsd_init_head_s { O(arenas_tdata, arena_tdata_t *,yes, no, yes) \ O(narenas_tdata, unsigned, yes, no, no) \ O(arenas_tdata_bypass, bool, no, no, no) \ - O(tcache_enabled, tcache_enabled_t, \ - yes, yes, no) \ + O(tcache_enabled, bool, yes, yes, no) \ O(rtree_ctx, rtree_ctx_t, no, yes, no) \ O(witnesses, witness_list_t, no, no, yes) \ O(rtree_leaf_elm_witnesses, rtree_leaf_elm_witness_tsd_t, \ @@ -44,7 +43,7 @@ struct tsd_init_head_s { NULL, \ 0, \ false, \ - tcache_enabled_default, \ + TCACHE_ENABLED_DEFAULT, \ RTREE_CTX_ZERO_INITIALIZER, \ ql_head_initializer(witnesses), \ RTREE_ELM_WITNESS_TSD_INITIALIZER, \ diff --git a/src/tcache.c b/src/tcache.c index aa2917b2..b8ce4a07 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -326,7 +326,7 @@ tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { bool tsd_tcache_enabled_data_init(tsd_t *tsd) { /* Called upon tsd initialization. */ - tsd_tcache_enabled_set(tsd, (tcache_enabled_t)opt_tcache); + tsd_tcache_enabled_set(tsd, opt_tcache); if (opt_tcache) { /* Trigger tcache init. */ tsd_tcache_data_init(tsd); @@ -501,13 +501,13 @@ tcache_cleanup(tsd_t *tsd) { tcache_t *tcache = tsd_tcachep_get(tsd); if (!tcache_available(tsd)) { - assert(tsd_tcache_enabled_get(tsd) == tcache_enabled_false); + assert(tsd_tcache_enabled_get(tsd) == false); if (config_debug) { assert(tcache->tbins[0].avail == NULL); } return; } - assert(tsd_tcache_enabled_get(tsd) == tcache_enabled_true); + assert(tsd_tcache_enabled_get(tsd)); assert(tcache->tbins[0].avail != NULL); tcache_destroy(tsd, tcache, true); -- GitLab From 4dec507546040896338d8bbdb2075c7ad3a4b9f3 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 5 Apr 2017 22:04:12 -0700 Subject: [PATCH 389/544] Bypass witness_fork in TSD when !config_debug. With the tcache change, we plan to leave some blank space when !config_debug (unused tbins, witnesses) at the end of the tsd. Let's not touch the memory. --- src/witness.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/witness.c b/src/witness.c index 034ea92b..cbffaeaa 100644 --- a/src/witness.c +++ b/src/witness.c @@ -96,16 +96,25 @@ witnesses_cleanup(tsd_t *tsd) { void witness_prefork(tsd_t *tsd) { + if (!config_debug) { + return; + } tsd_witness_fork_set(tsd, true); } void witness_postfork_parent(tsd_t *tsd) { + if (!config_debug) { + return; + } tsd_witness_fork_set(tsd, false); } void witness_postfork_child(tsd_t *tsd) { + if (!config_debug) { + return; + } #ifndef JEMALLOC_MUTEX_INIT_CB witness_list_t *witnesses; -- GitLab From 36bd90b96212772f1adbd421a6b091b542278995 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Thu, 6 Apr 2017 12:35:22 -0700 Subject: [PATCH 390/544] Optimizing TSD and thread cache layout. 1) Re-organize TSD so that frequently accessed fields are closer to the beginning and more compact. Assuming 64-bit, the first 2.5 cachelines now contains everything needed on tcache fast path, expect the tcache struct itself. 2) Re-organize tcache and tbins. Take lg_fill_div out of tbin, and reduce tbin to 24 bytes (down from 32). Split tbins into tbins_small and tbins_large, and place tbins_small close to the beginning. --- include/jemalloc/internal/arena_externs.h | 2 +- .../jemalloc/internal/jemalloc_internal.h.in | 69 ++++++++++------- include/jemalloc/internal/rtree_structs.h | 3 - include/jemalloc/internal/tcache_inlines.h | 12 +-- include/jemalloc/internal/tcache_structs.h | 30 ++++++-- include/jemalloc/internal/tcache_types.h | 7 +- include/jemalloc/internal/tsd_structs.h | 55 +++++++++++--- include/jemalloc/internal/tsd_types.h | 14 ++-- src/arena.c | 16 ++-- src/tcache.c | 76 +++++++++++-------- 10 files changed, 185 insertions(+), 99 deletions(-) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index a35fe184..0f86dc05 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -51,7 +51,7 @@ bool arena_muzzy_decay_time_set(tsdn_t *tsdn, arena_t *arena, void arena_decay(tsdn_t *tsdn, arena_t *arena, bool all); void arena_reset(tsd_t *tsd, arena_t *arena); void arena_destroy(tsd_t *tsd, arena_t *arena); -void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, +void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, tcache_bin_t *tbin, szind_t binind, uint64_t prof_accumbytes); void arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, bool zero); diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 3b137fcb..c00912bf 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -538,33 +538,35 @@ bool malloc_initialized(void); #include "jemalloc/internal/mutex_inlines.h" #ifndef JEMALLOC_ENABLE_INLINE -pszind_t psz2ind(size_t psz); -size_t pind2sz_compute(pszind_t pind); -size_t pind2sz_lookup(pszind_t pind); -size_t pind2sz(pszind_t pind); -size_t psz2u(size_t psz); -szind_t size2index_compute(size_t size); -szind_t size2index_lookup(size_t size); -szind_t size2index(size_t size); -size_t index2size_compute(szind_t index); -size_t index2size_lookup(szind_t index); -size_t index2size(szind_t index); -size_t s2u_compute(size_t size); -size_t s2u_lookup(size_t size); -size_t s2u(size_t size); -size_t sa2u(size_t size, size_t alignment); -arena_t *arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal); -arena_t *arena_choose(tsd_t *tsd, arena_t *arena); -arena_t *arena_ichoose(tsd_t *tsd, arena_t *arena); -arena_tdata_t *arena_tdata_get(tsd_t *tsd, unsigned ind, +pszind_t psz2ind(size_t psz); +size_t pind2sz_compute(pszind_t pind); +size_t pind2sz_lookup(pszind_t pind); +size_t pind2sz(pszind_t pind); +size_t psz2u(size_t psz); +szind_t size2index_compute(size_t size); +szind_t size2index_lookup(size_t size); +szind_t size2index(size_t size); +size_t index2size_compute(szind_t index); +size_t index2size_lookup(szind_t index); +size_t index2size(szind_t index); +size_t s2u_compute(size_t size); +size_t s2u_lookup(size_t size); +size_t s2u(size_t size); +size_t sa2u(size_t size, size_t alignment); +arena_t *arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal); +arena_t *arena_choose(tsd_t *tsd, arena_t *arena); +arena_t *arena_ichoose(tsd_t *tsd, arena_t *arena); +arena_tdata_t *arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing); -arena_t *arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing); -ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind); -bool tcache_available(tsd_t *tsd); -tcache_t *tcache_get(tsd_t *tsd); -malloc_cpuid_t malloc_getcpu(void); -unsigned percpu_arena_choose(void); -unsigned percpu_arena_ind_limit(void); +arena_t *arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing); +ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind); +bool tcache_available(tsd_t *tsd); +tcache_bin_t *tcache_small_bin_get(tcache_t *tcache, szind_t binind); +tcache_bin_t *tcache_large_bin_get(tcache_t *tcache, szind_t binind); +tcache_t *tcache_get(tsd_t *tsd); +malloc_cpuid_t malloc_getcpu(void); +unsigned percpu_arena_choose(void); +unsigned percpu_arena_ind_limit(void); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) @@ -933,6 +935,18 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) { return &tdata->decay_ticker; } +JEMALLOC_ALWAYS_INLINE tcache_bin_t * +tcache_small_bin_get(tcache_t *tcache, szind_t binind) { + assert(binind < NBINS); + return &tcache->tbins_small[binind]; +} + +JEMALLOC_ALWAYS_INLINE tcache_bin_t * +tcache_large_bin_get(tcache_t *tcache, szind_t binind) { + assert(binind >= NBINS &&binind < nhbins); + return &tcache->tbins_large[binind - NBINS]; +} + JEMALLOC_ALWAYS_INLINE bool tcache_available(tsd_t *tsd) { cassert(config_tcache); @@ -945,7 +959,8 @@ tcache_available(tsd_t *tsd) { if (likely(tsd_tcache_enabled_get(tsd) == true)) { /* Associated arena == null implies tcache init in progress. */ if (tsd_tcachep_get(tsd)->arena != NULL) { - assert(tsd_tcachep_get(tsd)->tbins[0].avail != NULL); + assert(tcache_small_bin_get(tsd_tcachep_get(tsd), + 0)->avail != NULL); } return true; } diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h index 8dd9cdaa..123248ae 100644 --- a/include/jemalloc/internal/rtree_structs.h +++ b/include/jemalloc/internal/rtree_structs.h @@ -53,9 +53,6 @@ struct rtree_ctx_cache_elm_s { }; struct rtree_ctx_s { -#ifndef _MSC_VER - JEMALLOC_ALIGNED(CACHELINE) -#endif rtree_ctx_cache_elm_t cache[RTREE_CTX_NCACHE]; }; diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index 929d8a7e..dae43f99 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -73,7 +73,7 @@ tcache_alloc_easy(tcache_bin_t *tbin, bool *tcache_success) { ret = *(tbin->avail - tbin->ncached); tbin->ncached--; - if (unlikely((int)tbin->ncached < tbin->low_water)) { + if (unlikely((low_water_t)tbin->ncached < tbin->low_water)) { tbin->low_water = tbin->ncached; } @@ -89,7 +89,7 @@ tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, size_t usize JEMALLOC_CC_SILENCE_INIT(0); assert(binind < NBINS); - tbin = &tcache->tbins[binind]; + tbin = tcache_small_bin_get(tcache, binind); ret = tcache_alloc_easy(tbin, &tcache_success); assert(tcache_success == (ret != NULL)); if (unlikely(!tcache_success)) { @@ -150,8 +150,8 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, tcache_bin_t *tbin; bool tcache_success; - assert(binind < nhbins); - tbin = &tcache->tbins[binind]; + assert(binind >= NBINS &&binind < nhbins); + tbin = tcache_large_bin_get(tcache, binind); ret = tcache_alloc_easy(tbin, &tcache_success); assert(tcache_success == (ret != NULL)); if (unlikely(!tcache_success)) { @@ -215,7 +215,7 @@ tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, arena_dalloc_junk_small(ptr, &arena_bin_info[binind]); } - tbin = &tcache->tbins[binind]; + tbin = tcache_small_bin_get(tcache, binind); tbin_info = &tcache_bin_info[binind]; if (unlikely(tbin->ncached == tbin_info->ncached_max)) { tcache_bin_flush_small(tsd, tcache, tbin, binind, @@ -241,7 +241,7 @@ tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, large_dalloc_junk(ptr, index2size(binind)); } - tbin = &tcache->tbins[binind]; + tbin = tcache_large_bin_get(tcache, binind); tbin_info = &tcache_bin_info[binind]; if (unlikely(tbin->ncached == tbin_info->ncached_max)) { tcache_bin_flush_large(tsd, tbin, binind, diff --git a/include/jemalloc/internal/tcache_structs.h b/include/jemalloc/internal/tcache_structs.h index d7ec4b69..4e101609 100644 --- a/include/jemalloc/internal/tcache_structs.h +++ b/include/jemalloc/internal/tcache_structs.h @@ -10,10 +10,14 @@ struct tcache_bin_info_s { }; struct tcache_bin_s { + low_water_t low_water; /* Min # cached since last GC. */ + uint32_t ncached; /* # of cached objects. */ + /* + * ncached and stats are both modified frequently. Let's keep them + * close so that they have a higher chance of being on the same + * cacheline, thus less write-backs. + */ tcache_bin_stats_t tstats; - int low_water; /* Min # cached since last GC. */ - unsigned lg_fill_div; /* Fill (ncached_max >> lg_fill_div). */ - unsigned ncached; /* # of cached objects. */ /* * To make use of adjacent cacheline prefetch, the items in the avail * stack goes to higher address for newer allocations. avail points @@ -25,11 +29,9 @@ struct tcache_bin_s { }; struct tcache_s { - ql_elm(tcache_t) link; /* Used for aggregating stats. */ + /* Data accessed frequently first: prof, ticker and small bins. */ uint64_t prof_accumbytes;/* Cleared after arena_prof_accum(). */ ticker_t gc_ticker; /* Drives incremental GC. */ - szind_t next_gc_bin; /* Next bin to GC. */ - arena_t *arena; /* Associated arena. */ /* * The pointer stacks associated with tbins follow as a contiguous * array. During tcache initialization, the avail pointer in each @@ -37,9 +39,21 @@ struct tcache_s { * this array. */ #ifdef JEMALLOC_TCACHE - tcache_bin_t tbins[NSIZES]; + tcache_bin_t tbins_small[NBINS]; +#else + tcache_bin_t tbins_small[0]; +#endif + /* Data accessed less often below. */ + ql_elm(tcache_t) link; /* Used for aggregating stats. */ + arena_t *arena; /* Associated arena. */ + szind_t next_gc_bin; /* Next bin to GC. */ +#ifdef JEMALLOC_TCACHE + /* For small bins, fill (ncached_max >> lg_fill_div). */ + uint8_t lg_fill_div[NBINS]; + tcache_bin_t tbins_large[NSIZES-NBINS]; #else - tcache_bin_t tbins[0]; + uint8_t lg_fill_div[0]; + tcache_bin_t tbins_large[0]; #endif }; diff --git a/include/jemalloc/internal/tcache_types.h b/include/jemalloc/internal/tcache_types.h index 70f89608..a60db6ff 100644 --- a/include/jemalloc/internal/tcache_types.h +++ b/include/jemalloc/internal/tcache_types.h @@ -6,6 +6,9 @@ typedef struct tcache_bin_s tcache_bin_t; typedef struct tcache_s tcache_t; typedef struct tcaches_s tcaches_t; +/* ncached is cast to this type for comparison. */ +typedef int32_t low_water_t; + /* * tcache pointers close to NULL are used to encode state information that is * used for two purposes: preventing thread caching on a per thread basis and @@ -48,9 +51,9 @@ typedef struct tcaches_s tcaches_t; ((TCACHE_GC_SWEEP / NBINS) + ((TCACHE_GC_SWEEP / NBINS == 0) ? 0 : 1)) /* Used in TSD static initializer only. Real init in tcache_data_init(). */ -#define TCACHE_ZERO_INITIALIZER {{NULL}} +#define TCACHE_ZERO_INITIALIZER {0} /* Used in TSD static initializer only. Will be initialized to opt_tcache. */ -#define TCACHE_ENABLED_DEFAULT false +#define TCACHE_ENABLED_ZERO_INITIALIZER false #endif /* JEMALLOC_INTERNAL_TCACHE_TYPES_H */ diff --git a/include/jemalloc/internal/tsd_structs.h b/include/jemalloc/internal/tsd_structs.h index f327c769..2dca0bdb 100644 --- a/include/jemalloc/internal/tsd_structs.h +++ b/include/jemalloc/internal/tsd_structs.h @@ -14,19 +14,54 @@ struct tsd_init_head_s { }; #endif +/* + * Thread-Specific-Data layout + * --- data accessed on tcache fast path: state, rtree_ctx, stats, prof --- + * s: state + * e: tcache_enabled + * m: thread_allocated (config_stats) + * f: thread_deallocated (config_stats) + * p: prof_tdata (config_prof) + * c: rtree_ctx (rtree cache accessed on deallocation) + * t: tcache + * --- data not accessed on tcache fast path: arena related fields --- + * d: arenas_tdata_bypass + * r: narenas_tdata + * x: blank space (1 byte) + * i: iarena + * a: arena + * o: arenas_tdata + * Loading TSD data is on the critical path of basically all malloc operations. + * In particular, tcache and rtree_ctx rely on hot CPU cache to be effective. + * Use a compact layout to reduce cache footprint. + * +--- 64-bit and 64B cacheline; 1B each letter; First byte on the left. ---+ + * |---------------------------- 1st cacheline ----------------------------| + * | sedxrrrr mmmmmmmm ffffffff pppppppp [c * 32 ........ ........ .......] | + * |---------------------------- 2nd cacheline ----------------------------| + * | [c * 64 ........ ........ ........ ........ ........ ........ .......] | + * |---------------------------- 3nd cacheline ----------------------------| + * | [c * 32 ........ ........ .......] iiiiiiii aaaaaaaa oooooooo [t...... | + * +-------------------------------------------------------------------------+ + * Note: the entire tcache is embedded into TSD and spans multiple cachelines. + * + * The last 3 members (i, a and o) before tcache isn't really needed on tcache + * fast path. However we have a number of unused tcache bins and witnesses + * (never touched unless config_debug) at the end of tcache, so we place them + * there to avoid breaking the cachelines and possibly paging in an extra page. + */ #define MALLOC_TSD \ /* O(name, type, [gs]et, init, cleanup) */ \ - O(tcache, tcache_t, yes, no, yes) \ + O(tcache_enabled, bool, yes, yes, no) \ + O(arenas_tdata_bypass, bool, no, no, no) \ + O(narenas_tdata, uint32_t, yes, no, no) \ O(thread_allocated, uint64_t, yes, no, no) \ O(thread_deallocated, uint64_t, yes, no, no) \ O(prof_tdata, prof_tdata_t *, yes, no, yes) \ + O(rtree_ctx, rtree_ctx_t, no, yes, no) \ O(iarena, arena_t *, yes, no, yes) \ O(arena, arena_t *, yes, no, yes) \ O(arenas_tdata, arena_tdata_t *,yes, no, yes) \ - O(narenas_tdata, unsigned, yes, no, no) \ - O(arenas_tdata_bypass, bool, no, no, no) \ - O(tcache_enabled, bool, yes, yes, no) \ - O(rtree_ctx, rtree_ctx_t, no, yes, no) \ + O(tcache, tcache_t, yes, no, yes) \ O(witnesses, witness_list_t, no, no, yes) \ O(rtree_leaf_elm_witnesses, rtree_leaf_elm_witness_tsd_t, \ no, no, no) \ @@ -34,17 +69,17 @@ struct tsd_init_head_s { #define TSD_INITIALIZER { \ tsd_state_uninitialized, \ - TCACHE_ZERO_INITIALIZER, \ + TCACHE_ENABLED_ZERO_INITIALIZER, \ + false, \ + 0, \ 0, \ 0, \ NULL, \ + RTREE_CTX_ZERO_INITIALIZER, \ NULL, \ NULL, \ NULL, \ - 0, \ - false, \ - TCACHE_ENABLED_DEFAULT, \ - RTREE_CTX_ZERO_INITIALIZER, \ + TCACHE_ZERO_INITIALIZER, \ ql_head_initializer(witnesses), \ RTREE_ELM_WITNESS_TSD_INITIALIZER, \ false \ diff --git a/include/jemalloc/internal/tsd_types.h b/include/jemalloc/internal/tsd_types.h index 29c6378a..4d5fef57 100644 --- a/include/jemalloc/internal/tsd_types.h +++ b/include/jemalloc/internal/tsd_types.h @@ -17,12 +17,14 @@ typedef struct tsdn_s tsdn_t; #define TSDN_NULL ((tsdn_t *)0) -typedef enum { - tsd_state_uninitialized, - tsd_state_nominal, - tsd_state_purgatory, - tsd_state_reincarnated -} tsd_state_t; +enum { + tsd_state_uninitialized = 0, + tsd_state_nominal = 1, + tsd_state_purgatory = 2, + tsd_state_reincarnated = 3 +}; +/* Manually limit tsd_state_t to a single byte. */ +typedef uint8_t tsd_state_t; /* * TLS/TSD-agnostic macro-based implementation of thread-specific data. There diff --git a/src/arena.c b/src/arena.c index feb1f760..b78719e4 100644 --- a/src/arena.c +++ b/src/arena.c @@ -287,8 +287,14 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, atomic_store_zu(&astats->tcache_bytes, 0, ATOMIC_RELAXED); malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx); ql_foreach(tcache, &arena->tcache_ql, link) { - for (szind_t i = 0; i < nhbins; i++) { - tbin = &tcache->tbins[i]; + szind_t i = 0; + for (; i < NBINS; i++) { + tbin = tcache_small_bin_get(tcache, i); + arena_stats_accum_zu(&astats->tcache_bytes, + tbin->ncached * index2size(i)); + } + for (; i < nhbins; i++) { + tbin = tcache_large_bin_get(tcache, i); arena_stats_accum_zu(&astats->tcache_bytes, tbin->ncached * index2size(i)); } @@ -1317,8 +1323,8 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, } void -arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_bin_t *tbin, - szind_t binind, uint64_t prof_accumbytes) { +arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, + tcache_bin_t *tbin, szind_t binind, uint64_t prof_accumbytes) { unsigned i, nfill; arena_bin_t *bin; @@ -1330,7 +1336,7 @@ arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_bin_t *tbin, bin = &arena->bins[binind]; malloc_mutex_lock(tsdn, &bin->lock); for (i = 0, nfill = (tcache_bin_info[binind].ncached_max >> - tbin->lg_fill_div); i < nfill; i++) { + tcache->lg_fill_div[binind]); i < nfill; i++) { extent_t *slab; void *ptr; if ((slab = bin->slabcur) != NULL && extent_nfree_get(slab) > diff --git a/src/tcache.c b/src/tcache.c index b8ce4a07..34b46afd 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -40,9 +40,13 @@ tcache_salloc(tsdn_t *tsdn, const void *ptr) { void tcache_event_hard(tsd_t *tsd, tcache_t *tcache) { szind_t binind = tcache->next_gc_bin; - tcache_bin_t *tbin = &tcache->tbins[binind]; - tcache_bin_info_t *tbin_info = &tcache_bin_info[binind]; + tcache_bin_t *tbin; + if (binind < NBINS) { + tbin = tcache_small_bin_get(tcache, binind); + } else { + tbin = tcache_large_bin_get(tcache, binind); + } if (tbin->low_water > 0) { /* * Flush (ceiling) 3/4 of the objects below the low water mark. @@ -51,24 +55,26 @@ tcache_event_hard(tsd_t *tsd, tcache_t *tcache) { tcache_bin_flush_small(tsd, tcache, tbin, binind, tbin->ncached - tbin->low_water + (tbin->low_water >> 2)); + /* + * Reduce fill count by 2X. Limit lg_fill_div such that + * the fill count is always at least 1. + */ + tcache_bin_info_t *tbin_info = &tcache_bin_info[binind]; + if ((tbin_info->ncached_max >> + (tcache->lg_fill_div[binind] + 1)) >= 1) { + tcache->lg_fill_div[binind]++; + } } else { tcache_bin_flush_large(tsd, tbin, binind, tbin->ncached - tbin->low_water + (tbin->low_water >> 2), tcache); } - /* - * Reduce fill count by 2X. Limit lg_fill_div such that the - * fill count is always at least 1. - */ - if ((tbin_info->ncached_max >> (tbin->lg_fill_div+1)) >= 1) { - tbin->lg_fill_div++; - } } else if (tbin->low_water < 0) { /* - * Increase fill count by 2X. Make sure lg_fill_div stays - * greater than 0. + * Increase fill count by 2X for small bins. Make sure + * lg_fill_div stays greater than 0. */ - if (tbin->lg_fill_div > 1) { - tbin->lg_fill_div--; + if (binind < NBINS && tcache->lg_fill_div[binind] > 1) { + tcache->lg_fill_div[binind]--; } } tbin->low_water = tbin->ncached; @@ -85,8 +91,8 @@ tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, void *ret; assert(tcache->arena); - arena_tcache_fill_small(tsdn, arena, tbin, binind, config_prof ? - tcache->prof_accumbytes : 0); + arena_tcache_fill_small(tsdn, arena, tcache, tbin, binind, + config_prof ? tcache->prof_accumbytes : 0); if (config_prof) { tcache->prof_accumbytes = 0; } @@ -175,7 +181,7 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, memmove(tbin->avail - rem, tbin->avail - tbin->ncached, rem * sizeof(void *)); tbin->ncached = rem; - if ((int)tbin->ncached < tbin->low_water) { + if ((low_water_t)tbin->ncached < tbin->low_water) { tbin->low_water = tbin->ncached; } } @@ -273,7 +279,7 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, memmove(tbin->avail - rem, tbin->avail - tbin->ncached, rem * sizeof(void *)); tbin->ncached = rem; - if ((int)tbin->ncached < tbin->low_water) { + if ((low_water_t)tbin->ncached < tbin->low_water) { tbin->low_water = tbin->ncached; } } @@ -347,17 +353,24 @@ tcache_init(tsd_t *tsd, tcache_t *tcache, void *avail_stack) { size_t stack_offset = 0; assert((TCACHE_NSLOTS_SMALL_MAX & 1U) == 0); - memset(tcache->tbins, 0, sizeof(tcache_bin_t) * nhbins); - for (unsigned i = 0; i < nhbins; i++) { - tcache->tbins[i].lg_fill_div = 1; + memset(tcache->tbins_small, 0, sizeof(tcache_bin_t) * NBINS); + memset(tcache->tbins_large, 0, sizeof(tcache_bin_t) * (nhbins - NBINS)); + unsigned i = 0; + for (; i < NBINS; i++) { + tcache->lg_fill_div[i] = 1; stack_offset += tcache_bin_info[i].ncached_max * sizeof(void *); /* * avail points past the available space. Allocations will * access the slots toward higher addresses (for the benefit of * prefetch). */ - tcache->tbins[i].avail = (void **)((uintptr_t)avail_stack + - (uintptr_t)stack_offset); + tcache_small_bin_get(tcache, i)->avail = + (void **)((uintptr_t)avail_stack + (uintptr_t)stack_offset); + } + for (; i < nhbins; i++) { + stack_offset += tcache_bin_info[i].ncached_max * sizeof(void *); + tcache_large_bin_get(tcache, i)->avail = + (void **)((uintptr_t)avail_stack + (uintptr_t)stack_offset); } assert(stack_offset == stack_nelms * sizeof(void *)); } @@ -370,7 +383,7 @@ tsd_tcache_data_init(tsd_t *tsd) { } tcache_t *tcache = &tsd->tcache; - assert(tcache->tbins[0].avail == NULL); + assert(tcache_small_bin_get(tcache, 0)->avail == NULL); size_t size = stack_nelms * sizeof(void *); /* Avoid false cacheline sharing. */ size = sa2u(size, CACHELINE); @@ -443,7 +456,7 @@ tcache_flush_cache(tsd_t *tsd, tcache_t *tcache) { unsigned i; for (i = 0; i < NBINS; i++) { - tcache_bin_t *tbin = &tcache->tbins[i]; + tcache_bin_t *tbin = tcache_small_bin_get(tcache, i); tcache_bin_flush_small(tsd, tcache, tbin, i, 0); if (config_stats) { @@ -451,7 +464,7 @@ tcache_flush_cache(tsd_t *tsd, tcache_t *tcache) { } } for (; i < nhbins; i++) { - tcache_bin_t *tbin = &tcache->tbins[i]; + tcache_bin_t *tbin = tcache_large_bin_get(tcache, i); tcache_bin_flush_large(tsd, tbin, i, 0, tcache); if (config_stats) { @@ -483,7 +496,8 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache, bool tsd_tcache) { if (tsd_tcache) { /* Release the avail array for the TSD embedded auto tcache. */ - void *avail_array = (void *)((uintptr_t)tcache->tbins[0].avail - + void *avail_array = + (void *)((uintptr_t)tcache_small_bin_get(tcache, 0)->avail - (uintptr_t)tcache_bin_info[0].ncached_max * sizeof(void *)); idalloctm(tsd_tsdn(tsd), avail_array, NULL, true, true); } else { @@ -503,16 +517,16 @@ tcache_cleanup(tsd_t *tsd) { if (!tcache_available(tsd)) { assert(tsd_tcache_enabled_get(tsd) == false); if (config_debug) { - assert(tcache->tbins[0].avail == NULL); + assert(tcache_small_bin_get(tcache, 0)->avail == NULL); } return; } assert(tsd_tcache_enabled_get(tsd)); - assert(tcache->tbins[0].avail != NULL); + assert(tcache_small_bin_get(tcache, 0)->avail != NULL); tcache_destroy(tsd, tcache, true); if (config_debug) { - tcache->tbins[0].avail = NULL; + tcache_small_bin_get(tcache, 0)->avail = NULL; } } @@ -525,7 +539,7 @@ tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { /* Merge and reset tcache stats. */ for (i = 0; i < NBINS; i++) { arena_bin_t *bin = &arena->bins[i]; - tcache_bin_t *tbin = &tcache->tbins[i]; + tcache_bin_t *tbin = tcache_small_bin_get(tcache, i); malloc_mutex_lock(tsdn, &bin->lock); bin->stats.nrequests += tbin->tstats.nrequests; malloc_mutex_unlock(tsdn, &bin->lock); @@ -533,7 +547,7 @@ tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { } for (; i < nhbins; i++) { - tcache_bin_t *tbin = &tcache->tbins[i]; + tcache_bin_t *tbin = tcache_large_bin_get(tcache, i); arena_stats_large_nrequests_add(tsdn, &arena->stats, i, tbin->tstats.nrequests); tbin->tstats.nrequests = 0; -- GitLab From 0a0fcd3e6a0816f0a56fa852416d0ece861c0abb Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 28 Mar 2017 17:30:54 -0700 Subject: [PATCH 391/544] Add hooking functionality This allows us to hook chosen functions and do interesting things there (in particular: reentrancy checking). --- Makefile.in | 2 + include/jemalloc/internal/hooks.h | 19 +++++ .../jemalloc/internal/jemalloc_internal.h.in | 7 ++ include/jemalloc/internal/malloc_io.h | 2 +- include/jemalloc/internal/private_symbols.txt | 1 + include/jemalloc/internal/stats_externs.h | 2 +- src/hooks.c | 12 +++ src/prof.c | 7 ++ src/tsd.c | 9 +++ test/include/test/jemalloc_test.h.in | 2 + test/include/test/test.h | 6 ++ test/src/test.c | 76 ++++++++++++++++++- test/unit/hooks.c | 38 ++++++++++ test/unit/prof_accum.c | 2 +- test/unit/prof_active.c | 2 +- test/unit/prof_gdump.c | 2 +- test/unit/prof_reset.c | 2 +- test/unit/prof_tctx.c | 2 +- test/unit/tsd.c | 1 + 19 files changed, 183 insertions(+), 11 deletions(-) create mode 100644 include/jemalloc/internal/hooks.h create mode 100644 src/hooks.c create mode 100644 test/unit/hooks.c diff --git a/Makefile.in b/Makefile.in index 4fb852da..26c811c8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -98,6 +98,7 @@ C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/extent_dss.c \ $(srcroot)src/extent_mmap.c \ $(srcroot)src/hash.c \ + $(srcroot)src/hooks.c \ $(srcroot)src/large.c \ $(srcroot)src/malloc_io.c \ $(srcroot)src/mutex.c \ @@ -161,6 +162,7 @@ TESTS_UNIT := \ $(srcroot)test/unit/extent_quantize.c \ $(srcroot)test/unit/fork.c \ $(srcroot)test/unit/hash.c \ + $(srcroot)test/unit/hooks.c \ $(srcroot)test/unit/junk.c \ $(srcroot)test/unit/junk_alloc.c \ $(srcroot)test/unit/junk_free.c \ diff --git a/include/jemalloc/internal/hooks.h b/include/jemalloc/internal/hooks.h new file mode 100644 index 00000000..608b268f --- /dev/null +++ b/include/jemalloc/internal/hooks.h @@ -0,0 +1,19 @@ +#ifndef JEMALLOC_INTERNAL_HOOKS_H +#define JEMALLOC_INTERNAL_HOOKS_H + +extern void (*hooks_arena_new_hook)(); +extern void (*hooks_libc_hook)(); + +#define JEMALLOC_HOOK(fn, hook) ((void)(hook != NULL && (hook(), 0)), fn) + +#define open JEMALLOC_HOOK(open, hooks_libc_hook) +#define read JEMALLOC_HOOK(read, hooks_libc_hook) +#define write JEMALLOC_HOOK(write, hooks_libc_hook) +#define readlink JEMALLOC_HOOK(readlink, hooks_libc_hook) +#define close JEMALLOC_HOOK(close, hooks_libc_hook) +#define creat JEMALLOC_HOOK(creat, hooks_libc_hook) +#define secure_getenv JEMALLOC_HOOK(secure_getenv, hooks_libc_hook) +/* Note that this is undef'd and re-define'd in src/prof.c. */ +#define _Unwind_Backtrace JEMALLOC_HOOK(_Unwind_Backtrace, hooks_libc_hook) + +#endif /* JEMALLOC_INTERNAL_HOOKS_H */ diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index c00912bf..1c0bf43a 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -23,7 +23,14 @@ extern "C" { # define JEMALLOC_N(n) @private_namespace@##n # include "../jemalloc@install_suffix@.h" #endif + +/* + * Note that the ordering matters here; the hook itself is name-mangled. We + * want the inclusion of hooks to happen early, so that we hook as much as + * possible. + */ #include "jemalloc/internal/private_namespace.h" +#include "jemalloc/internal/hooks.h" static const bool config_debug = #ifdef JEMALLOC_DEBUG diff --git a/include/jemalloc/internal/malloc_io.h b/include/jemalloc/internal/malloc_io.h index 7ff3d5b1..8b2fb96f 100644 --- a/include/jemalloc/internal/malloc_io.h +++ b/include/jemalloc/internal/malloc_io.h @@ -56,7 +56,7 @@ size_t malloc_snprintf(char *str, size_t size, const char *format, ...) JEMALLOC_FORMAT_PRINTF(3, 4); void malloc_vcprintf(void (*write_cb)(void *, const char *), void *cbopaque, const char *format, va_list ap); -void malloc_cprintf(void (*write)(void *, const char *), void *cbopaque, +void malloc_cprintf(void (*write_cb)(void *, const char *), void *cbopaque, const char *format, ...) JEMALLOC_FORMAT_PRINTF(3, 4); void malloc_printf(const char *format, ...) JEMALLOC_FORMAT_PRINTF(1, 2); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index e2bb0592..deae8243 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -232,6 +232,7 @@ hash_rotl_64 hash_x64_128 hash_x86_128 hash_x86_32 +hooks_libc_hook iaalloc ialloc iallocztm diff --git a/include/jemalloc/internal/stats_externs.h b/include/jemalloc/internal/stats_externs.h index a0a1ab6c..519441c9 100644 --- a/include/jemalloc/internal/stats_externs.h +++ b/include/jemalloc/internal/stats_externs.h @@ -3,7 +3,7 @@ extern bool opt_stats_print; -void stats_print(void (*write)(void *, const char *), void *cbopaque, +void stats_print(void (*write_cb)(void *, const char *), void *cbopaque, const char *opts); #endif /* JEMALLOC_INTERNAL_STATS_EXTERNS_H */ diff --git a/src/hooks.c b/src/hooks.c new file mode 100644 index 00000000..c32471e9 --- /dev/null +++ b/src/hooks.c @@ -0,0 +1,12 @@ +#include "jemalloc/internal/jemalloc_internal.h" + +/* + * The hooks are a little bit screwy -- they're not genuinely exported in the + * sense that we want them available to end-users, but we do want them visible + * from outside the generated library, so that we can use them in test code. + */ +JEMALLOC_EXPORT +void (*hooks_arena_new_hook)() = NULL; + +JEMALLOC_EXPORT +void (*hooks_libc_hook)() = NULL; diff --git a/src/prof.c b/src/prof.c index a0290b8f..db1ef035 100644 --- a/src/prof.c +++ b/src/prof.c @@ -8,7 +8,14 @@ #endif #ifdef JEMALLOC_PROF_LIBGCC +/* + * We have a circular dependency -- jemalloc_internal.h tells us if we should + * use libgcc's unwinding functionality, but after we've included that, we've + * already hooked _Unwind_Backtrace. We'll temporarily disable hooking. + */ +#undef _Unwind_Backtrace #include +#define _Unwind_Backtrace JEMALLOC_HOOK(_Unwind_Backtrace, hooks_libc_hook) #endif /******************************************************************************/ diff --git a/src/tsd.c b/src/tsd.c index 8b54770e..0d5de8ea 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -149,6 +149,15 @@ _tls_callback(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { return true; } +/* + * We need to be able to say "read" here (in the "pragma section"), but have + * hooked "read". We won't read for the rest of the file, so we can get away + * with unhooking. + */ +#ifdef read +# undef read +#endif + #ifdef _MSC_VER # ifdef _M_IX86 # pragma comment(linker, "/INCLUDE:__tls_used") diff --git a/test/include/test/jemalloc_test.h.in b/test/include/test/jemalloc_test.h.in index 0770d020..e3882b29 100644 --- a/test/include/test/jemalloc_test.h.in +++ b/test/include/test/jemalloc_test.h.in @@ -45,6 +45,7 @@ extern "C" { # define JEMALLOC_MANGLE # include "jemalloc/internal/jemalloc_internal.h" + /******************************************************************************/ /* * For integration tests, expose the public jemalloc interfaces, but only @@ -68,6 +69,7 @@ static const bool config_debug = # define JEMALLOC_N(n) @private_namespace@##n # include "jemalloc/internal/private_namespace.h" +# include "jemalloc/internal/hooks.h" /* Hermetic headers. */ # include "jemalloc/internal/assert.h" diff --git a/test/include/test/test.h b/test/include/test/test.h index d7f05fad..fd0e5265 100644 --- a/test/include/test/test.h +++ b/test/include/test/test.h @@ -310,6 +310,9 @@ label_test_end: \ #define test(...) \ p_test(__VA_ARGS__, NULL) +#define test_no_reentrancy(...) \ + p_test_no_reentrancy(__VA_ARGS__, NULL) + #define test_no_malloc_init(...) \ p_test_no_malloc_init(__VA_ARGS__, NULL) @@ -321,11 +324,14 @@ label_test_end: \ } \ } while (0) +bool test_is_reentrant(); + void test_skip(const char *format, ...) JEMALLOC_FORMAT_PRINTF(1, 2); void test_fail(const char *format, ...) JEMALLOC_FORMAT_PRINTF(1, 2); /* For private use by macros. */ test_status_t p_test(test_t *t, ...); +test_status_t p_test_no_reentrancy(test_t *t, ...); test_status_t p_test_no_malloc_init(test_t *t, ...); void p_test_init(const char *name); void p_test_fini(void); diff --git a/test/src/test.c b/test/src/test.c index c5101d4e..fe6dc60e 100644 --- a/test/src/test.c +++ b/test/src/test.c @@ -1,10 +1,42 @@ #include "test/jemalloc_test.h" +/* Test status state. */ + static unsigned test_count = 0; static test_status_t test_counts[test_status_count] = {0, 0, 0}; static test_status_t test_status = test_status_pass; static const char * test_name = ""; +/* Reentrancy testing helpers. */ + +#define NUM_REENTRANT_ALLOCS 20 +static bool reentrant = false; +static bool hook_ran = false; +static void *to_free[NUM_REENTRANT_ALLOCS]; + +static void +reentrancy_hook() { + hook_ran = true; + hooks_libc_hook = NULL; + + void *to_free_local[NUM_REENTRANT_ALLOCS]; + size_t alloc_size = 1; + for (int i = 0; i < NUM_REENTRANT_ALLOCS; i++) { + to_free[i] = malloc(alloc_size); + to_free_local[i] = malloc(alloc_size); + alloc_size *= 2; + } + for (int i = 0; i < NUM_REENTRANT_ALLOCS; i++) { + free(to_free_local[i]); + } +} + +/* Actual test infrastructure. */ +bool +test_is_reentrant() { + return reentrant; +} + JEMALLOC_FORMAT_PRINTF(1, 2) void test_skip(const char *format, ...) { @@ -49,11 +81,13 @@ p_test_init(const char *name) { void p_test_fini(void) { test_counts[test_status]++; - malloc_printf("%s: %s\n", test_name, test_status_string(test_status)); + malloc_printf("%s: %s (%s)\n", test_name, + test_status_string(test_status), + reentrant ? "reentrant" : "non-reentrant"); } static test_status_t -p_test_impl(bool do_malloc_init, test_t *t, va_list ap) { +p_test_impl(bool do_malloc_init, bool do_reentrant, test_t *t, va_list ap) { test_status_t ret; if (do_malloc_init) { @@ -71,10 +105,27 @@ p_test_impl(bool do_malloc_init, test_t *t, va_list ap) { ret = test_status_pass; for (; t != NULL; t = va_arg(ap, test_t *)) { + /* Non-reentrant run. */ + reentrant = false; t(); if (test_status > ret) { ret = test_status; } + /* Reentrant run. */ + if (do_reentrant) { + reentrant = true; + hooks_libc_hook = &reentrancy_hook; + t(); + if (test_status > ret) { + ret = test_status; + } + if (hook_ran) { + hook_ran = false; + for (int i = 0; i < NUM_REENTRANT_ALLOCS; i++) { + free(to_free[i]); + } + } + } } malloc_printf("--- %s: %u/%u, %s: %u/%u, %s: %u/%u ---\n", @@ -95,7 +146,20 @@ p_test(test_t *t, ...) { ret = test_status_pass; va_start(ap, t); - ret = p_test_impl(true, t, ap); + ret = p_test_impl(true, true, t, ap); + va_end(ap); + + return ret; +} + +test_status_t +p_test_no_reentrancy(test_t *t, ...) { + test_status_t ret; + va_list ap; + + ret = test_status_pass; + va_start(ap, t); + ret = p_test_impl(true, false, t, ap); va_end(ap); return ret; @@ -108,7 +172,11 @@ p_test_no_malloc_init(test_t *t, ...) { ret = test_status_pass; va_start(ap, t); - ret = p_test_impl(false, t, ap); + /* + * We also omit reentrancy from bootstrapping tests, since we don't + * (yet) care about general reentrancy during bootstrapping. + */ + ret = p_test_impl(false, false, t, ap); va_end(ap); return ret; diff --git a/test/unit/hooks.c b/test/unit/hooks.c new file mode 100644 index 00000000..b70172e1 --- /dev/null +++ b/test/unit/hooks.c @@ -0,0 +1,38 @@ +#include "test/jemalloc_test.h" + +static bool hook_called = false; + +static void +hook() { + hook_called = true; +} + +static int +func_to_hook(int arg1, int arg2) { + return arg1 + arg2; +} + +#define func_to_hook JEMALLOC_HOOK(func_to_hook, hooks_libc_hook) + +TEST_BEGIN(unhooked_call) { + hooks_libc_hook = NULL; + hook_called = false; + assert_d_eq(3, func_to_hook(1, 2), "Hooking changed return value."); + assert_false(hook_called, "Nulling out hook didn't take."); +} +TEST_END + +TEST_BEGIN(hooked_call) { + hooks_libc_hook = &hook; + hook_called = false; + assert_d_eq(3, func_to_hook(1, 2), "Hooking changed return value."); + assert_true(hook_called, "Hook should have executed."); +} +TEST_END + +int +main(void) { + return test( + unhooked_call, + hooked_call); +} diff --git a/test/unit/prof_accum.c b/test/unit/prof_accum.c index 6ccab82b..25220063 100644 --- a/test/unit/prof_accum.c +++ b/test/unit/prof_accum.c @@ -76,6 +76,6 @@ TEST_END int main(void) { - return test( + return test_no_reentrancy( test_idump); } diff --git a/test/unit/prof_active.c b/test/unit/prof_active.c index 275aac89..850a24a7 100644 --- a/test/unit/prof_active.c +++ b/test/unit/prof_active.c @@ -112,6 +112,6 @@ TEST_END int main(void) { - return test( + return test_no_reentrancy( test_prof_active); } diff --git a/test/unit/prof_gdump.c b/test/unit/prof_gdump.c index 97ade68c..fcb434cb 100644 --- a/test/unit/prof_gdump.c +++ b/test/unit/prof_gdump.c @@ -69,6 +69,6 @@ TEST_END int main(void) { - return test( + return test_no_reentrancy( test_gdump); } diff --git a/test/unit/prof_reset.c b/test/unit/prof_reset.c index 6120714e..7cce42d2 100644 --- a/test/unit/prof_reset.c +++ b/test/unit/prof_reset.c @@ -278,7 +278,7 @@ main(void) { /* Intercept dumping prior to running any tests. */ prof_dump_open = prof_dump_open_intercept; - return test( + return test_no_reentrancy( test_prof_reset_basic, test_prof_reset_cleanup, test_prof_reset, diff --git a/test/unit/prof_tctx.c b/test/unit/prof_tctx.c index 183f7ce0..30c6b178 100644 --- a/test/unit/prof_tctx.c +++ b/test/unit/prof_tctx.c @@ -41,6 +41,6 @@ TEST_END int main(void) { - return test( + return test_no_reentrancy( test_prof_realloc); } diff --git a/test/unit/tsd.c b/test/unit/tsd.c index 5bfcdf49..4a0f3185 100644 --- a/test/unit/tsd.c +++ b/test/unit/tsd.c @@ -79,6 +79,7 @@ thd_start(void *arg) { } TEST_BEGIN(test_tsd_main_thread) { + test_skip_if(test_is_reentrant()); thd_start((void *)(uintptr_t)0xa5f3e329); } TEST_END -- GitLab From b407a65401bca5828760c8fd5e940e91475a2b3e Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Fri, 31 Mar 2017 19:59:45 -0700 Subject: [PATCH 392/544] Add basic reentrancy-checking support, and allow arena_new to reenter. This checks whether or not we're reentrant using thread-local data, and, if we are, moves certain internal allocations to use arena 0 (which should be properly initialized after bootstrapping). The immediate thing this allows is spinning up threads in arena_new, which will enable spinning up background threads there. --- include/jemalloc/internal/hooks.h | 4 +- .../jemalloc/internal/jemalloc_internal.h.in | 9 +- include/jemalloc/internal/private_symbols.txt | 4 + include/jemalloc/internal/tsd_structs.h | 6 +- src/arena.c | 13 +++ src/jemalloc.c | 94 ++++++++++++++++--- test/src/test.c | 76 ++++++++++----- test/stress/microbench.c | 2 +- test/unit/stats.c | 2 +- test/unit/tsd.c | 3 +- 10 files changed, 168 insertions(+), 45 deletions(-) diff --git a/include/jemalloc/internal/hooks.h b/include/jemalloc/internal/hooks.h index 608b268f..cd49afcb 100644 --- a/include/jemalloc/internal/hooks.h +++ b/include/jemalloc/internal/hooks.h @@ -1,8 +1,8 @@ #ifndef JEMALLOC_INTERNAL_HOOKS_H #define JEMALLOC_INTERNAL_HOOKS_H -extern void (*hooks_arena_new_hook)(); -extern void (*hooks_libc_hook)(); +extern JEMALLOC_EXPORT void (*hooks_arena_new_hook)(); +extern JEMALLOC_EXPORT void (*hooks_libc_hook)(); #define JEMALLOC_HOOK(fn, hook) ((void)(hook != NULL && (hook(), 0)), fn) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 1c0bf43a..62dae0c4 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -1013,6 +1013,11 @@ arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { return arena; } + /* During reentrancy, arena 0 is the safest bet. */ + if (*tsd_reentrancy_levelp_get(tsd) > 1) { + return arena_get(tsd_tsdn(tsd), 0, true); + } + ret = internal ? tsd_iarena_get(tsd) : tsd_arena_get(tsd); if (unlikely(ret == NULL)) { ret = arena_choose_hard(tsd, internal); @@ -1193,7 +1198,9 @@ idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool is_internal, if (config_stats && is_internal) { arena_internal_sub(iaalloc(tsdn, ptr), isalloc(tsdn, ptr)); } - + if (!is_internal && *tsd_reentrancy_levelp_get(tsdn_tsd(tsdn)) != 0) { + tcache = NULL; + } arena_dalloc(tsdn, ptr, tcache, slow_path); } diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index deae8243..4931d489 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -232,6 +232,7 @@ hash_rotl_64 hash_x64_128 hash_x86_128 hash_x86_32 +hooks_arena_new_hook hooks_libc_hook iaalloc ialloc @@ -537,6 +538,9 @@ tsd_init_head tsd_narenas_tdata_get tsd_narenas_tdata_set tsd_narenas_tdatap_get +tsd_reentrancy_level_get +tsd_reentrancy_level_set +tsd_reentrancy_levelp_get tsd_wrapper_get tsd_wrapper_set tsd_nominal diff --git a/include/jemalloc/internal/tsd_structs.h b/include/jemalloc/internal/tsd_structs.h index 2dca0bdb..12df63d1 100644 --- a/include/jemalloc/internal/tsd_structs.h +++ b/include/jemalloc/internal/tsd_structs.h @@ -65,7 +65,8 @@ struct tsd_init_head_s { O(witnesses, witness_list_t, no, no, yes) \ O(rtree_leaf_elm_witnesses, rtree_leaf_elm_witness_tsd_t, \ no, no, no) \ - O(witness_fork, bool, yes, no, no) + O(witness_fork, bool, yes, no, no) \ + O(reentrancy_level, int, no, no, no) #define TSD_INITIALIZER { \ tsd_state_uninitialized, \ @@ -82,7 +83,8 @@ struct tsd_init_head_s { TCACHE_ZERO_INITIALIZER, \ ql_head_initializer(witnesses), \ RTREE_ELM_WITNESS_TSD_INITIALIZER, \ - false \ + false, \ + 0 \ } struct tsd_s { diff --git a/src/arena.c b/src/arena.c index b78719e4..19069bbe 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1952,6 +1952,19 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena->base = base; + /* We don't support reetrancy for arena 0 bootstrapping. */ + if (ind != 0 && hooks_arena_new_hook) { + /* + * If we're here, then arena 0 already exists, so bootstrapping + * is done enough that we should have tsd. + */ + int *reentrancy_level = tsd_reentrancy_levelp_get(tsdn_tsd( + tsdn)); + ++*reentrancy_level; + hooks_arena_new_hook(); + --*reentrancy_level; + } + return arena; label_error: if (ind != 0) { diff --git a/src/jemalloc.c b/src/jemalloc.c index 9d66f7f6..7b205ff6 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1656,6 +1656,14 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { szind_t ind = 0; size_t usize = 0; + /* + * For reentrancy checking, we get the old reentrancy level from tsd and + * reset it once we're done. In case of early bailout though, we never + * bother getting the old level, so we shouldn't try to reset it. This + * is indicated by leaving the pointer as NULL. + */ + int *reentrancy_level = NULL; + /* Initialize (if we can't prove we don't have to). */ if (sopts->slow) { if (unlikely(malloc_init())) { @@ -1708,7 +1716,27 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { * some reason. Let's grab it right away. */ tsd = tsd_fetch(); - witness_assert_lockless(tsd_tsdn(tsd)); + + /* + * If we need to handle reentrancy, we can do it out of a + * known-initialized arena (i.e. arena 0). + */ + reentrancy_level = tsd_reentrancy_levelp_get(tsd); + ++*reentrancy_level; + if (*reentrancy_level == 1) { + witness_assert_lockless(tsd_tsdn(tsd)); + } + if (unlikely(*reentrancy_level > 1)) { + /* + * We should never specify particular arenas or tcaches from + * within our internal allocations. + */ + assert(dopts->tcache_ind == TCACHE_IND_AUTOMATIC); + assert(dopts->arena_ind = ARENA_IND_AUTOMATIC); + dopts->tcache_ind = TCACHE_IND_NONE; + /* We know that arena 0 has already been initialized. */ + dopts->arena_ind = 0; + } /* If profiling is on, get our profiling context. */ if (config_prof && opt_prof) { @@ -1769,9 +1797,15 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { UTRACE(0, size, allocation); } - witness_assert_lockless(tsd_tsdn(tsd)); - /* Success! */ + if (*reentrancy_level == 1) { + witness_assert_lockless(tsd_tsdn(tsd)); + } + /* + * If we got here, we never bailed out on a failure path, so + * reentrancy_level is non-null. + */ + --*reentrancy_level; *dopts->result = allocation; return 0; @@ -1795,6 +1829,10 @@ label_oom: *dopts->result = NULL; } + if (reentrancy_level != NULL) { + --*reentrancy_level; + } + return ENOMEM; /* @@ -1822,6 +1860,10 @@ label_invalid_alignment: *dopts->result = NULL; } + if (reentrancy_level != NULL) { + --*reentrancy_level; + } + return EINVAL; } @@ -1996,7 +2038,9 @@ irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize) { JEMALLOC_ALWAYS_INLINE_C void ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { - witness_assert_lockless(tsd_tsdn(tsd)); + if (*tsd_reentrancy_levelp_get(tsd) == 0) { + witness_assert_lockless(tsd_tsdn(tsd)); + } assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); @@ -2021,7 +2065,9 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { JEMALLOC_ALWAYS_INLINE_C void isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) { - witness_assert_lockless(tsd_tsdn(tsd)); + if (*tsd_reentrancy_levelp_get(tsd) == 0) { + witness_assert_lockless(tsd_tsdn(tsd)); + } assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); @@ -2056,7 +2102,11 @@ je_realloc(void *ptr, size_t size) { /* realloc(ptr, 0) is equivalent to free(ptr). */ UTRACE(ptr, 0, 0); tsd = tsd_fetch(); - ifree(tsd, ptr, tcache_get(tsd), true); + tcache_t *tcache = NULL; + if (likely(*tsd_reentrancy_levelp_get(tsd) == 0)) { + tcache = tcache_get(tsd); + } + ifree(tsd, ptr, tcache, true); return NULL; } size = 1; @@ -2111,13 +2161,21 @@ je_free(void *ptr) { UTRACE(ptr, 0, 0); if (likely(ptr != NULL)) { tsd_t *tsd = tsd_fetch(); - witness_assert_lockless(tsd_tsdn(tsd)); + if (*tsd_reentrancy_levelp_get(tsd) == 0) { + witness_assert_lockless(tsd_tsdn(tsd)); + } + tcache_t *tcache = NULL; + if (likely(*tsd_reentrancy_levelp_get(tsd) == 0)) { + tcache = tcache_get(tsd); + } if (likely(!malloc_slow)) { - ifree(tsd, ptr, tcache_get(tsd), false); + ifree(tsd, ptr, tcache, false); } else { - ifree(tsd, ptr, tcache_get(tsd), true); + ifree(tsd, ptr, tcache, true); + } + if (*tsd_reentrancy_levelp_get(tsd) == 0) { + witness_assert_lockless(tsd_tsdn(tsd)); } - witness_assert_lockless(tsd_tsdn(tsd)); } } @@ -2599,13 +2657,19 @@ je_dallocx(void *ptr, int flags) { tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { + /* Not allowed to be reentrant and specify a custom tcache. */ + assert(*tsd_reentrancy_levelp_get(tsd) == 0); if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) { tcache = NULL; } else { tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags)); } } else { - tcache = tcache_get(tsd); + if (likely(*tsd_reentrancy_levelp_get(tsd) == 0)) { + tcache = tcache_get(tsd); + } else { + tcache = NULL; + } } UTRACE(ptr, 0, 0); @@ -2646,13 +2710,19 @@ je_sdallocx(void *ptr, size_t size, int flags) { witness_assert_lockless(tsd_tsdn(tsd)); if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { + /* Not allowed to be reentrant and specify a custom tcache. */ + assert(*tsd_reentrancy_levelp_get(tsd) == 0); if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) { tcache = NULL; } else { tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags)); } } else { - tcache = tcache_get(tsd); + if (likely(*tsd_reentrancy_levelp_get(tsd) == 0)) { + tcache = tcache_get(tsd); + } else { + tcache = NULL; + } } UTRACE(ptr, 0, 0); diff --git a/test/src/test.c b/test/src/test.c index fe6dc60e..01a4d738 100644 --- a/test/src/test.c +++ b/test/src/test.c @@ -10,31 +10,56 @@ static const char * test_name = ""; /* Reentrancy testing helpers. */ #define NUM_REENTRANT_ALLOCS 20 -static bool reentrant = false; -static bool hook_ran = false; -static void *to_free[NUM_REENTRANT_ALLOCS]; +typedef enum { + non_reentrant = 0, + libc_reentrant = 1, + arena_new_reentrant = 2 +} reentrancy_t; +static reentrancy_t reentrancy; + +static bool libc_hook_ran = false; +static bool arena_new_hook_ran = false; + +static const char * +reentrancy_t_str(reentrancy_t r) { + switch (r) { + case non_reentrant: + return "non-reentrant"; + case libc_reentrant: + return "libc-reentrant"; + case arena_new_reentrant: + return "arena_new-reentrant"; + default: + unreachable(); + } +} static void -reentrancy_hook() { - hook_ran = true; - hooks_libc_hook = NULL; +do_hook(bool *hook_ran, void (**hook)()) { + *hook_ran = true; + *hook = NULL; - void *to_free_local[NUM_REENTRANT_ALLOCS]; size_t alloc_size = 1; for (int i = 0; i < NUM_REENTRANT_ALLOCS; i++) { - to_free[i] = malloc(alloc_size); - to_free_local[i] = malloc(alloc_size); + free(malloc(alloc_size)); alloc_size *= 2; } - for (int i = 0; i < NUM_REENTRANT_ALLOCS; i++) { - free(to_free_local[i]); - } +} + +static void +libc_reentrancy_hook() { + do_hook(&libc_hook_ran, &hooks_libc_hook); +} + +static void +arena_new_reentrancy_hook() { + do_hook(&arena_new_hook_ran, &hooks_arena_new_hook); } /* Actual test infrastructure. */ bool test_is_reentrant() { - return reentrant; + return reentrancy != non_reentrant; } JEMALLOC_FORMAT_PRINTF(1, 2) @@ -81,9 +106,8 @@ p_test_init(const char *name) { void p_test_fini(void) { test_counts[test_status]++; - malloc_printf("%s: %s (%s)\n", test_name, - test_status_string(test_status), - reentrant ? "reentrant" : "non-reentrant"); + malloc_printf("%s (%s): %s\n", test_name, reentrancy_t_str(reentrancy), + test_status_string(test_status)); } static test_status_t @@ -106,24 +130,28 @@ p_test_impl(bool do_malloc_init, bool do_reentrant, test_t *t, va_list ap) { ret = test_status_pass; for (; t != NULL; t = va_arg(ap, test_t *)) { /* Non-reentrant run. */ - reentrant = false; + reentrancy = non_reentrant; + hooks_arena_new_hook = hooks_libc_hook = NULL; t(); if (test_status > ret) { ret = test_status; } /* Reentrant run. */ if (do_reentrant) { - reentrant = true; - hooks_libc_hook = &reentrancy_hook; + reentrancy = libc_reentrant; + hooks_arena_new_hook = NULL; + hooks_libc_hook = &libc_reentrancy_hook; t(); if (test_status > ret) { ret = test_status; } - if (hook_ran) { - hook_ran = false; - for (int i = 0; i < NUM_REENTRANT_ALLOCS; i++) { - free(to_free[i]); - } + + reentrancy = arena_new_reentrant; + hooks_libc_hook = NULL; + hooks_arena_new_hook = &arena_new_reentrancy_hook; + t(); + if (test_status > ret) { + ret = test_status; } } } diff --git a/test/stress/microbench.c b/test/stress/microbench.c index 6ed15001..73cbcab0 100644 --- a/test/stress/microbench.c +++ b/test/stress/microbench.c @@ -156,7 +156,7 @@ TEST_END int main(void) { - return test( + return test_no_reentrancy( test_malloc_vs_mallocx, test_free_vs_dallocx, test_dallocx_vs_sdallocx, diff --git a/test/unit/stats.c b/test/unit/stats.c index f8c6b104..1619f5b6 100644 --- a/test/unit/stats.c +++ b/test/unit/stats.c @@ -351,7 +351,7 @@ TEST_END int main(void) { - return test( + return test_no_reentrancy( test_stats_summary, test_stats_large, test_stats_arenas_summary, diff --git a/test/unit/tsd.c b/test/unit/tsd.c index 4a0f3185..38114674 100644 --- a/test/unit/tsd.c +++ b/test/unit/tsd.c @@ -79,7 +79,6 @@ thd_start(void *arg) { } TEST_BEGIN(test_tsd_main_thread) { - test_skip_if(test_is_reentrant()); thd_start((void *)(uintptr_t)0xa5f3e329); } TEST_END @@ -144,7 +143,7 @@ main(void) { data_tsd_boot(); data_test_started = true; - return test( + return test_no_reentrancy( test_tsd_main_thread, test_tsd_sub_thread, test_tsd_reincarnation); -- GitLab From 04ef218d872ae73964f9f6c8d1186c4a1e270d70 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 7 Apr 2017 14:20:57 -0700 Subject: [PATCH 393/544] Move reentrancy_level to the beginning of TSD. --- include/jemalloc/internal/tsd_structs.h | 14 +++++++------- src/arena.c | 2 +- src/jemalloc.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/jemalloc/internal/tsd_structs.h b/include/jemalloc/internal/tsd_structs.h index 12df63d1..7f34d1b4 100644 --- a/include/jemalloc/internal/tsd_structs.h +++ b/include/jemalloc/internal/tsd_structs.h @@ -26,8 +26,8 @@ struct tsd_init_head_s { * t: tcache * --- data not accessed on tcache fast path: arena related fields --- * d: arenas_tdata_bypass - * r: narenas_tdata - * x: blank space (1 byte) + * r: reentrancy_level + * x: narenas_tdata * i: iarena * a: arena * o: arenas_tdata @@ -36,7 +36,7 @@ struct tsd_init_head_s { * Use a compact layout to reduce cache footprint. * +--- 64-bit and 64B cacheline; 1B each letter; First byte on the left. ---+ * |---------------------------- 1st cacheline ----------------------------| - * | sedxrrrr mmmmmmmm ffffffff pppppppp [c * 32 ........ ........ .......] | + * | sedrxxxx mmmmmmmm ffffffff pppppppp [c * 32 ........ ........ .......] | * |---------------------------- 2nd cacheline ----------------------------| * | [c * 64 ........ ........ ........ ........ ........ ........ .......] | * |---------------------------- 3nd cacheline ----------------------------| @@ -53,6 +53,7 @@ struct tsd_init_head_s { /* O(name, type, [gs]et, init, cleanup) */ \ O(tcache_enabled, bool, yes, yes, no) \ O(arenas_tdata_bypass, bool, no, no, no) \ + O(reentrancy_level, int8_t, no, no, no) \ O(narenas_tdata, uint32_t, yes, no, no) \ O(thread_allocated, uint64_t, yes, no, no) \ O(thread_deallocated, uint64_t, yes, no, no) \ @@ -65,8 +66,7 @@ struct tsd_init_head_s { O(witnesses, witness_list_t, no, no, yes) \ O(rtree_leaf_elm_witnesses, rtree_leaf_elm_witness_tsd_t, \ no, no, no) \ - O(witness_fork, bool, yes, no, no) \ - O(reentrancy_level, int, no, no, no) + O(witness_fork, bool, yes, no, no) #define TSD_INITIALIZER { \ tsd_state_uninitialized, \ @@ -75,6 +75,7 @@ struct tsd_init_head_s { 0, \ 0, \ 0, \ + 0, \ NULL, \ RTREE_CTX_ZERO_INITIALIZER, \ NULL, \ @@ -83,8 +84,7 @@ struct tsd_init_head_s { TCACHE_ZERO_INITIALIZER, \ ql_head_initializer(witnesses), \ RTREE_ELM_WITNESS_TSD_INITIALIZER, \ - false, \ - 0 \ + false \ } struct tsd_s { diff --git a/src/arena.c b/src/arena.c index 19069bbe..198c6e49 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1958,7 +1958,7 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { * If we're here, then arena 0 already exists, so bootstrapping * is done enough that we should have tsd. */ - int *reentrancy_level = tsd_reentrancy_levelp_get(tsdn_tsd( + int8_t *reentrancy_level = tsd_reentrancy_levelp_get(tsdn_tsd( tsdn)); ++*reentrancy_level; hooks_arena_new_hook(); diff --git a/src/jemalloc.c b/src/jemalloc.c index 7b205ff6..513d9cd2 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1662,7 +1662,7 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { * bother getting the old level, so we shouldn't try to reset it. This * is indicated by leaving the pointer as NULL. */ - int *reentrancy_level = NULL; + int8_t *reentrancy_level = NULL; /* Initialize (if we can't prove we don't have to). */ if (sopts->slow) { -- GitLab From 701daa5298b3befe2aff05ce590533165abb9ba4 Mon Sep 17 00:00:00 2001 From: Rafael Folco Date: Mon, 10 Apr 2017 12:39:38 +0000 Subject: [PATCH 394/544] Port CPU_SPINWAIT to __powerpc64__ Hyper-threaded CPUs may need a special instruction inside spin loops in order to yield to another virtual CPU. The 'pause' instruction that is available for x86 is not supported on Power. Apparently the extended mnemonics like yield, mdoio, and mdoom are not actually implemented on POWER8, although mentioned in the ISA 2.07 document. The recommended magic bits are an 'or 31,31,31'. --- configure.ac | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 37745c40..894e72d0 100644 --- a/configure.ac +++ b/configure.ac @@ -398,8 +398,9 @@ case "${host_cpu}" in fi fi ;; - powerpc) + powerpc*) AC_DEFINE_UNQUOTED([HAVE_ALTIVEC], [ ]) + CPU_SPINWAIT='__asm__ volatile("or 31,31,31")' ;; *) ;; -- GitLab From 8209df24ea5bc1dcb560ac64cf2b4ff552f8c9ff Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 10 Apr 2017 13:26:21 -0700 Subject: [PATCH 395/544] Turn on -Werror for travis CI builds --- .travis.yml | 56 +++++++++++++++++++++---------------------- scripts/gen_travis.py | 4 +++- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index efac8547..2235206d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,85 +3,85 @@ language: generic matrix: include: - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" addons: apt: packages: - gcc-multilib - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx - env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx - env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=clang CXX=clang++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" + env: CC=clang CXX=clang++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" addons: apt: packages: - gcc-multilib - os: linux - env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache" + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-debug" + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds" addons: apt: packages: - gcc-multilib - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-prof" + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" addons: apt: packages: - gcc-multilib - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-stats" + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" addons: apt: packages: - gcc-multilib - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-tcache" + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-tcache" EXTRA_CFLAGS="-Werror -Wno-array-bounds" addons: apt: packages: - gcc-multilib - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-prof" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-stats" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-tcache" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-tcache" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-stats" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-tcache" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-tcache" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --disable-tcache" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --disable-tcache" EXTRA_CFLAGS="-Werror -Wno-array-bounds" before_script: diff --git a/scripts/gen_travis.py b/scripts/gen_travis.py index 93fe3283..35a10ee6 100755 --- a/scripts/gen_travis.py +++ b/scripts/gen_travis.py @@ -72,7 +72,9 @@ for unusual_combination in unusual_combinations_to_test: if os == 'osx' and '--enable-prof' in configure_flags: continue - env_string = '{} COMPILER_FLAGS="{}" CONFIGURE_FLAGS="{}"'.format( + # We get some spurious errors when -Warray-bounds is enabled. + env_string = ('{} COMPILER_FLAGS="{}" CONFIGURE_FLAGS="{}" ' + 'EXTRA_CFLAGS="-Werror -Wno-array-bounds"').format( compilers, " ".join(compiler_flags), " ".join(configure_flags)) include_rows += ' - os: %s\n' % os -- GitLab From bfa530b75b15b6965566d8d47ad8d722da722f52 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 7 Apr 2017 14:12:30 -0700 Subject: [PATCH 396/544] Pass dealloc_ctx down free() fast path. This gets rid of the redundent rtree lookup down fast path. --- include/jemalloc/internal/arena_inlines_b.h | 20 +++++++++++---- include/jemalloc/internal/arena_structs_b.h | 6 +++++ include/jemalloc/internal/arena_types.h | 1 + .../jemalloc/internal/jemalloc_internal.h.in | 12 ++++----- src/ckh.c | 10 ++++---- src/jemalloc.c | 18 +++++++++---- src/prof.c | 25 +++++++++++-------- src/tcache.c | 4 +-- 8 files changed, 62 insertions(+), 34 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index ea69a688..96889c1b 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -15,7 +15,8 @@ arena_t *arena_aalloc(tsdn_t *tsdn, const void *ptr); size_t arena_salloc(tsdn_t *tsdn, const void *ptr); size_t arena_vsalloc(tsdn_t *tsdn, const void *ptr); void arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr); -void arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path); +void arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, + dalloc_ctx_t *dalloc_ctx, bool slow_path); void arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size); void arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, bool slow_path); @@ -194,7 +195,8 @@ arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) { } JEMALLOC_ALWAYS_INLINE void -arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path) { +arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, + dalloc_ctx_t *dalloc_ctx, bool slow_path) { assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); @@ -203,13 +205,21 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path) { return; } - rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn)); szind_t szind; bool slab; - rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, - true, &szind, &slab); + rtree_ctx_t *rtree_ctx; + if (dalloc_ctx != NULL) { + szind = dalloc_ctx->szind; + slab = dalloc_ctx->slab; + assert(szind != NSIZES); + } else { + rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn)); + rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true, &szind, &slab); + } if (config_debug) { + rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn)); extent_t *extent = rtree_extent_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, true); assert(szind == extent_szind_get(extent)); diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 00e0d0c8..b6ba3dbc 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -256,4 +256,10 @@ struct arena_tdata_s { ticker_t decay_ticker; }; +/* Used to pass rtree lookup context down the deallocation path. */ +struct dalloc_ctx_s { + szind_t szind; + bool slab; +}; + #endif /* JEMALLOC_INTERNAL_ARENA_STRUCTS_B_H */ diff --git a/include/jemalloc/internal/arena_types.h b/include/jemalloc/internal/arena_types.h index ba53c408..435b930d 100644 --- a/include/jemalloc/internal/arena_types.h +++ b/include/jemalloc/internal/arena_types.h @@ -19,6 +19,7 @@ typedef struct arena_decay_s arena_decay_t; typedef struct arena_bin_s arena_bin_t; typedef struct arena_s arena_t; typedef struct arena_tdata_s arena_tdata_t; +typedef struct dalloc_ctx_s dalloc_ctx_t; typedef enum { percpu_arena_disabled = 0, diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 62dae0c4..17c77aa3 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -1095,8 +1095,8 @@ void *ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); void *ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero); size_t ivsalloc(tsdn_t *tsdn, const void *ptr); -void idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool is_internal, - bool slow_path); +void idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, + dalloc_ctx_t *dalloc_ctx, bool is_internal, bool slow_path); void idalloc(tsd_t *tsd, void *ptr); void isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, bool slow_path); @@ -1188,8 +1188,8 @@ ivsalloc(tsdn_t *tsdn, const void *ptr) { } JEMALLOC_ALWAYS_INLINE void -idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool is_internal, - bool slow_path) { +idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, dalloc_ctx_t *dalloc_ctx, + bool is_internal, bool slow_path) { assert(ptr != NULL); assert(!is_internal || tcache == NULL); assert(!is_internal || arena_ind_get(iaalloc(tsdn, ptr)) < @@ -1201,12 +1201,12 @@ idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool is_internal, if (!is_internal && *tsd_reentrancy_levelp_get(tsdn_tsd(tsdn)) != 0) { tcache = NULL; } - arena_dalloc(tsdn, ptr, tcache, slow_path); + arena_dalloc(tsdn, ptr, tcache, dalloc_ctx, slow_path); } JEMALLOC_ALWAYS_INLINE void idalloc(tsd_t *tsd, void *ptr) { - idalloctm(tsd_tsdn(tsd), ptr, tcache_get(tsd), false, true); + idalloctm(tsd_tsdn(tsd), ptr, tcache_get(tsd), NULL, false, true); } JEMALLOC_ALWAYS_INLINE void diff --git a/src/ckh.c b/src/ckh.c index 463f8dd1..03262ef5 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -282,12 +282,12 @@ ckh_grow(tsd_t *tsd, ckh_t *ckh) { ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; if (!ckh_rebuild(ckh, tab)) { - idalloctm(tsd_tsdn(tsd), tab, NULL, true, true); + idalloctm(tsd_tsdn(tsd), tab, NULL, NULL, true, true); break; } /* Rebuilding failed, so back out partially rebuilt table. */ - idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, true, true); + idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, NULL, true, true); ckh->tab = tab; ckh->lg_curbuckets = lg_prevbuckets; } @@ -329,7 +329,7 @@ ckh_shrink(tsd_t *tsd, ckh_t *ckh) { ckh->lg_curbuckets = lg_curcells - LG_CKH_BUCKET_CELLS; if (!ckh_rebuild(ckh, tab)) { - idalloctm(tsd_tsdn(tsd), tab, NULL, true, true); + idalloctm(tsd_tsdn(tsd), tab, NULL, NULL, true, true); #ifdef CKH_COUNT ckh->nshrinks++; #endif @@ -337,7 +337,7 @@ ckh_shrink(tsd_t *tsd, ckh_t *ckh) { } /* Rebuilding failed, so back out partially rebuilt table. */ - idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, true, true); + idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, NULL, true, true); ckh->tab = tab; ckh->lg_curbuckets = lg_prevbuckets; #ifdef CKH_COUNT @@ -418,7 +418,7 @@ ckh_delete(tsd_t *tsd, ckh_t *ckh) { (unsigned long long)ckh->nrelocs); #endif - idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, true, true); + idalloctm(tsd_tsdn(tsd), ckh->tab, NULL, NULL, true, true); if (config_debug) { memset(ckh, JEMALLOC_FREE_JUNK, sizeof(ckh_t)); } diff --git a/src/jemalloc.c b/src/jemalloc.c index 513d9cd2..bc659325 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -313,7 +313,7 @@ a0ialloc(size_t size, bool zero, bool is_internal) { static void a0idalloc(void *ptr, bool is_internal) { - idalloctm(TSDN_NULL, ptr, false, is_internal, true); + idalloctm(TSDN_NULL, ptr, NULL, NULL, is_internal, true); } void * @@ -2045,21 +2045,29 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); + dalloc_ctx_t dalloc_ctx; + rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd); + rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true, &dalloc_ctx.szind, &dalloc_ctx.slab); + assert(dalloc_ctx.szind != NSIZES); + size_t usize; if (config_prof && opt_prof) { - usize = isalloc(tsd_tsdn(tsd), ptr); + usize = index2size(dalloc_ctx.szind); prof_free(tsd, ptr, usize); } else if (config_stats) { - usize = isalloc(tsd_tsdn(tsd), ptr); + usize = index2size(dalloc_ctx.szind); } if (config_stats) { *tsd_thread_deallocatedp_get(tsd) += usize; } if (likely(!slow_path)) { - idalloctm(tsd_tsdn(tsd), ptr, tcache, false, false); + idalloctm(tsd_tsdn(tsd), ptr, tcache, &dalloc_ctx, false, + false); } else { - idalloctm(tsd_tsdn(tsd), ptr, tcache, false, true); + idalloctm(tsd_tsdn(tsd), ptr, tcache, &dalloc_ctx, false, + true); } } diff --git a/src/prof.c b/src/prof.c index db1ef035..40610d71 100644 --- a/src/prof.c +++ b/src/prof.c @@ -590,7 +590,7 @@ prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self, prof_gctx_t *gctx, prof_leave(tsd, tdata_self); /* Destroy gctx. */ malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock); - idalloctm(tsd_tsdn(tsd), gctx, NULL, true, true); + idalloctm(tsd_tsdn(tsd), gctx, NULL, NULL, true, true); } else { /* * Compensate for increment in prof_tctx_destroy() or @@ -704,7 +704,7 @@ prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) { } if (destroy_tctx) { - idalloctm(tsd_tsdn(tsd), tctx, NULL, true, true); + idalloctm(tsd_tsdn(tsd), tctx, NULL, NULL, true, true); } } @@ -736,8 +736,8 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, if (ckh_insert(tsd, &bt2gctx, btkey.v, gctx.v)) { /* OOM. */ prof_leave(tsd, tdata); - idalloctm(tsd_tsdn(tsd), gctx.v, NULL, true, - true); + idalloctm(tsd_tsdn(tsd), gctx.v, NULL, NULL, + true, true); return true; } new_gctx = true; @@ -761,7 +761,8 @@ prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, if (tgctx.v != NULL) { /* Lost race to insert. */ - idalloctm(tsd_tsdn(tsd), tgctx.v, NULL, true, true); + idalloctm(tsd_tsdn(tsd), tgctx.v, NULL, NULL, true, + true); } } prof_leave(tsd, tdata); @@ -833,7 +834,7 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) { if (new_gctx) { prof_gctx_try_destroy(tsd, tdata, gctx, tdata); } - idalloctm(tsd_tsdn(tsd), ret.v, NULL, true, true); + idalloctm(tsd_tsdn(tsd), ret.v, NULL, NULL, true, true); return NULL; } malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock); @@ -1245,7 +1246,7 @@ prof_gctx_finish(tsd_t *tsd, prof_gctx_tree_t *gctxs) { tctx_tree_remove(&gctx->tctxs, to_destroy); idalloctm(tsd_tsdn(tsd), to_destroy, - NULL, true, true); + NULL, NULL, true, true); } else { next = NULL; } @@ -1915,7 +1916,7 @@ prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim, if (ckh_new(tsd, &tdata->bt2tctx, PROF_CKH_MINITEMS, prof_bt_hash, prof_bt_keycomp)) { - idalloctm(tsd_tsdn(tsd), tdata, NULL, true, true); + idalloctm(tsd_tsdn(tsd), tdata, NULL, NULL, true, true); return NULL; } @@ -1971,10 +1972,11 @@ prof_tdata_destroy_locked(tsd_t *tsd, prof_tdata_t *tdata, assert(prof_tdata_should_destroy_unlocked(tdata, even_if_attached)); if (tdata->thread_name != NULL) { - idalloctm(tsd_tsdn(tsd), tdata->thread_name, NULL, true, true); + idalloctm(tsd_tsdn(tsd), tdata->thread_name, NULL, NULL, true, + true); } ckh_delete(tsd, &tdata->bt2tctx); - idalloctm(tsd_tsdn(tsd), tdata, NULL, true, true); + idalloctm(tsd_tsdn(tsd), tdata, NULL, NULL, true, true); } static void @@ -2171,7 +2173,8 @@ prof_thread_name_set(tsd_t *tsd, const char *thread_name) { } if (tdata->thread_name != NULL) { - idalloctm(tsd_tsdn(tsd), tdata->thread_name, NULL, true, true); + idalloctm(tsd_tsdn(tsd), tdata->thread_name, NULL, NULL, true, + true); tdata->thread_name = NULL; } if (strlen(s) > 0) { diff --git a/src/tcache.c b/src/tcache.c index 34b46afd..09776e1a 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -499,10 +499,10 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache, bool tsd_tcache) { void *avail_array = (void *)((uintptr_t)tcache_small_bin_get(tcache, 0)->avail - (uintptr_t)tcache_bin_info[0].ncached_max * sizeof(void *)); - idalloctm(tsd_tsdn(tsd), avail_array, NULL, true, true); + idalloctm(tsd_tsdn(tsd), avail_array, NULL, NULL, true, true); } else { /* Release both the tcache struct and avail array. */ - idalloctm(tsd_tsdn(tsd), tcache, NULL, true, true); + idalloctm(tsd_tsdn(tsd), tcache, NULL, NULL, true, true); } } -- GitLab From 57e36e1a12e5cc6af7942196a3f37c9d280ab767 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 10 Apr 2017 18:25:27 -0700 Subject: [PATCH 397/544] Header refactoring: Add CPP_PROLOGUE and CPP_EPILOGUE macros --- include/jemalloc/internal/jemalloc_internal.h.in | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 17c77aa3..73c5d3a5 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -2,9 +2,15 @@ #define JEMALLOC_INTERNAL_H #ifdef __cplusplus -extern "C" { +# define CPP_PROLOGUE extern "C" { +# define CPP_EPILOGUE } +#else +# define CPP_PROLOGUE +# define CPP_EPILOGUE #endif +CPP_PROLOGUE + #include "jemalloc_internal_defs.h" #include "jemalloc/internal/jemalloc_internal_decls.h" @@ -1300,8 +1306,6 @@ ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, #include "jemalloc/internal/prof_inlines_b.h" -#ifdef __cplusplus -} -#endif +CPP_EPILOGUE #endif /* JEMALLOC_INTERNAL_H */ -- GitLab From 2f00ce4da7b1c360a9b1129ebcdb087da562e2d4 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 10 Apr 2017 16:54:25 -0700 Subject: [PATCH 398/544] Header refactoring: break out ph.h dependencies --- include/jemalloc/internal/extent_externs.h | 2 ++ include/jemalloc/internal/extent_structs.h | 2 ++ include/jemalloc/internal/jemalloc_internal.h.in | 1 - src/extent.c | 2 ++ test/unit/ph.c | 2 ++ 5 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index 6c153d04..3fe4a0ad 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_EXTENT_EXTERNS_H #define JEMALLOC_INTERNAL_EXTENT_EXTERNS_H +#include "jemalloc/internal/ph.h" + extern rtree_t extents_rtree; extern const extent_hooks_t extent_hooks_default; diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 5d41bb81..87107a88 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_EXTENT_STRUCTS_H #define JEMALLOC_INTERNAL_EXTENT_STRUCTS_H +#include "jemalloc/internal/ph.h" + typedef enum { extent_state_active = 0, extent_state_dirty = 1, diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 73c5d3a5..7756b8f0 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -180,7 +180,6 @@ static const bool have_percpu_arena = #include #endif -#include "jemalloc/internal/ph.h" #ifndef __PGI #define RB_COMPACT #endif diff --git a/src/extent.c b/src/extent.c index e080773b..b6c3f4b4 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1,6 +1,8 @@ #define JEMALLOC_EXTENT_C_ #include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/ph.h" + /******************************************************************************/ /* Data. */ diff --git a/test/unit/ph.c b/test/unit/ph.c index 01df340c..88bf56f8 100644 --- a/test/unit/ph.c +++ b/test/unit/ph.c @@ -1,5 +1,7 @@ #include "test/jemalloc_test.h" +#include "jemalloc/internal/ph.h" + typedef struct node_s node_t; struct node_s { -- GitLab From 63a5cd4cc2a4812adc7f3a8bd3ea0633115b151e Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 10 Apr 2017 17:03:25 -0700 Subject: [PATCH 399/544] Header refactoring: break out rb.h dependencies --- include/jemalloc/internal/jemalloc_internal.h.in | 4 ---- include/jemalloc/internal/prof_structs.h | 2 ++ include/jemalloc/internal/rb.h | 4 ++++ test/unit/rb.c | 2 ++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 7756b8f0..532af2b8 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -180,10 +180,6 @@ static const bool have_percpu_arena = #include #endif -#ifndef __PGI -#define RB_COMPACT -#endif -#include "jemalloc/internal/rb.h" #include "jemalloc/internal/qr.h" #include "jemalloc/internal/ql.h" diff --git a/include/jemalloc/internal/prof_structs.h b/include/jemalloc/internal/prof_structs.h index fba8c295..e1936769 100644 --- a/include/jemalloc/internal/prof_structs.h +++ b/include/jemalloc/internal/prof_structs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_PROF_STRUCTS_H #define JEMALLOC_INTERNAL_PROF_STRUCTS_H +#include "jemalloc/internal/rb.h" + struct prof_bt_s { /* Backtrace, stored as len program counters. */ void **vec; diff --git a/include/jemalloc/internal/rb.h b/include/jemalloc/internal/rb.h index aa76061e..47fa5ca9 100644 --- a/include/jemalloc/internal/rb.h +++ b/include/jemalloc/internal/rb.h @@ -22,6 +22,10 @@ #ifndef RB_H_ #define RB_H_ +#ifndef __PGI +#define RB_COMPACT +#endif + #ifdef RB_COMPACT /* Node structure. */ #define rb_node(a_type) \ diff --git a/test/unit/rb.c b/test/unit/rb.c index 0bcc3c31..65c04920 100644 --- a/test/unit/rb.c +++ b/test/unit/rb.c @@ -1,5 +1,7 @@ #include "test/jemalloc_test.h" +#include "jemalloc/internal/rb.h" + #define rbtn_black_height(a_type, a_field, a_rbt, r_height) do { \ a_type *rbp_bh_t; \ for (rbp_bh_t = (a_rbt)->rbt_root, (r_height) = 0; rbp_bh_t != \ -- GitLab From 610cb83419d4dd741002b5af19b47f16110bf673 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 10 Apr 2017 17:06:53 -0700 Subject: [PATCH 400/544] Header refactoring: break out qr.h dependencies --- include/jemalloc/internal/jemalloc_internal.h.in | 1 - include/jemalloc/internal/ql.h | 2 ++ test/unit/qr.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index 532af2b8..fdeda7b6 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -180,7 +180,6 @@ static const bool have_percpu_arena = #include #endif -#include "jemalloc/internal/qr.h" #include "jemalloc/internal/ql.h" /* diff --git a/include/jemalloc/internal/ql.h b/include/jemalloc/internal/ql.h index b3a428c7..80290407 100644 --- a/include/jemalloc/internal/ql.h +++ b/include/jemalloc/internal/ql.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_QL_H #define JEMALLOC_INTERNAL_QL_H +#include "jemalloc/internal/qr.h" + /* List definitions. */ #define ql_head(a_type) \ struct { \ diff --git a/test/unit/qr.c b/test/unit/qr.c index 80c5c27d..271a1095 100644 --- a/test/unit/qr.c +++ b/test/unit/qr.c @@ -1,5 +1,7 @@ #include "test/jemalloc_test.h" +#include "jemalloc/internal/qr.h" + /* Number of ring entries, in [2..26]. */ #define NENTRIES 9 /* Split index, in [1..NENTRIES). */ -- GitLab From 0237870c60104b418ce78b86752bf44b3b478b97 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 10 Apr 2017 17:11:33 -0700 Subject: [PATCH 401/544] Header refactoring: break out ql.h dependencies --- include/jemalloc/internal/arena_structs_b.h | 3 +++ include/jemalloc/internal/ctl_structs.h | 2 ++ include/jemalloc/internal/extent_inlines.h | 2 ++ include/jemalloc/internal/extent_structs.h | 1 + include/jemalloc/internal/jemalloc_internal.h.in | 2 -- include/jemalloc/internal/tcache_structs.h | 2 ++ include/jemalloc/internal/tsd_structs.h | 2 ++ include/jemalloc/internal/tsd_types.h | 2 ++ include/jemalloc/internal/witness_inlines.h | 2 ++ include/jemalloc/internal/witness_types.h | 2 ++ test/unit/ql.c | 2 ++ 11 files changed, 20 insertions(+), 2 deletions(-) diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index b6ba3dbc..935cd169 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -1,5 +1,8 @@ #ifndef JEMALLOC_INTERNAL_ARENA_STRUCTS_B_H #define JEMALLOC_INTERNAL_ARENA_STRUCTS_B_H + +#include "jemalloc/internal/ql.h" + /* * Read-only information associated with each element of arena_t's bins array * is stored separately, partly to reduce memory usage (only one copy, rather diff --git a/include/jemalloc/internal/ctl_structs.h b/include/jemalloc/internal/ctl_structs.h index af0f78b9..2b48a68e 100644 --- a/include/jemalloc/internal/ctl_structs.h +++ b/include/jemalloc/internal/ctl_structs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_CTL_STRUCTS_H #define JEMALLOC_INTERNAL_CTL_STRUCTS_H +#include "jemalloc/internal/ql.h" + struct ctl_node_s { bool named; }; diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index f1b94776..6fc01017 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_EXTENT_INLINES_H #define JEMALLOC_INTERNAL_EXTENT_INLINES_H +#include "jemalloc/internal/ql.h" + #ifndef JEMALLOC_ENABLE_INLINE arena_t *extent_arena_get(const extent_t *extent); szind_t extent_szind_get_maybe_invalid(const extent_t *extent); diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 87107a88..2f81fa1c 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_EXTENT_STRUCTS_H #include "jemalloc/internal/ph.h" +#include "jemalloc/internal/ql.h" typedef enum { extent_state_active = 0, diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in index fdeda7b6..58240e39 100644 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ b/include/jemalloc/internal/jemalloc_internal.h.in @@ -180,8 +180,6 @@ static const bool have_percpu_arena = #include #endif -#include "jemalloc/internal/ql.h" - /* * jemalloc can conceptually be broken into components (arena, tcache, etc.), * but there are circular dependencies that cannot be broken without diff --git a/include/jemalloc/internal/tcache_structs.h b/include/jemalloc/internal/tcache_structs.h index 4e101609..c43e59b7 100644 --- a/include/jemalloc/internal/tcache_structs.h +++ b/include/jemalloc/internal/tcache_structs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_TCACHE_STRUCTS_H #define JEMALLOC_INTERNAL_TCACHE_STRUCTS_H +#include "jemalloc/internal/ql.h" + /* * Read-only information associated with each element of tcache_t's tbins array * is stored separately, mainly to reduce memory usage. diff --git a/include/jemalloc/internal/tsd_structs.h b/include/jemalloc/internal/tsd_structs.h index 7f34d1b4..ac74152c 100644 --- a/include/jemalloc/internal/tsd_structs.h +++ b/include/jemalloc/internal/tsd_structs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_TSD_STRUCTS_H #define JEMALLOC_INTERNAL_TSD_STRUCTS_H +#include "jemalloc/internal/ql.h" + #if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ !defined(_WIN32)) struct tsd_init_block_s { diff --git a/include/jemalloc/internal/tsd_types.h b/include/jemalloc/internal/tsd_types.h index 4d5fef57..27afd1d6 100644 --- a/include/jemalloc/internal/tsd_types.h +++ b/include/jemalloc/internal/tsd_types.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_TSD_TYPES_H #define JEMALLOC_INTERNAL_TSD_TYPES_H +#include "jemalloc/internal/ql.h" + /* Maximum number of malloc_tsd users with cleanup functions. */ #define MALLOC_TSD_CLEANUPS_MAX 2 diff --git a/include/jemalloc/internal/witness_inlines.h b/include/jemalloc/internal/witness_inlines.h index 51f3f6e7..c5027f11 100644 --- a/include/jemalloc/internal/witness_inlines.h +++ b/include/jemalloc/internal/witness_inlines.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_WITNESS_INLINES_H #define JEMALLOC_INTERNAL_WITNESS_INLINES_H +#include "jemalloc/internal/ql.h" + #ifndef JEMALLOC_ENABLE_INLINE bool witness_owner(tsd_t *tsd, const witness_t *witness); void witness_assert_owner(tsdn_t *tsdn, const witness_t *witness); diff --git a/include/jemalloc/internal/witness_types.h b/include/jemalloc/internal/witness_types.h index 95fc296c..d43a363b 100644 --- a/include/jemalloc/internal/witness_types.h +++ b/include/jemalloc/internal/witness_types.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_WITNESS_TYPES_H #define JEMALLOC_INTERNAL_WITNESS_TYPES_H +#include "jemalloc/internal/ql.h" + typedef struct witness_s witness_t; typedef unsigned witness_rank_t; typedef ql_head(witness_t) witness_list_t; diff --git a/test/unit/ql.c b/test/unit/ql.c index ae6481fd..b76c24c4 100644 --- a/test/unit/ql.c +++ b/test/unit/ql.c @@ -1,5 +1,7 @@ #include "test/jemalloc_test.h" +#include "jemalloc/internal/ql.h" + /* Number of ring entries, in [2..26]. */ #define NENTRIES 9 -- GitLab From 743d940dc34495e61145bbe4901ae2c2dcd4c4ef Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 10 Apr 2017 18:17:55 -0700 Subject: [PATCH 402/544] Header refactoring: Split up jemalloc_internal.h This is a biggy. jemalloc_internal.h has been doing multiple jobs for a while now: - The source of system-wide definitions. - The catch-all include file. - The module header file for jemalloc.c This commit splits up this functionality. The system-wide definitions responsibility has moved to jemalloc_preamble.h. The catch-all include file is now jemalloc_internal_includes.h. The module headers for jemalloc.c are now in jemalloc_internal_[externs|inlines|types].h, just as they are for the other modules. --- .gitignore | 2 +- configure.ac | 6 +- .../jemalloc/internal/jemalloc_internal.h.in | 1303 ----------------- .../internal/jemalloc_internal_externs.h | 61 + .../internal/jemalloc_internal_includes.h | 155 ++ .../internal/jemalloc_internal_inlines_a.h | 448 ++++++ .../internal/jemalloc_internal_inlines_b.h | 83 ++ .../internal/jemalloc_internal_inlines_c.h | 220 +++ .../internal/jemalloc_internal_types.h | 178 +++ .../jemalloc/internal/jemalloc_preamble.h.in | 187 +++ src/arena.c | 3 +- src/base.c | 3 +- src/bitmap.c | 3 +- src/ckh.c | 3 +- src/ctl.c | 3 +- src/extent.c | 4 +- src/extent_dss.c | 4 +- src/extent_mmap.c | 3 +- src/hash.c | 3 +- src/hooks.c | 2 +- src/jemalloc.c | 3 +- src/jemalloc_cpp.cpp | 3 +- src/large.c | 3 +- src/malloc_io.c | 3 +- src/mutex.c | 3 +- src/nstime.c | 3 +- src/pages.c | 3 +- src/prng.c | 3 +- src/prof.c | 4 +- src/rtree.c | 3 +- src/spin.c | 3 +- src/stats.c | 3 +- src/tcache.c | 3 +- src/ticker.c | 3 +- src/tsd.c | 3 +- src/witness.c | 3 +- src/zone.c | 3 +- test/include/test/jemalloc_test.h.in | 7 +- 38 files changed, 1396 insertions(+), 1337 deletions(-) delete mode 100644 include/jemalloc/internal/jemalloc_internal.h.in create mode 100644 include/jemalloc/internal/jemalloc_internal_externs.h create mode 100644 include/jemalloc/internal/jemalloc_internal_includes.h create mode 100644 include/jemalloc/internal/jemalloc_internal_inlines_a.h create mode 100644 include/jemalloc/internal/jemalloc_internal_inlines_b.h create mode 100644 include/jemalloc/internal/jemalloc_internal_inlines_c.h create mode 100644 include/jemalloc/internal/jemalloc_internal_types.h create mode 100644 include/jemalloc/internal/jemalloc_preamble.h.in diff --git a/.gitignore b/.gitignore index 548c7d1a..9bbc5d66 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,7 @@ /Makefile -/include/jemalloc/internal/jemalloc_internal.h +/include/jemalloc/internal/jemalloc_preamble.h /include/jemalloc/internal/jemalloc_internal_defs.h /include/jemalloc/internal/private_namespace.h /include/jemalloc/internal/private_unnamespace.h diff --git a/configure.ac b/configure.ac index 894e72d0..00868133 100644 --- a/configure.ac +++ b/configure.ac @@ -875,7 +875,7 @@ cfgoutputs_in="${cfgoutputs_in} doc/jemalloc.xml.in" cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_macros.h.in" cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_protos.h.in" cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_typedefs.h.in" -cfgoutputs_in="${cfgoutputs_in} include/jemalloc/internal/jemalloc_internal.h.in" +cfgoutputs_in="${cfgoutputs_in} include/jemalloc/internal/jemalloc_preamble.h.in" cfgoutputs_in="${cfgoutputs_in} test/test.sh.in" cfgoutputs_in="${cfgoutputs_in} test/include/test/jemalloc_test.h.in" @@ -887,7 +887,7 @@ cfgoutputs_out="${cfgoutputs_out} doc/jemalloc.xml" cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_macros.h" cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_protos.h" cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_typedefs.h" -cfgoutputs_out="${cfgoutputs_out} include/jemalloc/internal/jemalloc_internal.h" +cfgoutputs_out="${cfgoutputs_out} include/jemalloc/internal/jemalloc_preamble.h" cfgoutputs_out="${cfgoutputs_out} test/test.sh" cfgoutputs_out="${cfgoutputs_out} test/include/test/jemalloc_test.h" @@ -899,7 +899,7 @@ cfgoutputs_tup="${cfgoutputs_tup} doc/jemalloc.xml:doc/jemalloc.xml.in" cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_macros.h:include/jemalloc/jemalloc_macros.h.in" cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_protos.h:include/jemalloc/jemalloc_protos.h.in" cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_typedefs.h:include/jemalloc/jemalloc_typedefs.h.in" -cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/internal/jemalloc_internal.h" +cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/internal/jemalloc_preamble.h" cfgoutputs_tup="${cfgoutputs_tup} test/test.sh:test/test.sh.in" cfgoutputs_tup="${cfgoutputs_tup} test/include/test/jemalloc_test.h:test/include/test/jemalloc_test.h.in" diff --git a/include/jemalloc/internal/jemalloc_internal.h.in b/include/jemalloc/internal/jemalloc_internal.h.in deleted file mode 100644 index 58240e39..00000000 --- a/include/jemalloc/internal/jemalloc_internal.h.in +++ /dev/null @@ -1,1303 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_H -#define JEMALLOC_INTERNAL_H - -#ifdef __cplusplus -# define CPP_PROLOGUE extern "C" { -# define CPP_EPILOGUE } -#else -# define CPP_PROLOGUE -# define CPP_EPILOGUE -#endif - -CPP_PROLOGUE - -#include "jemalloc_internal_defs.h" -#include "jemalloc/internal/jemalloc_internal_decls.h" - -#ifdef JEMALLOC_UTRACE -#include -#endif - -#define JEMALLOC_NO_DEMANGLE -#ifdef JEMALLOC_JET -# define JEMALLOC_N(n) jet_##n -# include "jemalloc/internal/public_namespace.h" -# define JEMALLOC_NO_RENAME -# include "../jemalloc@install_suffix@.h" -# undef JEMALLOC_NO_RENAME -#else -# define JEMALLOC_N(n) @private_namespace@##n -# include "../jemalloc@install_suffix@.h" -#endif - -/* - * Note that the ordering matters here; the hook itself is name-mangled. We - * want the inclusion of hooks to happen early, so that we hook as much as - * possible. - */ -#include "jemalloc/internal/private_namespace.h" -#include "jemalloc/internal/hooks.h" - -static const bool config_debug = -#ifdef JEMALLOC_DEBUG - true -#else - false -#endif - ; -static const bool have_dss = -#ifdef JEMALLOC_DSS - true -#else - false -#endif - ; -static const bool config_fill = -#ifdef JEMALLOC_FILL - true -#else - false -#endif - ; -static const bool config_lazy_lock = -#ifdef JEMALLOC_LAZY_LOCK - true -#else - false -#endif - ; -static const char * const config_malloc_conf = JEMALLOC_CONFIG_MALLOC_CONF; -static const bool config_prof = -#ifdef JEMALLOC_PROF - true -#else - false -#endif - ; -static const bool config_prof_libgcc = -#ifdef JEMALLOC_PROF_LIBGCC - true -#else - false -#endif - ; -static const bool config_prof_libunwind = -#ifdef JEMALLOC_PROF_LIBUNWIND - true -#else - false -#endif - ; -static const bool maps_coalesce = -#ifdef JEMALLOC_MAPS_COALESCE - true -#else - false -#endif - ; -static const bool config_munmap = -#ifdef JEMALLOC_MUNMAP - true -#else - false -#endif - ; -static const bool config_stats = -#ifdef JEMALLOC_STATS - true -#else - false -#endif - ; -static const bool config_tcache = -#ifdef JEMALLOC_TCACHE - true -#else - false -#endif - ; -static const bool config_tls = -#ifdef JEMALLOC_TLS - true -#else - false -#endif - ; -static const bool config_utrace = -#ifdef JEMALLOC_UTRACE - true -#else - false -#endif - ; -static const bool config_xmalloc = -#ifdef JEMALLOC_XMALLOC - true -#else - false -#endif - ; -static const bool config_ivsalloc = -#ifdef JEMALLOC_IVSALLOC - true -#else - false -#endif - ; -static const bool config_cache_oblivious = -#ifdef JEMALLOC_CACHE_OBLIVIOUS - true -#else - false -#endif - ; -static const bool have_thp = -#ifdef JEMALLOC_THP - true -#else - false -#endif - ; -#ifdef JEMALLOC_HAVE_SCHED_GETCPU -/* Currently percpu_arena depends on sched_getcpu. */ -#define JEMALLOC_PERCPU_ARENA -#endif -static const bool have_percpu_arena = -#ifdef JEMALLOC_PERCPU_ARENA - true -#else - false -#endif - ; - -#if (defined(JEMALLOC_OSATOMIC) || defined(JEMALLOC_OSSPIN)) -#include -#endif - -#ifdef JEMALLOC_ZONE -#include -#include -#include -#endif - -/* - * jemalloc can conceptually be broken into components (arena, tcache, etc.), - * but there are circular dependencies that cannot be broken without - * substantial performance degradation. - * - * Historically, we dealt with this by each header into four sections (types, - * structs, externs, and inlines), and included each header file multiple times - * in this file, picking out the portion we want on each pass using the - * following #defines: - * JEMALLOC_H_TYPES : Preprocessor-defined constants and psuedo-opaque data - * types. - * JEMALLOC_H_STRUCTS : Data structures. - * JEMALLOC_H_EXTERNS : Extern data declarations and function prototypes. - * JEMALLOC_H_INLINES : Inline functions. - * - * We're moving toward a world in which the dependencies are explicit; each file - * will #include the headers it depends on (rather than relying on them being - * implicitly available via this file including every header file in the - * project). - * - * We're now in an intermediate state: we've broken up the header files to avoid - * having to include each one multiple times, but have not yet moved the - * dependency information into the header files (i.e. we still rely on the - * ordering in this file to ensure all a header's dependencies are available in - * its translation unit). Each component is now broken up into multiple header - * files, corresponding to the sections above (e.g. instead of "tsd.h", we now - * have "tsd_types.h", "tsd_structs.h", "tsd_externs.h", "tsd_inlines.h"). - * - * Those files which have been converted to explicitly include their - * inter-component dependencies are now in the initial HERMETIC HEADERS - * section. These headers may still rely on this file for system headers and - * global jemalloc headers, however. - */ - -#include "jemalloc/internal/jemalloc_internal_macros.h" - -/******************************************************************************/ -/* HERMETIC HEADERS */ -/******************************************************************************/ - -#include "jemalloc/internal/assert.h" -#include "jemalloc/internal/atomic.h" -#include "jemalloc/internal/bit_util.h" -#include "jemalloc/internal/malloc_io.h" -#include "jemalloc/internal/util.h" - -/******************************************************************************/ -/* TYPES */ -/******************************************************************************/ - -/* Page size index type. */ -typedef unsigned pszind_t; - -/* Size class index type. */ -typedef unsigned szind_t; - -/* Processor / core id type. */ -typedef int malloc_cpuid_t; - -/* - * Flags bits: - * - * a: arena - * t: tcache - * 0: unused - * z: zero - * n: alignment - * - * aaaaaaaa aaaatttt tttttttt 0znnnnnn - */ -#define MALLOCX_ARENA_BITS 12 -#define MALLOCX_TCACHE_BITS 12 -#define MALLOCX_LG_ALIGN_BITS 6 -#define MALLOCX_ARENA_SHIFT 20 -#define MALLOCX_TCACHE_SHIFT 8 -#define MALLOCX_ARENA_MASK \ - (((1 << MALLOCX_ARENA_BITS) - 1) << MALLOCX_ARENA_SHIFT) -/* NB: Arena index bias decreases the maximum number of arenas by 1. */ -#define MALLOCX_ARENA_MAX ((1 << MALLOCX_ARENA_BITS) - 2) -#define MALLOCX_TCACHE_MASK \ - (((1 << MALLOCX_TCACHE_BITS) - 1) << MALLOCX_TCACHE_SHIFT) -#define MALLOCX_TCACHE_MAX ((1 << MALLOCX_TCACHE_BITS) - 3) -#define MALLOCX_LG_ALIGN_MASK ((1 << MALLOCX_LG_ALIGN_BITS) - 1) -/* Use MALLOCX_ALIGN_GET() if alignment may not be specified in flags. */ -#define MALLOCX_ALIGN_GET_SPECIFIED(flags) \ - (ZU(1) << (flags & MALLOCX_LG_ALIGN_MASK)) -#define MALLOCX_ALIGN_GET(flags) \ - (MALLOCX_ALIGN_GET_SPECIFIED(flags) & (SIZE_T_MAX-1)) -#define MALLOCX_ZERO_GET(flags) \ - ((bool)(flags & MALLOCX_ZERO)) - -#define MALLOCX_TCACHE_GET(flags) \ - (((unsigned)((flags & MALLOCX_TCACHE_MASK) >> MALLOCX_TCACHE_SHIFT)) - 2) -#define MALLOCX_ARENA_GET(flags) \ - (((unsigned)(((unsigned)flags) >> MALLOCX_ARENA_SHIFT)) - 1) - -/* Smallest size class to support. */ -#define TINY_MIN (1U << LG_TINY_MIN) - -/* - * Minimum allocation alignment is 2^LG_QUANTUM bytes (ignoring tiny size - * classes). - */ -#ifndef LG_QUANTUM -# if (defined(__i386__) || defined(_M_IX86)) -# define LG_QUANTUM 4 -# endif -# ifdef __ia64__ -# define LG_QUANTUM 4 -# endif -# ifdef __alpha__ -# define LG_QUANTUM 4 -# endif -# if (defined(__sparc64__) || defined(__sparcv9) || defined(__sparc_v9__)) -# define LG_QUANTUM 4 -# endif -# if (defined(__amd64__) || defined(__x86_64__) || defined(_M_X64)) -# define LG_QUANTUM 4 -# endif -# ifdef __arm__ -# define LG_QUANTUM 3 -# endif -# ifdef __aarch64__ -# define LG_QUANTUM 4 -# endif -# ifdef __hppa__ -# define LG_QUANTUM 4 -# endif -# ifdef __mips__ -# define LG_QUANTUM 3 -# endif -# ifdef __or1k__ -# define LG_QUANTUM 3 -# endif -# ifdef __powerpc__ -# define LG_QUANTUM 4 -# endif -# ifdef __riscv__ -# define LG_QUANTUM 4 -# endif -# ifdef __s390__ -# define LG_QUANTUM 4 -# endif -# ifdef __SH4__ -# define LG_QUANTUM 4 -# endif -# ifdef __tile__ -# define LG_QUANTUM 4 -# endif -# ifdef __le32__ -# define LG_QUANTUM 4 -# endif -# ifndef LG_QUANTUM -# error "Unknown minimum alignment for architecture; specify via " - "--with-lg-quantum" -# endif -#endif - -#define QUANTUM ((size_t)(1U << LG_QUANTUM)) -#define QUANTUM_MASK (QUANTUM - 1) - -/* Return the smallest quantum multiple that is >= a. */ -#define QUANTUM_CEILING(a) \ - (((a) + QUANTUM_MASK) & ~QUANTUM_MASK) - -#define LONG ((size_t)(1U << LG_SIZEOF_LONG)) -#define LONG_MASK (LONG - 1) - -/* Return the smallest long multiple that is >= a. */ -#define LONG_CEILING(a) \ - (((a) + LONG_MASK) & ~LONG_MASK) - -#define SIZEOF_PTR (1U << LG_SIZEOF_PTR) -#define PTR_MASK (SIZEOF_PTR - 1) - -/* Return the smallest (void *) multiple that is >= a. */ -#define PTR_CEILING(a) \ - (((a) + PTR_MASK) & ~PTR_MASK) - -/* - * Maximum size of L1 cache line. This is used to avoid cache line aliasing. - * In addition, this controls the spacing of cacheline-spaced size classes. - * - * CACHELINE cannot be based on LG_CACHELINE because __declspec(align()) can - * only handle raw constants. - */ -#define LG_CACHELINE 6 -#define CACHELINE 64 -#define CACHELINE_MASK (CACHELINE - 1) - -/* Return the smallest cacheline multiple that is >= s. */ -#define CACHELINE_CEILING(s) \ - (((s) + CACHELINE_MASK) & ~CACHELINE_MASK) - -/* Return the nearest aligned address at or below a. */ -#define ALIGNMENT_ADDR2BASE(a, alignment) \ - ((void *)((uintptr_t)(a) & ((~(alignment)) + 1))) - -/* Return the offset between a and the nearest aligned address at or below a. */ -#define ALIGNMENT_ADDR2OFFSET(a, alignment) \ - ((size_t)((uintptr_t)(a) & (alignment - 1))) - -/* Return the smallest alignment multiple that is >= s. */ -#define ALIGNMENT_CEILING(s, alignment) \ - (((s) + (alignment - 1)) & ((~(alignment)) + 1)) - -/* Declare a variable-length array. */ -#if __STDC_VERSION__ < 199901L -# ifdef _MSC_VER -# include -# define alloca _alloca -# else -# ifdef JEMALLOC_HAS_ALLOCA_H -# include -# else -# include -# endif -# endif -# define VARIABLE_ARRAY(type, name, count) \ - type *name = alloca(sizeof(type) * (count)) -#else -# define VARIABLE_ARRAY(type, name, count) type name[(count)] -#endif - -#include "jemalloc/internal/nstime_types.h" -#include "jemalloc/internal/spin_types.h" -#include "jemalloc/internal/prng_types.h" -#include "jemalloc/internal/ticker_types.h" -#include "jemalloc/internal/ckh_types.h" -#include "jemalloc/internal/size_classes.h" -#include "jemalloc/internal/smoothstep.h" -#include "jemalloc/internal/stats_types.h" -#include "jemalloc/internal/ctl_types.h" -#include "jemalloc/internal/witness_types.h" -#include "jemalloc/internal/mutex_types.h" -#include "jemalloc/internal/tsd_types.h" -#include "jemalloc/internal/extent_types.h" -#include "jemalloc/internal/extent_dss_types.h" -#include "jemalloc/internal/base_types.h" -#include "jemalloc/internal/arena_types.h" -#include "jemalloc/internal/bitmap_types.h" -#include "jemalloc/internal/rtree_types.h" -#include "jemalloc/internal/pages_types.h" -#include "jemalloc/internal/tcache_types.h" -#include "jemalloc/internal/prof_types.h" - - -/******************************************************************************/ -/* STRUCTS */ -/******************************************************************************/ - -#include "jemalloc/internal/nstime_structs.h" -#include "jemalloc/internal/spin_structs.h" -#include "jemalloc/internal/ticker_structs.h" -#include "jemalloc/internal/ckh_structs.h" -#include "jemalloc/internal/witness_structs.h" -#include "jemalloc/internal/mutex_structs.h" -#include "jemalloc/internal/stats_structs.h" -#include "jemalloc/internal/ctl_structs.h" -#include "jemalloc/internal/bitmap_structs.h" -#include "jemalloc/internal/arena_structs_a.h" -#include "jemalloc/internal/extent_structs.h" -#include "jemalloc/internal/extent_dss_structs.h" -#include "jemalloc/internal/base_structs.h" -#include "jemalloc/internal/prof_structs.h" -#include "jemalloc/internal/arena_structs_b.h" -#include "jemalloc/internal/rtree_structs.h" -#include "jemalloc/internal/tcache_structs.h" -#include "jemalloc/internal/tsd_structs.h" - - -/******************************************************************************/ -/* EXTERNS */ -/******************************************************************************/ - -extern bool opt_abort; -extern const char *opt_junk; -extern bool opt_junk_alloc; -extern bool opt_junk_free; -extern bool opt_utrace; -extern bool opt_xmalloc; -extern bool opt_zero; -extern unsigned opt_narenas; - -/* Number of CPUs. */ -extern unsigned ncpus; - -/* Number of arenas used for automatic multiplexing of threads and arenas. */ -extern unsigned narenas_auto; - -/* - * Arenas that are used to service external requests. Not all elements of the - * arenas array are necessarily used; arenas are created lazily as needed. - */ -extern atomic_p_t arenas[]; - -/* - * pind2sz_tab encodes the same information as could be computed by - * pind2sz_compute(). - */ -extern size_t const pind2sz_tab[NPSIZES+1]; -/* - * index2size_tab encodes the same information as could be computed (at - * unacceptable cost in some code paths) by index2size_compute(). - */ -extern size_t const index2size_tab[NSIZES]; -/* - * size2index_tab is a compact lookup table that rounds request sizes up to - * size classes. In order to reduce cache footprint, the table is compressed, - * and all accesses are via size2index(). - */ -extern uint8_t const size2index_tab[]; - -void *a0malloc(size_t size); -void a0dalloc(void *ptr); -void *bootstrap_malloc(size_t size); -void *bootstrap_calloc(size_t num, size_t size); -void bootstrap_free(void *ptr); -void arena_set(unsigned ind, arena_t *arena); -unsigned narenas_total_get(void); -arena_t *arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); -arena_tdata_t *arena_tdata_get_hard(tsd_t *tsd, unsigned ind); -arena_t *arena_choose_hard(tsd_t *tsd, bool internal); -void arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind); -void iarena_cleanup(tsd_t *tsd); -void arena_cleanup(tsd_t *tsd); -void arenas_tdata_cleanup(tsd_t *tsd); -void jemalloc_prefork(void); -void jemalloc_postfork_parent(void); -void jemalloc_postfork_child(void); -bool malloc_initialized(void); - -#include "jemalloc/internal/nstime_externs.h" -#include "jemalloc/internal/ckh_externs.h" -#include "jemalloc/internal/stats_externs.h" -#include "jemalloc/internal/ctl_externs.h" -#include "jemalloc/internal/witness_externs.h" -#include "jemalloc/internal/mutex_externs.h" -#include "jemalloc/internal/bitmap_externs.h" -#include "jemalloc/internal/extent_externs.h" -#include "jemalloc/internal/extent_dss_externs.h" -#include "jemalloc/internal/extent_mmap_externs.h" -#include "jemalloc/internal/base_externs.h" -#include "jemalloc/internal/arena_externs.h" -#include "jemalloc/internal/rtree_externs.h" -#include "jemalloc/internal/pages_externs.h" -#include "jemalloc/internal/large_externs.h" -#include "jemalloc/internal/tcache_externs.h" -#include "jemalloc/internal/prof_externs.h" -#include "jemalloc/internal/tsd_externs.h" - -/******************************************************************************/ -/* INLINES */ -/******************************************************************************/ - -#include "jemalloc/internal/spin_inlines.h" -#include "jemalloc/internal/prng_inlines.h" -#include "jemalloc/internal/ticker_inlines.h" -#include "jemalloc/internal/tsd_inlines.h" -#include "jemalloc/internal/witness_inlines.h" -#include "jemalloc/internal/mutex_inlines.h" - -#ifndef JEMALLOC_ENABLE_INLINE -pszind_t psz2ind(size_t psz); -size_t pind2sz_compute(pszind_t pind); -size_t pind2sz_lookup(pszind_t pind); -size_t pind2sz(pszind_t pind); -size_t psz2u(size_t psz); -szind_t size2index_compute(size_t size); -szind_t size2index_lookup(size_t size); -szind_t size2index(size_t size); -size_t index2size_compute(szind_t index); -size_t index2size_lookup(szind_t index); -size_t index2size(szind_t index); -size_t s2u_compute(size_t size); -size_t s2u_lookup(size_t size); -size_t s2u(size_t size); -size_t sa2u(size_t size, size_t alignment); -arena_t *arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal); -arena_t *arena_choose(tsd_t *tsd, arena_t *arena); -arena_t *arena_ichoose(tsd_t *tsd, arena_t *arena); -arena_tdata_t *arena_tdata_get(tsd_t *tsd, unsigned ind, - bool refresh_if_missing); -arena_t *arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing); -ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind); -bool tcache_available(tsd_t *tsd); -tcache_bin_t *tcache_small_bin_get(tcache_t *tcache, szind_t binind); -tcache_bin_t *tcache_large_bin_get(tcache_t *tcache, szind_t binind); -tcache_t *tcache_get(tsd_t *tsd); -malloc_cpuid_t malloc_getcpu(void); -unsigned percpu_arena_choose(void); -unsigned percpu_arena_ind_limit(void); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) -JEMALLOC_ALWAYS_INLINE pszind_t -psz2ind(size_t psz) { - if (unlikely(psz > LARGE_MAXCLASS)) { - return NPSIZES; - } - { - pszind_t x = lg_floor((psz<<1)-1); - pszind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_PAGE) ? 0 : x - - (LG_SIZE_CLASS_GROUP + LG_PAGE); - pszind_t grp = shift << LG_SIZE_CLASS_GROUP; - - pszind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? - LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1; - - size_t delta_inverse_mask = ZD(-1) << lg_delta; - pszind_t mod = ((((psz-1) & delta_inverse_mask) >> lg_delta)) & - ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); - - pszind_t ind = grp + mod; - return ind; - } -} - -JEMALLOC_INLINE size_t -pind2sz_compute(pszind_t pind) { - if (unlikely(pind == NPSIZES)) { - return LARGE_MAXCLASS + PAGE; - } - { - size_t grp = pind >> LG_SIZE_CLASS_GROUP; - size_t mod = pind & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); - - size_t grp_size_mask = ~((!!grp)-1); - size_t grp_size = ((ZU(1) << (LG_PAGE + - (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask; - - size_t shift = (grp == 0) ? 1 : grp; - size_t lg_delta = shift + (LG_PAGE-1); - size_t mod_size = (mod+1) << lg_delta; - - size_t sz = grp_size + mod_size; - return sz; - } -} - -JEMALLOC_INLINE size_t -pind2sz_lookup(pszind_t pind) { - size_t ret = (size_t)pind2sz_tab[pind]; - assert(ret == pind2sz_compute(pind)); - return ret; -} - -JEMALLOC_INLINE size_t -pind2sz(pszind_t pind) { - assert(pind < NPSIZES+1); - return pind2sz_lookup(pind); -} - -JEMALLOC_INLINE size_t -psz2u(size_t psz) { - if (unlikely(psz > LARGE_MAXCLASS)) { - return LARGE_MAXCLASS + PAGE; - } - { - size_t x = lg_floor((psz<<1)-1); - size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? - LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1; - size_t delta = ZU(1) << lg_delta; - size_t delta_mask = delta - 1; - size_t usize = (psz + delta_mask) & ~delta_mask; - return usize; - } -} - -JEMALLOC_INLINE szind_t -size2index_compute(size_t size) { - if (unlikely(size > LARGE_MAXCLASS)) { - return NSIZES; - } -#if (NTBINS != 0) - if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { - szind_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; - szind_t lg_ceil = lg_floor(pow2_ceil_zu(size)); - return (lg_ceil < lg_tmin ? 0 : lg_ceil - lg_tmin); - } -#endif - { - szind_t x = lg_floor((size<<1)-1); - szind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM) ? 0 : - x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM); - szind_t grp = shift << LG_SIZE_CLASS_GROUP; - - szind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) - ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; - - size_t delta_inverse_mask = ZD(-1) << lg_delta; - szind_t mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) & - ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); - - szind_t index = NTBINS + grp + mod; - return index; - } -} - -JEMALLOC_ALWAYS_INLINE szind_t -size2index_lookup(size_t size) { - assert(size <= LOOKUP_MAXCLASS); - { - szind_t ret = (size2index_tab[(size-1) >> LG_TINY_MIN]); - assert(ret == size2index_compute(size)); - return ret; - } -} - -JEMALLOC_ALWAYS_INLINE szind_t -size2index(size_t size) { - assert(size > 0); - if (likely(size <= LOOKUP_MAXCLASS)) { - return size2index_lookup(size); - } - return size2index_compute(size); -} - -JEMALLOC_INLINE size_t -index2size_compute(szind_t index) { -#if (NTBINS > 0) - if (index < NTBINS) { - return (ZU(1) << (LG_TINY_MAXCLASS - NTBINS + 1 + index)); - } -#endif - { - size_t reduced_index = index - NTBINS; - size_t grp = reduced_index >> LG_SIZE_CLASS_GROUP; - size_t mod = reduced_index & ((ZU(1) << LG_SIZE_CLASS_GROUP) - - 1); - - size_t grp_size_mask = ~((!!grp)-1); - size_t grp_size = ((ZU(1) << (LG_QUANTUM + - (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask; - - size_t shift = (grp == 0) ? 1 : grp; - size_t lg_delta = shift + (LG_QUANTUM-1); - size_t mod_size = (mod+1) << lg_delta; - - size_t usize = grp_size + mod_size; - return usize; - } -} - -JEMALLOC_ALWAYS_INLINE size_t -index2size_lookup(szind_t index) { - size_t ret = (size_t)index2size_tab[index]; - assert(ret == index2size_compute(index)); - return ret; -} - -JEMALLOC_ALWAYS_INLINE size_t -index2size(szind_t index) { - assert(index < NSIZES); - return index2size_lookup(index); -} - -JEMALLOC_ALWAYS_INLINE size_t -s2u_compute(size_t size) { - if (unlikely(size > LARGE_MAXCLASS)) { - return 0; - } -#if (NTBINS > 0) - if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { - size_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; - size_t lg_ceil = lg_floor(pow2_ceil_zu(size)); - return (lg_ceil < lg_tmin ? (ZU(1) << lg_tmin) : - (ZU(1) << lg_ceil)); - } -#endif - { - size_t x = lg_floor((size<<1)-1); - size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) - ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; - size_t delta = ZU(1) << lg_delta; - size_t delta_mask = delta - 1; - size_t usize = (size + delta_mask) & ~delta_mask; - return usize; - } -} - -JEMALLOC_ALWAYS_INLINE size_t -s2u_lookup(size_t size) { - size_t ret = index2size_lookup(size2index_lookup(size)); - - assert(ret == s2u_compute(size)); - return ret; -} - -/* - * Compute usable size that would result from allocating an object with the - * specified size. - */ -JEMALLOC_ALWAYS_INLINE size_t -s2u(size_t size) { - assert(size > 0); - if (likely(size <= LOOKUP_MAXCLASS)) { - return s2u_lookup(size); - } - return s2u_compute(size); -} - -/* - * Compute usable size that would result from allocating an object with the - * specified size and alignment. - */ -JEMALLOC_ALWAYS_INLINE size_t -sa2u(size_t size, size_t alignment) { - size_t usize; - - assert(alignment != 0 && ((alignment - 1) & alignment) == 0); - - /* Try for a small size class. */ - if (size <= SMALL_MAXCLASS && alignment < PAGE) { - /* - * Round size up to the nearest multiple of alignment. - * - * This done, we can take advantage of the fact that for each - * small size class, every object is aligned at the smallest - * power of two that is non-zero in the base two representation - * of the size. For example: - * - * Size | Base 2 | Minimum alignment - * -----+----------+------------------ - * 96 | 1100000 | 32 - * 144 | 10100000 | 32 - * 192 | 11000000 | 64 - */ - usize = s2u(ALIGNMENT_CEILING(size, alignment)); - if (usize < LARGE_MINCLASS) { - return usize; - } - } - - /* Large size class. Beware of overflow. */ - - if (unlikely(alignment > LARGE_MAXCLASS)) { - return 0; - } - - /* Make sure result is a large size class. */ - if (size <= LARGE_MINCLASS) { - usize = LARGE_MINCLASS; - } else { - usize = s2u(size); - if (usize < size) { - /* size_t overflow. */ - return 0; - } - } - - /* - * Calculate the multi-page mapping that large_palloc() would need in - * order to guarantee the alignment. - */ - if (usize + large_pad + PAGE_CEILING(alignment) - PAGE < usize) { - /* size_t overflow. */ - return 0; - } - return usize; -} - -JEMALLOC_ALWAYS_INLINE malloc_cpuid_t -malloc_getcpu(void) { - assert(have_percpu_arena); -#if defined(JEMALLOC_HAVE_SCHED_GETCPU) - return (malloc_cpuid_t)sched_getcpu(); -#else - not_reached(); - return -1; -#endif -} - -/* Return the chosen arena index based on current cpu. */ -JEMALLOC_ALWAYS_INLINE unsigned -percpu_arena_choose(void) { - unsigned arena_ind; - assert(have_percpu_arena && (percpu_arena_mode != percpu_arena_disabled)); - - malloc_cpuid_t cpuid = malloc_getcpu(); - assert(cpuid >= 0); - if ((percpu_arena_mode == percpu_arena) || - ((unsigned)cpuid < ncpus / 2)) { - arena_ind = cpuid; - } else { - assert(percpu_arena_mode == per_phycpu_arena); - /* Hyper threads on the same physical CPU share arena. */ - arena_ind = cpuid - ncpus / 2; - } - - return arena_ind; -} - -/* Return the limit of percpu auto arena range, i.e. arenas[0...ind_limit). */ -JEMALLOC_ALWAYS_INLINE unsigned -percpu_arena_ind_limit(void) { - assert(have_percpu_arena && (percpu_arena_mode != percpu_arena_disabled)); - if (percpu_arena_mode == per_phycpu_arena && ncpus > 1) { - if (ncpus % 2) { - /* This likely means a misconfig. */ - return ncpus / 2 + 1; - } - return ncpus / 2; - } else { - return ncpus; - } -} - -JEMALLOC_INLINE arena_tdata_t * -arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing) { - arena_tdata_t *tdata; - arena_tdata_t *arenas_tdata = tsd_arenas_tdata_get(tsd); - - if (unlikely(arenas_tdata == NULL)) { - /* arenas_tdata hasn't been initialized yet. */ - return arena_tdata_get_hard(tsd, ind); - } - if (unlikely(ind >= tsd_narenas_tdata_get(tsd))) { - /* - * ind is invalid, cache is old (too small), or tdata to be - * initialized. - */ - return (refresh_if_missing ? arena_tdata_get_hard(tsd, ind) : - NULL); - } - - tdata = &arenas_tdata[ind]; - if (likely(tdata != NULL) || !refresh_if_missing) { - return tdata; - } - return arena_tdata_get_hard(tsd, ind); -} - -JEMALLOC_INLINE arena_t * -arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing) { - arena_t *ret; - - assert(ind <= MALLOCX_ARENA_MAX); - - ret = (arena_t *)atomic_load_p(&arenas[ind], ATOMIC_ACQUIRE); - if (unlikely(ret == NULL)) { - if (init_if_missing) { - ret = arena_init(tsdn, ind, - (extent_hooks_t *)&extent_hooks_default); - } - } - return ret; -} - -JEMALLOC_INLINE ticker_t * -decay_ticker_get(tsd_t *tsd, unsigned ind) { - arena_tdata_t *tdata; - - tdata = arena_tdata_get(tsd, ind, true); - if (unlikely(tdata == NULL)) { - return NULL; - } - return &tdata->decay_ticker; -} - -JEMALLOC_ALWAYS_INLINE tcache_bin_t * -tcache_small_bin_get(tcache_t *tcache, szind_t binind) { - assert(binind < NBINS); - return &tcache->tbins_small[binind]; -} - -JEMALLOC_ALWAYS_INLINE tcache_bin_t * -tcache_large_bin_get(tcache_t *tcache, szind_t binind) { - assert(binind >= NBINS &&binind < nhbins); - return &tcache->tbins_large[binind - NBINS]; -} - -JEMALLOC_ALWAYS_INLINE bool -tcache_available(tsd_t *tsd) { - cassert(config_tcache); - - /* - * Thread specific auto tcache might be unavailable if: 1) during tcache - * initialization, or 2) disabled through thread.tcache.enabled mallctl - * or config options. This check covers all cases. - */ - if (likely(tsd_tcache_enabled_get(tsd) == true)) { - /* Associated arena == null implies tcache init in progress. */ - if (tsd_tcachep_get(tsd)->arena != NULL) { - assert(tcache_small_bin_get(tsd_tcachep_get(tsd), - 0)->avail != NULL); - } - return true; - } - - return false; -} - -JEMALLOC_ALWAYS_INLINE tcache_t * -tcache_get(tsd_t *tsd) { - if (!config_tcache) { - return NULL; - } - if (!tcache_available(tsd)) { - return NULL; - } - - return tsd_tcachep_get(tsd); -} -#endif - -#include "jemalloc/internal/rtree_inlines.h" -#include "jemalloc/internal/base_inlines.h" -#include "jemalloc/internal/bitmap_inlines.h" -/* - * Include portions of arena code interleaved with tcache code in order to - * resolve circular dependencies. - */ -#include "jemalloc/internal/prof_inlines_a.h" -#include "jemalloc/internal/arena_inlines_a.h" -#include "jemalloc/internal/extent_inlines.h" - -#ifndef JEMALLOC_ENABLE_INLINE -extent_t *iealloc(tsdn_t *tsdn, const void *ptr); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) -/* Choose an arena based on a per-thread value. */ -JEMALLOC_INLINE arena_t * -arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { - arena_t *ret; - - if (arena != NULL) { - return arena; - } - - /* During reentrancy, arena 0 is the safest bet. */ - if (*tsd_reentrancy_levelp_get(tsd) > 1) { - return arena_get(tsd_tsdn(tsd), 0, true); - } - - ret = internal ? tsd_iarena_get(tsd) : tsd_arena_get(tsd); - if (unlikely(ret == NULL)) { - ret = arena_choose_hard(tsd, internal); - assert(ret); - if (config_tcache && tcache_available(tsd)) { - tcache_t *tcache = tcache_get(tsd); - if (tcache->arena != NULL) { - /* See comments in tcache_data_init().*/ - assert(tcache->arena == - arena_get(tsd_tsdn(tsd), 0, false)); - if (tcache->arena != ret) { - tcache_arena_reassociate(tsd_tsdn(tsd), - tcache, ret); - } - } else { - tcache_arena_associate(tsd_tsdn(tsd), tcache, - ret); - } - } - } - - /* - * Note that for percpu arena, if the current arena is outside of the - * auto percpu arena range, (i.e. thread is assigned to a manually - * managed arena), then percpu arena is skipped. - */ - if (have_percpu_arena && (percpu_arena_mode != percpu_arena_disabled) && - (arena_ind_get(ret) < percpu_arena_ind_limit()) && - (ret->last_thd != tsd_tsdn(tsd))) { - unsigned ind = percpu_arena_choose(); - if (arena_ind_get(ret) != ind) { - percpu_arena_update(tsd, ind); - ret = tsd_arena_get(tsd); - } - ret->last_thd = tsd_tsdn(tsd); - } - - return ret; -} - -JEMALLOC_INLINE arena_t * -arena_choose(tsd_t *tsd, arena_t *arena) { - return arena_choose_impl(tsd, arena, false); -} - -JEMALLOC_INLINE arena_t * -arena_ichoose(tsd_t *tsd, arena_t *arena) { - return arena_choose_impl(tsd, arena, true); -} - -JEMALLOC_ALWAYS_INLINE extent_t * -iealloc(tsdn_t *tsdn, const void *ptr) { - rtree_ctx_t rtree_ctx_fallback; - rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - - return rtree_extent_read(tsdn, &extents_rtree, rtree_ctx, - (uintptr_t)ptr, true); -} -#endif - -#include "jemalloc/internal/tcache_inlines.h" -#include "jemalloc/internal/arena_inlines_b.h" -#include "jemalloc/internal/hash_inlines.h" - -#ifndef JEMALLOC_ENABLE_INLINE -arena_t *iaalloc(tsdn_t *tsdn, const void *ptr); -size_t isalloc(tsdn_t *tsdn, const void *ptr); -void *iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, - tcache_t *tcache, bool is_internal, arena_t *arena, bool slow_path); -void *ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, - bool slow_path); -void *ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, - tcache_t *tcache, bool is_internal, arena_t *arena); -void *ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, - tcache_t *tcache, arena_t *arena); -void *ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero); -size_t ivsalloc(tsdn_t *tsdn, const void *ptr); -void idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, - dalloc_ctx_t *dalloc_ctx, bool is_internal, bool slow_path); -void idalloc(tsd_t *tsd, void *ptr); -void isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - bool slow_path); -void *iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, - size_t extra, size_t alignment, bool zero, tcache_t *tcache, - arena_t *arena); -void *iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, - size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); -void *iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, - size_t alignment, bool zero); -bool ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, - size_t alignment, bool zero); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) -JEMALLOC_ALWAYS_INLINE arena_t * -iaalloc(tsdn_t *tsdn, const void *ptr) { - assert(ptr != NULL); - - return arena_aalloc(tsdn, ptr); -} - -JEMALLOC_ALWAYS_INLINE size_t -isalloc(tsdn_t *tsdn, const void *ptr) { - assert(ptr != NULL); - - return arena_salloc(tsdn, ptr); -} - -JEMALLOC_ALWAYS_INLINE void * -iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, - bool is_internal, arena_t *arena, bool slow_path) { - void *ret; - - assert(size != 0); - assert(!is_internal || tcache == NULL); - assert(!is_internal || arena == NULL || arena_ind_get(arena) < - narenas_auto); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - - ret = arena_malloc(tsdn, arena, size, ind, zero, tcache, slow_path); - if (config_stats && is_internal && likely(ret != NULL)) { - arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn, ret)); - } - return ret; -} - -JEMALLOC_ALWAYS_INLINE void * -ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, bool slow_path) { - return iallocztm(tsd_tsdn(tsd), size, ind, zero, tcache_get(tsd), false, - NULL, slow_path); -} - -JEMALLOC_ALWAYS_INLINE void * -ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, - tcache_t *tcache, bool is_internal, arena_t *arena) { - void *ret; - - assert(usize != 0); - assert(usize == sa2u(usize, alignment)); - assert(!is_internal || tcache == NULL); - assert(!is_internal || arena == NULL || arena_ind_get(arena) < - narenas_auto); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - - ret = arena_palloc(tsdn, arena, usize, alignment, zero, tcache); - assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret); - if (config_stats && is_internal && likely(ret != NULL)) { - arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn, ret)); - } - return ret; -} - -JEMALLOC_ALWAYS_INLINE void * -ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, - tcache_t *tcache, arena_t *arena) { - return ipallocztm(tsdn, usize, alignment, zero, tcache, false, arena); -} - -JEMALLOC_ALWAYS_INLINE void * -ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero) { - return ipallocztm(tsd_tsdn(tsd), usize, alignment, zero, - tcache_get(tsd), false, NULL); -} - -JEMALLOC_ALWAYS_INLINE size_t -ivsalloc(tsdn_t *tsdn, const void *ptr) { - return arena_vsalloc(tsdn, ptr); -} - -JEMALLOC_ALWAYS_INLINE void -idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, dalloc_ctx_t *dalloc_ctx, - bool is_internal, bool slow_path) { - assert(ptr != NULL); - assert(!is_internal || tcache == NULL); - assert(!is_internal || arena_ind_get(iaalloc(tsdn, ptr)) < - narenas_auto); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - if (config_stats && is_internal) { - arena_internal_sub(iaalloc(tsdn, ptr), isalloc(tsdn, ptr)); - } - if (!is_internal && *tsd_reentrancy_levelp_get(tsdn_tsd(tsdn)) != 0) { - tcache = NULL; - } - arena_dalloc(tsdn, ptr, tcache, dalloc_ctx, slow_path); -} - -JEMALLOC_ALWAYS_INLINE void -idalloc(tsd_t *tsd, void *ptr) { - idalloctm(tsd_tsdn(tsd), ptr, tcache_get(tsd), NULL, false, true); -} - -JEMALLOC_ALWAYS_INLINE void -isdalloct(tsdn_t *tsdn, void *ptr, size_t size, - tcache_t *tcache, bool slow_path) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - arena_sdalloc(tsdn, ptr, size, tcache, slow_path); -} - -JEMALLOC_ALWAYS_INLINE void * -iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, - size_t extra, size_t alignment, bool zero, tcache_t *tcache, - arena_t *arena) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - void *p; - size_t usize, copysize; - - usize = sa2u(size + extra, alignment); - if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { - return NULL; - } - p = ipalloct(tsdn, usize, alignment, zero, tcache, arena); - if (p == NULL) { - if (extra == 0) { - return NULL; - } - /* Try again, without extra this time. */ - usize = sa2u(size, alignment); - if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { - return NULL; - } - p = ipalloct(tsdn, usize, alignment, zero, tcache, arena); - if (p == NULL) { - return NULL; - } - } - /* - * Copy at most size bytes (not size+extra), since the caller has no - * expectation that the extra bytes will be reliably preserved. - */ - copysize = (size < oldsize) ? size : oldsize; - memcpy(p, ptr, copysize); - isdalloct(tsdn, ptr, oldsize, tcache, true); - return p; -} - -JEMALLOC_ALWAYS_INLINE void * -iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment, - bool zero, tcache_t *tcache, arena_t *arena) { - assert(ptr != NULL); - assert(size != 0); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - - if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1)) - != 0) { - /* - * Existing object alignment is inadequate; allocate new space - * and copy. - */ - return iralloct_realign(tsdn, ptr, oldsize, size, 0, alignment, - zero, tcache, arena); - } - - return arena_ralloc(tsdn, arena, ptr, oldsize, size, alignment, zero, - tcache); -} - -JEMALLOC_ALWAYS_INLINE void * -iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment, - bool zero) { - return iralloct(tsd_tsdn(tsd), ptr, oldsize, size, alignment, zero, - tcache_get(tsd), NULL); -} - -JEMALLOC_ALWAYS_INLINE bool -ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, - size_t alignment, bool zero) { - assert(ptr != NULL); - assert(size != 0); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - - if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1)) - != 0) { - /* Existing object alignment is inadequate. */ - return true; - } - - return arena_ralloc_no_move(tsdn, ptr, oldsize, size, extra, zero); -} -#endif - -#include "jemalloc/internal/prof_inlines_b.h" - -CPP_EPILOGUE - -#endif /* JEMALLOC_INTERNAL_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_externs.h b/include/jemalloc/internal/jemalloc_internal_externs.h new file mode 100644 index 00000000..7ac39bea --- /dev/null +++ b/include/jemalloc/internal/jemalloc_internal_externs.h @@ -0,0 +1,61 @@ +#ifndef JEMALLOC_INTERNAL_EXTERNS_H +#define JEMALLOC_INTERNAL_EXTERNS_H + +extern bool opt_abort; +extern const char *opt_junk; +extern bool opt_junk_alloc; +extern bool opt_junk_free; +extern bool opt_utrace; +extern bool opt_xmalloc; +extern bool opt_zero; +extern unsigned opt_narenas; + +/* Number of CPUs. */ +extern unsigned ncpus; + +/* Number of arenas used for automatic multiplexing of threads and arenas. */ +extern unsigned narenas_auto; + +/* + * Arenas that are used to service external requests. Not all elements of the + * arenas array are necessarily used; arenas are created lazily as needed. + */ +extern atomic_p_t arenas[]; + +/* + * pind2sz_tab encodes the same information as could be computed by + * pind2sz_compute(). + */ +extern size_t const pind2sz_tab[NPSIZES+1]; +/* + * index2size_tab encodes the same information as could be computed (at + * unacceptable cost in some code paths) by index2size_compute(). + */ +extern size_t const index2size_tab[NSIZES]; +/* + * size2index_tab is a compact lookup table that rounds request sizes up to + * size classes. In order to reduce cache footprint, the table is compressed, + * and all accesses are via size2index(). + */ +extern uint8_t const size2index_tab[]; + +void *a0malloc(size_t size); +void a0dalloc(void *ptr); +void *bootstrap_malloc(size_t size); +void *bootstrap_calloc(size_t num, size_t size); +void bootstrap_free(void *ptr); +void arena_set(unsigned ind, arena_t *arena); +unsigned narenas_total_get(void); +arena_t *arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); +arena_tdata_t *arena_tdata_get_hard(tsd_t *tsd, unsigned ind); +arena_t *arena_choose_hard(tsd_t *tsd, bool internal); +void arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind); +void iarena_cleanup(tsd_t *tsd); +void arena_cleanup(tsd_t *tsd); +void arenas_tdata_cleanup(tsd_t *tsd); +void jemalloc_prefork(void); +void jemalloc_postfork_parent(void); +void jemalloc_postfork_child(void); +bool malloc_initialized(void); + +#endif /* JEMALLOC_INTERNAL_EXTERNS_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h new file mode 100644 index 00000000..45035137 --- /dev/null +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -0,0 +1,155 @@ +#ifndef JEMALLOC_INTERNAL_INCLUDES_H +#define JEMALLOC_INTERNAL_INCLUDES_H + +/* + * jemalloc can conceptually be broken into components (arena, tcache, etc.), + * but there are circular dependencies that cannot be broken without + * substantial performance degradation. + * + * Historically, we dealt with this by each header into four sections (types, + * structs, externs, and inlines), and included each header file multiple times + * in this file, picking out the portion we want on each pass using the + * following #defines: + * JEMALLOC_H_TYPES : Preprocessor-defined constants and psuedo-opaque data + * types. + * JEMALLOC_H_STRUCTS : Data structures. + * JEMALLOC_H_EXTERNS : Extern data declarations and function prototypes. + * JEMALLOC_H_INLINES : Inline functions. + * + * We're moving toward a world in which the dependencies are explicit; each file + * will #include the headers it depends on (rather than relying on them being + * implicitly available via this file including every header file in the + * project). + * + * We're now in an intermediate state: we've broken up the header files to avoid + * having to include each one multiple times, but have not yet moved the + * dependency information into the header files (i.e. we still rely on the + * ordering in this file to ensure all a header's dependencies are available in + * its translation unit). Each component is now broken up into multiple header + * files, corresponding to the sections above (e.g. instead of "tsd.h", we now + * have "tsd_types.h", "tsd_structs.h", "tsd_externs.h", "tsd_inlines.h"). + * + * Those files which have been converted to explicitly include their + * inter-component dependencies are now in the initial HERMETIC HEADERS + * section. All headers may still rely on jemalloc_preamble.h (which, by fiat, + * must be included first in every translation unit) for system headers and + * global jemalloc definitions, however. + */ + +CPP_PROLOGUE + +/******************************************************************************/ +/* HERMETIC HEADERS */ +/******************************************************************************/ + +#include "jemalloc/internal/assert.h" +#include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/bit_util.h" +#include "jemalloc/internal/malloc_io.h" +#include "jemalloc/internal/util.h" + +/******************************************************************************/ +/* TYPES */ +/******************************************************************************/ + +#include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/nstime_types.h" +#include "jemalloc/internal/spin_types.h" +#include "jemalloc/internal/prng_types.h" +#include "jemalloc/internal/ticker_types.h" +#include "jemalloc/internal/ckh_types.h" +#include "jemalloc/internal/size_classes.h" +#include "jemalloc/internal/smoothstep.h" +#include "jemalloc/internal/stats_types.h" +#include "jemalloc/internal/ctl_types.h" +#include "jemalloc/internal/witness_types.h" +#include "jemalloc/internal/mutex_types.h" +#include "jemalloc/internal/tsd_types.h" +#include "jemalloc/internal/extent_types.h" +#include "jemalloc/internal/extent_dss_types.h" +#include "jemalloc/internal/base_types.h" +#include "jemalloc/internal/arena_types.h" +#include "jemalloc/internal/bitmap_types.h" +#include "jemalloc/internal/rtree_types.h" +#include "jemalloc/internal/pages_types.h" +#include "jemalloc/internal/tcache_types.h" +#include "jemalloc/internal/prof_types.h" + +/******************************************************************************/ +/* STRUCTS */ +/******************************************************************************/ + +#include "jemalloc/internal/nstime_structs.h" +#include "jemalloc/internal/spin_structs.h" +#include "jemalloc/internal/ticker_structs.h" +#include "jemalloc/internal/ckh_structs.h" +#include "jemalloc/internal/witness_structs.h" +#include "jemalloc/internal/mutex_structs.h" +#include "jemalloc/internal/stats_structs.h" +#include "jemalloc/internal/ctl_structs.h" +#include "jemalloc/internal/bitmap_structs.h" +#include "jemalloc/internal/arena_structs_a.h" +#include "jemalloc/internal/extent_structs.h" +#include "jemalloc/internal/extent_dss_structs.h" +#include "jemalloc/internal/base_structs.h" +#include "jemalloc/internal/prof_structs.h" +#include "jemalloc/internal/arena_structs_b.h" +#include "jemalloc/internal/rtree_structs.h" +#include "jemalloc/internal/tcache_structs.h" +#include "jemalloc/internal/tsd_structs.h" + +/******************************************************************************/ +/* EXTERNS */ +/******************************************************************************/ + +#include "jemalloc/internal/jemalloc_internal_externs.h" +#include "jemalloc/internal/nstime_externs.h" +#include "jemalloc/internal/ckh_externs.h" +#include "jemalloc/internal/stats_externs.h" +#include "jemalloc/internal/ctl_externs.h" +#include "jemalloc/internal/witness_externs.h" +#include "jemalloc/internal/mutex_externs.h" +#include "jemalloc/internal/bitmap_externs.h" +#include "jemalloc/internal/extent_externs.h" +#include "jemalloc/internal/extent_dss_externs.h" +#include "jemalloc/internal/extent_mmap_externs.h" +#include "jemalloc/internal/base_externs.h" +#include "jemalloc/internal/arena_externs.h" +#include "jemalloc/internal/rtree_externs.h" +#include "jemalloc/internal/pages_externs.h" +#include "jemalloc/internal/large_externs.h" +#include "jemalloc/internal/tcache_externs.h" +#include "jemalloc/internal/prof_externs.h" +#include "jemalloc/internal/tsd_externs.h" + +/******************************************************************************/ +/* INLINES */ +/******************************************************************************/ + +#include "jemalloc/internal/spin_inlines.h" +#include "jemalloc/internal/prng_inlines.h" +#include "jemalloc/internal/ticker_inlines.h" +#include "jemalloc/internal/tsd_inlines.h" +#include "jemalloc/internal/witness_inlines.h" +#include "jemalloc/internal/mutex_inlines.h" +#include "jemalloc/internal/jemalloc_internal_inlines_a.h" +#include "jemalloc/internal/rtree_inlines.h" +#include "jemalloc/internal/base_inlines.h" +#include "jemalloc/internal/bitmap_inlines.h" +/* + * Include portions of arena code interleaved with tcache code in order to + * resolve circular dependencies. + */ +#include "jemalloc/internal/prof_inlines_a.h" +#include "jemalloc/internal/arena_inlines_a.h" +#include "jemalloc/internal/extent_inlines.h" +#include "jemalloc/internal/jemalloc_internal_inlines_b.h" +#include "jemalloc/internal/tcache_inlines.h" +#include "jemalloc/internal/arena_inlines_b.h" +#include "jemalloc/internal/hash_inlines.h" +#include "jemalloc/internal/jemalloc_internal_inlines_c.h" +#include "jemalloc/internal/prof_inlines_b.h" + +CPP_EPILOGUE + +#endif /* JEMALLOC_INTERNAL_INCLUDES_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_a.h b/include/jemalloc/internal/jemalloc_internal_inlines_a.h new file mode 100644 index 00000000..256329a0 --- /dev/null +++ b/include/jemalloc/internal/jemalloc_internal_inlines_a.h @@ -0,0 +1,448 @@ +#ifndef JEMALLOC_INTERNAL_INLINES_A_H +#define JEMALLOC_INTERNAL_INLINES_A_H + +#ifndef JEMALLOC_ENABLE_INLINE +pszind_t psz2ind(size_t psz); +size_t pind2sz_compute(pszind_t pind); +size_t pind2sz_lookup(pszind_t pind); +size_t pind2sz(pszind_t pind); +size_t psz2u(size_t psz); +szind_t size2index_compute(size_t size); +szind_t size2index_lookup(size_t size); +szind_t size2index(size_t size); +size_t index2size_compute(szind_t index); +size_t index2size_lookup(szind_t index); +size_t index2size(szind_t index); +size_t s2u_compute(size_t size); +size_t s2u_lookup(size_t size); +size_t s2u(size_t size); +size_t sa2u(size_t size, size_t alignment); +arena_t *arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal); +arena_t *arena_choose(tsd_t *tsd, arena_t *arena); +arena_t *arena_ichoose(tsd_t *tsd, arena_t *arena); +arena_tdata_t *arena_tdata_get(tsd_t *tsd, unsigned ind, + bool refresh_if_missing); +arena_t *arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing); +ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind); +bool tcache_available(tsd_t *tsd); +tcache_bin_t *tcache_small_bin_get(tcache_t *tcache, szind_t binind); +tcache_bin_t *tcache_large_bin_get(tcache_t *tcache, szind_t binind); +tcache_t *tcache_get(tsd_t *tsd); +malloc_cpuid_t malloc_getcpu(void); +unsigned percpu_arena_choose(void); +unsigned percpu_arena_ind_limit(void); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) +JEMALLOC_ALWAYS_INLINE pszind_t +psz2ind(size_t psz) { + if (unlikely(psz > LARGE_MAXCLASS)) { + return NPSIZES; + } + { + pszind_t x = lg_floor((psz<<1)-1); + pszind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_PAGE) ? 0 : x - + (LG_SIZE_CLASS_GROUP + LG_PAGE); + pszind_t grp = shift << LG_SIZE_CLASS_GROUP; + + pszind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? + LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1; + + size_t delta_inverse_mask = ZD(-1) << lg_delta; + pszind_t mod = ((((psz-1) & delta_inverse_mask) >> lg_delta)) & + ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); + + pszind_t ind = grp + mod; + return ind; + } +} + +JEMALLOC_INLINE size_t +pind2sz_compute(pszind_t pind) { + if (unlikely(pind == NPSIZES)) { + return LARGE_MAXCLASS + PAGE; + } + { + size_t grp = pind >> LG_SIZE_CLASS_GROUP; + size_t mod = pind & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); + + size_t grp_size_mask = ~((!!grp)-1); + size_t grp_size = ((ZU(1) << (LG_PAGE + + (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask; + + size_t shift = (grp == 0) ? 1 : grp; + size_t lg_delta = shift + (LG_PAGE-1); + size_t mod_size = (mod+1) << lg_delta; + + size_t sz = grp_size + mod_size; + return sz; + } +} + +JEMALLOC_INLINE size_t +pind2sz_lookup(pszind_t pind) { + size_t ret = (size_t)pind2sz_tab[pind]; + assert(ret == pind2sz_compute(pind)); + return ret; +} + +JEMALLOC_INLINE size_t +pind2sz(pszind_t pind) { + assert(pind < NPSIZES+1); + return pind2sz_lookup(pind); +} + +JEMALLOC_INLINE size_t +psz2u(size_t psz) { + if (unlikely(psz > LARGE_MAXCLASS)) { + return LARGE_MAXCLASS + PAGE; + } + { + size_t x = lg_floor((psz<<1)-1); + size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? + LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1; + size_t delta = ZU(1) << lg_delta; + size_t delta_mask = delta - 1; + size_t usize = (psz + delta_mask) & ~delta_mask; + return usize; + } +} + +JEMALLOC_INLINE szind_t +size2index_compute(size_t size) { + if (unlikely(size > LARGE_MAXCLASS)) { + return NSIZES; + } +#if (NTBINS != 0) + if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { + szind_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; + szind_t lg_ceil = lg_floor(pow2_ceil_zu(size)); + return (lg_ceil < lg_tmin ? 0 : lg_ceil - lg_tmin); + } +#endif + { + szind_t x = lg_floor((size<<1)-1); + szind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM) ? 0 : + x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM); + szind_t grp = shift << LG_SIZE_CLASS_GROUP; + + szind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) + ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; + + size_t delta_inverse_mask = ZD(-1) << lg_delta; + szind_t mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) & + ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); + + szind_t index = NTBINS + grp + mod; + return index; + } +} + +JEMALLOC_ALWAYS_INLINE szind_t +size2index_lookup(size_t size) { + assert(size <= LOOKUP_MAXCLASS); + { + szind_t ret = (size2index_tab[(size-1) >> LG_TINY_MIN]); + assert(ret == size2index_compute(size)); + return ret; + } +} + +JEMALLOC_ALWAYS_INLINE szind_t +size2index(size_t size) { + assert(size > 0); + if (likely(size <= LOOKUP_MAXCLASS)) { + return size2index_lookup(size); + } + return size2index_compute(size); +} + +JEMALLOC_INLINE size_t +index2size_compute(szind_t index) { +#if (NTBINS > 0) + if (index < NTBINS) { + return (ZU(1) << (LG_TINY_MAXCLASS - NTBINS + 1 + index)); + } +#endif + { + size_t reduced_index = index - NTBINS; + size_t grp = reduced_index >> LG_SIZE_CLASS_GROUP; + size_t mod = reduced_index & ((ZU(1) << LG_SIZE_CLASS_GROUP) - + 1); + + size_t grp_size_mask = ~((!!grp)-1); + size_t grp_size = ((ZU(1) << (LG_QUANTUM + + (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask; + + size_t shift = (grp == 0) ? 1 : grp; + size_t lg_delta = shift + (LG_QUANTUM-1); + size_t mod_size = (mod+1) << lg_delta; + + size_t usize = grp_size + mod_size; + return usize; + } +} + +JEMALLOC_ALWAYS_INLINE size_t +index2size_lookup(szind_t index) { + size_t ret = (size_t)index2size_tab[index]; + assert(ret == index2size_compute(index)); + return ret; +} + +JEMALLOC_ALWAYS_INLINE size_t +index2size(szind_t index) { + assert(index < NSIZES); + return index2size_lookup(index); +} + +JEMALLOC_ALWAYS_INLINE size_t +s2u_compute(size_t size) { + if (unlikely(size > LARGE_MAXCLASS)) { + return 0; + } +#if (NTBINS > 0) + if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { + size_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; + size_t lg_ceil = lg_floor(pow2_ceil_zu(size)); + return (lg_ceil < lg_tmin ? (ZU(1) << lg_tmin) : + (ZU(1) << lg_ceil)); + } +#endif + { + size_t x = lg_floor((size<<1)-1); + size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) + ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; + size_t delta = ZU(1) << lg_delta; + size_t delta_mask = delta - 1; + size_t usize = (size + delta_mask) & ~delta_mask; + return usize; + } +} + +JEMALLOC_ALWAYS_INLINE size_t +s2u_lookup(size_t size) { + size_t ret = index2size_lookup(size2index_lookup(size)); + + assert(ret == s2u_compute(size)); + return ret; +} + +/* + * Compute usable size that would result from allocating an object with the + * specified size. + */ +JEMALLOC_ALWAYS_INLINE size_t +s2u(size_t size) { + assert(size > 0); + if (likely(size <= LOOKUP_MAXCLASS)) { + return s2u_lookup(size); + } + return s2u_compute(size); +} + +/* + * Compute usable size that would result from allocating an object with the + * specified size and alignment. + */ +JEMALLOC_ALWAYS_INLINE size_t +sa2u(size_t size, size_t alignment) { + size_t usize; + + assert(alignment != 0 && ((alignment - 1) & alignment) == 0); + + /* Try for a small size class. */ + if (size <= SMALL_MAXCLASS && alignment < PAGE) { + /* + * Round size up to the nearest multiple of alignment. + * + * This done, we can take advantage of the fact that for each + * small size class, every object is aligned at the smallest + * power of two that is non-zero in the base two representation + * of the size. For example: + * + * Size | Base 2 | Minimum alignment + * -----+----------+------------------ + * 96 | 1100000 | 32 + * 144 | 10100000 | 32 + * 192 | 11000000 | 64 + */ + usize = s2u(ALIGNMENT_CEILING(size, alignment)); + if (usize < LARGE_MINCLASS) { + return usize; + } + } + + /* Large size class. Beware of overflow. */ + + if (unlikely(alignment > LARGE_MAXCLASS)) { + return 0; + } + + /* Make sure result is a large size class. */ + if (size <= LARGE_MINCLASS) { + usize = LARGE_MINCLASS; + } else { + usize = s2u(size); + if (usize < size) { + /* size_t overflow. */ + return 0; + } + } + + /* + * Calculate the multi-page mapping that large_palloc() would need in + * order to guarantee the alignment. + */ + if (usize + large_pad + PAGE_CEILING(alignment) - PAGE < usize) { + /* size_t overflow. */ + return 0; + } + return usize; +} + +JEMALLOC_ALWAYS_INLINE malloc_cpuid_t +malloc_getcpu(void) { + assert(have_percpu_arena); +#if defined(JEMALLOC_HAVE_SCHED_GETCPU) + return (malloc_cpuid_t)sched_getcpu(); +#else + not_reached(); + return -1; +#endif +} + +/* Return the chosen arena index based on current cpu. */ +JEMALLOC_ALWAYS_INLINE unsigned +percpu_arena_choose(void) { + unsigned arena_ind; + assert(have_percpu_arena && (percpu_arena_mode != percpu_arena_disabled)); + + malloc_cpuid_t cpuid = malloc_getcpu(); + assert(cpuid >= 0); + if ((percpu_arena_mode == percpu_arena) || + ((unsigned)cpuid < ncpus / 2)) { + arena_ind = cpuid; + } else { + assert(percpu_arena_mode == per_phycpu_arena); + /* Hyper threads on the same physical CPU share arena. */ + arena_ind = cpuid - ncpus / 2; + } + + return arena_ind; +} + +/* Return the limit of percpu auto arena range, i.e. arenas[0...ind_limit). */ +JEMALLOC_ALWAYS_INLINE unsigned +percpu_arena_ind_limit(void) { + assert(have_percpu_arena && (percpu_arena_mode != percpu_arena_disabled)); + if (percpu_arena_mode == per_phycpu_arena && ncpus > 1) { + if (ncpus % 2) { + /* This likely means a misconfig. */ + return ncpus / 2 + 1; + } + return ncpus / 2; + } else { + return ncpus; + } +} + +JEMALLOC_INLINE arena_tdata_t * +arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing) { + arena_tdata_t *tdata; + arena_tdata_t *arenas_tdata = tsd_arenas_tdata_get(tsd); + + if (unlikely(arenas_tdata == NULL)) { + /* arenas_tdata hasn't been initialized yet. */ + return arena_tdata_get_hard(tsd, ind); + } + if (unlikely(ind >= tsd_narenas_tdata_get(tsd))) { + /* + * ind is invalid, cache is old (too small), or tdata to be + * initialized. + */ + return (refresh_if_missing ? arena_tdata_get_hard(tsd, ind) : + NULL); + } + + tdata = &arenas_tdata[ind]; + if (likely(tdata != NULL) || !refresh_if_missing) { + return tdata; + } + return arena_tdata_get_hard(tsd, ind); +} + +JEMALLOC_INLINE arena_t * +arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing) { + arena_t *ret; + + assert(ind <= MALLOCX_ARENA_MAX); + + ret = (arena_t *)atomic_load_p(&arenas[ind], ATOMIC_ACQUIRE); + if (unlikely(ret == NULL)) { + if (init_if_missing) { + ret = arena_init(tsdn, ind, + (extent_hooks_t *)&extent_hooks_default); + } + } + return ret; +} + +JEMALLOC_INLINE ticker_t * +decay_ticker_get(tsd_t *tsd, unsigned ind) { + arena_tdata_t *tdata; + + tdata = arena_tdata_get(tsd, ind, true); + if (unlikely(tdata == NULL)) { + return NULL; + } + return &tdata->decay_ticker; +} + +JEMALLOC_ALWAYS_INLINE tcache_bin_t * +tcache_small_bin_get(tcache_t *tcache, szind_t binind) { + assert(binind < NBINS); + return &tcache->tbins_small[binind]; +} + +JEMALLOC_ALWAYS_INLINE tcache_bin_t * +tcache_large_bin_get(tcache_t *tcache, szind_t binind) { + assert(binind >= NBINS &&binind < nhbins); + return &tcache->tbins_large[binind - NBINS]; +} + +JEMALLOC_ALWAYS_INLINE bool +tcache_available(tsd_t *tsd) { + cassert(config_tcache); + + /* + * Thread specific auto tcache might be unavailable if: 1) during tcache + * initialization, or 2) disabled through thread.tcache.enabled mallctl + * or config options. This check covers all cases. + */ + if (likely(tsd_tcache_enabled_get(tsd) == true)) { + /* Associated arena == null implies tcache init in progress. */ + if (tsd_tcachep_get(tsd)->arena != NULL) { + assert(tcache_small_bin_get(tsd_tcachep_get(tsd), + 0)->avail != NULL); + } + return true; + } + + return false; +} + +JEMALLOC_ALWAYS_INLINE tcache_t * +tcache_get(tsd_t *tsd) { + if (!config_tcache) { + return NULL; + } + if (!tcache_available(tsd)) { + return NULL; + } + + return tsd_tcachep_get(tsd); +} +#endif + +#endif /* JEMALLOC_INTERNAL_INLINES_A_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_b.h b/include/jemalloc/internal/jemalloc_internal_inlines_b.h new file mode 100644 index 00000000..52afb42d --- /dev/null +++ b/include/jemalloc/internal/jemalloc_internal_inlines_b.h @@ -0,0 +1,83 @@ +#ifndef JEMALLOC_INTERNAL_INLINES_B_H +#define JEMALLOC_INTERNAL_INLINES_B_H + +#ifndef JEMALLOC_ENABLE_INLINE +extent_t *iealloc(tsdn_t *tsdn, const void *ptr); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) +/* Choose an arena based on a per-thread value. */ +JEMALLOC_INLINE arena_t * +arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { + arena_t *ret; + + if (arena != NULL) { + return arena; + } + + /* During reentrancy, arena 0 is the safest bet. */ + if (*tsd_reentrancy_levelp_get(tsd) > 1) { + return arena_get(tsd_tsdn(tsd), 0, true); + } + + ret = internal ? tsd_iarena_get(tsd) : tsd_arena_get(tsd); + if (unlikely(ret == NULL)) { + ret = arena_choose_hard(tsd, internal); + assert(ret); + if (config_tcache && tcache_available(tsd)) { + tcache_t *tcache = tcache_get(tsd); + if (tcache->arena != NULL) { + /* See comments in tcache_data_init().*/ + assert(tcache->arena == + arena_get(tsd_tsdn(tsd), 0, false)); + if (tcache->arena != ret) { + tcache_arena_reassociate(tsd_tsdn(tsd), + tcache, ret); + } + } else { + tcache_arena_associate(tsd_tsdn(tsd), tcache, + ret); + } + } + } + + /* + * Note that for percpu arena, if the current arena is outside of the + * auto percpu arena range, (i.e. thread is assigned to a manually + * managed arena), then percpu arena is skipped. + */ + if (have_percpu_arena && (percpu_arena_mode != percpu_arena_disabled) && + (arena_ind_get(ret) < percpu_arena_ind_limit()) && + (ret->last_thd != tsd_tsdn(tsd))) { + unsigned ind = percpu_arena_choose(); + if (arena_ind_get(ret) != ind) { + percpu_arena_update(tsd, ind); + ret = tsd_arena_get(tsd); + } + ret->last_thd = tsd_tsdn(tsd); + } + + return ret; +} + +JEMALLOC_INLINE arena_t * +arena_choose(tsd_t *tsd, arena_t *arena) { + return arena_choose_impl(tsd, arena, false); +} + +JEMALLOC_INLINE arena_t * +arena_ichoose(tsd_t *tsd, arena_t *arena) { + return arena_choose_impl(tsd, arena, true); +} + +JEMALLOC_ALWAYS_INLINE extent_t * +iealloc(tsdn_t *tsdn, const void *ptr) { + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + + return rtree_extent_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true); +} +#endif + +#endif /* JEMALLOC_INTERNAL_INLINES_B_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_c.h b/include/jemalloc/internal/jemalloc_internal_inlines_c.h new file mode 100644 index 00000000..05debd22 --- /dev/null +++ b/include/jemalloc/internal/jemalloc_internal_inlines_c.h @@ -0,0 +1,220 @@ +#ifndef JEMALLOC_INTERNAL_INLINES_C_H +#define JEMALLOC_INTERNAL_INLINES_C_H + +#ifndef JEMALLOC_ENABLE_INLINE +arena_t *iaalloc(tsdn_t *tsdn, const void *ptr); +size_t isalloc(tsdn_t *tsdn, const void *ptr); +void *iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, + tcache_t *tcache, bool is_internal, arena_t *arena, bool slow_path); +void *ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, + bool slow_path); +void *ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, + tcache_t *tcache, bool is_internal, arena_t *arena); +void *ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, + tcache_t *tcache, arena_t *arena); +void *ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero); +size_t ivsalloc(tsdn_t *tsdn, const void *ptr); +void idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, + dalloc_ctx_t *dalloc_ctx, bool is_internal, bool slow_path); +void idalloc(tsd_t *tsd, void *ptr); +void isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, + bool slow_path); +void *iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, + size_t extra, size_t alignment, bool zero, tcache_t *tcache, + arena_t *arena); +void *iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, + size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); +void *iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, + size_t alignment, bool zero); +bool ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, + size_t alignment, bool zero); +#endif + +#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) +JEMALLOC_ALWAYS_INLINE arena_t * +iaalloc(tsdn_t *tsdn, const void *ptr) { + assert(ptr != NULL); + + return arena_aalloc(tsdn, ptr); +} + +JEMALLOC_ALWAYS_INLINE size_t +isalloc(tsdn_t *tsdn, const void *ptr) { + assert(ptr != NULL); + + return arena_salloc(tsdn, ptr); +} + +JEMALLOC_ALWAYS_INLINE void * +iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, + bool is_internal, arena_t *arena, bool slow_path) { + void *ret; + + assert(size != 0); + assert(!is_internal || tcache == NULL); + assert(!is_internal || arena == NULL || arena_ind_get(arena) < + narenas_auto); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + + ret = arena_malloc(tsdn, arena, size, ind, zero, tcache, slow_path); + if (config_stats && is_internal && likely(ret != NULL)) { + arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn, ret)); + } + return ret; +} + +JEMALLOC_ALWAYS_INLINE void * +ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, bool slow_path) { + return iallocztm(tsd_tsdn(tsd), size, ind, zero, tcache_get(tsd), false, + NULL, slow_path); +} + +JEMALLOC_ALWAYS_INLINE void * +ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, + tcache_t *tcache, bool is_internal, arena_t *arena) { + void *ret; + + assert(usize != 0); + assert(usize == sa2u(usize, alignment)); + assert(!is_internal || tcache == NULL); + assert(!is_internal || arena == NULL || arena_ind_get(arena) < + narenas_auto); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + + ret = arena_palloc(tsdn, arena, usize, alignment, zero, tcache); + assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret); + if (config_stats && is_internal && likely(ret != NULL)) { + arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn, ret)); + } + return ret; +} + +JEMALLOC_ALWAYS_INLINE void * +ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, + tcache_t *tcache, arena_t *arena) { + return ipallocztm(tsdn, usize, alignment, zero, tcache, false, arena); +} + +JEMALLOC_ALWAYS_INLINE void * +ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero) { + return ipallocztm(tsd_tsdn(tsd), usize, alignment, zero, + tcache_get(tsd), false, NULL); +} + +JEMALLOC_ALWAYS_INLINE size_t +ivsalloc(tsdn_t *tsdn, const void *ptr) { + return arena_vsalloc(tsdn, ptr); +} + +JEMALLOC_ALWAYS_INLINE void +idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, dalloc_ctx_t *dalloc_ctx, + bool is_internal, bool slow_path) { + assert(ptr != NULL); + assert(!is_internal || tcache == NULL); + assert(!is_internal || arena_ind_get(iaalloc(tsdn, ptr)) < + narenas_auto); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + if (config_stats && is_internal) { + arena_internal_sub(iaalloc(tsdn, ptr), isalloc(tsdn, ptr)); + } + if (!is_internal && *tsd_reentrancy_levelp_get(tsdn_tsd(tsdn)) != 0) { + tcache = NULL; + } + arena_dalloc(tsdn, ptr, tcache, dalloc_ctx, slow_path); +} + +JEMALLOC_ALWAYS_INLINE void +idalloc(tsd_t *tsd, void *ptr) { + idalloctm(tsd_tsdn(tsd), ptr, tcache_get(tsd), NULL, false, true); +} + +JEMALLOC_ALWAYS_INLINE void +isdalloct(tsdn_t *tsdn, void *ptr, size_t size, + tcache_t *tcache, bool slow_path) { + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + arena_sdalloc(tsdn, ptr, size, tcache, slow_path); +} + +JEMALLOC_ALWAYS_INLINE void * +iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, + size_t extra, size_t alignment, bool zero, tcache_t *tcache, + arena_t *arena) { + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + void *p; + size_t usize, copysize; + + usize = sa2u(size + extra, alignment); + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { + return NULL; + } + p = ipalloct(tsdn, usize, alignment, zero, tcache, arena); + if (p == NULL) { + if (extra == 0) { + return NULL; + } + /* Try again, without extra this time. */ + usize = sa2u(size, alignment); + if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { + return NULL; + } + p = ipalloct(tsdn, usize, alignment, zero, tcache, arena); + if (p == NULL) { + return NULL; + } + } + /* + * Copy at most size bytes (not size+extra), since the caller has no + * expectation that the extra bytes will be reliably preserved. + */ + copysize = (size < oldsize) ? size : oldsize; + memcpy(p, ptr, copysize); + isdalloct(tsdn, ptr, oldsize, tcache, true); + return p; +} + +JEMALLOC_ALWAYS_INLINE void * +iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment, + bool zero, tcache_t *tcache, arena_t *arena) { + assert(ptr != NULL); + assert(size != 0); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + + if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1)) + != 0) { + /* + * Existing object alignment is inadequate; allocate new space + * and copy. + */ + return iralloct_realign(tsdn, ptr, oldsize, size, 0, alignment, + zero, tcache, arena); + } + + return arena_ralloc(tsdn, arena, ptr, oldsize, size, alignment, zero, + tcache); +} + +JEMALLOC_ALWAYS_INLINE void * +iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, size_t alignment, + bool zero) { + return iralloct(tsd_tsdn(tsd), ptr, oldsize, size, alignment, zero, + tcache_get(tsd), NULL); +} + +JEMALLOC_ALWAYS_INLINE bool +ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, + size_t alignment, bool zero) { + assert(ptr != NULL); + assert(size != 0); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + + if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1)) + != 0) { + /* Existing object alignment is inadequate. */ + return true; + } + + return arena_ralloc_no_move(tsdn, ptr, oldsize, size, extra, zero); +} +#endif + +#endif /* JEMALLOC_INTERNAL_INLINES_C_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_types.h b/include/jemalloc/internal/jemalloc_internal_types.h new file mode 100644 index 00000000..663ed8b5 --- /dev/null +++ b/include/jemalloc/internal/jemalloc_internal_types.h @@ -0,0 +1,178 @@ +#ifndef JEMALLOC_INTERNAL_TYPES_H +#define JEMALLOC_INTERNAL_TYPES_H + +/* Page size index type. */ +typedef unsigned pszind_t; + +/* Size class index type. */ +typedef unsigned szind_t; + +/* Processor / core id type. */ +typedef int malloc_cpuid_t; + +/* + * Flags bits: + * + * a: arena + * t: tcache + * 0: unused + * z: zero + * n: alignment + * + * aaaaaaaa aaaatttt tttttttt 0znnnnnn + */ +#define MALLOCX_ARENA_BITS 12 +#define MALLOCX_TCACHE_BITS 12 +#define MALLOCX_LG_ALIGN_BITS 6 +#define MALLOCX_ARENA_SHIFT 20 +#define MALLOCX_TCACHE_SHIFT 8 +#define MALLOCX_ARENA_MASK \ + (((1 << MALLOCX_ARENA_BITS) - 1) << MALLOCX_ARENA_SHIFT) +/* NB: Arena index bias decreases the maximum number of arenas by 1. */ +#define MALLOCX_ARENA_MAX ((1 << MALLOCX_ARENA_BITS) - 2) +#define MALLOCX_TCACHE_MASK \ + (((1 << MALLOCX_TCACHE_BITS) - 1) << MALLOCX_TCACHE_SHIFT) +#define MALLOCX_TCACHE_MAX ((1 << MALLOCX_TCACHE_BITS) - 3) +#define MALLOCX_LG_ALIGN_MASK ((1 << MALLOCX_LG_ALIGN_BITS) - 1) +/* Use MALLOCX_ALIGN_GET() if alignment may not be specified in flags. */ +#define MALLOCX_ALIGN_GET_SPECIFIED(flags) \ + (ZU(1) << (flags & MALLOCX_LG_ALIGN_MASK)) +#define MALLOCX_ALIGN_GET(flags) \ + (MALLOCX_ALIGN_GET_SPECIFIED(flags) & (SIZE_T_MAX-1)) +#define MALLOCX_ZERO_GET(flags) \ + ((bool)(flags & MALLOCX_ZERO)) + +#define MALLOCX_TCACHE_GET(flags) \ + (((unsigned)((flags & MALLOCX_TCACHE_MASK) >> MALLOCX_TCACHE_SHIFT)) - 2) +#define MALLOCX_ARENA_GET(flags) \ + (((unsigned)(((unsigned)flags) >> MALLOCX_ARENA_SHIFT)) - 1) + +/* Smallest size class to support. */ +#define TINY_MIN (1U << LG_TINY_MIN) + +/* + * Minimum allocation alignment is 2^LG_QUANTUM bytes (ignoring tiny size + * classes). + */ +#ifndef LG_QUANTUM +# if (defined(__i386__) || defined(_M_IX86)) +# define LG_QUANTUM 4 +# endif +# ifdef __ia64__ +# define LG_QUANTUM 4 +# endif +# ifdef __alpha__ +# define LG_QUANTUM 4 +# endif +# if (defined(__sparc64__) || defined(__sparcv9) || defined(__sparc_v9__)) +# define LG_QUANTUM 4 +# endif +# if (defined(__amd64__) || defined(__x86_64__) || defined(_M_X64)) +# define LG_QUANTUM 4 +# endif +# ifdef __arm__ +# define LG_QUANTUM 3 +# endif +# ifdef __aarch64__ +# define LG_QUANTUM 4 +# endif +# ifdef __hppa__ +# define LG_QUANTUM 4 +# endif +# ifdef __mips__ +# define LG_QUANTUM 3 +# endif +# ifdef __or1k__ +# define LG_QUANTUM 3 +# endif +# ifdef __powerpc__ +# define LG_QUANTUM 4 +# endif +# ifdef __riscv__ +# define LG_QUANTUM 4 +# endif +# ifdef __s390__ +# define LG_QUANTUM 4 +# endif +# ifdef __SH4__ +# define LG_QUANTUM 4 +# endif +# ifdef __tile__ +# define LG_QUANTUM 4 +# endif +# ifdef __le32__ +# define LG_QUANTUM 4 +# endif +# ifndef LG_QUANTUM +# error "Unknown minimum alignment for architecture; specify via " + "--with-lg-quantum" +# endif +#endif + +#define QUANTUM ((size_t)(1U << LG_QUANTUM)) +#define QUANTUM_MASK (QUANTUM - 1) + +/* Return the smallest quantum multiple that is >= a. */ +#define QUANTUM_CEILING(a) \ + (((a) + QUANTUM_MASK) & ~QUANTUM_MASK) + +#define LONG ((size_t)(1U << LG_SIZEOF_LONG)) +#define LONG_MASK (LONG - 1) + +/* Return the smallest long multiple that is >= a. */ +#define LONG_CEILING(a) \ + (((a) + LONG_MASK) & ~LONG_MASK) + +#define SIZEOF_PTR (1U << LG_SIZEOF_PTR) +#define PTR_MASK (SIZEOF_PTR - 1) + +/* Return the smallest (void *) multiple that is >= a. */ +#define PTR_CEILING(a) \ + (((a) + PTR_MASK) & ~PTR_MASK) + +/* + * Maximum size of L1 cache line. This is used to avoid cache line aliasing. + * In addition, this controls the spacing of cacheline-spaced size classes. + * + * CACHELINE cannot be based on LG_CACHELINE because __declspec(align()) can + * only handle raw constants. + */ +#define LG_CACHELINE 6 +#define CACHELINE 64 +#define CACHELINE_MASK (CACHELINE - 1) + +/* Return the smallest cacheline multiple that is >= s. */ +#define CACHELINE_CEILING(s) \ + (((s) + CACHELINE_MASK) & ~CACHELINE_MASK) + +/* Return the nearest aligned address at or below a. */ +#define ALIGNMENT_ADDR2BASE(a, alignment) \ + ((void *)((uintptr_t)(a) & ((~(alignment)) + 1))) + +/* Return the offset between a and the nearest aligned address at or below a. */ +#define ALIGNMENT_ADDR2OFFSET(a, alignment) \ + ((size_t)((uintptr_t)(a) & (alignment - 1))) + +/* Return the smallest alignment multiple that is >= s. */ +#define ALIGNMENT_CEILING(s, alignment) \ + (((s) + (alignment - 1)) & ((~(alignment)) + 1)) + +/* Declare a variable-length array. */ +#if __STDC_VERSION__ < 199901L +# ifdef _MSC_VER +# include +# define alloca _alloca +# else +# ifdef JEMALLOC_HAS_ALLOCA_H +# include +# else +# include +# endif +# endif +# define VARIABLE_ARRAY(type, name, count) \ + type *name = alloca(sizeof(type) * (count)) +#else +# define VARIABLE_ARRAY(type, name, count) type name[(count)] +#endif + +#endif /* JEMALLOC_INTERNAL_TYPES_H */ diff --git a/include/jemalloc/internal/jemalloc_preamble.h.in b/include/jemalloc/internal/jemalloc_preamble.h.in new file mode 100644 index 00000000..6e38fe65 --- /dev/null +++ b/include/jemalloc/internal/jemalloc_preamble.h.in @@ -0,0 +1,187 @@ +#ifndef JEMALLOC_PREAMBLE_H +#define JEMALLOC_PREAMBLE_H + +#ifdef __cplusplus +# define CPP_PROLOGUE extern "C" { +# define CPP_EPILOGUE } +#else +# define CPP_PROLOGUE +# define CPP_EPILOGUE +#endif + +CPP_PROLOGUE + +#include "jemalloc_internal_defs.h" +#include "jemalloc/internal/jemalloc_internal_decls.h" + +#ifdef JEMALLOC_UTRACE +#include +#endif + +#define JEMALLOC_NO_DEMANGLE +#ifdef JEMALLOC_JET +# define JEMALLOC_N(n) jet_##n +# include "jemalloc/internal/public_namespace.h" +# define JEMALLOC_NO_RENAME +# include "../jemalloc@install_suffix@.h" +# undef JEMALLOC_NO_RENAME +#else +# define JEMALLOC_N(n) @private_namespace@##n +# include "../jemalloc@install_suffix@.h" +#endif + +#if (defined(JEMALLOC_OSATOMIC) || defined(JEMALLOC_OSSPIN)) +#include +#endif + +#ifdef JEMALLOC_ZONE +#include +#include +#include +#endif + +#include "jemalloc/internal/jemalloc_internal_macros.h" + +/* + * Note that the ordering matters here; the hook itself is name-mangled. We + * want the inclusion of hooks to happen early, so that we hook as much as + * possible. + */ +#include "jemalloc/internal/private_namespace.h" +#include "jemalloc/internal/hooks.h" + +static const bool config_debug = +#ifdef JEMALLOC_DEBUG + true +#else + false +#endif + ; +static const bool have_dss = +#ifdef JEMALLOC_DSS + true +#else + false +#endif + ; +static const bool config_fill = +#ifdef JEMALLOC_FILL + true +#else + false +#endif + ; +static const bool config_lazy_lock = +#ifdef JEMALLOC_LAZY_LOCK + true +#else + false +#endif + ; +static const char * const config_malloc_conf = JEMALLOC_CONFIG_MALLOC_CONF; +static const bool config_prof = +#ifdef JEMALLOC_PROF + true +#else + false +#endif + ; +static const bool config_prof_libgcc = +#ifdef JEMALLOC_PROF_LIBGCC + true +#else + false +#endif + ; +static const bool config_prof_libunwind = +#ifdef JEMALLOC_PROF_LIBUNWIND + true +#else + false +#endif + ; +static const bool maps_coalesce = +#ifdef JEMALLOC_MAPS_COALESCE + true +#else + false +#endif + ; +static const bool config_munmap = +#ifdef JEMALLOC_MUNMAP + true +#else + false +#endif + ; +static const bool config_stats = +#ifdef JEMALLOC_STATS + true +#else + false +#endif + ; +static const bool config_tcache = +#ifdef JEMALLOC_TCACHE + true +#else + false +#endif + ; +static const bool config_tls = +#ifdef JEMALLOC_TLS + true +#else + false +#endif + ; +static const bool config_utrace = +#ifdef JEMALLOC_UTRACE + true +#else + false +#endif + ; +static const bool config_xmalloc = +#ifdef JEMALLOC_XMALLOC + true +#else + false +#endif + ; +static const bool config_ivsalloc = +#ifdef JEMALLOC_IVSALLOC + true +#else + false +#endif + ; +static const bool config_cache_oblivious = +#ifdef JEMALLOC_CACHE_OBLIVIOUS + true +#else + false +#endif + ; +static const bool have_thp = +#ifdef JEMALLOC_THP + true +#else + false +#endif + ; +#ifdef JEMALLOC_HAVE_SCHED_GETCPU +/* Currently percpu_arena depends on sched_getcpu. */ +#define JEMALLOC_PERCPU_ARENA +#endif +static const bool have_percpu_arena = +#ifdef JEMALLOC_PERCPU_ARENA + true +#else + false +#endif + ; + +CPP_EPILOGUE + +#endif /* JEMALLOC_PREAMBLE_H */ diff --git a/src/arena.c b/src/arena.c index 198c6e49..5d313e32 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1,5 +1,6 @@ #define JEMALLOC_ARENA_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" /******************************************************************************/ /* Data. */ diff --git a/src/base.c b/src/base.c index 4275259e..eb68a175 100644 --- a/src/base.c +++ b/src/base.c @@ -1,5 +1,6 @@ #define JEMALLOC_BASE_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" /******************************************************************************/ /* Data. */ diff --git a/src/bitmap.c b/src/bitmap.c index a629aca6..2eb50f1b 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -1,5 +1,6 @@ #define JEMALLOC_BITMAP_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" /******************************************************************************/ diff --git a/src/ckh.c b/src/ckh.c index 03262ef5..a359a5cc 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -35,7 +35,8 @@ * ******************************************************************************/ #define JEMALLOC_CKH_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" /******************************************************************************/ /* Function prototypes for non-inline static functions. */ diff --git a/src/ctl.c b/src/ctl.c index a59a741f..6d6fadc7 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1,5 +1,6 @@ #define JEMALLOC_CTL_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" /******************************************************************************/ /* Data. */ diff --git a/src/extent.c b/src/extent.c index b6c3f4b4..2344e9cd 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1,8 +1,10 @@ #define JEMALLOC_EXTENT_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/ph.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" + /******************************************************************************/ /* Data. */ diff --git a/src/extent_dss.c b/src/extent_dss.c index 99919090..c609f14c 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -1,5 +1,7 @@ #define JEMALLOC_EXTENT_DSS_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" + /******************************************************************************/ /* Data. */ diff --git a/src/extent_mmap.c b/src/extent_mmap.c index 7265159a..5717573e 100644 --- a/src/extent_mmap.c +++ b/src/extent_mmap.c @@ -1,5 +1,6 @@ #define JEMALLOC_EXTENT_MMAP_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" /******************************************************************************/ diff --git a/src/hash.c b/src/hash.c index ffd4f2be..7b2bdc2b 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1,2 +1,3 @@ #define JEMALLOC_HASH_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" diff --git a/src/hooks.c b/src/hooks.c index c32471e9..6266ecd4 100644 --- a/src/hooks.c +++ b/src/hooks.c @@ -1,4 +1,4 @@ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" /* * The hooks are a little bit screwy -- they're not genuinely exported in the diff --git a/src/jemalloc.c b/src/jemalloc.c index bc659325..27f9711c 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1,5 +1,6 @@ #define JEMALLOC_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" /******************************************************************************/ /* Data. */ diff --git a/src/jemalloc_cpp.cpp b/src/jemalloc_cpp.cpp index 9692b5ba..b6d7c9a5 100644 --- a/src/jemalloc_cpp.cpp +++ b/src/jemalloc_cpp.cpp @@ -2,7 +2,8 @@ #include #define JEMALLOC_CPP_CPP_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" // All operators in this file are exported. diff --git a/src/large.c b/src/large.c index 3f96c521..18987c1a 100644 --- a/src/large.c +++ b/src/large.c @@ -1,5 +1,6 @@ #define JEMALLOC_LARGE_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" /******************************************************************************/ diff --git a/src/malloc_io.c b/src/malloc_io.c index fd6ff0f0..98ef7a65 100644 --- a/src/malloc_io.c +++ b/src/malloc_io.c @@ -1,5 +1,6 @@ #define JEMALLOC_MALLOC_IO_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" #ifdef assert # undef assert diff --git a/src/mutex.c b/src/mutex.c index 8c593101..26af5239 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -1,5 +1,6 @@ #define JEMALLOC_MUTEX_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" #if defined(JEMALLOC_LAZY_LOCK) && !defined(_WIN32) #include diff --git a/src/nstime.c b/src/nstime.c index 70b2f9d8..ee8d78e7 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -1,4 +1,5 @@ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" #define BILLION UINT64_C(1000000000) #define MILLION UINT64_C(1000000) diff --git a/src/pages.c b/src/pages.c index fa986ba6..53ca653b 100644 --- a/src/pages.c +++ b/src/pages.c @@ -1,5 +1,6 @@ #define JEMALLOC_PAGES_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" #ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT #include diff --git a/src/prng.c b/src/prng.c index bf908790..83c04bf9 100644 --- a/src/prng.c +++ b/src/prng.c @@ -1,2 +1,3 @@ #define JEMALLOC_PRNG_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" diff --git a/src/prof.c b/src/prof.c index 40610d71..1844c2f3 100644 --- a/src/prof.c +++ b/src/prof.c @@ -1,5 +1,7 @@ #define JEMALLOC_PROF_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" + /******************************************************************************/ #ifdef JEMALLOC_PROF_LIBUNWIND diff --git a/src/rtree.c b/src/rtree.c index de4990bd..051428f1 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -1,5 +1,6 @@ #define JEMALLOC_RTREE_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" /* * Only the most significant bits of keys passed to rtree_{read,write}() are diff --git a/src/spin.c b/src/spin.c index d7eb5fa8..d2d39419 100644 --- a/src/spin.c +++ b/src/spin.c @@ -1,2 +1,3 @@ #define JEMALLOC_SPIN_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" diff --git a/src/stats.c b/src/stats.c index aa7ca507..110d62f7 100644 --- a/src/stats.c +++ b/src/stats.c @@ -1,5 +1,6 @@ #define JEMALLOC_STATS_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" const char *global_mutex_names[num_global_prof_mutexes] = { #define OP(mtx) #mtx, diff --git a/src/tcache.c b/src/tcache.c index 09776e1a..99749fbc 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -1,5 +1,6 @@ #define JEMALLOC_TCACHE_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" /******************************************************************************/ /* Data. */ diff --git a/src/ticker.c b/src/ticker.c index b0149e1c..d7b8cd26 100644 --- a/src/ticker.c +++ b/src/ticker.c @@ -1,2 +1,3 @@ #define JEMALLOC_TICKER_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" diff --git a/src/tsd.c b/src/tsd.c index 0d5de8ea..3e72548c 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -1,5 +1,6 @@ #define JEMALLOC_TSD_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" /******************************************************************************/ /* Data. */ diff --git a/src/witness.c b/src/witness.c index cbffaeaa..26b16e77 100644 --- a/src/witness.c +++ b/src/witness.c @@ -1,5 +1,6 @@ #define JEMALLOC_WITNESS_C_ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" void witness_init(witness_t *witness, const char *name, witness_rank_t rank, diff --git a/src/zone.c b/src/zone.c index e69f0b4a..a8a571fd 100644 --- a/src/zone.c +++ b/src/zone.c @@ -1,4 +1,5 @@ -#include "jemalloc/internal/jemalloc_internal.h" +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" #ifndef JEMALLOC_ZONE # error "This source file is for zones on Darwin (OS X)." #endif diff --git a/test/include/test/jemalloc_test.h.in b/test/include/test/jemalloc_test.h.in index e3882b29..02eaac2b 100644 --- a/test/include/test/jemalloc_test.h.in +++ b/test/include/test/jemalloc_test.h.in @@ -43,8 +43,8 @@ extern "C" { #ifdef JEMALLOC_UNIT_TEST # define JEMALLOC_JET # define JEMALLOC_MANGLE -# include "jemalloc/internal/jemalloc_internal.h" - +# include "jemalloc/internal/jemalloc_preamble.h" +# include "jemalloc/internal/jemalloc_internal_includes.h" /******************************************************************************/ /* @@ -96,7 +96,8 @@ static const bool config_debug = # include "jemalloc/jemalloc_protos_jet.h" # define JEMALLOC_JET -# include "jemalloc/internal/jemalloc_internal.h" +# include "jemalloc/internal/jemalloc_preamble.h" +# include "jemalloc/internal/jemalloc_internal_includes.h" # include "jemalloc/internal/public_unnamespace.h" # undef JEMALLOC_JET -- GitLab From e709fae1d73b874796d7f629ef39a44e9b53fa87 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 10 Apr 2017 19:04:40 -0700 Subject: [PATCH 403/544] Header refactoring: move atomic.h out of the catch-all --- include/jemalloc/internal/arena_structs_b.h | 1 + include/jemalloc/internal/atomic.h | 4 ++++ include/jemalloc/internal/extent_structs.h | 1 + include/jemalloc/internal/jemalloc_internal_externs.h | 2 ++ include/jemalloc/internal/jemalloc_internal_includes.h | 1 - include/jemalloc/internal/jemalloc_internal_inlines_a.h | 2 ++ include/jemalloc/internal/mutex_structs.h | 2 ++ include/jemalloc/internal/prng_inlines.h | 2 ++ include/jemalloc/internal/rtree_structs.h | 2 ++ include/jemalloc/internal/stats_structs.h | 2 ++ src/jemalloc.c | 2 ++ 11 files changed, 20 insertions(+), 1 deletion(-) diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 935cd169..1f4fb6b1 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -1,6 +1,7 @@ #ifndef JEMALLOC_INTERNAL_ARENA_STRUCTS_B_H #define JEMALLOC_INTERNAL_ARENA_STRUCTS_B_H +#include "jemalloc/internal/atomic.h" #include "jemalloc/internal/ql.h" /* diff --git a/include/jemalloc/internal/atomic.h b/include/jemalloc/internal/atomic.h index adadb1a3..1bfae7d7 100644 --- a/include/jemalloc/internal/atomic.h +++ b/include/jemalloc/internal/atomic.h @@ -3,6 +3,8 @@ #define ATOMIC_INLINE static inline +CPP_PROLOGUE + #if defined(JEMALLOC_GCC_ATOMIC_ATOMICS) # include "jemalloc/internal/atomic_gcc_atomic.h" #elif defined(JEMALLOC_GCC_SYNC_ATOMICS) @@ -74,4 +76,6 @@ JEMALLOC_GENERATE_INT_ATOMICS(uint64_t, u64, 3) #undef ATOMIC_INLINE +CPP_EPILOGUE + #endif /* JEMALLOC_INTERNAL_ATOMIC_H */ diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 2f81fa1c..3d3d418b 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -1,6 +1,7 @@ #ifndef JEMALLOC_INTERNAL_EXTENT_STRUCTS_H #define JEMALLOC_INTERNAL_EXTENT_STRUCTS_H +#include "jemalloc/internal/atomic.h" #include "jemalloc/internal/ph.h" #include "jemalloc/internal/ql.h" diff --git a/include/jemalloc/internal/jemalloc_internal_externs.h b/include/jemalloc/internal/jemalloc_internal_externs.h index 7ac39bea..56d39d48 100644 --- a/include/jemalloc/internal/jemalloc_internal_externs.h +++ b/include/jemalloc/internal/jemalloc_internal_externs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_EXTERNS_H #define JEMALLOC_INTERNAL_EXTERNS_H +#include "jemalloc/internal/atomic.h" + extern bool opt_abort; extern const char *opt_junk; extern bool opt_junk_alloc; diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 45035137..53374f99 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -43,7 +43,6 @@ CPP_PROLOGUE /******************************************************************************/ #include "jemalloc/internal/assert.h" -#include "jemalloc/internal/atomic.h" #include "jemalloc/internal/bit_util.h" #include "jemalloc/internal/malloc_io.h" #include "jemalloc/internal/util.h" diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_a.h b/include/jemalloc/internal/jemalloc_internal_inlines_a.h index 256329a0..822b4d75 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_a.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_a.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_INLINES_A_H #define JEMALLOC_INTERNAL_INLINES_A_H +#include "jemalloc/internal/atomic.h" + #ifndef JEMALLOC_ENABLE_INLINE pszind_t psz2ind(size_t psz); size_t pind2sz_compute(pszind_t pind); diff --git a/include/jemalloc/internal/mutex_structs.h b/include/jemalloc/internal/mutex_structs.h index ff090b22..7b7085d4 100644 --- a/include/jemalloc/internal/mutex_structs.h +++ b/include/jemalloc/internal/mutex_structs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_MUTEX_STRUCTS_H #define JEMALLOC_INTERNAL_MUTEX_STRUCTS_H +#include "jemalloc/internal/atomic.h" + struct mutex_prof_data_s { /* * Counters touched on the slow path, i.e. when there is lock diff --git a/include/jemalloc/internal/prng_inlines.h b/include/jemalloc/internal/prng_inlines.h index 3f06ccd4..7026d52a 100644 --- a/include/jemalloc/internal/prng_inlines.h +++ b/include/jemalloc/internal/prng_inlines.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_PRNG_INLINES_H #define JEMALLOC_INTERNAL_PRNG_INLINES_H +#include "jemalloc/internal/atomic.h" + #ifndef JEMALLOC_ENABLE_INLINE uint32_t prng_state_next_u32(uint32_t state); uint64_t prng_state_next_u64(uint64_t state); diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h index 123248ae..175a013c 100644 --- a/include/jemalloc/internal/rtree_structs.h +++ b/include/jemalloc/internal/rtree_structs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_RTREE_STRUCTS_H #define JEMALLOC_INTERNAL_RTREE_STRUCTS_H +#include "jemalloc/internal/atomic.h" + struct rtree_node_elm_s { atomic_p_t child; /* (rtree_{node,leaf}_elm_t *) */ }; diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index 75a4a783..dc994b52 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_STATS_STRUCTS_H #define JEMALLOC_INTERNAL_STATS_STRUCTS_H +#include "jemalloc/internal/atomic.h" + #ifdef JEMALLOC_ATOMIC_U64 typedef atomic_u64_t arena_stats_u64_t; #else diff --git a/src/jemalloc.c b/src/jemalloc.c index 27f9711c..77ee857c 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/atomic.h" + /******************************************************************************/ /* Data. */ -- GitLab From f35213bae4ee6294a0743607637f9be8989622f1 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 11 Apr 2017 14:56:43 -0700 Subject: [PATCH 404/544] Pass dalloc_ctx down the sdalloc path. This avoids redundant rtree lookups. --- include/jemalloc/internal/arena_inlines_b.h | 38 +++++++++++-------- .../internal/jemalloc_internal_inlines_c.h | 10 ++--- src/arena.c | 2 +- src/jemalloc.c | 13 ++++++- src/large.c | 2 +- 5 files changed, 41 insertions(+), 24 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 96889c1b..382289ee 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -19,7 +19,7 @@ void arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, dalloc_ctx_t *dalloc_ctx, bool slow_path); void arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size); void arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - bool slow_path); + dalloc_ctx_t *dalloc_ctx, bool slow_path); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) @@ -293,7 +293,7 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) { JEMALLOC_ALWAYS_INLINE void arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - bool slow_path) { + dalloc_ctx_t *dalloc_ctx, bool slow_path) { assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); assert(size <= LARGE_MAXCLASS); @@ -305,7 +305,22 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, szind_t szind; bool slab; - if (!config_prof || !opt_prof) { + UNUSED dalloc_ctx_t local_ctx; + if (config_prof && opt_prof) { + if (dalloc_ctx == NULL) { + /* Uncommon case and should be a static check. */ + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, + &rtree_ctx_fallback); + rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true, &local_ctx.szind, + &local_ctx.slab); + assert(local_ctx.szind == size2index(size)); + dalloc_ctx = &local_ctx; + } + slab = dalloc_ctx->slab; + szind = dalloc_ctx->szind; + } else { /* * There is no risk of being confused by a promoted sampled * object, so base szind and slab on the given size. @@ -314,21 +329,14 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, slab = (szind < NBINS); } - if ((config_prof && opt_prof) || config_debug) { + if (config_debug) { rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn)); - rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, true, &szind, &slab); - - assert(szind == size2index(size)); - assert((config_prof && opt_prof) || slab == (szind < NBINS)); - - if (config_debug) { - extent_t *extent = rtree_extent_read(tsdn, - &extents_rtree, rtree_ctx, (uintptr_t)ptr, true); - assert(szind == extent_szind_get(extent)); - assert(slab == extent_slab_get(extent)); - } + extent_t *extent = rtree_extent_read(tsdn, + &extents_rtree, rtree_ctx, (uintptr_t)ptr, true); + assert(szind == extent_szind_get(extent)); + assert(slab == extent_slab_get(extent)); } if (likely(slab)) { diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_c.h b/include/jemalloc/internal/jemalloc_internal_inlines_c.h index 05debd22..4fb34241 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_c.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_c.h @@ -18,7 +18,7 @@ void idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, dalloc_ctx_t *dalloc_ctx, bool is_internal, bool slow_path); void idalloc(tsd_t *tsd, void *ptr); void isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - bool slow_path); + dalloc_ctx_t *dalloc_ctx, bool slow_path); void *iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); @@ -129,10 +129,10 @@ idalloc(tsd_t *tsd, void *ptr) { } JEMALLOC_ALWAYS_INLINE void -isdalloct(tsdn_t *tsdn, void *ptr, size_t size, - tcache_t *tcache, bool slow_path) { +isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, + dalloc_ctx_t *dalloc_ctx, bool slow_path) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - arena_sdalloc(tsdn, ptr, size, tcache, slow_path); + arena_sdalloc(tsdn, ptr, size, tcache, dalloc_ctx, slow_path); } JEMALLOC_ALWAYS_INLINE void * @@ -168,7 +168,7 @@ iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, */ copysize = (size < oldsize) ? size : oldsize; memcpy(p, ptr, copysize); - isdalloct(tsdn, ptr, oldsize, tcache, true); + isdalloct(tsdn, ptr, oldsize, tcache, NULL, true); return p; } diff --git a/src/arena.c b/src/arena.c index 5d313e32..16728b34 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1752,7 +1752,7 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, size_t copysize = (usize < oldsize) ? usize : oldsize; memcpy(ret, ptr, copysize); - isdalloct(tsdn, ptr, oldsize, tcache, true); + isdalloct(tsdn, ptr, oldsize, tcache, NULL, true); return ret; } diff --git a/src/jemalloc.c b/src/jemalloc.c index 77ee857c..e71949a1 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -2083,17 +2083,26 @@ isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) { assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); + dalloc_ctx_t dalloc_ctx, *ctx; if (config_prof && opt_prof) { + rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd); + rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true, &dalloc_ctx.szind, &dalloc_ctx.slab); + assert(dalloc_ctx.szind == size2index(usize)); prof_free(tsd, ptr, usize); + ctx = &dalloc_ctx; + } else { + ctx = NULL; } + if (config_stats) { *tsd_thread_deallocatedp_get(tsd) += usize; } if (likely(!slow_path)) { - isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, false); + isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, ctx, false); } else { - isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, true); + isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, ctx, true); } } diff --git a/src/large.c b/src/large.c index 18987c1a..3b53eb33 100644 --- a/src/large.c +++ b/src/large.c @@ -304,7 +304,7 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, size_t copysize = (usize < oldusize) ? usize : oldusize; memcpy(ret, extent_addr_get(extent), copysize); - isdalloct(tsdn, extent_addr_get(extent), oldusize, tcache, true); + isdalloct(tsdn, extent_addr_get(extent), oldusize, tcache, NULL, true); return ret; } -- GitLab From ccfe68a916baecc50fd7eae3d5be945469016e4c Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 11 Apr 2017 18:13:10 -0700 Subject: [PATCH 405/544] Pass alloc_ctx down profiling path. With this change, when profiling is enabled, we avoid doing redundant rtree lookups. Also changed dalloc_atx_t to alloc_atx_t, as it's now used on allocation path as well (to speed up profiling). --- include/jemalloc/internal/arena_inlines_b.h | 63 ++++++++------ include/jemalloc/internal/arena_structs_b.h | 4 +- include/jemalloc/internal/arena_types.h | 2 +- .../internal/jemalloc_internal_inlines_c.h | 12 +-- include/jemalloc/internal/prof_inlines_b.h | 33 ++++---- src/arena.c | 11 ++- src/jemalloc.c | 84 ++++++++++++------- src/prof.c | 2 +- test/unit/prof_tctx.c | 4 +- 9 files changed, 133 insertions(+), 82 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 382289ee..8c76e0b0 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -3,9 +3,10 @@ #ifndef JEMALLOC_ENABLE_INLINE szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin); -prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr); +prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr, + alloc_ctx_t *ctx); void arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, - prof_tctx_t *tctx); + alloc_ctx_t *ctx, prof_tctx_t *tctx); void arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx); void arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks); void arena_decay_tick(tsdn_t *tsdn, arena_t *arena); @@ -16,10 +17,10 @@ size_t arena_salloc(tsdn_t *tsdn, const void *ptr); size_t arena_vsalloc(tsdn_t *tsdn, const void *ptr); void arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr); void arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, - dalloc_ctx_t *dalloc_ctx, bool slow_path); + alloc_ctx_t *alloc_ctx, bool slow_path); void arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size); void arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - dalloc_ctx_t *dalloc_ctx, bool slow_path); + alloc_ctx_t *alloc_ctx, bool slow_path); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) @@ -30,27 +31,41 @@ arena_bin_index(arena_t *arena, arena_bin_t *bin) { return binind; } -JEMALLOC_INLINE prof_tctx_t * -arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr) { +JEMALLOC_ALWAYS_INLINE prof_tctx_t * +arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx) { cassert(config_prof); assert(ptr != NULL); - const extent_t *extent = iealloc(tsdn, ptr); - if (unlikely(!extent_slab_get(extent))) { - return large_prof_tctx_get(tsdn, extent); + /* Static check. */ + if (alloc_ctx == NULL) { + const extent_t *extent = iealloc(tsdn, ptr); + if (unlikely(!extent_slab_get(extent))) { + return large_prof_tctx_get(tsdn, extent); + } + } else { + if (unlikely(!alloc_ctx->slab)) { + return large_prof_tctx_get(tsdn, iealloc(tsdn, ptr)); + } } return (prof_tctx_t *)(uintptr_t)1U; } -JEMALLOC_INLINE void +JEMALLOC_ALWAYS_INLINE void arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, - prof_tctx_t *tctx) { + alloc_ctx_t *alloc_ctx, prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); - extent_t *extent = iealloc(tsdn, ptr); - if (unlikely(!extent_slab_get(extent))) { - large_prof_tctx_set(tsdn, extent, tctx); + /* Static check. */ + if (alloc_ctx == NULL) { + extent_t *extent = iealloc(tsdn, ptr); + if (unlikely(!extent_slab_get(extent))) { + large_prof_tctx_set(tsdn, extent, tctx); + } + } else { + if (unlikely(!alloc_ctx->slab)) { + large_prof_tctx_set(tsdn, iealloc(tsdn, ptr), tctx); + } } } @@ -196,7 +211,7 @@ arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) { JEMALLOC_ALWAYS_INLINE void arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, - dalloc_ctx_t *dalloc_ctx, bool slow_path) { + alloc_ctx_t *alloc_ctx, bool slow_path) { assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); @@ -208,9 +223,9 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, szind_t szind; bool slab; rtree_ctx_t *rtree_ctx; - if (dalloc_ctx != NULL) { - szind = dalloc_ctx->szind; - slab = dalloc_ctx->slab; + if (alloc_ctx != NULL) { + szind = alloc_ctx->szind; + slab = alloc_ctx->slab; assert(szind != NSIZES); } else { rtree_ctx = tsd_rtree_ctx(tsdn_tsd(tsdn)); @@ -293,7 +308,7 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) { JEMALLOC_ALWAYS_INLINE void arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - dalloc_ctx_t *dalloc_ctx, bool slow_path) { + alloc_ctx_t *alloc_ctx, bool slow_path) { assert(!tsdn_null(tsdn) || tcache == NULL); assert(ptr != NULL); assert(size <= LARGE_MAXCLASS); @@ -305,9 +320,9 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, szind_t szind; bool slab; - UNUSED dalloc_ctx_t local_ctx; + UNUSED alloc_ctx_t local_ctx; if (config_prof && opt_prof) { - if (dalloc_ctx == NULL) { + if (alloc_ctx == NULL) { /* Uncommon case and should be a static check. */ rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, @@ -316,10 +331,10 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, (uintptr_t)ptr, true, &local_ctx.szind, &local_ctx.slab); assert(local_ctx.szind == size2index(size)); - dalloc_ctx = &local_ctx; + alloc_ctx = &local_ctx; } - slab = dalloc_ctx->slab; - szind = dalloc_ctx->szind; + slab = alloc_ctx->slab; + szind = alloc_ctx->szind; } else { /* * There is no risk of being confused by a promoted sampled diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 1f4fb6b1..1370b535 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -260,8 +260,8 @@ struct arena_tdata_s { ticker_t decay_ticker; }; -/* Used to pass rtree lookup context down the deallocation path. */ -struct dalloc_ctx_s { +/* Used to pass rtree lookup context down the path. */ +struct alloc_ctx_s { szind_t szind; bool slab; }; diff --git a/include/jemalloc/internal/arena_types.h b/include/jemalloc/internal/arena_types.h index 435b930d..e243aabf 100644 --- a/include/jemalloc/internal/arena_types.h +++ b/include/jemalloc/internal/arena_types.h @@ -19,7 +19,7 @@ typedef struct arena_decay_s arena_decay_t; typedef struct arena_bin_s arena_bin_t; typedef struct arena_s arena_t; typedef struct arena_tdata_s arena_tdata_t; -typedef struct dalloc_ctx_s dalloc_ctx_t; +typedef struct alloc_ctx_s alloc_ctx_t; typedef enum { percpu_arena_disabled = 0, diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_c.h b/include/jemalloc/internal/jemalloc_internal_inlines_c.h index 4fb34241..7884a206 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_c.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_c.h @@ -15,10 +15,10 @@ void *ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, void *ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero); size_t ivsalloc(tsdn_t *tsdn, const void *ptr); void idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, - dalloc_ctx_t *dalloc_ctx, bool is_internal, bool slow_path); + alloc_ctx_t *alloc_ctx, bool is_internal, bool slow_path); void idalloc(tsd_t *tsd, void *ptr); void isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - dalloc_ctx_t *dalloc_ctx, bool slow_path); + alloc_ctx_t *alloc_ctx, bool slow_path); void *iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); @@ -107,7 +107,7 @@ ivsalloc(tsdn_t *tsdn, const void *ptr) { } JEMALLOC_ALWAYS_INLINE void -idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, dalloc_ctx_t *dalloc_ctx, +idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, alloc_ctx_t *alloc_ctx, bool is_internal, bool slow_path) { assert(ptr != NULL); assert(!is_internal || tcache == NULL); @@ -120,7 +120,7 @@ idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, dalloc_ctx_t *dalloc_ctx, if (!is_internal && *tsd_reentrancy_levelp_get(tsdn_tsd(tsdn)) != 0) { tcache = NULL; } - arena_dalloc(tsdn, ptr, tcache, dalloc_ctx, slow_path); + arena_dalloc(tsdn, ptr, tcache, alloc_ctx, slow_path); } JEMALLOC_ALWAYS_INLINE void @@ -130,9 +130,9 @@ idalloc(tsd_t *tsd, void *ptr) { JEMALLOC_ALWAYS_INLINE void isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - dalloc_ctx_t *dalloc_ctx, bool slow_path) { + alloc_ctx_t *alloc_ctx, bool slow_path) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - arena_sdalloc(tsdn, ptr, size, tcache, dalloc_ctx, slow_path); + arena_sdalloc(tsdn, ptr, size, tcache, alloc_ctx, slow_path); } JEMALLOC_ALWAYS_INLINE void * diff --git a/include/jemalloc/internal/prof_inlines_b.h b/include/jemalloc/internal/prof_inlines_b.h index 5ee72c53..6a79c01e 100644 --- a/include/jemalloc/internal/prof_inlines_b.h +++ b/include/jemalloc/internal/prof_inlines_b.h @@ -5,20 +5,22 @@ bool prof_active_get_unlocked(void); bool prof_gdump_get_unlocked(void); prof_tdata_t *prof_tdata_get(tsd_t *tsd, bool create); -prof_tctx_t *prof_tctx_get(tsdn_t *tsdn, const void *ptr); +prof_tctx_t *prof_tctx_get(tsdn_t *tsdn, const void *ptr, + alloc_ctx_t *alloc_ctx); void prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, - prof_tctx_t *tctx); + alloc_ctx_t *alloc_ctx, prof_tctx_t *tctx); void prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx); bool prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update, prof_tdata_t **tdata_out); prof_tctx_t *prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update); void prof_malloc(tsdn_t *tsdn, const void *ptr, size_t usize, - prof_tctx_t *tctx); + alloc_ctx_t *alloc_ctx, prof_tctx_t *tctx); void prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, prof_tctx_t *tctx, bool prof_active, bool updated, const void *old_ptr, size_t old_usize, prof_tctx_t *old_tctx); -void prof_free(tsd_t *tsd, const void *ptr, size_t usize); +void prof_free(tsd_t *tsd, const void *ptr, size_t usize, + alloc_ctx_t *alloc_ctx); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PROF_C_)) @@ -67,19 +69,20 @@ prof_tdata_get(tsd_t *tsd, bool create) { } JEMALLOC_ALWAYS_INLINE prof_tctx_t * -prof_tctx_get(tsdn_t *tsdn, const void *ptr) { +prof_tctx_get(tsdn_t *tsdn, const void *ptr, alloc_ctx_t *alloc_ctx) { cassert(config_prof); assert(ptr != NULL); - return arena_prof_tctx_get(tsdn, ptr); + return arena_prof_tctx_get(tsdn, ptr, alloc_ctx); } JEMALLOC_ALWAYS_INLINE void -prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, prof_tctx_t *tctx) { +prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, + alloc_ctx_t *alloc_ctx, prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); - arena_prof_tctx_set(tsdn, ptr, usize, tctx); + arena_prof_tctx_set(tsdn, ptr, usize, alloc_ctx, tctx); } JEMALLOC_ALWAYS_INLINE void @@ -145,7 +148,8 @@ prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update) { } JEMALLOC_ALWAYS_INLINE void -prof_malloc(tsdn_t *tsdn, const void *ptr, size_t usize, prof_tctx_t *tctx) { +prof_malloc(tsdn_t *tsdn, const void *ptr, size_t usize, alloc_ctx_t *alloc_ctx, + prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); assert(usize == isalloc(tsdn, ptr)); @@ -153,7 +157,8 @@ prof_malloc(tsdn_t *tsdn, const void *ptr, size_t usize, prof_tctx_t *tctx) { if (unlikely((uintptr_t)tctx > (uintptr_t)1U)) { prof_malloc_sample_object(tsdn, ptr, usize, tctx); } else { - prof_tctx_set(tsdn, ptr, usize, (prof_tctx_t *)(uintptr_t)1U); + prof_tctx_set(tsdn, ptr, usize, alloc_ctx, + (prof_tctx_t *)(uintptr_t)1U); } } @@ -188,7 +193,7 @@ prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, prof_tctx_t *tctx, if (unlikely(sampled)) { prof_malloc_sample_object(tsd_tsdn(tsd), ptr, usize, tctx); } else if (moved) { - prof_tctx_set(tsd_tsdn(tsd), ptr, usize, + prof_tctx_set(tsd_tsdn(tsd), ptr, usize, NULL, (prof_tctx_t *)(uintptr_t)1U); } else if (unlikely(old_sampled)) { /* @@ -199,7 +204,7 @@ prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, prof_tctx_t *tctx, */ prof_tctx_reset(tsd_tsdn(tsd), ptr, tctx); } else { - assert((uintptr_t)prof_tctx_get(tsd_tsdn(tsd), ptr) == + assert((uintptr_t)prof_tctx_get(tsd_tsdn(tsd), ptr, NULL) == (uintptr_t)1U); } @@ -216,8 +221,8 @@ prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, prof_tctx_t *tctx, } JEMALLOC_ALWAYS_INLINE void -prof_free(tsd_t *tsd, const void *ptr, size_t usize) { - prof_tctx_t *tctx = prof_tctx_get(tsd_tsdn(tsd), ptr); +prof_free(tsd_t *tsd, const void *ptr, size_t usize, alloc_ctx_t *alloc_ctx) { + prof_tctx_t *tctx = prof_tctx_get(tsd_tsdn(tsd), ptr, alloc_ctx); cassert(config_prof); assert(usize == isalloc(tsd_tsdn(tsd), ptr)); diff --git a/src/arena.c b/src/arena.c index 16728b34..4f5dcf6e 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1064,12 +1064,19 @@ arena_reset(tsd_t *tsd, arena_t *arena) { size_t usize; malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx); + alloc_ctx_t alloc_ctx; + rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd); + rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab); + assert(alloc_ctx.szind != NSIZES); + if (config_stats || (config_prof && opt_prof)) { - usize = isalloc(tsd_tsdn(tsd), ptr); + usize = index2size(alloc_ctx.szind); + assert(usize == isalloc(tsd_tsdn(tsd), ptr)); } /* Remove large allocation from prof sample set. */ if (config_prof && opt_prof) { - prof_free(tsd, ptr, usize); + prof_free(tsd, ptr, usize, &alloc_ctx); } large_dalloc(tsd_tsdn(tsd), extent); malloc_mutex_lock(tsd_tsdn(tsd), &arena->large_mtx); diff --git a/src/jemalloc.c b/src/jemalloc.c index e71949a1..fb164ee9 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1749,7 +1749,14 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { */ prof_tctx_t *tctx = prof_alloc_prep( tsd, usize, prof_active_get_unlocked(), true); + + alloc_ctx_t alloc_ctx; if (likely((uintptr_t)tctx == (uintptr_t)1U)) { + if (usize > SMALL_MAXCLASS) { + alloc_ctx.slab = false; + } else { + alloc_ctx.slab = true; + } allocation = imalloc_no_sample( sopts, dopts, tsd, usize, usize, ind); } else if ((uintptr_t)tctx > (uintptr_t)1U) { @@ -1759,6 +1766,7 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { */ allocation = imalloc_sample( sopts, dopts, tsd, usize, ind); + alloc_ctx.slab = false; } else { allocation = NULL; } @@ -1767,9 +1775,7 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { prof_alloc_rollback(tsd, tctx, true); goto label_oom; } - - prof_malloc(tsd_tsdn(tsd), allocation, usize, tctx); - + prof_malloc(tsd_tsdn(tsd), allocation, usize, &alloc_ctx, tctx); } else { /* * If dopts->alignment > 0, then ind is still 0, but usize was @@ -2016,13 +2022,14 @@ irealloc_prof_sample(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize, } JEMALLOC_ALWAYS_INLINE_C void * -irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize) { +irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize, + alloc_ctx_t *alloc_ctx) { void *p; bool prof_active; prof_tctx_t *old_tctx, *tctx; prof_active = prof_active_get_unlocked(); - old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr); + old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr, alloc_ctx); tctx = prof_alloc_prep(tsd, usize, prof_active, true); if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { p = irealloc_prof_sample(tsd, old_ptr, old_usize, usize, tctx); @@ -2048,28 +2055,28 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); - dalloc_ctx_t dalloc_ctx; + alloc_ctx_t alloc_ctx; rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd); rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx, - (uintptr_t)ptr, true, &dalloc_ctx.szind, &dalloc_ctx.slab); - assert(dalloc_ctx.szind != NSIZES); + (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab); + assert(alloc_ctx.szind != NSIZES); size_t usize; if (config_prof && opt_prof) { - usize = index2size(dalloc_ctx.szind); - prof_free(tsd, ptr, usize); + usize = index2size(alloc_ctx.szind); + prof_free(tsd, ptr, usize, &alloc_ctx); } else if (config_stats) { - usize = index2size(dalloc_ctx.szind); + usize = index2size(alloc_ctx.szind); } if (config_stats) { *tsd_thread_deallocatedp_get(tsd) += usize; } if (likely(!slow_path)) { - idalloctm(tsd_tsdn(tsd), ptr, tcache, &dalloc_ctx, false, + idalloctm(tsd_tsdn(tsd), ptr, tcache, &alloc_ctx, false, false); } else { - idalloctm(tsd_tsdn(tsd), ptr, tcache, &dalloc_ctx, false, + idalloctm(tsd_tsdn(tsd), ptr, tcache, &alloc_ctx, false, true); } } @@ -2083,14 +2090,14 @@ isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) { assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); - dalloc_ctx_t dalloc_ctx, *ctx; + alloc_ctx_t alloc_ctx, *ctx; if (config_prof && opt_prof) { rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd); rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx, - (uintptr_t)ptr, true, &dalloc_ctx.szind, &dalloc_ctx.slab); - assert(dalloc_ctx.szind == size2index(usize)); - prof_free(tsd, ptr, usize); - ctx = &dalloc_ctx; + (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab); + assert(alloc_ctx.szind == size2index(usize)); + ctx = &alloc_ctx; + prof_free(tsd, ptr, usize, ctx); } else { ctx = NULL; } @@ -2138,11 +2145,18 @@ je_realloc(void *ptr, size_t size) { witness_assert_lockless(tsd_tsdn(tsd)); - old_usize = isalloc(tsd_tsdn(tsd), ptr); + alloc_ctx_t alloc_ctx; + rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd); + rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab); + assert(alloc_ctx.szind != NSIZES); + old_usize = index2size(alloc_ctx.szind); + assert(old_usize == isalloc(tsd_tsdn(tsd), ptr)); if (config_prof && opt_prof) { usize = s2u(size); ret = unlikely(usize == 0 || usize > LARGE_MAXCLASS) ? - NULL : irealloc_prof(tsd, ptr, old_usize, usize); + NULL : irealloc_prof(tsd, ptr, old_usize, usize, + &alloc_ctx); } else { if (config_stats) { usize = s2u(size); @@ -2398,13 +2412,13 @@ irallocx_prof_sample(tsdn_t *tsdn, void *old_ptr, size_t old_usize, JEMALLOC_ALWAYS_INLINE_C void * irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size, size_t alignment, size_t *usize, bool zero, tcache_t *tcache, - arena_t *arena) { + arena_t *arena, alloc_ctx_t *alloc_ctx) { void *p; bool prof_active; prof_tctx_t *old_tctx, *tctx; prof_active = prof_active_get_unlocked(); - old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr); + old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr, alloc_ctx); tctx = prof_alloc_prep(tsd, *usize, prof_active, false); if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) { p = irallocx_prof_sample(tsd_tsdn(tsd), old_ptr, old_usize, @@ -2474,15 +2488,20 @@ je_rallocx(void *ptr, size_t size, int flags) { tcache = tcache_get(tsd); } - old_usize = isalloc(tsd_tsdn(tsd), ptr); - + alloc_ctx_t alloc_ctx; + rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd); + rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab); + assert(alloc_ctx.szind != NSIZES); + old_usize = index2size(alloc_ctx.szind); + assert(old_usize == isalloc(tsd_tsdn(tsd), ptr)); if (config_prof && opt_prof) { usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment); if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { goto label_oom; } p = irallocx_prof(tsd, ptr, old_usize, size, alignment, &usize, - zero, tcache, arena); + zero, tcache, arena, &alloc_ctx); if (unlikely(p == NULL)) { goto label_oom; } @@ -2544,13 +2563,13 @@ ixallocx_prof_sample(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size, JEMALLOC_ALWAYS_INLINE_C size_t ixallocx_prof(tsd_t *tsd, void *ptr, size_t old_usize, size_t size, - size_t extra, size_t alignment, bool zero) { + size_t extra, size_t alignment, bool zero, alloc_ctx_t *alloc_ctx) { size_t usize_max, usize; bool prof_active; prof_tctx_t *old_tctx, *tctx; prof_active = prof_active_get_unlocked(); - old_tctx = prof_tctx_get(tsd_tsdn(tsd), ptr); + old_tctx = prof_tctx_get(tsd_tsdn(tsd), ptr, alloc_ctx); /* * usize isn't knowable before ixalloc() returns when extra is non-zero. * Therefore, compute its maximum possible value and use that in @@ -2605,8 +2624,13 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) { tsd = tsd_fetch(); witness_assert_lockless(tsd_tsdn(tsd)); - old_usize = isalloc(tsd_tsdn(tsd), ptr); - + alloc_ctx_t alloc_ctx; + rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd); + rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx, + (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab); + assert(alloc_ctx.szind != NSIZES); + old_usize = index2size(alloc_ctx.szind); + assert(old_usize == isalloc(tsd_tsdn(tsd), ptr)); /* * The API explicitly absolves itself of protecting against (size + * extra) numerical overflow, but we may need to clamp extra to avoid @@ -2626,7 +2650,7 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) { if (config_prof && opt_prof) { usize = ixallocx_prof(tsd, ptr, old_usize, size, extra, - alignment, zero); + alignment, zero, &alloc_ctx); } else { usize = ixallocx_helper(tsd_tsdn(tsd), ptr, old_usize, size, extra, alignment, zero); diff --git a/src/prof.c b/src/prof.c index 1844c2f3..334466b1 100644 --- a/src/prof.c +++ b/src/prof.c @@ -234,7 +234,7 @@ prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated) { void prof_malloc_sample_object(tsdn_t *tsdn, const void *ptr, size_t usize, prof_tctx_t *tctx) { - prof_tctx_set(tsdn, ptr, usize, tctx); + prof_tctx_set(tsdn, ptr, usize, NULL, tctx); malloc_mutex_lock(tsdn, tctx->tdata->lock); tctx->cnts.curobjs++; diff --git a/test/unit/prof_tctx.c b/test/unit/prof_tctx.c index 30c6b178..ff3b2b0c 100644 --- a/test/unit/prof_tctx.c +++ b/test/unit/prof_tctx.c @@ -15,7 +15,7 @@ TEST_BEGIN(test_prof_realloc) { prof_cnt_all(&curobjs_0, NULL, NULL, NULL); p = mallocx(1024, flags); assert_ptr_not_null(p, "Unexpected mallocx() failure"); - tctx_p = prof_tctx_get(tsdn, p); + tctx_p = prof_tctx_get(tsdn, p, NULL); assert_ptr_ne(tctx_p, (prof_tctx_t *)(uintptr_t)1U, "Expected valid tctx"); prof_cnt_all(&curobjs_1, NULL, NULL, NULL); @@ -25,7 +25,7 @@ TEST_BEGIN(test_prof_realloc) { q = rallocx(p, 2048, flags); assert_ptr_ne(p, q, "Expected move"); assert_ptr_not_null(p, "Unexpected rmallocx() failure"); - tctx_q = prof_tctx_get(tsdn, q); + tctx_q = prof_tctx_get(tsdn, q, NULL); assert_ptr_ne(tctx_q, (prof_tctx_t *)(uintptr_t)1U, "Expected valid tctx"); prof_cnt_all(&curobjs_2, NULL, NULL, NULL); -- GitLab From b348ba29bb94b6e9da8dcea1105d4614556aceb9 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 11 Apr 2017 23:13:45 -0700 Subject: [PATCH 406/544] Bundle 3 branches on fast path into tsd_state. Added tsd_state_nominal_slow, which on fast path malloc() incorporates tcache_enabled check, and on fast path free() bundles both malloc_slow and tcache_enabled branches. --- .../internal/jemalloc_internal_externs.h | 4 + include/jemalloc/internal/private_symbols.txt | 3 + include/jemalloc/internal/tcache_inlines.h | 1 + include/jemalloc/internal/tsd_externs.h | 2 + include/jemalloc/internal/tsd_inlines.h | 83 +++++++------- include/jemalloc/internal/tsd_structs.h | 2 +- include/jemalloc/internal/tsd_types.h | 10 +- src/jemalloc.c | 101 +++++++++++------- src/tcache.c | 2 + src/tsd.c | 40 ++++++- 10 files changed, 170 insertions(+), 78 deletions(-) diff --git a/include/jemalloc/internal/jemalloc_internal_externs.h b/include/jemalloc/internal/jemalloc_internal_externs.h index 56d39d48..45c119f8 100644 --- a/include/jemalloc/internal/jemalloc_internal_externs.h +++ b/include/jemalloc/internal/jemalloc_internal_externs.h @@ -3,6 +3,10 @@ #include "jemalloc/internal/atomic.h" +/* TSD checks this to set thread local slow state accordingly. */ +extern bool malloc_slow; + +/* Run-time options. */ extern bool opt_abort; extern const char *opt_junk; extern bool opt_junk_alloc; diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 4931d489..c1573aa6 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -289,6 +289,7 @@ malloc_mutex_postfork_parent malloc_mutex_prefork malloc_mutex_unlock malloc_printf +malloc_slow malloc_snprintf malloc_strtoumax malloc_tsd_boot0 @@ -526,6 +527,7 @@ tsd_cleanup tsd_cleanup_wrapper tsd_fetch tsd_fetch_impl +tsd_fetch_slow tsd_get tsd_get_allocates tsd_iarena_get @@ -541,6 +543,7 @@ tsd_narenas_tdatap_get tsd_reentrancy_level_get tsd_reentrancy_level_set tsd_reentrancy_levelp_get +tsd_slow_update tsd_wrapper_get tsd_wrapper_set tsd_nominal diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index dae43f99..ea29f350 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -40,6 +40,7 @@ tcache_enabled_set(tsd_t *tsd, bool enabled) { } /* Commit the state last. Above calls check current state. */ tsd_tcache_enabled_set(tsd, enabled); + tsd_slow_update(tsd); } JEMALLOC_ALWAYS_INLINE void diff --git a/include/jemalloc/internal/tsd_externs.h b/include/jemalloc/internal/tsd_externs.h index d15fd591..6b9dfdc6 100644 --- a/include/jemalloc/internal/tsd_externs.h +++ b/include/jemalloc/internal/tsd_externs.h @@ -14,5 +14,7 @@ void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block); #endif bool tsd_data_init(void *arg); void tsd_cleanup(void *arg); +tsd_t *tsd_fetch_slow(tsd_t *tsd); +void tsd_slow_update(tsd_t *tsd); #endif /* JEMALLOC_INTERNAL_TSD_EXTERNS_H */ diff --git a/include/jemalloc/internal/tsd_inlines.h b/include/jemalloc/internal/tsd_inlines.h index 7c3fba5f..46eefb6e 100644 --- a/include/jemalloc/internal/tsd_inlines.h +++ b/include/jemalloc/internal/tsd_inlines.h @@ -19,12 +19,54 @@ bool tsdn_null(const tsdn_t *tsdn); tsd_t *tsdn_tsd(tsdn_t *tsdn); rtree_ctx_t *tsd_rtree_ctx(tsd_t *tsd); rtree_ctx_t *tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback); +bool tsd_fast(tsd_t *tsd); +void tsd_assert_fast(tsd_t *tsd); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TSD_C_)) malloc_tsd_externs(, tsd_t) malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, , tsd_t, tsd_initializer, tsd_cleanup) +#define MALLOC_TSD_getset_yes(n, t) \ +JEMALLOC_ALWAYS_INLINE t \ +tsd_##n##_get(tsd_t *tsd) { \ + return *tsd_##n##p_get(tsd); \ +} \ +JEMALLOC_ALWAYS_INLINE void \ +tsd_##n##_set(tsd_t *tsd, t n) { \ + assert(tsd->state == tsd_state_nominal || \ + tsd->state == tsd_state_nominal_slow || \ + tsd->state == tsd_state_reincarnated); \ + tsd->n = n; \ +} +#define MALLOC_TSD_getset_no(n, t) +#define O(n, t, gs, i, c) \ +JEMALLOC_ALWAYS_INLINE t * \ +tsd_##n##p_get(tsd_t *tsd) { \ + return &tsd->n; \ +} \ + \ +MALLOC_TSD_getset_##gs(n, t) +MALLOC_TSD +#undef MALLOC_TSD_getset_yes +#undef MALLOC_TSD_getset_no +#undef O + +JEMALLOC_ALWAYS_INLINE void +tsd_assert_fast(tsd_t *tsd) { + assert(!malloc_slow && tsd_tcache_enabled_get(tsd)); +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_fast(tsd_t *tsd) { + bool fast = (tsd->state == tsd_state_nominal); + if (fast) { + tsd_assert_fast(tsd); + } + + return fast; +} + JEMALLOC_ALWAYS_INLINE tsd_t * tsd_fetch_impl(bool init) { tsd_t *tsd = tsd_get(init); @@ -35,19 +77,10 @@ tsd_fetch_impl(bool init) { assert(tsd != NULL); if (unlikely(tsd->state != tsd_state_nominal)) { - if (tsd->state == tsd_state_uninitialized) { - tsd->state = tsd_state_nominal; - /* Trigger cleanup handler registration. */ - tsd_set(tsd); - tsd_data_init(tsd); - } else if (tsd->state == tsd_state_purgatory) { - tsd->state = tsd_state_reincarnated; - tsd_set(tsd); - tsd_data_init(tsd); - } else { - assert(tsd->state == tsd_state_reincarnated); - } + return tsd_fetch_slow(tsd); } + assert(tsd_fast(tsd)); + tsd_assert_fast(tsd); return tsd; } @@ -64,33 +97,9 @@ tsd_tsdn(tsd_t *tsd) { JEMALLOC_INLINE bool tsd_nominal(tsd_t *tsd) { - return (tsd->state == tsd_state_nominal); + return (tsd->state <= tsd_state_nominal_max); } -#define MALLOC_TSD_getset_yes(n, t) \ -JEMALLOC_ALWAYS_INLINE t \ -tsd_##n##_get(tsd_t *tsd) { \ - return *tsd_##n##p_get(tsd); \ -} \ -JEMALLOC_ALWAYS_INLINE void \ -tsd_##n##_set(tsd_t *tsd, t n) { \ - assert(tsd->state == tsd_state_nominal || \ - tsd->state == tsd_state_reincarnated); \ - tsd->n = n; \ -} -#define MALLOC_TSD_getset_no(n, t) -#define O(n, t, gs, i, c) \ -JEMALLOC_ALWAYS_INLINE t * \ -tsd_##n##p_get(tsd_t *tsd) { \ - return &tsd->n; \ -} \ - \ -MALLOC_TSD_getset_##gs(n, t) -MALLOC_TSD -#undef MALLOC_TSD_getset_yes -#undef MALLOC_TSD_getset_no -#undef O - JEMALLOC_ALWAYS_INLINE tsdn_t * tsdn_fetch(void) { if (!tsd_booted_get()) { diff --git a/include/jemalloc/internal/tsd_structs.h b/include/jemalloc/internal/tsd_structs.h index ac74152c..c166fe6b 100644 --- a/include/jemalloc/internal/tsd_structs.h +++ b/include/jemalloc/internal/tsd_structs.h @@ -64,7 +64,7 @@ struct tsd_init_head_s { O(iarena, arena_t *, yes, no, yes) \ O(arena, arena_t *, yes, no, yes) \ O(arenas_tdata, arena_tdata_t *,yes, no, yes) \ - O(tcache, tcache_t, yes, no, yes) \ + O(tcache, tcache_t, no, no, yes) \ O(witnesses, witness_list_t, no, no, yes) \ O(rtree_leaf_elm_witnesses, rtree_leaf_elm_witness_tsd_t, \ no, no, no) \ diff --git a/include/jemalloc/internal/tsd_types.h b/include/jemalloc/internal/tsd_types.h index 27afd1d6..dc9efbb6 100644 --- a/include/jemalloc/internal/tsd_types.h +++ b/include/jemalloc/internal/tsd_types.h @@ -20,11 +20,15 @@ typedef struct tsdn_s tsdn_t; #define TSDN_NULL ((tsdn_t *)0) enum { - tsd_state_uninitialized = 0, - tsd_state_nominal = 1, + tsd_state_nominal = 0, /* Common case --> jnz. */ + tsd_state_nominal_slow = 1, /* Initialized but on slow path. */ + /* the above 2 nominal states should be lower values. */ + tsd_state_nominal_max = 1, /* used for comparison only. */ tsd_state_purgatory = 2, - tsd_state_reincarnated = 3 + tsd_state_reincarnated = 3, + tsd_state_uninitialized = 4 }; + /* Manually limit tsd_state_t to a single byte. */ typedef uint8_t tsd_state_t; diff --git a/src/jemalloc.c b/src/jemalloc.c index fb164ee9..4bec2dea 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -76,7 +76,7 @@ typedef enum { static malloc_init_t malloc_init_state = malloc_init_uninitialized; /* False should be the common case. Set to true to trigger initialization. */ -static bool malloc_slow = true; +bool malloc_slow = true; /* When malloc_slow is true, set the corresponding bits for sanity check. */ enum { @@ -1539,7 +1539,13 @@ imalloc_no_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd, /* Fill in the tcache. */ if (dopts->tcache_ind == TCACHE_IND_AUTOMATIC) { - tcache = tcache_get(tsd); + if (likely(!sopts->slow)) { + /* Getting tcache ptr unconditionally. */ + tcache = tsd_tcachep_get(tsd); + assert(tcache == tcache_get(tsd)); + } else { + tcache = tcache_get(tsd); + } } else if (dopts->tcache_ind == TCACHE_IND_NONE) { tcache = NULL; } else { @@ -1640,13 +1646,11 @@ compute_size_with_overflow(bool may_overflow, dynamic_opts_t *dopts, } JEMALLOC_ALWAYS_INLINE_C int -imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { +imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) { /* Where the actual allocated memory will live. */ void *allocation = NULL; /* Filled in by compute_size_with_overflow below. */ size_t size = 0; - /* We compute a value for this right before allocating. */ - tsd_t *tsd = NULL; /* * For unaligned allocations, we need only ind. For aligned * allocations, or in case of stats or profiling we need usize. @@ -1667,13 +1671,6 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { */ int8_t *reentrancy_level = NULL; - /* Initialize (if we can't prove we don't have to). */ - if (sopts->slow) { - if (unlikely(malloc_init())) { - goto label_oom; - } - } - /* Compute the amount of memory the user wants. */ if (unlikely(compute_size_with_overflow(sopts->may_overflow, dopts, &size))) { @@ -1714,11 +1711,6 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { } } - /* - * We always need the tsd, even if we aren't going to use the tcache for - * some reason. Let's grab it right away. - */ - tsd = tsd_fetch(); /* * If we need to handle reentrancy, we can do it out of a @@ -1752,11 +1744,7 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts) { alloc_ctx_t alloc_ctx; if (likely((uintptr_t)tctx == (uintptr_t)1U)) { - if (usize > SMALL_MAXCLASS) { - alloc_ctx.slab = false; - } else { - alloc_ctx.slab = true; - } + alloc_ctx.slab = (usize <= SMALL_MAXCLASS); allocation = imalloc_no_sample( sopts, dopts, tsd, usize, usize, ind); } else if ((uintptr_t)tctx > (uintptr_t)1U) { @@ -1879,12 +1867,29 @@ label_invalid_alignment: /* Returns the errno-style error code of the allocation. */ JEMALLOC_ALWAYS_INLINE_C int imalloc(static_opts_t *sopts, dynamic_opts_t *dopts) { - if (unlikely(malloc_slow)) { - sopts->slow = true; - return imalloc_body(sopts, dopts); - } else { + if (unlikely(!malloc_initialized()) && unlikely(malloc_init())) { + if (config_xmalloc && unlikely(opt_xmalloc)) { + malloc_write(sopts->oom_string); + abort(); + } + UTRACE(NULL, size, NULL); + set_errno(ENOMEM); + *dopts->result = NULL; + + return ENOMEM; + } + + /* We always need the tsd. Let's grab it right away. */ + tsd_t *tsd = tsd_fetch(); + assert(tsd); + if (likely(tsd_fast(tsd))) { + /* Fast and common path. */ + tsd_assert_fast(tsd); sopts->slow = false; - return imalloc_body(sopts, dopts); + return imalloc_body(sopts, dopts, tsd); + } else { + sopts->slow = true; + return imalloc_body(sopts, dopts, tsd); } } /******************************************************************************/ @@ -2198,13 +2203,23 @@ je_free(void *ptr) { if (*tsd_reentrancy_levelp_get(tsd) == 0) { witness_assert_lockless(tsd_tsdn(tsd)); } - tcache_t *tcache = NULL; - if (likely(*tsd_reentrancy_levelp_get(tsd) == 0)) { - tcache = tcache_get(tsd); - } - if (likely(!malloc_slow)) { + tcache_t *tcache; + if (likely(tsd_fast(tsd))) { + tsd_assert_fast(tsd); + if (likely(*tsd_reentrancy_levelp_get(tsd) == 0)) { + /* Getting tcache ptr unconditionally. */ + tcache = tsd_tcachep_get(tsd); + assert(tcache == tcache_get(tsd)); + } else { + tcache = NULL; + } ifree(tsd, ptr, tcache, false); } else { + if (likely(*tsd_reentrancy_levelp_get(tsd) == 0)) { + tcache = tcache_get(tsd); + } else { + tcache = NULL; + } ifree(tsd, ptr, tcache, true); } if (*tsd_reentrancy_levelp_get(tsd) == 0) { @@ -2699,6 +2714,7 @@ je_dallocx(void *ptr, int flags) { assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); + bool fast = tsd_fast(tsd); witness_assert_lockless(tsd_tsdn(tsd)); if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { /* Not allowed to be reentrant and specify a custom tcache. */ @@ -2710,14 +2726,20 @@ je_dallocx(void *ptr, int flags) { } } else { if (likely(*tsd_reentrancy_levelp_get(tsd) == 0)) { - tcache = tcache_get(tsd); + if (likely(fast)) { + tcache = tsd_tcachep_get(tsd); + assert(tcache == tcache_get(tsd)); + } else { + tcache = tcache_get(tsd); + } } else { tcache = NULL; } } UTRACE(ptr, 0, 0); - if (likely(!malloc_slow)) { + if (likely(fast)) { + tsd_assert_fast(tsd); ifree(tsd, ptr, tcache, false); } else { ifree(tsd, ptr, tcache, true); @@ -2749,6 +2771,7 @@ je_sdallocx(void *ptr, size_t size, int flags) { assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); + bool fast = tsd_fast(tsd); usize = inallocx(tsd_tsdn(tsd), size, flags); assert(usize == isalloc(tsd_tsdn(tsd), ptr)); @@ -2763,14 +2786,20 @@ je_sdallocx(void *ptr, size_t size, int flags) { } } else { if (likely(*tsd_reentrancy_levelp_get(tsd) == 0)) { - tcache = tcache_get(tsd); + if (likely(fast)) { + tcache = tsd_tcachep_get(tsd); + assert(tcache == tcache_get(tsd)); + } else { + tcache = tcache_get(tsd); + } } else { tcache = NULL; } } UTRACE(ptr, 0, 0); - if (likely(!malloc_slow)) { + if (likely(fast)) { + tsd_assert_fast(tsd); isfree(tsd, ptr, usize, tcache, false); } else { isfree(tsd, ptr, usize, tcache, true); diff --git a/src/tcache.c b/src/tcache.c index 99749fbc..7e71bb6a 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -334,6 +334,8 @@ bool tsd_tcache_enabled_data_init(tsd_t *tsd) { /* Called upon tsd initialization. */ tsd_tcache_enabled_set(tsd, opt_tcache); + tsd_slow_update(tsd); + if (opt_tcache) { /* Trigger tcache init. */ tsd_tcache_data_init(tsd); diff --git a/src/tsd.c b/src/tsd.c index 3e72548c..bdd3f3c5 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -12,6 +12,40 @@ malloc_tsd_data(, , tsd_t, TSD_INITIALIZER) /******************************************************************************/ +void +tsd_slow_update(tsd_t *tsd) { + if (tsd_nominal(tsd)) { + if (malloc_slow || !tsd->tcache_enabled) { + tsd->state = tsd_state_nominal_slow; + } else { + tsd->state = tsd_state_nominal; + } + } +} + +tsd_t * +tsd_fetch_slow(tsd_t *tsd) { + if (tsd->state == tsd_state_nominal_slow) { + /* On slow path but no work needed. */ + assert(malloc_slow || !tsd_tcache_enabled_get(tsd) || + *tsd_arenas_tdata_bypassp_get(tsd)); + } else if (tsd->state == tsd_state_uninitialized) { + tsd->state = tsd_state_nominal; + tsd_slow_update(tsd); + /* Trigger cleanup handler registration. */ + tsd_set(tsd); + tsd_data_init(tsd); + } else if (tsd->state == tsd_state_purgatory) { + tsd->state = tsd_state_reincarnated; + tsd_set(tsd); + tsd_data_init(tsd); + } else { + assert(tsd->state == tsd_state_reincarnated); + } + + return tsd; +} + void * malloc_tsd_malloc(size_t size) { return a0malloc(CACHELINE_CEILING(size)); @@ -82,6 +116,7 @@ tsd_cleanup(void *arg) { /* Do nothing. */ break; case tsd_state_nominal: + case tsd_state_nominal_slow: case tsd_state_reincarnated: /* * Reincarnated means another destructor deallocated memory @@ -129,7 +164,10 @@ malloc_tsd_boot0(void) { void malloc_tsd_boot1(void) { tsd_boot1(); - *tsd_arenas_tdata_bypassp_get(tsd_fetch()) = false; + tsd_t *tsd = tsd_fetch(); + /* malloc_slow has been set properly. Update tsd_slow. */ + tsd_slow_update(tsd); + *tsd_arenas_tdata_bypassp_get(tsd) = false; } #ifdef _WIN32 -- GitLab From c2fcf9c2cfcbaba58db1941c91c7a8a4b6623401 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 12 Apr 2017 16:16:27 -0700 Subject: [PATCH 407/544] Switch to fine-grained reentrancy support. Previously we had a general detection and support of reentrancy, at the cost of having branches and inc / dec operations on fast paths. To avoid taxing fast paths, we move the reentrancy operations onto tsd slow state, and only modify reentrancy level around external calls (that might trigger reentrancy). --- .../internal/jemalloc_internal_inlines_a.h | 23 ++++ .../internal/jemalloc_internal_inlines_b.h | 2 +- .../internal/jemalloc_internal_inlines_c.h | 4 +- include/jemalloc/internal/tsd_inlines.h | 8 +- include/jemalloc/internal/tsd_structs.h | 2 +- src/arena.c | 6 +- src/jemalloc.c | 121 ++++++++---------- src/tsd.c | 4 +- 8 files changed, 87 insertions(+), 83 deletions(-) diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_a.h b/include/jemalloc/internal/jemalloc_internal_inlines_a.h index 822b4d75..600d7226 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_a.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_a.h @@ -33,6 +33,8 @@ tcache_t *tcache_get(tsd_t *tsd); malloc_cpuid_t malloc_getcpu(void); unsigned percpu_arena_choose(void); unsigned percpu_arena_ind_limit(void); +void pre_reentrancy(tsd_t *tsd); +void post_reentrancy(tsd_t *tsd); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) @@ -445,6 +447,27 @@ tcache_get(tsd_t *tsd) { return tsd_tcachep_get(tsd); } + +JEMALLOC_INLINE void +pre_reentrancy(tsd_t *tsd) { + bool fast = tsd_fast(tsd); + ++*tsd_reentrancy_levelp_get(tsd); + if (fast) { + /* Prepare slow path for reentrancy. */ + tsd_slow_update(tsd); + assert(tsd->state == tsd_state_nominal_slow); + } +} + +JEMALLOC_INLINE void +post_reentrancy(tsd_t *tsd) { + int8_t *reentrancy_level = tsd_reentrancy_levelp_get(tsd); + assert(*reentrancy_level > 0); + if (--*reentrancy_level == 0) { + tsd_slow_update(tsd); + } +} + #endif #endif /* JEMALLOC_INTERNAL_INLINES_A_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_b.h b/include/jemalloc/internal/jemalloc_internal_inlines_b.h index 52afb42d..e7d564ce 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_b.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_b.h @@ -16,7 +16,7 @@ arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { } /* During reentrancy, arena 0 is the safest bet. */ - if (*tsd_reentrancy_levelp_get(tsd) > 1) { + if (unlikely(tsd_reentrancy_level_get(tsd) > 0)) { return arena_get(tsd_tsdn(tsd), 0, true); } diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_c.h b/include/jemalloc/internal/jemalloc_internal_inlines_c.h index 7884a206..bb1f2deb 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_c.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_c.h @@ -117,8 +117,8 @@ idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, alloc_ctx_t *alloc_ctx, if (config_stats && is_internal) { arena_internal_sub(iaalloc(tsdn, ptr), isalloc(tsdn, ptr)); } - if (!is_internal && *tsd_reentrancy_levelp_get(tsdn_tsd(tsdn)) != 0) { - tcache = NULL; + if (!is_internal && tsd_reentrancy_level_get(tsdn_tsd(tsdn)) != 0) { + assert(tcache == NULL); } arena_dalloc(tsdn, ptr, tcache, alloc_ctx, slow_path); } diff --git a/include/jemalloc/internal/tsd_inlines.h b/include/jemalloc/internal/tsd_inlines.h index 46eefb6e..93469bca 100644 --- a/include/jemalloc/internal/tsd_inlines.h +++ b/include/jemalloc/internal/tsd_inlines.h @@ -20,7 +20,7 @@ tsd_t *tsdn_tsd(tsdn_t *tsdn); rtree_ctx_t *tsd_rtree_ctx(tsd_t *tsd); rtree_ctx_t *tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback); bool tsd_fast(tsd_t *tsd); -void tsd_assert_fast(tsd_t *tsd); +bool tsd_assert_fast(tsd_t *tsd); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TSD_C_)) @@ -52,9 +52,11 @@ MALLOC_TSD #undef MALLOC_TSD_getset_no #undef O -JEMALLOC_ALWAYS_INLINE void +JEMALLOC_ALWAYS_INLINE bool tsd_assert_fast(tsd_t *tsd) { - assert(!malloc_slow && tsd_tcache_enabled_get(tsd)); + assert(!malloc_slow && tsd_tcache_enabled_get(tsd) && + tsd_reentrancy_level_get(tsd) == 0); + return true; } JEMALLOC_ALWAYS_INLINE bool diff --git a/include/jemalloc/internal/tsd_structs.h b/include/jemalloc/internal/tsd_structs.h index c166fe6b..40fea97b 100644 --- a/include/jemalloc/internal/tsd_structs.h +++ b/include/jemalloc/internal/tsd_structs.h @@ -55,7 +55,7 @@ struct tsd_init_head_s { /* O(name, type, [gs]et, init, cleanup) */ \ O(tcache_enabled, bool, yes, yes, no) \ O(arenas_tdata_bypass, bool, no, no, no) \ - O(reentrancy_level, int8_t, no, no, no) \ + O(reentrancy_level, int8_t, yes, no, no) \ O(narenas_tdata, uint32_t, yes, no, no) \ O(thread_allocated, uint64_t, yes, no, no) \ O(thread_deallocated, uint64_t, yes, no, no) \ diff --git a/src/arena.c b/src/arena.c index 4f5dcf6e..5b540ce3 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1966,11 +1966,9 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { * If we're here, then arena 0 already exists, so bootstrapping * is done enough that we should have tsd. */ - int8_t *reentrancy_level = tsd_reentrancy_levelp_get(tsdn_tsd( - tsdn)); - ++*reentrancy_level; + pre_reentrancy(tsdn_tsd(tsdn)); hooks_arena_new_hook(); - --*reentrancy_level; + post_reentrancy(tsdn_tsd(tsdn)); } return arena; diff --git a/src/jemalloc.c b/src/jemalloc.c index 4bec2dea..4c38517b 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1663,13 +1663,8 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) { szind_t ind = 0; size_t usize = 0; - /* - * For reentrancy checking, we get the old reentrancy level from tsd and - * reset it once we're done. In case of early bailout though, we never - * bother getting the old level, so we shouldn't try to reset it. This - * is indicated by leaving the pointer as NULL. - */ - int8_t *reentrancy_level = NULL; + /* Reentrancy is only checked on slow path. */ + int8_t reentrancy_level; /* Compute the amount of memory the user wants. */ if (unlikely(compute_size_with_overflow(sopts->may_overflow, dopts, @@ -1716,12 +1711,11 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) { * If we need to handle reentrancy, we can do it out of a * known-initialized arena (i.e. arena 0). */ - reentrancy_level = tsd_reentrancy_levelp_get(tsd); - ++*reentrancy_level; - if (*reentrancy_level == 1) { + reentrancy_level = tsd_reentrancy_level_get(tsd); + if (reentrancy_level == 0) { witness_assert_lockless(tsd_tsdn(tsd)); } - if (unlikely(*reentrancy_level > 1)) { + if (sopts->slow && unlikely(reentrancy_level > 0)) { /* * We should never specify particular arenas or tcaches from * within our internal allocations. @@ -1795,14 +1789,9 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) { } /* Success! */ - if (*reentrancy_level == 1) { + if (reentrancy_level == 0) { witness_assert_lockless(tsd_tsdn(tsd)); } - /* - * If we got here, we never bailed out on a failure path, so - * reentrancy_level is non-null. - */ - --*reentrancy_level; *dopts->result = allocation; return 0; @@ -1826,10 +1815,6 @@ label_oom: *dopts->result = NULL; } - if (reentrancy_level != NULL) { - --*reentrancy_level; - } - return ENOMEM; /* @@ -1857,10 +1842,6 @@ label_invalid_alignment: *dopts->result = NULL; } - if (reentrancy_level != NULL) { - --*reentrancy_level; - } - return EINVAL; } @@ -2053,8 +2034,11 @@ irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize, JEMALLOC_ALWAYS_INLINE_C void ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { - if (*tsd_reentrancy_levelp_get(tsd) == 0) { + assert(slow_path || tsd_assert_fast(tsd)); + if (tsd_reentrancy_level_get(tsd) == 0) { witness_assert_lockless(tsd_tsdn(tsd)); + } else { + assert(slow_path); } assert(ptr != NULL); @@ -2088,8 +2072,11 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { JEMALLOC_ALWAYS_INLINE_C void isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) { - if (*tsd_reentrancy_levelp_get(tsd) == 0) { + assert(slow_path || tsd_assert_fast(tsd)); + if (tsd_reentrancy_level_get(tsd) == 0) { witness_assert_lockless(tsd_tsdn(tsd)); + } else { + assert(slow_path); } assert(ptr != NULL); @@ -2129,14 +2116,14 @@ je_realloc(void *ptr, size_t size) { if (unlikely(size == 0)) { if (ptr != NULL) { - tsd_t *tsd; - /* realloc(ptr, 0) is equivalent to free(ptr). */ UTRACE(ptr, 0, 0); - tsd = tsd_fetch(); - tcache_t *tcache = NULL; - if (likely(*tsd_reentrancy_levelp_get(tsd) == 0)) { + tcache_t *tcache; + tsd_t *tsd = tsd_fetch(); + if (tsd_reentrancy_level_get(tsd) == 0) { tcache = tcache_get(tsd); + } else { + tcache = NULL; } ifree(tsd, ptr, tcache, true); return NULL; @@ -2200,29 +2187,25 @@ je_free(void *ptr) { UTRACE(ptr, 0, 0); if (likely(ptr != NULL)) { tsd_t *tsd = tsd_fetch(); - if (*tsd_reentrancy_levelp_get(tsd) == 0) { + if (tsd_reentrancy_level_get(tsd) == 0) { witness_assert_lockless(tsd_tsdn(tsd)); } + tcache_t *tcache; if (likely(tsd_fast(tsd))) { tsd_assert_fast(tsd); - if (likely(*tsd_reentrancy_levelp_get(tsd) == 0)) { - /* Getting tcache ptr unconditionally. */ - tcache = tsd_tcachep_get(tsd); - assert(tcache == tcache_get(tsd)); - } else { - tcache = NULL; - } + /* Unconditionally get tcache ptr on fast path. */ + tcache = tsd_tcachep_get(tsd); ifree(tsd, ptr, tcache, false); } else { - if (likely(*tsd_reentrancy_levelp_get(tsd) == 0)) { + if (likely(tsd_reentrancy_level_get(tsd) == 0)) { tcache = tcache_get(tsd); } else { tcache = NULL; } ifree(tsd, ptr, tcache, true); } - if (*tsd_reentrancy_levelp_get(tsd) == 0) { + if (tsd_reentrancy_level_get(tsd) == 0) { witness_assert_lockless(tsd_tsdn(tsd)); } } @@ -2707,33 +2690,32 @@ je_sallocx(const void *ptr, int flags) { JEMALLOC_EXPORT void JEMALLOC_NOTHROW je_dallocx(void *ptr, int flags) { - tsd_t *tsd; - tcache_t *tcache; - assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); - tsd = tsd_fetch(); + tsd_t *tsd = tsd_fetch(); bool fast = tsd_fast(tsd); witness_assert_lockless(tsd_tsdn(tsd)); + + tcache_t *tcache; if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { /* Not allowed to be reentrant and specify a custom tcache. */ - assert(*tsd_reentrancy_levelp_get(tsd) == 0); + assert(tsd_reentrancy_level_get(tsd) == 0); if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) { tcache = NULL; } else { tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags)); } } else { - if (likely(*tsd_reentrancy_levelp_get(tsd) == 0)) { - if (likely(fast)) { - tcache = tsd_tcachep_get(tsd); - assert(tcache == tcache_get(tsd)); - } else { + if (likely(fast)) { + tcache = tsd_tcachep_get(tsd); + assert(tcache == tcache_get(tsd)); + } else { + if (likely(tsd_reentrancy_level_get(tsd) == 0)) { tcache = tcache_get(tsd); + } else { + tcache = NULL; } - } else { - tcache = NULL; } } @@ -2749,10 +2731,9 @@ je_dallocx(void *ptr, int flags) { JEMALLOC_ALWAYS_INLINE_C size_t inallocx(tsdn_t *tsdn, size_t size, int flags) { - size_t usize; - witness_assert_lockless(tsdn); + size_t usize; if (likely((flags & MALLOCX_LG_ALIGN_MASK) == 0)) { usize = s2u(size); } else { @@ -2764,36 +2745,34 @@ inallocx(tsdn_t *tsdn, size_t size, int flags) { JEMALLOC_EXPORT void JEMALLOC_NOTHROW je_sdallocx(void *ptr, size_t size, int flags) { - tsd_t *tsd; - size_t usize; - tcache_t *tcache; - assert(ptr != NULL); assert(malloc_initialized() || IS_INITIALIZER); - tsd = tsd_fetch(); + + tsd_t *tsd = tsd_fetch(); bool fast = tsd_fast(tsd); - usize = inallocx(tsd_tsdn(tsd), size, flags); + size_t usize = inallocx(tsd_tsdn(tsd), size, flags); assert(usize == isalloc(tsd_tsdn(tsd), ptr)); - witness_assert_lockless(tsd_tsdn(tsd)); + + tcache_t *tcache; if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { /* Not allowed to be reentrant and specify a custom tcache. */ - assert(*tsd_reentrancy_levelp_get(tsd) == 0); + assert(tsd_reentrancy_level_get(tsd) == 0); if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) { tcache = NULL; } else { tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags)); } } else { - if (likely(*tsd_reentrancy_levelp_get(tsd) == 0)) { - if (likely(fast)) { - tcache = tsd_tcachep_get(tsd); - assert(tcache == tcache_get(tsd)); - } else { + if (likely(fast)) { + tcache = tsd_tcachep_get(tsd); + assert(tcache == tcache_get(tsd)); + } else { + if (likely(tsd_reentrancy_level_get(tsd) == 0)) { tcache = tcache_get(tsd); + } else { + tcache = NULL; } - } else { - tcache = NULL; } } diff --git a/src/tsd.c b/src/tsd.c index bdd3f3c5..cb7dd3fb 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -15,7 +15,8 @@ malloc_tsd_data(, , tsd_t, TSD_INITIALIZER) void tsd_slow_update(tsd_t *tsd) { if (tsd_nominal(tsd)) { - if (malloc_slow || !tsd->tcache_enabled) { + if (malloc_slow || !tsd->tcache_enabled || + tsd_reentrancy_level_get(tsd) > 0) { tsd->state = tsd_state_nominal_slow; } else { tsd->state = tsd_state_nominal; @@ -28,6 +29,7 @@ tsd_fetch_slow(tsd_t *tsd) { if (tsd->state == tsd_state_nominal_slow) { /* On slow path but no work needed. */ assert(malloc_slow || !tsd_tcache_enabled_get(tsd) || + tsd_reentrancy_level_get(tsd) > 0 || *tsd_arenas_tdata_bypassp_get(tsd)); } else if (tsd->state == tsd_state_uninitialized) { tsd->state = tsd_state_nominal; -- GitLab From d16f1e53df3836f95deeca73419bb8c541aa579f Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 14 Apr 2017 20:54:49 -0700 Subject: [PATCH 408/544] Skip percpu arena when choosing iarena. --- include/jemalloc/internal/jemalloc_internal_inlines_b.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_b.h b/include/jemalloc/internal/jemalloc_internal_inlines_b.h index e7d564ce..f22708a5 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_b.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_b.h @@ -47,7 +47,7 @@ arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { * managed arena), then percpu arena is skipped. */ if (have_percpu_arena && (percpu_arena_mode != percpu_arena_disabled) && - (arena_ind_get(ret) < percpu_arena_ind_limit()) && + !internal && (arena_ind_get(ret) < percpu_arena_ind_limit()) && (ret->last_thd != tsd_tsdn(tsd))) { unsigned ind = percpu_arena_choose(); if (arena_ind_get(ret) != ind) { -- GitLab From 3c9c41edb28b02c5ec45cfea0f076276e985cf9e Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 14 Apr 2017 11:05:38 -0700 Subject: [PATCH 409/544] Improve rtree cache with a two-level cache design. Two levels of rcache is implemented: a direct mapped cache as L1, combined with a LRU cache as L2. The L1 cache offers low cost on cache hit, but could suffer collision under circumstances. This is complemented by the L2 LRU cache, which is slower on cache access (overhead from linear search + reordering), but solves collison of L1 rather well. --- include/jemalloc/internal/rtree_inlines.h | 61 ++++++++++++++++------- include/jemalloc/internal/rtree_structs.h | 3 ++ include/jemalloc/internal/rtree_types.h | 30 ++++++----- src/prof.c | 1 + src/rtree.c | 37 +++++++++++--- 5 files changed, 97 insertions(+), 35 deletions(-) diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index ce03c578..6791f50c 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -64,6 +64,15 @@ rtree_leafkey(uintptr_t key) { return (key & mask); } +JEMALLOC_ALWAYS_INLINE size_t +rtree_cache_direct_map(uintptr_t key) { + unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR+3); + unsigned cumbits = (rtree_levels[RTREE_HEIGHT-1].cumbits - + rtree_levels[RTREE_HEIGHT-1].bits); + unsigned maskbits = ptrbits - cumbits; + return (size_t)((key >> maskbits) & (RTREE_CTX_NCACHE - 1)); +} + JEMALLOC_ALWAYS_INLINE uintptr_t rtree_subkey(uintptr_t key, unsigned level) { unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR+3); @@ -320,36 +329,54 @@ rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, assert(key != 0); assert(!dependent || !init_missing); + size_t slot = rtree_cache_direct_map(key); uintptr_t leafkey = rtree_leafkey(key); assert(leafkey != RTREE_LEAFKEY_INVALID); -#define RTREE_CACHE_CHECK(i) do { \ - if (likely(rtree_ctx->cache[i].leafkey == leafkey)) { \ - rtree_leaf_elm_t *leaf = rtree_ctx->cache[i].leaf; \ + /* Fast path: L1 direct mapped cache. */ + if (likely(rtree_ctx->cache[slot].leafkey == leafkey)) { + rtree_leaf_elm_t *leaf = rtree_ctx->cache[slot].leaf; + assert(leaf != NULL); + uintptr_t subkey = rtree_subkey(key, RTREE_HEIGHT-1); + return &leaf[subkey]; + } + /* + * Search the L2 LRU cache. On hit, swap the matching element into the + * slot in L1 cache, and move the position in L2 up by 1. + */ +#define RTREE_CACHE_CHECK_L2(i) do { \ + if (likely(rtree_ctx->l2_cache[i].leafkey == leafkey)) { \ + rtree_leaf_elm_t *leaf = rtree_ctx->l2_cache[i].leaf; \ assert(leaf != NULL); \ if (i > 0) { \ /* Bubble up by one. */ \ - rtree_ctx->cache[i].leafkey = \ - rtree_ctx->cache[i - 1].leafkey; \ - rtree_ctx->cache[i].leaf = \ - rtree_ctx->cache[i - 1].leaf; \ - rtree_ctx->cache[i - 1].leafkey = leafkey; \ - rtree_ctx->cache[i - 1].leaf = leaf; \ + rtree_ctx->l2_cache[i].leafkey = \ + rtree_ctx->l2_cache[i - 1].leafkey; \ + rtree_ctx->l2_cache[i].leaf = \ + rtree_ctx->l2_cache[i - 1].leaf; \ + rtree_ctx->l2_cache[i - 1].leafkey = \ + rtree_ctx->cache[slot].leafkey; \ + rtree_ctx->l2_cache[i - 1].leaf = \ + rtree_ctx->cache[slot].leaf; \ + } else { \ + rtree_ctx->l2_cache[0].leafkey = \ + rtree_ctx->cache[slot].leafkey; \ + rtree_ctx->l2_cache[0].leaf = \ + rtree_ctx->cache[slot].leaf; \ } \ + rtree_ctx->cache[slot].leafkey = leafkey; \ + rtree_ctx->cache[slot].leaf = leaf; \ uintptr_t subkey = rtree_subkey(key, RTREE_HEIGHT-1); \ return &leaf[subkey]; \ } \ } while (0) /* Check the first cache entry. */ - RTREE_CACHE_CHECK(0); - /* - * Search the remaining cache elements, and on success move the matching - * element up by one slot. - */ - for (unsigned i = 1; i < RTREE_CTX_NCACHE; i++) { - RTREE_CACHE_CHECK(i); + RTREE_CACHE_CHECK_L2(0); + /* Search the remaining cache elements. */ + for (unsigned i = 1; i < RTREE_CTX_NCACHE_L2; i++) { + RTREE_CACHE_CHECK_L2(i); } -#undef RTREE_CACHE_CHECK +#undef RTREE_CACHE_CHECK_L2 return rtree_leaf_elm_lookup_hard(tsdn, rtree, rtree_ctx, key, dependent, init_missing); diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h index 175a013c..7ff92e61 100644 --- a/include/jemalloc/internal/rtree_structs.h +++ b/include/jemalloc/internal/rtree_structs.h @@ -55,7 +55,10 @@ struct rtree_ctx_cache_elm_s { }; struct rtree_ctx_s { + /* Direct mapped cache. */ rtree_ctx_cache_elm_t cache[RTREE_CTX_NCACHE]; + /* L2 LRU cache. */ + rtree_ctx_cache_elm_t l2_cache[RTREE_CTX_NCACHE_L2]; }; struct rtree_s { diff --git a/include/jemalloc/internal/rtree_types.h b/include/jemalloc/internal/rtree_types.h index e480542d..d9a4cf4d 100644 --- a/include/jemalloc/internal/rtree_types.h +++ b/include/jemalloc/internal/rtree_types.h @@ -42,19 +42,25 @@ typedef struct rtree_s rtree_t; #define RTREE_LEAFKEY_INVALID ((uintptr_t)1) /* - * Number of leafkey/leaf pairs to cache. Each entry supports an entire leaf, - * so the cache hit rate is typically high even with a small number of entries. - * In rare cases extent activity will straddle the boundary between two leaf - * nodes. Furthermore, an arena may use a combination of dss and mmap. Four - * entries covers both of these considerations as long as locality of reference - * is high, and/or total memory usage doesn't exceed the range supported by - * those entries. Note that as memory usage grows past the amount that this - * cache can directly cover, the cache will become less effective if locality of - * reference is low, but the consequence is merely cache misses while traversing - * the tree nodes, and the cache will itself suffer cache misses if made overly - * large, not to mention the cost of linear search. + * Number of leafkey/leaf pairs to cache in L1 and L2 level respectively. Each + * entry supports an entire leaf, so the cache hit rate is typically high even + * with a small number of entries. In rare cases extent activity will straddle + * the boundary between two leaf nodes. Furthermore, an arena may use a + * combination of dss and mmap. Note that as memory usage grows past the amount + * that this cache can directly cover, the cache will become less effective if + * locality of reference is low, but the consequence is merely cache misses + * while traversing the tree nodes. + * + * The L1 direct mapped cache offers consistent and low cost on cache hit. + * However collision could affect hit rate negatively. This is resolved by + * combining with a L2 LRU cache, which requires linear search and re-ordering + * on access but suffers no collision. Note that, the cache will itself suffer + * cache misses if made overly large, plus the cost of linear search in the LRU + * cache. */ -#define RTREE_CTX_NCACHE 8 +#define RTREE_CTX_LG_NCACHE 4 +#define RTREE_CTX_NCACHE (1 << RTREE_CTX_LG_NCACHE) +#define RTREE_CTX_NCACHE_L2 8 /* * Zero initializer required for tsd initialization only. Proper initialization diff --git a/src/prof.c b/src/prof.c index 334466b1..b33e9397 100644 --- a/src/prof.c +++ b/src/prof.c @@ -310,6 +310,7 @@ prof_leave(tsd_t *tsd, prof_tdata_t *tdata) { } #ifdef JEMALLOC_PROF_LIBUNWIND +JEMALLOC_ALIGNED(CACHELINE) void prof_backtrace(prof_bt_t *bt) { int nframes; diff --git a/src/rtree.c b/src/rtree.c index 051428f1..8d11d99f 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -256,6 +256,16 @@ rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, leaf = rtree->root; #endif + if (config_debug) { + uintptr_t leafkey = rtree_leafkey(key); + for (unsigned i = 0; i < RTREE_CTX_NCACHE; i++) { + assert(rtree_ctx->cache[i].leafkey != leafkey); + } + for (unsigned i = 0; i < RTREE_CTX_NCACHE_L2; i++) { + assert(rtree_ctx->l2_cache[i].leafkey != leafkey); + } + } + #define RTREE_GET_CHILD(level) { \ assert(level < RTREE_HEIGHT-1); \ if (level != 0 && !dependent && \ @@ -277,20 +287,30 @@ rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, dependent); \ } \ } + /* + * Cache replacement upon hard lookup (i.e. L1 & L2 rtree cache miss): + * (1) evict last entry in L2 cache; (2) move the collision slot from L1 + * cache down to L2; and 3) fill L1. + */ #define RTREE_GET_LEAF(level) { \ assert(level == RTREE_HEIGHT-1); \ if (!dependent && unlikely(!rtree_leaf_valid(leaf))) { \ return NULL; \ } \ - if (RTREE_CTX_NCACHE > 1) { \ - memmove(&rtree_ctx->cache[1], \ - &rtree_ctx->cache[0], \ + if (RTREE_CTX_NCACHE_L2 > 1) { \ + memmove(&rtree_ctx->l2_cache[1], \ + &rtree_ctx->l2_cache[0], \ sizeof(rtree_ctx_cache_elm_t) * \ - (RTREE_CTX_NCACHE-1)); \ + (RTREE_CTX_NCACHE_L2 - 1)); \ } \ + size_t slot = rtree_cache_direct_map(key); \ + rtree_ctx->l2_cache[0].leafkey = \ + rtree_ctx->cache[slot].leafkey; \ + rtree_ctx->l2_cache[0].leaf = \ + rtree_ctx->cache[slot].leaf; \ uintptr_t leafkey = rtree_leafkey(key); \ - rtree_ctx->cache[0].leafkey = leafkey; \ - rtree_ctx->cache[0].leaf = leaf; \ + rtree_ctx->cache[slot].leafkey = leafkey; \ + rtree_ctx->cache[slot].leaf = leaf; \ uintptr_t subkey = rtree_subkey(key, level); \ return &leaf[subkey]; \ } @@ -433,6 +453,11 @@ rtree_ctx_data_init(rtree_ctx_t *ctx) { cache->leafkey = RTREE_LEAFKEY_INVALID; cache->leaf = NULL; } + for (unsigned i = 0; i < RTREE_CTX_NCACHE_L2; i++) { + rtree_ctx_cache_elm_t *cache = &ctx->l2_cache[i]; + cache->leafkey = RTREE_LEAFKEY_INVALID; + cache->leaf = NULL; + } } bool -- GitLab From 675701660cede59972707f60af32117023f91728 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 16 Apr 2017 17:40:16 -0700 Subject: [PATCH 410/544] Update base_unmap() to match extent_dalloc_wrapper(). Reverse the order of forced versus lazy purging attempts in base_unmap(), in order to match the order in extent_dalloc_wrapper(), which was reversed by 64e458f5cdd64f9b67cb495f177ef96bf3ce4e0e (Implement two-phase decay-based purging.). --- src/base.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/base.c b/src/base.c index eb68a175..00c6c6a2 100644 --- a/src/base.c +++ b/src/base.c @@ -31,14 +31,14 @@ static void base_unmap(extent_hooks_t *extent_hooks, unsigned ind, void *addr, size_t size) { /* - * Cascade through dalloc, decommit, purge_lazy, and purge_forced, + * Cascade through dalloc, decommit, purge_forced, and purge_lazy, * stopping at first success. This cascade is performed for consistency * with the cascade in extent_dalloc_wrapper() because an application's * custom hooks may not support e.g. dalloc. This function is only ever * called as a side effect of arena destruction, so although it might * seem pointless to do anything besides dalloc here, the application - * may in fact want the end state of all associated virtual memory to in - * some consistent-but-allocated state. + * may in fact want the end state of all associated virtual memory to be + * in some consistent-but-allocated state. */ if (extent_hooks == &extent_hooks_default) { if (!extent_dalloc_mmap(addr, size)) { @@ -47,10 +47,10 @@ base_unmap(extent_hooks_t *extent_hooks, unsigned ind, void *addr, if (!pages_decommit(addr, size)) { return; } - if (!pages_purge_lazy(addr, size)) { + if (!pages_purge_forced(addr, size)) { return; } - if (!pages_purge_forced(addr, size)) { + if (!pages_purge_lazy(addr, size)) { return; } /* Nothing worked. This should never happen. */ @@ -66,16 +66,16 @@ base_unmap(extent_hooks_t *extent_hooks, unsigned ind, void *addr, ind)) { return; } - if (extent_hooks->purge_lazy != NULL && - !extent_hooks->purge_lazy(extent_hooks, addr, size, 0, size, - ind)) { - return; - } if (extent_hooks->purge_forced != NULL && !extent_hooks->purge_forced(extent_hooks, addr, size, 0, size, ind)) { return; } + if (extent_hooks->purge_lazy != NULL && + !extent_hooks->purge_lazy(extent_hooks, addr, size, 0, size, + ind)) { + return; + } /* Nothing worked. That's the application's problem. */ } } -- GitLab From 69aa5528091db805accc32af8d350f32b91bfd1a Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 16 Apr 2017 18:39:14 -0700 Subject: [PATCH 411/544] Allocate increasingly large base blocks. Limit the total number of base block by leveraging the exponential size class sequence, similarly to extent_grow_retained(). --- include/jemalloc/internal/base_structs.h | 9 +++- src/base.c | 62 ++++++++++++++---------- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/include/jemalloc/internal/base_structs.h b/include/jemalloc/internal/base_structs.h index 13d5bd46..d79f38ee 100644 --- a/include/jemalloc/internal/base_structs.h +++ b/include/jemalloc/internal/base_structs.h @@ -21,11 +21,18 @@ struct base_s { * User-configurable extent hook functions. Points to an * extent_hooks_t. */ - atomic_p_t extent_hooks; + atomic_p_t extent_hooks; /* Protects base_alloc() and base_stats_get() operations. */ malloc_mutex_t mtx; + /* + * Most recent size class in the series of increasingly large base + * extents. Logarithmic spacing between subsequent allocations ensures + * that the total number of distinct mappings remains small. + */ + pszind_t pind_last; + /* Serial number generation state. */ size_t extent_sn_next; diff --git a/src/base.c b/src/base.c index 00c6c6a2..515d3361 100644 --- a/src/base.c +++ b/src/base.c @@ -155,19 +155,33 @@ base_extent_bump_alloc(tsdn_t *tsdn, base_t *base, extent_t *extent, */ static base_block_t * base_block_alloc(extent_hooks_t *extent_hooks, unsigned ind, - size_t *extent_sn_next, size_t size, size_t alignment) { - base_block_t *block; - size_t usize, header_size, gap_size, block_size; - + pszind_t *pind_last, size_t *extent_sn_next, size_t size, + size_t alignment) { alignment = ALIGNMENT_CEILING(alignment, QUANTUM); - usize = ALIGNMENT_CEILING(size, alignment); - header_size = sizeof(base_block_t); - gap_size = ALIGNMENT_CEILING(header_size, alignment) - header_size; - block_size = HUGEPAGE_CEILING(header_size + gap_size + usize); - block = (base_block_t *)base_map(extent_hooks, ind, block_size); + size_t usize = ALIGNMENT_CEILING(size, alignment); + size_t header_size = sizeof(base_block_t); + size_t gap_size = ALIGNMENT_CEILING(header_size, alignment) - + header_size; + /* + * Create increasingly larger blocks in order to limit the total number + * of disjoint virtual memory ranges. Choose the next size in the page + * size class series (skipping size classes that are not a multiple of + * HUGEPAGE), or a size large enough to satisfy the requested size and + * alignment, whichever is larger. + */ + size_t min_block_size = HUGEPAGE_CEILING(psz2u(header_size + gap_size + + usize)); + pszind_t pind_next = (*pind_last + 1 < NPSIZES) ? *pind_last + 1 : + *pind_last; + size_t next_block_size = HUGEPAGE_CEILING(pind2sz(pind_next)); + size_t block_size = (min_block_size > next_block_size) ? min_block_size + : next_block_size; + base_block_t *block = (base_block_t *)base_map(extent_hooks, ind, + block_size); if (block == NULL) { return NULL; } + *pind_last = psz2ind(block_size); block->size = block_size; block->next = NULL; assert(block_size >= header_size); @@ -182,13 +196,11 @@ base_block_alloc(extent_hooks_t *extent_hooks, unsigned ind, */ static extent_t * base_extent_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) { - extent_hooks_t *extent_hooks = base_extent_hooks_get(base); - base_block_t *block; - malloc_mutex_assert_owner(tsdn, &base->mtx); - block = base_block_alloc(extent_hooks, base_ind_get(base), - &base->extent_sn_next, size, alignment); + extent_hooks_t *extent_hooks = base_extent_hooks_get(base); + base_block_t *block = base_block_alloc(extent_hooks, base_ind_get(base), + &base->pind_last, &base->extent_sn_next, size, alignment); if (block == NULL) { return NULL; } @@ -211,21 +223,18 @@ b0get(void) { base_t * base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { - base_t *base; - size_t extent_sn_next, base_alignment, base_size, gap_size; - base_block_t *block; - szind_t i; - - extent_sn_next = 0; - block = base_block_alloc(extent_hooks, ind, &extent_sn_next, - sizeof(base_t), QUANTUM); + pszind_t pind_last = 0; + size_t extent_sn_next = 0; + base_block_t *block = base_block_alloc(extent_hooks, ind, &pind_last, + &extent_sn_next, sizeof(base_t), QUANTUM); if (block == NULL) { return NULL; } - base_alignment = CACHELINE; - base_size = ALIGNMENT_CEILING(sizeof(base_t), base_alignment); - base = (base_t *)base_extent_bump_alloc_helper(&block->extent, + size_t gap_size; + size_t base_alignment = CACHELINE; + size_t base_size = ALIGNMENT_CEILING(sizeof(base_t), base_alignment); + base_t *base = (base_t *)base_extent_bump_alloc_helper(&block->extent, &gap_size, base_size, base_alignment); base->ind = ind; atomic_store_p(&base->extent_hooks, extent_hooks, ATOMIC_RELAXED); @@ -233,9 +242,10 @@ base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { base_unmap(extent_hooks, ind, block, block->size); return NULL; } + base->pind_last = pind_last; base->extent_sn_next = extent_sn_next; base->blocks = block; - for (i = 0; i < NSIZES; i++) { + for (szind_t i = 0; i < NSIZES; i++) { extent_heap_new(&base->avail[i]); } if (config_stats) { -- GitLab From 76b35f4b2fdcc6eeb0ee7ecfbeaa05ef3fa2753e Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 16 Apr 2017 21:51:26 -0700 Subject: [PATCH 412/544] Track extent structure serial number (esn) in extent_t. This enables stable sorting of extent_t structures. --- include/jemalloc/internal/base_externs.h | 23 +++--- include/jemalloc/internal/extent_inlines.h | 44 +++++++++++- include/jemalloc/internal/extent_structs.h | 18 ++++- include/jemalloc/internal/private_symbols.txt | 6 ++ src/base.c | 71 +++++++++++-------- src/extent.c | 3 +- test/unit/base.c | 4 +- 7 files changed, 121 insertions(+), 48 deletions(-) diff --git a/include/jemalloc/internal/base_externs.h b/include/jemalloc/internal/base_externs.h index 2c555cff..0a1114f4 100644 --- a/include/jemalloc/internal/base_externs.h +++ b/include/jemalloc/internal/base_externs.h @@ -1,18 +1,19 @@ #ifndef JEMALLOC_INTERNAL_BASE_EXTERNS_H #define JEMALLOC_INTERNAL_BASE_EXTERNS_H -base_t *b0get(void); -base_t *base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); -void base_delete(base_t *base); -extent_hooks_t *base_extent_hooks_get(base_t *base); -extent_hooks_t *base_extent_hooks_set(base_t *base, +base_t *b0get(void); +base_t *base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); +void base_delete(base_t *base); +extent_hooks_t *base_extent_hooks_get(base_t *base); +extent_hooks_t *base_extent_hooks_set(base_t *base, extent_hooks_t *extent_hooks); -void *base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment); -void base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated, +void *base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment); +extent_t *base_alloc_extent(tsdn_t *tsdn, base_t *base); +void base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated, size_t *resident, size_t *mapped); -void base_prefork(tsdn_t *tsdn, base_t *base); -void base_postfork_parent(tsdn_t *tsdn, base_t *base); -void base_postfork_child(tsdn_t *tsdn, base_t *base); -bool base_boot(tsdn_t *tsdn); +void base_prefork(tsdn_t *tsdn, base_t *base); +void base_postfork_parent(tsdn_t *tsdn, base_t *base); +void base_postfork_child(tsdn_t *tsdn, base_t *base); +bool base_boot(tsdn_t *tsdn); #endif /* JEMALLOC_INTERNAL_BASE_EXTERNS_H */ diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index 6fc01017..e1c5cea1 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -17,6 +17,8 @@ unsigned extent_nfree_get(const extent_t *extent); void *extent_base_get(const extent_t *extent); void *extent_addr_get(const extent_t *extent); size_t extent_size_get(const extent_t *extent); +size_t extent_esn_get(const extent_t *extent); +size_t extent_bsize_get(const extent_t *extent); void *extent_before_get(const extent_t *extent); void *extent_last_get(const extent_t *extent); void *extent_past_get(const extent_t *extent); @@ -27,6 +29,8 @@ void extent_arena_set(extent_t *extent, arena_t *arena); void extent_addr_set(extent_t *extent, void *addr); void extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment); void extent_size_set(extent_t *extent, size_t size); +void extent_esn_set(extent_t *extent, size_t esn); +void extent_bsize_set(extent_t *extent, size_t bsize); void extent_szind_set(extent_t *extent, szind_t szind); void extent_nfree_set(extent_t *extent, unsigned nfree); void extent_nfree_inc(extent_t *extent); @@ -40,6 +44,7 @@ void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx); void extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, bool slab, szind_t szind, size_t sn, extent_state_t state, bool zeroed, bool committed); +void extent_binit(extent_t *extent, void *addr, size_t size, size_t sn); void extent_list_init(extent_list_t *list); extent_t *extent_list_first(const extent_list_t *list); extent_t *extent_list_last(const extent_list_t *list); @@ -141,7 +146,17 @@ extent_addr_get(const extent_t *extent) { JEMALLOC_INLINE size_t extent_size_get(const extent_t *extent) { - return extent->e_size; + return (extent->e_size_esn & EXTENT_SIZE_MASK); +} + +JEMALLOC_INLINE size_t +extent_esn_get(const extent_t *extent) { + return (extent->e_size_esn & EXTENT_ESN_MASK); +} + +JEMALLOC_INLINE size_t +extent_bsize_get(const extent_t *extent) { + return extent->e_bsize; } JEMALLOC_INLINE void * @@ -213,7 +228,19 @@ extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment) { JEMALLOC_INLINE void extent_size_set(extent_t *extent, size_t size) { - extent->e_size = size; + assert((size & ~EXTENT_SIZE_MASK) == 0); + extent->e_size_esn = size | (extent->e_size_esn & ~EXTENT_SIZE_MASK); +} + +JEMALLOC_INLINE void +extent_esn_set(extent_t *extent, size_t esn) { + extent->e_size_esn = (extent->e_size_esn & ~EXTENT_ESN_MASK) | (esn & + EXTENT_ESN_MASK); +} + +JEMALLOC_INLINE void +extent_bsize_set(extent_t *extent, size_t bsize) { + extent->e_bsize = bsize; } JEMALLOC_INLINE void @@ -298,6 +325,19 @@ extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, } } +JEMALLOC_INLINE void +extent_binit(extent_t *extent, void *addr, size_t bsize, size_t sn) { + extent_arena_set(extent, NULL); + extent_addr_set(extent, addr); + extent_bsize_set(extent, bsize); + extent_slab_set(extent, false); + extent_szind_set(extent, NSIZES); + extent_sn_set(extent, sn); + extent_state_set(extent, extent_state_active); + extent_zeroed_set(extent, true); + extent_committed_set(extent, true); +} + JEMALLOC_INLINE void extent_list_init(extent_list_t *list) { ql_new(list); diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 3d3d418b..38c3c8a1 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -23,8 +23,8 @@ struct extent_s { * z: zeroed * t: state * i: szind - * n: sn * f: nfree + * n: sn * * nnnnnnnn ... nnnnnfff fffffffi iiiiiiit tzcbaaaa aaaaaaaa * @@ -102,8 +102,20 @@ struct extent_s { /* Pointer to the extent that this structure is responsible for. */ void *e_addr; - /* Extent size. */ - size_t e_size; + union { + /* + * Extent size and serial number associated with the extent + * structure (different than the serial number for the extent at + * e_addr). + * + * ssssssss [...] ssssssss ssssnnnn nnnnnnnn + */ + size_t e_size_esn; + #define EXTENT_SIZE_MASK ((size_t)~(PAGE-1)) + #define EXTENT_ESN_MASK ((size_t)PAGE-1) + /* Base extent size, which may not be a multiple of PAGE. */ + size_t e_bsize; + }; /* * List linkage, used by a variety of lists: diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index c1573aa6..dd35d50f 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -86,6 +86,7 @@ b0get base_alloc base_boot base_delete +base_extent_alloc base_extent_hooks_get base_extent_hooks_set base_ind_get @@ -143,6 +144,9 @@ extent_arena_set extent_base_get extent_before_get extent_boot +extent_binit +extent_bsize_get +extent_bsize_set extent_commit_wrapper extent_committed_get extent_committed_set @@ -156,6 +160,8 @@ extent_dss_boot extent_dss_mergeable extent_dss_prec_get extent_dss_prec_set +extent_esn_get +extent_esn_set extent_heap_empty extent_heap_first extent_heap_insert diff --git a/src/base.c b/src/base.c index 515d3361..caec9557 100644 --- a/src/base.c +++ b/src/base.c @@ -88,8 +88,7 @@ base_extent_init(size_t *extent_sn_next, extent_t *extent, void *addr, sn = *extent_sn_next; (*extent_sn_next)++; - extent_init(extent, NULL, addr, size, false, NSIZES, sn, - extent_state_active, true, true); + extent_binit(extent, addr, size, sn); } static void * @@ -103,23 +102,22 @@ base_extent_bump_alloc_helper(extent_t *extent, size_t *gap_size, size_t size, *gap_size = ALIGNMENT_CEILING((uintptr_t)extent_addr_get(extent), alignment) - (uintptr_t)extent_addr_get(extent); ret = (void *)((uintptr_t)extent_addr_get(extent) + *gap_size); - assert(extent_size_get(extent) >= *gap_size + size); - extent_init(extent, NULL, (void *)((uintptr_t)extent_addr_get(extent) + - *gap_size + size), extent_size_get(extent) - *gap_size - size, - false, NSIZES, extent_sn_get(extent), extent_state_active, true, - true); + assert(extent_bsize_get(extent) >= *gap_size + size); + extent_binit(extent, (void *)((uintptr_t)extent_addr_get(extent) + + *gap_size + size), extent_bsize_get(extent) - *gap_size - size, + extent_sn_get(extent)); return ret; } static void base_extent_bump_alloc_post(tsdn_t *tsdn, base_t *base, extent_t *extent, size_t gap_size, void *addr, size_t size) { - if (extent_size_get(extent) > 0) { + if (extent_bsize_get(extent) > 0) { /* * Compute the index for the largest size class that does not * exceed extent's size. */ - szind_t index_floor = size2index(extent_size_get(extent) + 1) - + szind_t index_floor = size2index(extent_bsize_get(extent) + 1) - 1; extent_heap_insert(&base->avail[index_floor], extent); } @@ -286,28 +284,16 @@ base_extent_hooks_set(base_t *base, extent_hooks_t *extent_hooks) { return old_extent_hooks; } -/* - * base_alloc() returns zeroed memory, which is always demand-zeroed for the - * auto arenas, in order to make multi-page sparse data structures such as radix - * tree nodes efficient with respect to physical memory usage. Upon success a - * pointer to at least size bytes with specified alignment is returned. Note - * that size is rounded up to the nearest multiple of alignment to avoid false - * sharing. - */ -void * -base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) { - void *ret; - size_t usize, asize; - szind_t i; - extent_t *extent; - +static void * +base_alloc_impl(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment, + size_t *esn) { alignment = QUANTUM_CEILING(alignment); - usize = ALIGNMENT_CEILING(size, alignment); - asize = usize + alignment - QUANTUM; + size_t usize = ALIGNMENT_CEILING(size, alignment); + size_t asize = usize + alignment - QUANTUM; - extent = NULL; + extent_t *extent = NULL; malloc_mutex_lock(tsdn, &base->mtx); - for (i = size2index(asize); i < NSIZES; i++) { + for (szind_t i = size2index(asize); i < NSIZES; i++) { extent = extent_heap_remove_first(&base->avail[i]); if (extent != NULL) { /* Use existing space. */ @@ -318,17 +304,46 @@ base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) { /* Try to allocate more space. */ extent = base_extent_alloc(tsdn, base, usize, alignment); } + void *ret; if (extent == NULL) { ret = NULL; goto label_return; } ret = base_extent_bump_alloc(tsdn, base, extent, usize, alignment); + if (esn != NULL) { + *esn = extent_sn_get(extent); + } label_return: malloc_mutex_unlock(tsdn, &base->mtx); return ret; } +/* + * base_alloc() returns zeroed memory, which is always demand-zeroed for the + * auto arenas, in order to make multi-page sparse data structures such as radix + * tree nodes efficient with respect to physical memory usage. Upon success a + * pointer to at least size bytes with specified alignment is returned. Note + * that size is rounded up to the nearest multiple of alignment to avoid false + * sharing. + */ +void * +base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) { + return base_alloc_impl(tsdn, base, size, alignment, NULL); +} + +extent_t * +base_alloc_extent(tsdn_t *tsdn, base_t *base) { + size_t esn; + extent_t *extent = base_alloc_impl(tsdn, base, sizeof(extent_t), + CACHELINE, &esn); + if (extent == NULL) { + return NULL; + } + extent_esn_set(extent, esn); + return extent; +} + void base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated, size_t *resident, size_t *mapped) { diff --git a/src/extent.c b/src/extent.c index 2344e9cd..c999ae64 100644 --- a/src/extent.c +++ b/src/extent.c @@ -98,8 +98,7 @@ extent_alloc(tsdn_t *tsdn, arena_t *arena) { extent = extent_list_last(&arena->extent_freelist); if (extent == NULL) { malloc_mutex_unlock(tsdn, &arena->extent_freelist_mtx); - return base_alloc(tsdn, arena->base, sizeof(extent_t), - CACHELINE); + return base_alloc_extent(tsdn, arena->base); } extent_list_remove(&arena->extent_freelist, extent); malloc_mutex_unlock(tsdn, &arena->extent_freelist_mtx); diff --git a/test/unit/base.c b/test/unit/base.c index 87116a3c..f498394e 100644 --- a/test/unit/base.c +++ b/test/unit/base.c @@ -154,10 +154,10 @@ TEST_BEGIN(test_base_hooks_not_null) { * that the first block's remaining space is considered for subsequent * allocation. */ - assert_zu_ge(extent_size_get(&base->blocks->extent), QUANTUM, + assert_zu_ge(extent_bsize_get(&base->blocks->extent), QUANTUM, "Remainder insufficient for test"); /* Use up all but one quantum of block. */ - while (extent_size_get(&base->blocks->extent) > QUANTUM) { + while (extent_bsize_get(&base->blocks->extent) > QUANTUM) { p = base_alloc(tsdn, base, QUANTUM, QUANTUM); assert_ptr_not_null(p, "Unexpected base_alloc() failure"); } -- GitLab From 881fbf762f18c8a94e71e94fb78f03d59bd4ad58 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 16 Apr 2017 22:31:16 -0700 Subject: [PATCH 413/544] Prefer old/low extent_t structures during reuse. Rather than using a LIFO queue to track available extent_t structures, use a red-black tree, and always choose the oldest/lowest available during reuse. --- doc/jemalloc.xml.in | 8 ++--- include/jemalloc/internal/arena_structs_b.h | 9 +++--- include/jemalloc/internal/ctl_types.h | 2 +- include/jemalloc/internal/extent_externs.h | 2 ++ include/jemalloc/internal/extent_inlines.h | 31 +++++++++++++++++++ include/jemalloc/internal/extent_structs.h | 25 +++++++++------ include/jemalloc/internal/private_symbols.txt | 3 ++ src/arena.c | 14 ++++----- src/ctl.c | 2 +- src/extent.c | 21 +++++++------ 10 files changed, 80 insertions(+), 37 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 91127a03..3b98395d 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -2691,14 +2691,14 @@ struct extent_hooks_s { counters. - + - stats.arenas.<i>.mutexes.extent_freelist.{counter} + stats.arenas.<i>.mutexes.extent_avail.{counter} (counter specific type) r- [] - Statistics on arena.<i>.extent_freelist - mutex (arena scope; extent freelist related). + Statistics on arena.<i>.extent_avail + mutex (arena scope; extent avail related). {counter} is one of the counters in mutex profiling counters. diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 1370b535..14c473c5 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -233,12 +233,13 @@ struct arena_s { atomic_u_t extent_grow_next; /* - * Freelist of extent structures that were allocated via base_alloc(). + * Available extent structures that were allocated via + * base_alloc_extent(). * - * Synchronization: extent_freelist_mtx. + * Synchronization: extent_avail_mtx. */ - extent_list_t extent_freelist; - malloc_mutex_t extent_freelist_mtx; + extent_tree_t extent_avail; + malloc_mutex_t extent_avail_mtx; /* * bins is used to store heaps of free regions. diff --git a/include/jemalloc/internal/ctl_types.h b/include/jemalloc/internal/ctl_types.h index 065ccda5..e7986092 100644 --- a/include/jemalloc/internal/ctl_types.h +++ b/include/jemalloc/internal/ctl_types.h @@ -14,7 +14,7 @@ typedef enum { #define ARENA_PROF_MUTEXES \ OP(large) \ - OP(extent_freelist) \ + OP(extent_avail) \ OP(extents_dirty) \ OP(extents_muzzy) \ OP(extents_retained) \ diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index 3fe4a0ad..58e57e70 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -1,6 +1,7 @@ #ifndef JEMALLOC_INTERNAL_EXTENT_EXTERNS_H #define JEMALLOC_INTERNAL_EXTENT_EXTERNS_H +#include "jemalloc/internal/rb.h" #include "jemalloc/internal/ph.h" extern rtree_t extents_rtree; @@ -17,6 +18,7 @@ size_t extent_size_quantize_floor(size_t size); size_t extent_size_quantize_ceil(size_t size); #endif +rb_proto(, extent_avail_, extent_tree_t, extent_t) ph_proto(, extent_heap_, extent_heap_t, extent_t) bool extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state, diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index e1c5cea1..fbe51e47 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -53,8 +53,10 @@ void extent_list_replace(extent_list_t *list, extent_t *to_remove, extent_t *to_insert); void extent_list_remove(extent_list_t *list, extent_t *extent); int extent_sn_comp(const extent_t *a, const extent_t *b); +int extent_esn_comp(const extent_t *a, const extent_t *b); int extent_ad_comp(const extent_t *a, const extent_t *b); int extent_snad_comp(const extent_t *a, const extent_t *b); +int extent_esnead_comp(const extent_t *a, const extent_t *b); #endif #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_)) @@ -378,6 +380,14 @@ extent_sn_comp(const extent_t *a, const extent_t *b) { return (a_sn > b_sn) - (a_sn < b_sn); } +JEMALLOC_INLINE int +extent_esn_comp(const extent_t *a, const extent_t *b) { + size_t a_esn = extent_esn_get(a); + size_t b_esn = extent_esn_get(b); + + return (a_esn > b_esn) - (a_esn < b_esn); +} + JEMALLOC_INLINE int extent_ad_comp(const extent_t *a, const extent_t *b) { uintptr_t a_addr = (uintptr_t)extent_addr_get(a); @@ -386,6 +396,14 @@ extent_ad_comp(const extent_t *a, const extent_t *b) { return (a_addr > b_addr) - (a_addr < b_addr); } +JEMALLOC_INLINE int +extent_ead_comp(const extent_t *a, const extent_t *b) { + uintptr_t a_eaddr = (uintptr_t)a; + uintptr_t b_eaddr = (uintptr_t)b; + + return (a_eaddr > b_eaddr) - (a_eaddr < b_eaddr); +} + JEMALLOC_INLINE int extent_snad_comp(const extent_t *a, const extent_t *b) { int ret; @@ -398,6 +416,19 @@ extent_snad_comp(const extent_t *a, const extent_t *b) { ret = extent_ad_comp(a, b); return ret; } + +JEMALLOC_INLINE int +extent_esnead_comp(const extent_t *a, const extent_t *b) { + int ret; + + ret = extent_esn_comp(a, b); + if (ret != 0) { + return ret; + } + + ret = extent_ead_comp(a, b); + return ret; +} #endif #endif /* JEMALLOC_INTERNAL_EXTENT_INLINES_H */ diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 38c3c8a1..7066b8f6 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -2,8 +2,9 @@ #define JEMALLOC_INTERNAL_EXTENT_STRUCTS_H #include "jemalloc/internal/atomic.h" -#include "jemalloc/internal/ph.h" #include "jemalloc/internal/ql.h" +#include "jemalloc/internal/rb.h" +#include "jemalloc/internal/ph.h" typedef enum { extent_state_active = 0, @@ -117,15 +118,18 @@ struct extent_s { size_t e_bsize; }; - /* - * List linkage, used by a variety of lists: - * - arena_bin_t's slabs_full - * - extents_t's LRU - * - stashed dirty extents - * - arena's large allocations - * - arena's extent structure freelist - */ - ql_elm(extent_t) ql_link; + union { + /* + * List linkage, used by a variety of lists: + * - arena_bin_t's slabs_full + * - extents_t's LRU + * - stashed dirty extents + * - arena's large allocations + */ + ql_elm(extent_t) ql_link; + /* Red-black tree linkage, used by arena's extent_avail. */ + rb_node(extent_t) rb_link; + }; /* Linkage for per size class sn/address-ordered heaps. */ phn(extent_t) ph_link; @@ -142,6 +146,7 @@ struct extent_s { }; }; typedef ql_head(extent_t) extent_list_t; +typedef rb_tree(extent_t) extent_tree_t; typedef ph(extent_t) extent_heap_t; /* Quantized collection of extents, with built-in LRU queue. */ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index dd35d50f..34c27897 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -160,8 +160,11 @@ extent_dss_boot extent_dss_mergeable extent_dss_prec_get extent_dss_prec_set +extent_ead_comp +extent_esn_comp extent_esn_get extent_esn_set +extent_esnead_comp extent_heap_empty extent_heap_first extent_heap_insert diff --git a/src/arena.c b/src/arena.c index 5b540ce3..74511405 100644 --- a/src/arena.c +++ b/src/arena.c @@ -314,8 +314,8 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, /* Gather per arena mutex profiling data. */ READ_ARENA_MUTEX_PROF_DATA(large_mtx, arena_prof_mutex_large); - READ_ARENA_MUTEX_PROF_DATA(extent_freelist_mtx, - arena_prof_mutex_extent_freelist) + READ_ARENA_MUTEX_PROF_DATA(extent_avail_mtx, + arena_prof_mutex_extent_avail) READ_ARENA_MUTEX_PROF_DATA(extents_dirty.mtx, arena_prof_mutex_extents_dirty) READ_ARENA_MUTEX_PROF_DATA(extents_muzzy.mtx, @@ -1937,8 +1937,8 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { ATOMIC_RELAXED); } - extent_list_init(&arena->extent_freelist); - if (malloc_mutex_init(&arena->extent_freelist_mtx, "extent_freelist", + extent_avail_new(&arena->extent_avail); + if (malloc_mutex_init(&arena->extent_avail_mtx, "extent_avail", WITNESS_RANK_EXTENT_FREELIST)) { goto label_error; } @@ -2007,7 +2007,7 @@ arena_prefork2(tsdn_t *tsdn, arena_t *arena) { void arena_prefork3(tsdn_t *tsdn, arena_t *arena) { - malloc_mutex_prefork(tsdn, &arena->extent_freelist_mtx); + malloc_mutex_prefork(tsdn, &arena->extent_avail_mtx); } void @@ -2036,7 +2036,7 @@ arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) { } malloc_mutex_postfork_parent(tsdn, &arena->large_mtx); base_postfork_parent(tsdn, arena->base); - malloc_mutex_postfork_parent(tsdn, &arena->extent_freelist_mtx); + malloc_mutex_postfork_parent(tsdn, &arena->extent_avail_mtx); extents_postfork_parent(tsdn, &arena->extents_dirty); extents_postfork_parent(tsdn, &arena->extents_muzzy); extents_postfork_parent(tsdn, &arena->extents_retained); @@ -2056,7 +2056,7 @@ arena_postfork_child(tsdn_t *tsdn, arena_t *arena) { } malloc_mutex_postfork_child(tsdn, &arena->large_mtx); base_postfork_child(tsdn, arena->base); - malloc_mutex_postfork_child(tsdn, &arena->extent_freelist_mtx); + malloc_mutex_postfork_child(tsdn, &arena->extent_avail_mtx); extents_postfork_child(tsdn, &arena->extents_dirty); extents_postfork_child(tsdn, &arena->extents_muzzy); extents_postfork_child(tsdn, &arena->extents_retained); diff --git a/src/ctl.c b/src/ctl.c index 6d6fadc7..7a1b03f1 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -2475,7 +2475,7 @@ stats_mutexes_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, continue; } MUTEX_PROF_RESET(arena->large_mtx); - MUTEX_PROF_RESET(arena->extent_freelist_mtx); + MUTEX_PROF_RESET(arena->extent_avail_mtx); MUTEX_PROF_RESET(arena->extents_dirty.mtx); MUTEX_PROF_RESET(arena->extents_muzzy.mtx); MUTEX_PROF_RESET(arena->extents_retained.mtx); diff --git a/src/extent.c b/src/extent.c index c999ae64..0bfc555d 100644 --- a/src/extent.c +++ b/src/extent.c @@ -88,20 +88,21 @@ static void extent_record(tsdn_t *tsdn, arena_t *arena, /******************************************************************************/ +rb_gen(UNUSED, extent_avail_, extent_tree_t, extent_t, rb_link, + extent_esnead_comp) + extent_t * extent_alloc(tsdn_t *tsdn, arena_t *arena) { - extent_t *extent; - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - malloc_mutex_lock(tsdn, &arena->extent_freelist_mtx); - extent = extent_list_last(&arena->extent_freelist); + malloc_mutex_lock(tsdn, &arena->extent_avail_mtx); + extent_t *extent = extent_avail_first(&arena->extent_avail); if (extent == NULL) { - malloc_mutex_unlock(tsdn, &arena->extent_freelist_mtx); + malloc_mutex_unlock(tsdn, &arena->extent_avail_mtx); return base_alloc_extent(tsdn, arena->base); } - extent_list_remove(&arena->extent_freelist, extent); - malloc_mutex_unlock(tsdn, &arena->extent_freelist_mtx); + extent_avail_remove(&arena->extent_avail, extent); + malloc_mutex_unlock(tsdn, &arena->extent_avail_mtx); return extent; } @@ -109,9 +110,9 @@ void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - malloc_mutex_lock(tsdn, &arena->extent_freelist_mtx); - extent_list_append(&arena->extent_freelist, extent); - malloc_mutex_unlock(tsdn, &arena->extent_freelist_mtx); + malloc_mutex_lock(tsdn, &arena->extent_avail_mtx); + extent_avail_insert(&arena->extent_avail, extent); + malloc_mutex_unlock(tsdn, &arena->extent_avail_mtx); } extent_hooks_t * -- GitLab From 855c127348b2764fe3f25966949377e327efe1c8 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 17 Apr 2017 15:32:44 -0700 Subject: [PATCH 414/544] Remove the function alignment of prof_backtrace. This was an attempt to avoid triggering slow path in libunwind, however turns out to be ineffective. --- src/prof.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/prof.c b/src/prof.c index b33e9397..334466b1 100644 --- a/src/prof.c +++ b/src/prof.c @@ -310,7 +310,6 @@ prof_leave(tsd_t *tsd, prof_tdata_t *tdata) { } #ifdef JEMALLOC_PROF_LIBUNWIND -JEMALLOC_ALIGNED(CACHELINE) void prof_backtrace(prof_bt_t *bt) { int nframes; -- GitLab From c43a83d225551273c30c087ba90cbe2ca3c15e55 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 17 Apr 2017 15:50:13 -0700 Subject: [PATCH 415/544] Fix LD_PRELOAD_VAR configuration logic for 64-bit AIX. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 00868133..a3cfc88f 100644 --- a/configure.ac +++ b/configure.ac @@ -591,7 +591,7 @@ case "${host}" in JE_APPEND_VS(LIBS, -lposix4 -lsocket -lnsl) ;; *-ibm-aix*) - if "$LG_SIZEOF_PTR" = "8"; then + if "${LG_SIZEOF_PTR}" = "3"; then dnl 64bit AIX LD_PRELOAD_VAR="LDR_PRELOAD64" else -- GitLab From a01f99307719dcc8ca27cc70f0f0011beff914fa Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 17 Apr 2017 15:54:53 -0700 Subject: [PATCH 416/544] Only disable munmap(2) by default on 64-bit Linux. This reduces the likelihood of address space exhaustion on 32-bit systems. This resolves #350. --- INSTALL | 8 +++++--- configure.ac | 8 ++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/INSTALL b/INSTALL index d7496612..042f8291 100644 --- a/INSTALL +++ b/INSTALL @@ -161,9 +161,11 @@ any of the following arguments (not a definitive list) to 'configure': --disable-munmap Disable virtual memory deallocation via munmap(2); instead keep track of the virtual memory for later use. munmap() is disabled by default (i.e. - --disable-munmap is implied) on Linux, which has a quirk in its virtual - memory allocation algorithm that causes semi-permanent VM map holes under - normal jemalloc operation. + --disable-munmap is implied) on [64-bit] Linux, which has a quirk in its + virtual memory allocation algorithm that causes semi-permanent VM map holes + under normal jemalloc operation. Although munmap() causes issues on 32-bit + Linux as well, it is not disabled by default due to the practical + possibility of address space exhaustion. --disable-fill Disable support for junk/zero filling of memory. See the "opt.junk" and diff --git a/configure.ac b/configure.ac index a3cfc88f..f6d08ccd 100644 --- a/configure.ac +++ b/configure.ac @@ -557,7 +557,9 @@ case "${host}" in AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) AC_DEFINE([JEMALLOC_C11_ATOMICS]) force_tls="0" - default_munmap="0" + if "${LG_SIZEOF_PTR}" = "3"; then + default_munmap="0" + fi ;; *-*-linux* | *-*-kfreebsd*) dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE. @@ -568,7 +570,9 @@ case "${host}" in AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) AC_DEFINE([JEMALLOC_USE_CXX_THROW], [ ]) - default_munmap="0" + if "${LG_SIZEOF_PTR}" = "3"; then + default_munmap="0" + fi ;; *-*-netbsd*) AC_MSG_CHECKING([ABI]) -- GitLab From 22366518b7309cc7dbe7908818e01a88632bd665 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 17 Apr 2017 15:22:14 -0700 Subject: [PATCH 417/544] Move CPP_PROLOGUE and CPP_EPILOGUE to the .cpp This lets us avoid having to specify them in every C file. --- include/jemalloc/internal/atomic.h | 4 ---- .../jemalloc/internal/jemalloc_internal_includes.h | 4 ---- include/jemalloc/internal/jemalloc_preamble.h.in | 12 ------------ include/jemalloc/internal/malloc_io.h | 1 - src/jemalloc_cpp.cpp | 8 ++++++++ 5 files changed, 8 insertions(+), 21 deletions(-) diff --git a/include/jemalloc/internal/atomic.h b/include/jemalloc/internal/atomic.h index 1bfae7d7..adadb1a3 100644 --- a/include/jemalloc/internal/atomic.h +++ b/include/jemalloc/internal/atomic.h @@ -3,8 +3,6 @@ #define ATOMIC_INLINE static inline -CPP_PROLOGUE - #if defined(JEMALLOC_GCC_ATOMIC_ATOMICS) # include "jemalloc/internal/atomic_gcc_atomic.h" #elif defined(JEMALLOC_GCC_SYNC_ATOMICS) @@ -76,6 +74,4 @@ JEMALLOC_GENERATE_INT_ATOMICS(uint64_t, u64, 3) #undef ATOMIC_INLINE -CPP_EPILOGUE - #endif /* JEMALLOC_INTERNAL_ATOMIC_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 53374f99..6871883b 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -36,8 +36,6 @@ * global jemalloc definitions, however. */ -CPP_PROLOGUE - /******************************************************************************/ /* HERMETIC HEADERS */ /******************************************************************************/ @@ -149,6 +147,4 @@ CPP_PROLOGUE #include "jemalloc/internal/jemalloc_internal_inlines_c.h" #include "jemalloc/internal/prof_inlines_b.h" -CPP_EPILOGUE - #endif /* JEMALLOC_INTERNAL_INCLUDES_H */ diff --git a/include/jemalloc/internal/jemalloc_preamble.h.in b/include/jemalloc/internal/jemalloc_preamble.h.in index 6e38fe65..7c796c61 100644 --- a/include/jemalloc/internal/jemalloc_preamble.h.in +++ b/include/jemalloc/internal/jemalloc_preamble.h.in @@ -1,16 +1,6 @@ #ifndef JEMALLOC_PREAMBLE_H #define JEMALLOC_PREAMBLE_H -#ifdef __cplusplus -# define CPP_PROLOGUE extern "C" { -# define CPP_EPILOGUE } -#else -# define CPP_PROLOGUE -# define CPP_EPILOGUE -#endif - -CPP_PROLOGUE - #include "jemalloc_internal_defs.h" #include "jemalloc/internal/jemalloc_internal_decls.h" @@ -182,6 +172,4 @@ static const bool have_percpu_arena = #endif ; -CPP_EPILOGUE - #endif /* JEMALLOC_PREAMBLE_H */ diff --git a/include/jemalloc/internal/malloc_io.h b/include/jemalloc/internal/malloc_io.h index 8b2fb96f..47ae58ec 100644 --- a/include/jemalloc/internal/malloc_io.h +++ b/include/jemalloc/internal/malloc_io.h @@ -40,7 +40,6 @@ */ #define MALLOC_PRINTF_BUFSIZE 4096 - int buferror(int err, char *buf, size_t buflen); uintmax_t malloc_strtoumax(const char *restrict nptr, char **restrict endptr, int base); diff --git a/src/jemalloc_cpp.cpp b/src/jemalloc_cpp.cpp index b6d7c9a5..71999a8a 100644 --- a/src/jemalloc_cpp.cpp +++ b/src/jemalloc_cpp.cpp @@ -2,9 +2,17 @@ #include #define JEMALLOC_CPP_CPP_ +#ifdef __cplusplus +extern "C" { +#endif + #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#ifdef __cplusplus +} +#endif + // All operators in this file are exported. // Possibly alias hidden versions of malloc and sdallocx to avoid an extra plt -- GitLab From 0b00ffe55f01958a048ded483eababd051247b8d Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 11 Apr 2017 12:57:18 -0700 Subject: [PATCH 418/544] Header refactoring: move bit_util.h out of the catchall --- include/jemalloc/internal/bitmap_inlines.h | 2 ++ include/jemalloc/internal/jemalloc_internal_includes.h | 1 - include/jemalloc/internal/jemalloc_internal_inlines_a.h | 1 + include/jemalloc/internal/prng_inlines.h | 1 + test/unit/bit_util.c | 2 ++ 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/jemalloc/internal/bitmap_inlines.h b/include/jemalloc/internal/bitmap_inlines.h index 506d5269..fc4bad4c 100644 --- a/include/jemalloc/internal/bitmap_inlines.h +++ b/include/jemalloc/internal/bitmap_inlines.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_BITMAP_INLINES_H #define JEMALLOC_INTERNAL_BITMAP_INLINES_H +#include "jemalloc/internal/bit_util.h" + #ifndef JEMALLOC_ENABLE_INLINE bool bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo); bool bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 6871883b..64cda53a 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -41,7 +41,6 @@ /******************************************************************************/ #include "jemalloc/internal/assert.h" -#include "jemalloc/internal/bit_util.h" #include "jemalloc/internal/malloc_io.h" #include "jemalloc/internal/util.h" diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_a.h b/include/jemalloc/internal/jemalloc_internal_inlines_a.h index 600d7226..978814b4 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_a.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_a.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_INLINES_A_H #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/bit_util.h" #ifndef JEMALLOC_ENABLE_INLINE pszind_t psz2ind(size_t psz); diff --git a/include/jemalloc/internal/prng_inlines.h b/include/jemalloc/internal/prng_inlines.h index 7026d52a..c39c63f5 100644 --- a/include/jemalloc/internal/prng_inlines.h +++ b/include/jemalloc/internal/prng_inlines.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_PRNG_INLINES_H #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/bit_util.h" #ifndef JEMALLOC_ENABLE_INLINE uint32_t prng_state_next_u32(uint32_t state); diff --git a/test/unit/bit_util.c b/test/unit/bit_util.c index fe5c4473..42a97013 100644 --- a/test/unit/bit_util.c +++ b/test/unit/bit_util.c @@ -1,5 +1,7 @@ #include "test/jemalloc_test.h" +#include "jemalloc/internal/bit_util.h" + #define TEST_POW2_CEIL(t, suf, pri) do { \ unsigned i, pow2; \ t x; \ -- GitLab From 54373be0840881cb1123a190013dd11c34ab62f1 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 11 Apr 2017 13:06:31 -0700 Subject: [PATCH 419/544] Header refactoring: move malloc_io.h out of the catchall --- include/jemalloc/internal/ctl_externs.h | 2 ++ include/jemalloc/internal/jemalloc_internal_includes.h | 1 - src/ckh.c | 2 ++ src/jemalloc.c | 1 + src/malloc_io.c | 1 + src/mutex.c | 2 ++ src/pages.c | 2 ++ src/prof.c | 2 ++ src/witness.c | 2 ++ 9 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/jemalloc/internal/ctl_externs.h b/include/jemalloc/internal/ctl_externs.h index 17bbba06..875a8101 100644 --- a/include/jemalloc/internal/ctl_externs.h +++ b/include/jemalloc/internal/ctl_externs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_CTL_EXTERNS_H #define JEMALLOC_INTERNAL_CTL_EXTERNS_H +#include "jemalloc/internal/malloc_io.h" + /* Maximum ctl tree depth. */ #define CTL_MAX_DEPTH 7 diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 64cda53a..d4d0c201 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -41,7 +41,6 @@ /******************************************************************************/ #include "jemalloc/internal/assert.h" -#include "jemalloc/internal/malloc_io.h" #include "jemalloc/internal/util.h" /******************************************************************************/ diff --git a/src/ckh.c b/src/ckh.c index a359a5cc..a9d181bd 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -38,6 +38,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/malloc_io.h" + /******************************************************************************/ /* Function prototypes for non-inline static functions. */ diff --git a/src/jemalloc.c b/src/jemalloc.c index 4c38517b..4b4e9430 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/malloc_io.h" /******************************************************************************/ /* Data. */ diff --git a/src/malloc_io.c b/src/malloc_io.c index 98ef7a65..11dc68db 100644 --- a/src/malloc_io.c +++ b/src/malloc_io.c @@ -1,6 +1,7 @@ #define JEMALLOC_MALLOC_IO_C_ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/malloc_io.h" #ifdef assert # undef assert diff --git a/src/mutex.c b/src/mutex.c index 26af5239..92c23dab 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/malloc_io.h" + #if defined(JEMALLOC_LAZY_LOCK) && !defined(_WIN32) #include #endif diff --git a/src/pages.c b/src/pages.c index 53ca653b..f1138231 100644 --- a/src/pages.c +++ b/src/pages.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/malloc_io.h" + #ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT #include #endif diff --git a/src/prof.c b/src/prof.c index 334466b1..276ca360 100644 --- a/src/prof.c +++ b/src/prof.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/malloc_io.h" + /******************************************************************************/ #ifdef JEMALLOC_PROF_LIBUNWIND diff --git a/src/witness.c b/src/witness.c index 26b16e77..bd040826 100644 --- a/src/witness.c +++ b/src/witness.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/malloc_io.h" + void witness_init(witness_t *witness, const char *name, witness_rank_t rank, witness_comp_t *comp, void *opaque) { -- GitLab From f692e6c214ec3fb5cb64e4131470793c6494afbd Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 11 Apr 2017 13:31:16 -0700 Subject: [PATCH 420/544] Header refactoring: move util.h out of the catchall --- include/jemalloc/internal/jemalloc_internal_includes.h | 1 - include/jemalloc/internal/tcache_inlines.h | 2 ++ src/arena.c | 2 ++ src/ckh.c | 1 + src/ctl.c | 2 ++ src/jemalloc.c | 1 + src/large.c | 2 ++ src/malloc_io.c | 2 ++ test/unit/junk.c | 2 ++ test/unit/mallctl.c | 2 ++ test/unit/stats_print.c | 2 ++ 11 files changed, 18 insertions(+), 1 deletion(-) diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index d4d0c201..3a9c6ca2 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -41,7 +41,6 @@ /******************************************************************************/ #include "jemalloc/internal/assert.h" -#include "jemalloc/internal/util.h" /******************************************************************************/ /* TYPES */ diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index ea29f350..77e559a7 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_TCACHE_INLINES_H #define JEMALLOC_INTERNAL_TCACHE_INLINES_H +#include "jemalloc/internal/util.h" + #ifndef JEMALLOC_ENABLE_INLINE void tcache_event(tsd_t *tsd, tcache_t *tcache); void tcache_flush(void); diff --git a/src/arena.c b/src/arena.c index 74511405..27a0f75c 100644 --- a/src/arena.c +++ b/src/arena.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/util.h" + /******************************************************************************/ /* Data. */ diff --git a/src/ckh.c b/src/ckh.c index a9d181bd..ce977e14 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -39,6 +39,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/malloc_io.h" +#include "jemalloc/internal/util.h" /******************************************************************************/ /* Function prototypes for non-inline static functions. */ diff --git a/src/ctl.c b/src/ctl.c index 7a1b03f1..29689c8e 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/util.h" + /******************************************************************************/ /* Data. */ diff --git a/src/jemalloc.c b/src/jemalloc.c index 4b4e9430..7e3ec6ea 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/malloc_io.h" +#include "jemalloc/internal/util.h" /******************************************************************************/ /* Data. */ diff --git a/src/large.c b/src/large.c index 3b53eb33..aa3ea1ff 100644 --- a/src/large.c +++ b/src/large.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/util.h" + /******************************************************************************/ void * diff --git a/src/malloc_io.c b/src/malloc_io.c index 11dc68db..6b99afcd 100644 --- a/src/malloc_io.c +++ b/src/malloc_io.c @@ -1,7 +1,9 @@ #define JEMALLOC_MALLOC_IO_C_ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" + #include "jemalloc/internal/malloc_io.h" +#include "jemalloc/internal/util.h" #ifdef assert # undef assert diff --git a/test/unit/junk.c b/test/unit/junk.c index cfa8d0f2..f9390e41 100644 --- a/test/unit/junk.c +++ b/test/unit/junk.c @@ -1,5 +1,7 @@ #include "test/jemalloc_test.h" +#include "jemalloc/internal/util.h" + static arena_dalloc_junk_small_t *arena_dalloc_junk_small_orig; static large_dalloc_junk_t *large_dalloc_junk_orig; static large_dalloc_maybe_junk_t *large_dalloc_maybe_junk_orig; diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 4241063e..b8c6a255 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -1,5 +1,7 @@ #include "test/jemalloc_test.h" +#include "jemalloc/internal/util.h" + TEST_BEGIN(test_mallctl_errors) { uint64_t epoch; size_t sz; diff --git a/test/unit/stats_print.c b/test/unit/stats_print.c index 81778b04..acb26b06 100644 --- a/test/unit/stats_print.c +++ b/test/unit/stats_print.c @@ -1,5 +1,7 @@ #include "test/jemalloc_test.h" +#include "jemalloc/internal/util.h" + typedef enum { TOKEN_TYPE_NONE, TOKEN_TYPE_ERROR, -- GitLab From d9ec36e22dfe61f3fb972dee33a5cae529e46b07 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 11 Apr 2017 14:43:12 -0700 Subject: [PATCH 421/544] Header refactoring: move assert.h out of the catch-all --- include/jemalloc/internal/hash_inlines.h | 2 ++ include/jemalloc/internal/jemalloc_internal_includes.h | 6 ------ src/arena.c | 1 + src/base.c | 2 ++ src/bitmap.c | 2 ++ src/ckh.c | 1 + src/ctl.c | 1 + src/extent.c | 3 ++- src/extent_dss.c | 2 ++ src/extent_mmap.c | 2 ++ src/jemalloc.c | 1 + src/large.c | 1 + src/mutex.c | 1 + src/nstime.c | 2 ++ src/pages.c | 1 + src/prof.c | 1 + src/rtree.c | 2 ++ src/stats.c | 2 ++ src/tcache.c | 2 ++ src/tsd.c | 2 ++ src/witness.c | 1 + src/zone.c | 3 +++ 22 files changed, 34 insertions(+), 7 deletions(-) diff --git a/include/jemalloc/internal/hash_inlines.h b/include/jemalloc/internal/hash_inlines.h index b134492a..321c17cc 100644 --- a/include/jemalloc/internal/hash_inlines.h +++ b/include/jemalloc/internal/hash_inlines.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_HASH_INLINES_H #define JEMALLOC_INTERNAL_HASH_INLINES_H +#include "jemalloc/internal/assert.h" + /* * The following hash function is based on MurmurHash3, placed into the public * domain by Austin Appleby. See https://github.com/aappleby/smhasher for diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 3a9c6ca2..1539c909 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -36,12 +36,6 @@ * global jemalloc definitions, however. */ -/******************************************************************************/ -/* HERMETIC HEADERS */ -/******************************************************************************/ - -#include "jemalloc/internal/assert.h" - /******************************************************************************/ /* TYPES */ /******************************************************************************/ diff --git a/src/arena.c b/src/arena.c index 27a0f75c..bb45a90c 100644 --- a/src/arena.c +++ b/src/arena.c @@ -2,6 +2,7 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" #include "jemalloc/internal/util.h" /******************************************************************************/ diff --git a/src/base.c b/src/base.c index caec9557..3de6e3b0 100644 --- a/src/base.c +++ b/src/base.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" + /******************************************************************************/ /* Data. */ diff --git a/src/bitmap.c b/src/bitmap.c index 2eb50f1b..275636b9 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" + /******************************************************************************/ void diff --git a/src/ckh.c b/src/ckh.c index ce977e14..aaa97924 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -38,6 +38,7 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" #include "jemalloc/internal/malloc_io.h" #include "jemalloc/internal/util.h" diff --git a/src/ctl.c b/src/ctl.c index 29689c8e..4fba2cd2 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -2,6 +2,7 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" #include "jemalloc/internal/util.h" /******************************************************************************/ diff --git a/src/extent.c b/src/extent.c index 0bfc555d..6b7da3f9 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1,9 +1,10 @@ #define JEMALLOC_EXTENT_C_ #include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" #include "jemalloc/internal/ph.h" -#include "jemalloc/internal/jemalloc_internal_includes.h" /******************************************************************************/ /* Data. */ diff --git a/src/extent_dss.c b/src/extent_dss.c index c609f14c..06bccc83 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" + /******************************************************************************/ /* Data. */ diff --git a/src/extent_mmap.c b/src/extent_mmap.c index 5717573e..9381dc16 100644 --- a/src/extent_mmap.c +++ b/src/extent_mmap.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" + /******************************************************************************/ static void * diff --git a/src/jemalloc.c b/src/jemalloc.c index 7e3ec6ea..d6b21586 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -2,6 +2,7 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/malloc_io.h" #include "jemalloc/internal/util.h" diff --git a/src/large.c b/src/large.c index aa3ea1ff..629656d0 100644 --- a/src/large.c +++ b/src/large.c @@ -2,6 +2,7 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" #include "jemalloc/internal/util.h" /******************************************************************************/ diff --git a/src/mutex.c b/src/mutex.c index 92c23dab..3bb5ce1d 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -2,6 +2,7 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" #include "jemalloc/internal/malloc_io.h" #if defined(JEMALLOC_LAZY_LOCK) && !defined(_WIN32) diff --git a/src/nstime.c b/src/nstime.c index ee8d78e7..e0895476 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -1,6 +1,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" + #define BILLION UINT64_C(1000000000) #define MILLION UINT64_C(1000000) diff --git a/src/pages.c b/src/pages.c index f1138231..7fa254f7 100644 --- a/src/pages.c +++ b/src/pages.c @@ -2,6 +2,7 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" #include "jemalloc/internal/malloc_io.h" #ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT diff --git a/src/prof.c b/src/prof.c index 276ca360..f2b21f72 100644 --- a/src/prof.c +++ b/src/prof.c @@ -2,6 +2,7 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" #include "jemalloc/internal/malloc_io.h" /******************************************************************************/ diff --git a/src/rtree.c b/src/rtree.c index 8d11d99f..ada6e9d5 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" + /* * Only the most significant bits of keys passed to rtree_{read,write}() are * used. diff --git a/src/stats.c b/src/stats.c index 110d62f7..bbba4679 100644 --- a/src/stats.c +++ b/src/stats.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" + const char *global_mutex_names[num_global_prof_mutexes] = { #define OP(mtx) #mtx, GLOBAL_PROF_MUTEXES diff --git a/src/tcache.c b/src/tcache.c index 7e71bb6a..971c016b 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" + /******************************************************************************/ /* Data. */ diff --git a/src/tsd.c b/src/tsd.c index cb7dd3fb..686b4ef4 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -2,6 +2,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" + /******************************************************************************/ /* Data. */ diff --git a/src/witness.c b/src/witness.c index bd040826..edb736bf 100644 --- a/src/witness.c +++ b/src/witness.c @@ -2,6 +2,7 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/assert.h" #include "jemalloc/internal/malloc_io.h" void diff --git a/src/zone.c b/src/zone.c index a8a571fd..37bc8da9 100644 --- a/src/zone.c +++ b/src/zone.c @@ -1,5 +1,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" + +#include "jemalloc/internal/assert.h" + #ifndef JEMALLOC_ZONE # error "This source file is for zones on Darwin (OS X)." #endif -- GitLab From 7ebc83894f025332d44cae361bd89c53c04acfc7 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 17 Apr 2017 15:52:44 -0700 Subject: [PATCH 422/544] Header refactoring: move jemalloc_internal_types.h out of the catch-all --- include/jemalloc/internal/arena_inlines_b.h | 2 ++ include/jemalloc/internal/jemalloc_internal_includes.h | 1 - include/jemalloc/internal/jemalloc_internal_inlines_a.h | 1 + include/jemalloc/internal/jemalloc_internal_inlines_c.h | 2 ++ include/jemalloc/internal/size_classes.sh | 5 +++-- include/jemalloc/internal/tcache_inlines.h | 1 + src/jemalloc.c | 1 + 7 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 8c76e0b0..4264f4b3 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_ARENA_INLINES_B_H #define JEMALLOC_INTERNAL_ARENA_INLINES_B_H +#include "jemalloc/internal/jemalloc_internal_types.h" + #ifndef JEMALLOC_ENABLE_INLINE szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin); prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr, diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 1539c909..7a51c2d4 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -40,7 +40,6 @@ /* TYPES */ /******************************************************************************/ -#include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/nstime_types.h" #include "jemalloc/internal/spin_types.h" #include "jemalloc/internal/prng_types.h" diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_a.h b/include/jemalloc/internal/jemalloc_internal_inlines_a.h index 978814b4..0d922f12 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_a.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_a.h @@ -3,6 +3,7 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/bit_util.h" +#include "jemalloc/internal/jemalloc_internal_types.h" #ifndef JEMALLOC_ENABLE_INLINE pszind_t psz2ind(size_t psz); diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_c.h b/include/jemalloc/internal/jemalloc_internal_inlines_c.h index bb1f2deb..8c793819 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_c.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_c.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_INLINES_C_H #define JEMALLOC_INTERNAL_INLINES_C_H +#include "jemalloc/internal/jemalloc_internal_types.h" + #ifndef JEMALLOC_ENABLE_INLINE arena_t *iaalloc(tsdn_t *tsdn, const void *ptr); size_t isalloc(tsdn_t *tsdn, const void *ptr); diff --git a/include/jemalloc/internal/size_classes.sh b/include/jemalloc/internal/size_classes.sh index 60bdbd21..da1e006c 100755 --- a/include/jemalloc/internal/size_classes.sh +++ b/include/jemalloc/internal/size_classes.sh @@ -279,9 +279,10 @@ cat < Date: Mon, 17 Apr 2017 16:17:02 -0700 Subject: [PATCH 423/544] Header refactoring: unify nstime.h and move it out of the catch-all --- include/jemalloc/internal/arena_structs_b.h | 1 + .../internal/jemalloc_internal_includes.h | 3 --- include/jemalloc/internal/mutex_inlines.h | 2 ++ include/jemalloc/internal/mutex_structs.h | 1 + .../internal/{nstime_externs.h => nstime.h} | 17 +++++++++++++---- include/jemalloc/internal/nstime_structs.h | 8 -------- include/jemalloc/internal/nstime_types.h | 11 ----------- src/ctl.c | 1 + src/nstime.c | 2 ++ test/include/test/jemalloc_test.h.in | 4 +--- 10 files changed, 21 insertions(+), 29 deletions(-) rename include/jemalloc/internal/{nstime_externs.h => nstime.h} (73%) delete mode 100644 include/jemalloc/internal/nstime_structs.h delete mode 100644 include/jemalloc/internal/nstime_types.h diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 14c473c5..f2195f68 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_ARENA_STRUCTS_B_H #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/nstime.h" #include "jemalloc/internal/ql.h" /* diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 7a51c2d4..f31fed6a 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -40,7 +40,6 @@ /* TYPES */ /******************************************************************************/ -#include "jemalloc/internal/nstime_types.h" #include "jemalloc/internal/spin_types.h" #include "jemalloc/internal/prng_types.h" #include "jemalloc/internal/ticker_types.h" @@ -66,7 +65,6 @@ /* STRUCTS */ /******************************************************************************/ -#include "jemalloc/internal/nstime_structs.h" #include "jemalloc/internal/spin_structs.h" #include "jemalloc/internal/ticker_structs.h" #include "jemalloc/internal/ckh_structs.h" @@ -90,7 +88,6 @@ /******************************************************************************/ #include "jemalloc/internal/jemalloc_internal_externs.h" -#include "jemalloc/internal/nstime_externs.h" #include "jemalloc/internal/ckh_externs.h" #include "jemalloc/internal/stats_externs.h" #include "jemalloc/internal/ctl_externs.h" diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index 0552e190..5ec439f7 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_MUTEX_INLINES_H #define JEMALLOC_INTERNAL_MUTEX_INLINES_H +#include "jemalloc/internal/nstime.h" + void malloc_mutex_lock_slow(malloc_mutex_t *mutex); #ifndef JEMALLOC_ENABLE_INLINE diff --git a/include/jemalloc/internal/mutex_structs.h b/include/jemalloc/internal/mutex_structs.h index 7b7085d4..dc755547 100644 --- a/include/jemalloc/internal/mutex_structs.h +++ b/include/jemalloc/internal/mutex_structs.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_MUTEX_STRUCTS_H #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/nstime.h" struct mutex_prof_data_s { /* diff --git a/include/jemalloc/internal/nstime_externs.h b/include/jemalloc/internal/nstime.h similarity index 73% rename from include/jemalloc/internal/nstime_externs.h rename to include/jemalloc/internal/nstime.h index 1abc84d9..cfccca09 100644 --- a/include/jemalloc/internal/nstime_externs.h +++ b/include/jemalloc/internal/nstime.h @@ -1,7 +1,15 @@ -#ifndef JEMALLOC_INTERNAL_NSTIME_EXTERNS_H -#define JEMALLOC_INTERNAL_NSTIME_EXTERNS_H +#ifndef JEMALLOC_INTERNAL_NSTIME_H +#define JEMALLOC_INTERNAL_NSTIME_H -void nstime_init(nstime_t *time, uint64_t ns); +/* Maximum supported number of seconds (~584 years). */ +#define NSTIME_SEC_MAX KQU(18446744072) +#define NSTIME_ZERO_INITIALIZER {0} + +typedef struct { + uint64_t ns; +} nstime_t; + +void nstime_init(nstime_t *time, uint64_t ns); void nstime_init2(nstime_t *time, uint64_t sec, uint64_t nsec); uint64_t nstime_ns(const nstime_t *time); uint64_t nstime_sec(const nstime_t *time); @@ -24,4 +32,5 @@ bool nstime_monotonic(void); bool nstime_update(nstime_t *time); #endif -#endif /* JEMALLOC_INTERNAL_NSTIME_EXTERNS_H */ + +#endif /* JEMALLOC_INTERNAL_NSTIME_H */ diff --git a/include/jemalloc/internal/nstime_structs.h b/include/jemalloc/internal/nstime_structs.h deleted file mode 100644 index a637f616..00000000 --- a/include/jemalloc/internal/nstime_structs.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_NSTIME_STRUCTS_H -#define JEMALLOC_INTERNAL_NSTIME_STRUCTS_H - -struct nstime_s { - uint64_t ns; -}; - -#endif /* JEMALLOC_INTERNAL_NSTIME_STRUCTS_H */ diff --git a/include/jemalloc/internal/nstime_types.h b/include/jemalloc/internal/nstime_types.h deleted file mode 100644 index 6e7e74cf..00000000 --- a/include/jemalloc/internal/nstime_types.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_NSTIME_TYPES_H -#define JEMALLOC_INTERNAL_NSTIME_TYPES_H - -typedef struct nstime_s nstime_t; - -/* Maximum supported number of seconds (~584 years). */ -#define NSTIME_SEC_MAX KQU(18446744072) - -#define NSTIME_ZERO_INITIALIZER {0} - -#endif /* JEMALLOC_INTERNAL_NSTIME_TYPES_H */ diff --git a/src/ctl.c b/src/ctl.c index 4fba2cd2..069e5356 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/nstime.h" #include "jemalloc/internal/util.h" /******************************************************************************/ diff --git a/src/nstime.c b/src/nstime.c index e0895476..9f5d192d 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -1,6 +1,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/nstime.h" + #include "jemalloc/internal/assert.h" #define BILLION UINT64_C(1000000000) diff --git a/test/include/test/jemalloc_test.h.in b/test/include/test/jemalloc_test.h.in index 02eaac2b..67caa86b 100644 --- a/test/include/test/jemalloc_test.h.in +++ b/test/include/test/jemalloc_test.h.in @@ -74,12 +74,10 @@ static const bool config_debug = /* Hermetic headers. */ # include "jemalloc/internal/assert.h" # include "jemalloc/internal/malloc_io.h" +# include "jemalloc/internal/nstime.h" # include "jemalloc/internal/util.h" /* Non-hermetic headers. */ -# include "jemalloc/internal/nstime_types.h" -# include "jemalloc/internal/nstime_structs.h" -# include "jemalloc/internal/nstime_externs.h" # include "jemalloc/internal/qr.h" # include "jemalloc/internal/ql.h" -- GitLab From 38e847c1c594fb9ad4862233f3602ade85da4e7f Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 17 Apr 2017 16:35:04 -0700 Subject: [PATCH 424/544] Header refactoring: unify spin.h and move it out of the catch-all. --- .../internal/jemalloc_internal_includes.h | 3 -- include/jemalloc/internal/rtree_inlines.h | 2 ++ include/jemalloc/internal/spin.h | 36 +++++++++++++++++++ include/jemalloc/internal/spin_inlines.h | 29 --------------- include/jemalloc/internal/spin_structs.h | 8 ----- include/jemalloc/internal/spin_types.h | 8 ----- src/extent_dss.c | 1 + src/jemalloc.c | 1 + src/spin.c | 3 +- 9 files changed, 42 insertions(+), 49 deletions(-) create mode 100644 include/jemalloc/internal/spin.h delete mode 100644 include/jemalloc/internal/spin_inlines.h delete mode 100644 include/jemalloc/internal/spin_structs.h delete mode 100644 include/jemalloc/internal/spin_types.h diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index f31fed6a..669194d0 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -40,7 +40,6 @@ /* TYPES */ /******************************************************************************/ -#include "jemalloc/internal/spin_types.h" #include "jemalloc/internal/prng_types.h" #include "jemalloc/internal/ticker_types.h" #include "jemalloc/internal/ckh_types.h" @@ -65,7 +64,6 @@ /* STRUCTS */ /******************************************************************************/ -#include "jemalloc/internal/spin_structs.h" #include "jemalloc/internal/ticker_structs.h" #include "jemalloc/internal/ckh_structs.h" #include "jemalloc/internal/witness_structs.h" @@ -110,7 +108,6 @@ /* INLINES */ /******************************************************************************/ -#include "jemalloc/internal/spin_inlines.h" #include "jemalloc/internal/prng_inlines.h" #include "jemalloc/internal/ticker_inlines.h" #include "jemalloc/internal/tsd_inlines.h" diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 6791f50c..030e5787 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_RTREE_INLINES_H #define JEMALLOC_INTERNAL_RTREE_INLINES_H +#include "jemalloc/internal/spin.h" + #ifndef JEMALLOC_ENABLE_INLINE uintptr_t rtree_leafkey(uintptr_t key); uintptr_t rtree_subkey(uintptr_t key, unsigned level); diff --git a/include/jemalloc/internal/spin.h b/include/jemalloc/internal/spin.h new file mode 100644 index 00000000..e2afc98c --- /dev/null +++ b/include/jemalloc/internal/spin.h @@ -0,0 +1,36 @@ +#ifndef JEMALLOC_INTERNAL_SPIN_H +#define JEMALLOC_INTERNAL_SPIN_H + +#ifdef JEMALLOC_SPIN_C_ +# define SPIN_INLINE extern inline +#else +# define SPIN_INLINE inline +#endif + +#define SPIN_INITIALIZER {0U} + +typedef struct { + unsigned iteration; +} spin_t; + +SPIN_INLINE void +spin_adaptive(spin_t *spin) { + volatile uint32_t i; + + if (spin->iteration < 5) { + for (i = 0; i < (1U << spin->iteration); i++) { + CPU_SPINWAIT; + } + spin->iteration++; + } else { +#ifdef _WIN32 + SwitchToThread(); +#else + sched_yield(); +#endif + } +} + +#undef SPIN_INLINE + +#endif /* JEMALLOC_INTERNAL_SPIN_H */ diff --git a/include/jemalloc/internal/spin_inlines.h b/include/jemalloc/internal/spin_inlines.h deleted file mode 100644 index 16573261..00000000 --- a/include/jemalloc/internal/spin_inlines.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_SPIN_INLINES_H -#define JEMALLOC_INTERNAL_SPIN_INLINES_H - -#ifndef JEMALLOC_ENABLE_INLINE -void spin_adaptive(spin_t *spin); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_SPIN_C_)) -JEMALLOC_INLINE void -spin_adaptive(spin_t *spin) { - volatile uint32_t i; - - if (spin->iteration < 5) { - for (i = 0; i < (1U << spin->iteration); i++) { - CPU_SPINWAIT; - } - spin->iteration++; - } else { -#ifdef _WIN32 - SwitchToThread(); -#else - sched_yield(); -#endif - } -} - -#endif - -#endif /* JEMALLOC_INTERNAL_SPIN_INLINES_H */ diff --git a/include/jemalloc/internal/spin_structs.h b/include/jemalloc/internal/spin_structs.h deleted file mode 100644 index ef71a765..00000000 --- a/include/jemalloc/internal/spin_structs.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_SPIN_STRUCTS_H -#define JEMALLOC_INTERNAL_SPIN_STRUCTS_H - -struct spin_s { - unsigned iteration; -}; - -#endif /* JEMALLOC_INTERNAL_SPIN_STRUCTS_H */ diff --git a/include/jemalloc/internal/spin_types.h b/include/jemalloc/internal/spin_types.h deleted file mode 100644 index 222e0698..00000000 --- a/include/jemalloc/internal/spin_types.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_SPIN_TYPES_H -#define JEMALLOC_INTERNAL_SPIN_TYPES_H - -typedef struct spin_s spin_t; - -#define SPIN_INITIALIZER {0U} - -#endif /* JEMALLOC_INTERNAL_SPIN_TYPES_H */ diff --git a/src/extent_dss.c b/src/extent_dss.c index 06bccc83..6b5d066f 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/spin.h" /******************************************************************************/ /* Data. */ diff --git a/src/jemalloc.c b/src/jemalloc.c index 3dad7265..0297cf56 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -6,6 +6,7 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/malloc_io.h" +#include "jemalloc/internal/spin.h" #include "jemalloc/internal/util.h" /******************************************************************************/ diff --git a/src/spin.c b/src/spin.c index d2d39419..24372c26 100644 --- a/src/spin.c +++ b/src/spin.c @@ -1,3 +1,4 @@ #define JEMALLOC_SPIN_C_ #include "jemalloc/internal/jemalloc_preamble.h" -#include "jemalloc/internal/jemalloc_internal_includes.h" + +#include "jemalloc/internal/spin.h" -- GitLab From 45f087eb033927338b9df847eb9be6886ef48cf7 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 16 Apr 2017 09:25:56 -0700 Subject: [PATCH 425/544] Revert "Remove BITMAP_USE_TREE." Some systems use a native 64 KiB page size, which means that the bitmap for the smallest size class can be 8192 bits, not just 512 bits as when the page size is 4 KiB. Linear search in bitmap_{sfu,ffu}() is unacceptably slow for such large bitmaps. This reverts commit 7c00f04ff40a34627e31488d02ff1081c749c7ba. --- include/jemalloc/internal/bitmap_inlines.h | 95 ++++++++++++++++++ include/jemalloc/internal/bitmap_structs.h | 11 +++ include/jemalloc/internal/bitmap_types.h | 107 +++++++++++++++++++++ src/bitmap.c | 78 +++++++++++++++ test/unit/bitmap.c | 16 +++ 5 files changed, 307 insertions(+) diff --git a/include/jemalloc/internal/bitmap_inlines.h b/include/jemalloc/internal/bitmap_inlines.h index fc4bad4c..c2362018 100644 --- a/include/jemalloc/internal/bitmap_inlines.h +++ b/include/jemalloc/internal/bitmap_inlines.h @@ -16,6 +16,12 @@ void bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BITMAP_C_)) JEMALLOC_INLINE bool bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) { +#ifdef BITMAP_USE_TREE + size_t rgoff = binfo->levels[binfo->nlevels].group_offset - 1; + bitmap_t rg = bitmap[rgoff]; + /* The bitmap is full iff the root group is 0. */ + return (rg == 0); +#else size_t i; for (i = 0; i < binfo->ngroups; i++) { @@ -24,6 +30,7 @@ bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) { } } return true; +#endif } JEMALLOC_INLINE bool @@ -52,6 +59,24 @@ bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); *gp = g; assert(bitmap_get(bitmap, binfo, bit)); +#ifdef BITMAP_USE_TREE + /* Propagate group state transitions up the tree. */ + if (g == 0) { + unsigned i; + for (i = 1; i < binfo->nlevels; i++) { + bit = goff; + goff = bit >> LG_BITMAP_GROUP_NBITS; + gp = &bitmap[binfo->levels[i].group_offset + goff]; + g = *gp; + assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); + g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); + *gp = g; + if (g != 0) { + break; + } + } + } +#endif } /* ffu: find first unset >= bit. */ @@ -59,6 +84,44 @@ JEMALLOC_INLINE size_t bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) { assert(min_bit < binfo->nbits); +#ifdef BITMAP_USE_TREE + size_t bit = 0; + for (unsigned level = binfo->nlevels; level--;) { + size_t lg_bits_per_group = (LG_BITMAP_GROUP_NBITS * (level + + 1)); + bitmap_t group = bitmap[binfo->levels[level].group_offset + (bit + >> lg_bits_per_group)]; + unsigned group_nmask = ((min_bit > bit) ? (min_bit - bit) : 0) + >> (lg_bits_per_group - LG_BITMAP_GROUP_NBITS); + assert(group_nmask <= BITMAP_GROUP_NBITS); + bitmap_t group_mask = ~((1LU << group_nmask) - 1); + bitmap_t group_masked = group & group_mask; + if (group_masked == 0LU) { + if (group == 0LU) { + return binfo->nbits; + } + /* + * min_bit was preceded by one or more unset bits in + * this group, but there are no other unset bits in this + * group. Try again starting at the first bit of the + * next sibling. This will recurse at most once per + * non-root level. + */ + size_t sib_base = bit + (1U << lg_bits_per_group); + assert(sib_base > min_bit); + assert(sib_base > bit); + if (sib_base >= binfo->nbits) { + return binfo->nbits; + } + return bitmap_ffu(bitmap, binfo, sib_base); + } + bit += (ffs_lu(group_masked) - 1) << (lg_bits_per_group - + LG_BITMAP_GROUP_NBITS); + } + assert(bit >= min_bit); + assert(bit < binfo->nbits); + return bit; +#else size_t i = min_bit >> LG_BITMAP_GROUP_NBITS; bitmap_t g = bitmap[i] & ~((1LU << (min_bit & BITMAP_GROUP_NBITS_MASK)) - 1); @@ -72,6 +135,7 @@ bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) { g = bitmap[i]; } while (i < binfo->ngroups); return binfo->nbits; +#endif } /* sfu: set first unset. */ @@ -83,6 +147,16 @@ bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) { assert(!bitmap_full(bitmap, binfo)); +#ifdef BITMAP_USE_TREE + i = binfo->nlevels - 1; + g = bitmap[binfo->levels[i].group_offset]; + bit = ffs_lu(g) - 1; + while (i > 0) { + i--; + g = bitmap[binfo->levels[i].group_offset + bit]; + bit = (bit << LG_BITMAP_GROUP_NBITS) + (ffs_lu(g) - 1); + } +#else i = 0; g = bitmap[0]; while ((bit = ffs_lu(g)) == 0) { @@ -90,6 +164,7 @@ bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) { g = bitmap[i]; } bit = (i << LG_BITMAP_GROUP_NBITS) + (bit - 1); +#endif bitmap_set(bitmap, binfo, bit); return bit; } @@ -111,6 +186,26 @@ bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); *gp = g; assert(!bitmap_get(bitmap, binfo, bit)); +#ifdef BITMAP_USE_TREE + /* Propagate group state transitions up the tree. */ + if (propagate) { + unsigned i; + for (i = 1; i < binfo->nlevels; i++) { + bit = goff; + goff = bit >> LG_BITMAP_GROUP_NBITS; + gp = &bitmap[binfo->levels[i].group_offset + goff]; + g = *gp; + propagate = (g == 0); + assert((g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))) + == 0); + g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); + *gp = g; + if (!propagate) { + break; + } + } + } +#endif /* BITMAP_USE_TREE */ } #endif diff --git a/include/jemalloc/internal/bitmap_structs.h b/include/jemalloc/internal/bitmap_structs.h index dde15328..297ae669 100644 --- a/include/jemalloc/internal/bitmap_structs.h +++ b/include/jemalloc/internal/bitmap_structs.h @@ -10,8 +10,19 @@ struct bitmap_info_s { /* Logical number of bits in bitmap (stored at bottom level). */ size_t nbits; +#ifdef BITMAP_USE_TREE + /* Number of levels necessary for nbits. */ + unsigned nlevels; + + /* + * Only the first (nlevels+1) elements are used, and levels are ordered + * bottom to top (e.g. the bottom level is stored in levels[0]). + */ + bitmap_level_t levels[BITMAP_MAX_LEVELS+1]; +#else /* BITMAP_USE_TREE */ /* Number of groups necessary for nbits. */ size_t ngroups; +#endif /* BITMAP_USE_TREE */ }; #endif /* JEMALLOC_INTERNAL_BITMAP_STRUCTS_H */ diff --git a/include/jemalloc/internal/bitmap_types.h b/include/jemalloc/internal/bitmap_types.h index 091ccead..b334769f 100644 --- a/include/jemalloc/internal/bitmap_types.h +++ b/include/jemalloc/internal/bitmap_types.h @@ -21,10 +21,115 @@ typedef unsigned long bitmap_t; #define BITMAP_GROUP_NBITS (1U << LG_BITMAP_GROUP_NBITS) #define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1) +/* + * Do some analysis on how big the bitmap is before we use a tree. For a brute + * force linear search, if we would have to call ffs_lu() more than 2^3 times, + * use a tree instead. + */ +#if LG_BITMAP_MAXBITS - LG_BITMAP_GROUP_NBITS > 3 +# define BITMAP_USE_TREE +#endif + /* Number of groups required to store a given number of bits. */ #define BITMAP_BITS2GROUPS(nbits) \ (((nbits) + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS) +/* + * Number of groups required at a particular level for a given number of bits. + */ +#define BITMAP_GROUPS_L0(nbits) \ + BITMAP_BITS2GROUPS(nbits) +#define BITMAP_GROUPS_L1(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits)) +#define BITMAP_GROUPS_L2(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))) +#define BITMAP_GROUPS_L3(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ + BITMAP_BITS2GROUPS((nbits))))) +#define BITMAP_GROUPS_L4(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))))) + +/* + * Assuming the number of levels, number of groups required for a given number + * of bits. + */ +#define BITMAP_GROUPS_1_LEVEL(nbits) \ + BITMAP_GROUPS_L0(nbits) +#define BITMAP_GROUPS_2_LEVEL(nbits) \ + (BITMAP_GROUPS_1_LEVEL(nbits) + BITMAP_GROUPS_L1(nbits)) +#define BITMAP_GROUPS_3_LEVEL(nbits) \ + (BITMAP_GROUPS_2_LEVEL(nbits) + BITMAP_GROUPS_L2(nbits)) +#define BITMAP_GROUPS_4_LEVEL(nbits) \ + (BITMAP_GROUPS_3_LEVEL(nbits) + BITMAP_GROUPS_L3(nbits)) +#define BITMAP_GROUPS_5_LEVEL(nbits) \ + (BITMAP_GROUPS_4_LEVEL(nbits) + BITMAP_GROUPS_L4(nbits)) + +/* + * Maximum number of groups required to support LG_BITMAP_MAXBITS. + */ +#ifdef BITMAP_USE_TREE + +#if LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_1_LEVEL(nbits) +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_1_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 2 +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_2_LEVEL(nbits) +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_2_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 3 +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_3_LEVEL(nbits) +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_3_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 4 +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_4_LEVEL(nbits) +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_4_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 5 +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_5_LEVEL(nbits) +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_5_LEVEL(BITMAP_MAXBITS) +#else +# error "Unsupported bitmap size" +#endif + +/* + * Maximum number of levels possible. This could be statically computed based + * on LG_BITMAP_MAXBITS: + * + * #define BITMAP_MAX_LEVELS \ + * (LG_BITMAP_MAXBITS / LG_SIZEOF_BITMAP) \ + * + !!(LG_BITMAP_MAXBITS % LG_SIZEOF_BITMAP) + * + * However, that would not allow the generic BITMAP_INFO_INITIALIZER() macro, so + * instead hardcode BITMAP_MAX_LEVELS to the largest number supported by the + * various cascading macros. The only additional cost this incurs is some + * unused trailing entries in bitmap_info_t structures; the bitmaps themselves + * are not impacted. + */ +#define BITMAP_MAX_LEVELS 5 + +#define BITMAP_INFO_INITIALIZER(nbits) { \ + /* nbits. */ \ + nbits, \ + /* nlevels. */ \ + (BITMAP_GROUPS_L0(nbits) > BITMAP_GROUPS_L1(nbits)) + \ + (BITMAP_GROUPS_L1(nbits) > BITMAP_GROUPS_L2(nbits)) + \ + (BITMAP_GROUPS_L2(nbits) > BITMAP_GROUPS_L3(nbits)) + \ + (BITMAP_GROUPS_L3(nbits) > BITMAP_GROUPS_L4(nbits)) + 1, \ + /* levels. */ \ + { \ + {0}, \ + {BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) + \ + BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L3(nbits) + BITMAP_GROUPS_L2(nbits) + \ + BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L4(nbits) + BITMAP_GROUPS_L3(nbits) + \ + BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) \ + + BITMAP_GROUPS_L0(nbits)} \ + } \ +} + +#else /* BITMAP_USE_TREE */ + #define BITMAP_GROUPS(nbits) BITMAP_BITS2GROUPS(nbits) #define BITMAP_GROUPS_MAX BITMAP_BITS2GROUPS(BITMAP_MAXBITS) @@ -35,4 +140,6 @@ typedef unsigned long bitmap_t; BITMAP_BITS2GROUPS(nbits) \ } +#endif /* BITMAP_USE_TREE */ + #endif /* JEMALLOC_INTERNAL_BITMAP_TYPES_H */ diff --git a/src/bitmap.c b/src/bitmap.c index 275636b9..468b3178 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -6,6 +6,82 @@ /******************************************************************************/ +#ifdef BITMAP_USE_TREE + +void +bitmap_info_init(bitmap_info_t *binfo, size_t nbits) { + unsigned i; + size_t group_count; + + assert(nbits > 0); + assert(nbits <= (ZU(1) << LG_BITMAP_MAXBITS)); + + /* + * Compute the number of groups necessary to store nbits bits, and + * progressively work upward through the levels until reaching a level + * that requires only one group. + */ + binfo->levels[0].group_offset = 0; + group_count = BITMAP_BITS2GROUPS(nbits); + for (i = 1; group_count > 1; i++) { + assert(i < BITMAP_MAX_LEVELS); + binfo->levels[i].group_offset = binfo->levels[i-1].group_offset + + group_count; + group_count = BITMAP_BITS2GROUPS(group_count); + } + binfo->levels[i].group_offset = binfo->levels[i-1].group_offset + + group_count; + assert(binfo->levels[i].group_offset <= BITMAP_GROUPS_MAX); + binfo->nlevels = i; + binfo->nbits = nbits; +} + +static size_t +bitmap_info_ngroups(const bitmap_info_t *binfo) { + return binfo->levels[binfo->nlevels].group_offset; +} + +void +bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo, bool fill) { + size_t extra; + unsigned i; + + /* + * Bits are actually inverted with regard to the external bitmap + * interface. + */ + + if (fill) { + /* The "filled" bitmap starts out with all 0 bits. */ + memset(bitmap, 0, bitmap_size(binfo)); + return; + } + + /* + * The "empty" bitmap starts out with all 1 bits, except for trailing + * unused bits (if any). Note that each group uses bit 0 to correspond + * to the first logical bit in the group, so extra bits are the most + * significant bits of the last group. + */ + memset(bitmap, 0xffU, bitmap_size(binfo)); + extra = (BITMAP_GROUP_NBITS - (binfo->nbits & BITMAP_GROUP_NBITS_MASK)) + & BITMAP_GROUP_NBITS_MASK; + if (extra != 0) { + bitmap[binfo->levels[1].group_offset - 1] >>= extra; + } + for (i = 1; i < binfo->nlevels; i++) { + size_t group_count = binfo->levels[i].group_offset - + binfo->levels[i-1].group_offset; + extra = (BITMAP_GROUP_NBITS - (group_count & + BITMAP_GROUP_NBITS_MASK)) & BITMAP_GROUP_NBITS_MASK; + if (extra != 0) { + bitmap[binfo->levels[i+1].group_offset - 1] >>= extra; + } + } +} + +#else /* BITMAP_USE_TREE */ + void bitmap_info_init(bitmap_info_t *binfo, size_t nbits) { assert(nbits > 0); @@ -37,6 +113,8 @@ bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo, bool fill) { } } +#endif /* BITMAP_USE_TREE */ + size_t bitmap_size(const bitmap_info_t *binfo) { return (bitmap_info_ngroups(binfo) << LG_SIZEOF_BITMAP); diff --git a/test/unit/bitmap.c b/test/unit/bitmap.c index f65ed53e..cafb2039 100644 --- a/test/unit/bitmap.c +++ b/test/unit/bitmap.c @@ -103,8 +103,24 @@ test_bitmap_initializer_body(const bitmap_info_t *binfo, size_t nbits) { assert_zu_eq(binfo->nbits, binfo_dyn.nbits, "Unexpected difference between static and dynamic initialization, " "nbits=%zu", nbits); +#ifdef BITMAP_USE_TREE + assert_u_eq(binfo->nlevels, binfo_dyn.nlevels, + "Unexpected difference between static and dynamic initialization, " + "nbits=%zu", nbits); + { + unsigned i; + + for (i = 0; i < binfo->nlevels; i++) { + assert_zu_eq(binfo->levels[i].group_offset, + binfo_dyn.levels[i].group_offset, + "Unexpected difference between static and dynamic " + "initialization, nbits=%zu, level=%u", nbits, i); + } + } +#else assert_zu_eq(binfo->ngroups, binfo_dyn.ngroups, "Unexpected difference between static and dynamic initialization"); +#endif } TEST_BEGIN(test_bitmap_initializer) { -- GitLab From da4cff0279b2e8f2b0482ae961f2e2f63662342d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sun, 16 Apr 2017 16:23:32 -0700 Subject: [PATCH 426/544] Support --with-lg-page values larger than system page size. All mappings continue to be PAGE-aligned, even if the system page size is smaller. This change is primarily intended to provide a mechanism for supporting multiple page sizes with the same binary; smaller page sizes work better in conjunction with jemalloc's design. This resolves #467. --- INSTALL | 9 +- include/jemalloc/internal/pages_externs.h | 6 +- include/jemalloc/internal/private_symbols.txt | 1 - src/extent_mmap.c | 60 +----- src/jemalloc.c | 4 +- src/pages.c | 182 +++++++++++++----- test/unit/pack.c | 2 +- test/unit/pages.c | 2 +- 8 files changed, 155 insertions(+), 111 deletions(-) diff --git a/INSTALL b/INSTALL index 042f8291..705f0ff5 100644 --- a/INSTALL +++ b/INSTALL @@ -219,9 +219,12 @@ any of the following arguments (not a definitive list) to 'configure': documentation. --with-lg-page= - Specify the base 2 log of the system page size. This option is only useful - when cross compiling, since the configure script automatically determines - the host's page size by default. + Specify the base 2 log of the allocator page size, which must in turn be at + least as large as the system page size. By default the configure script + determines the host's page size and sets the allocator page size equal to + the system page size, so this option need not be specified unless the + system page size may change between configuration and execution, e.g. when + cross compiling. --with-lg-page-sizes= Specify the comma-separated base 2 logs of the page sizes to support. This diff --git a/include/jemalloc/internal/pages_externs.h b/include/jemalloc/internal/pages_externs.h index 7e34efb3..af9a01b8 100644 --- a/include/jemalloc/internal/pages_externs.h +++ b/include/jemalloc/internal/pages_externs.h @@ -16,16 +16,14 @@ static const bool pages_can_purge_forced = #endif ; -void *pages_map(void *addr, size_t size, bool *commit); +void *pages_map(void *addr, size_t size, size_t alignment, bool *commit); void pages_unmap(void *addr, size_t size); -void *pages_trim(void *addr, size_t alloc_size, size_t leadsize, - size_t size, bool *commit); bool pages_commit(void *addr, size_t size); bool pages_decommit(void *addr, size_t size); bool pages_purge_lazy(void *addr, size_t size); bool pages_purge_forced(void *addr, size_t size); bool pages_huge(void *addr, size_t size); bool pages_nohuge(void *addr, size_t size); -void pages_boot(void); +bool pages_boot(void); #endif /* JEMALLOC_INTERNAL_PAGES_EXTERNS_H */ diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 34c27897..649a689f 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -360,7 +360,6 @@ pages_map pages_nohuge pages_purge_forced pages_purge_lazy -pages_trim pages_unmap percpu_arena_choose percpu_arena_ind_limit diff --git a/src/extent_mmap.c b/src/extent_mmap.c index 9381dc16..b1862753 100644 --- a/src/extent_mmap.c +++ b/src/extent_mmap.c @@ -6,66 +6,14 @@ /******************************************************************************/ -static void * -extent_alloc_mmap_slow(size_t size, size_t alignment, bool *zero, - bool *commit) { - void *ret; - size_t alloc_size; - - alloc_size = size + alignment - PAGE; - /* Beware size_t wrap-around. */ - if (alloc_size < size) { - return NULL; - } - do { - void *pages; - size_t leadsize; - pages = pages_map(NULL, alloc_size, commit); - if (pages == NULL) { - return NULL; - } - leadsize = ALIGNMENT_CEILING((uintptr_t)pages, alignment) - - (uintptr_t)pages; - ret = pages_trim(pages, alloc_size, leadsize, size, commit); - } while (ret == NULL); - - assert(ret != NULL); - *zero = true; - return ret; -} - void * extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit) { - void *ret; - size_t offset; - - /* - * Ideally, there would be a way to specify alignment to mmap() (like - * NetBSD has), but in the absence of such a feature, we have to work - * hard to efficiently create aligned mappings. The reliable, but - * slow method is to create a mapping that is over-sized, then trim the - * excess. However, that always results in one or two calls to - * pages_unmap(). - * - * Optimistically try mapping precisely the right amount before falling - * back to the slow method, with the expectation that the optimistic - * approach works most of the time. - */ - - assert(alignment != 0); - - ret = pages_map(new_addr, size, commit); - if (ret == NULL || ret == new_addr) { - return ret; - } - assert(new_addr == NULL); - offset = ALIGNMENT_ADDR2OFFSET(ret, alignment); - if (offset != 0) { - pages_unmap(ret, size); - return extent_alloc_mmap_slow(size, alignment, zero, commit); + void *ret = pages_map(new_addr, size, ALIGNMENT_CEILING(alignment, + PAGE), commit); + if (ret == NULL) { + return NULL; } - assert(ret != NULL); *zero = true; return ret; diff --git a/src/jemalloc.c b/src/jemalloc.c index 0297cf56..ea632c2e 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1220,7 +1220,9 @@ malloc_init_hard_a0_locked() { } } } - pages_boot(); + if (pages_boot()) { + return true; + } if (base_boot(TSDN_NULL)) { return true; } diff --git a/src/pages.c b/src/pages.c index 7fa254f7..46c307b8 100644 --- a/src/pages.c +++ b/src/pages.c @@ -12,6 +12,9 @@ /******************************************************************************/ /* Data. */ +/* Actual operating system page size, detected during bootstrap, <= PAGE. */ +static size_t os_page; + #ifndef _WIN32 # define PAGES_PROT_COMMIT (PROT_READ | PROT_WRITE) # define PAGES_PROT_DECOMMIT (PROT_NONE) @@ -20,20 +23,26 @@ static int mmap_flags; static bool os_overcommits; /******************************************************************************/ +/* + * Function prototypes for static functions that are referenced prior to + * definition. + */ -void * -pages_map(void *addr, size_t size, bool *commit) { - assert(PAGE_ADDR2BASE(addr) == addr); - assert(PAGE_CEILING(size) == size); +static void os_pages_unmap(void *addr, size_t size); - void *ret; +/******************************************************************************/ +static void * +os_pages_map(void *addr, size_t size, size_t alignment, bool *commit) { + assert(ALIGNMENT_ADDR2BASE(addr, os_page) == addr); + assert(ALIGNMENT_CEILING(size, os_page) == size); assert(size != 0); if (os_overcommits) { *commit = true; } + void *ret; #ifdef _WIN32 /* * If VirtualAlloc can't allocate at the given address when one is @@ -59,19 +68,48 @@ pages_map(void *addr, size_t size, bool *commit) { /* * We succeeded in mapping memory, but not in the right place. */ - pages_unmap(ret, size); + os_pages_unmap(ret, size); ret = NULL; } #endif - assert(ret == NULL || (addr == NULL && ret != addr) - || (addr != NULL && ret == addr)); + assert(ret == NULL || (addr == NULL && ret != addr) || (addr != NULL && + ret == addr)); return ret; } -void -pages_unmap(void *addr, size_t size) { - assert(PAGE_ADDR2BASE(addr) == addr); - assert(PAGE_CEILING(size) == size); +static void * +os_pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size, + bool *commit) { + void *ret = (void *)((uintptr_t)addr + leadsize); + + assert(alloc_size >= leadsize + size); +#ifdef _WIN32 + os_pages_unmap(addr, alloc_size); + void *new_addr = os_pages_map(ret, size, PAGE, commit); + if (new_addr == ret) { + return ret; + } + if (new_addr != NULL) { + os_pages_unmap(new_addr, size); + } + return NULL; +#else + size_t trailsize = alloc_size - leadsize - size; + + if (leadsize != 0) { + os_pages_unmap(addr, leadsize); + } + if (trailsize != 0) { + os_pages_unmap((void *)((uintptr_t)ret + size), trailsize); + } + return ret; +#endif +} + +static void +os_pages_unmap(void *addr, size_t size) { + assert(ALIGNMENT_ADDR2BASE(addr, os_page) == addr); + assert(ALIGNMENT_CEILING(size, os_page) == size); #ifdef _WIN32 if (VirtualFree(addr, 0, MEM_RELEASE) == 0) @@ -84,50 +122,80 @@ pages_unmap(void *addr, size_t size) { buferror(get_errno(), buf, sizeof(buf)); malloc_printf(": Error in " #ifdef _WIN32 - "VirtualFree" + "VirtualFree" #else - "munmap" + "munmap" #endif - "(): %s\n", buf); + "(): %s\n", buf); if (opt_abort) { abort(); } } } -void * -pages_trim(void *addr, size_t alloc_size, size_t leadsize, size_t size, - bool *commit) { - void *ret = (void *)((uintptr_t)addr + leadsize); - - assert(alloc_size >= leadsize + size); -#ifdef _WIN32 - { - void *new_addr; - - pages_unmap(addr, alloc_size); - new_addr = pages_map(ret, size, commit); - if (new_addr == ret) { - return ret; - } - if (new_addr) { - pages_unmap(new_addr, size); - } +static void * +pages_map_slow(size_t size, size_t alignment, bool *commit) { + size_t alloc_size = size + alignment - os_page; + /* Beware size_t wrap-around. */ + if (alloc_size < size) { return NULL; } -#else - { - size_t trailsize = alloc_size - leadsize - size; - if (leadsize != 0) { - pages_unmap(addr, leadsize); - } - if (trailsize != 0) { - pages_unmap((void *)((uintptr_t)ret + size), trailsize); + void *ret; + do { + void *pages = os_pages_map(NULL, alloc_size, alignment, commit); + if (pages == NULL) { + return NULL; } + size_t leadsize = ALIGNMENT_CEILING((uintptr_t)pages, alignment) + - (uintptr_t)pages; + ret = os_pages_trim(pages, alloc_size, leadsize, size, commit); + } while (ret == NULL); + + assert(ret != NULL); + assert(PAGE_ADDR2BASE(ret) == ret); + return ret; +} + +void * +pages_map(void *addr, size_t size, size_t alignment, bool *commit) { + assert(alignment >= PAGE); + assert(ALIGNMENT_ADDR2BASE(addr, alignment) == addr); + + /* + * Ideally, there would be a way to specify alignment to mmap() (like + * NetBSD has), but in the absence of such a feature, we have to work + * hard to efficiently create aligned mappings. The reliable, but + * slow method is to create a mapping that is over-sized, then trim the + * excess. However, that always results in one or two calls to + * os_pages_unmap(), and it can leave holes in the process's virtual + * memory map if memory grows downward. + * + * Optimistically try mapping precisely the right amount before falling + * back to the slow method, with the expectation that the optimistic + * approach works most of the time. + */ + + void *ret = os_pages_map(addr, size, os_page, commit); + if (ret == NULL || ret == addr) { return ret; } -#endif + assert(addr == NULL); + if (ALIGNMENT_ADDR2OFFSET(ret, alignment) != 0) { + os_pages_unmap(ret, size); + return pages_map_slow(size, alignment, commit); + } + + assert(PAGE_ADDR2BASE(ret) == ret); + return ret; +} + +void +pages_unmap(void *addr, size_t size) { + assert(PAGE_ADDR2BASE(addr) == addr); + assert(PAGE_CEILING(size) == size); + + os_pages_unmap(addr, size); } static bool @@ -155,7 +223,7 @@ pages_commit_impl(void *addr, size_t size, bool commit) { * We succeeded in mapping memory, but not in the right * place. */ - pages_unmap(result, size); + os_pages_unmap(result, size); return true; } return false; @@ -239,6 +307,21 @@ pages_nohuge(void *addr, size_t size) { #endif } +static size_t +os_page_detect(void) { +#ifdef _WIN32 + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwPageSize; +#else + long result = sysconf(_SC_PAGESIZE); + if (result == -1) { + return LG_PAGE; + } + return (size_t)result; +#endif +} + #ifdef JEMALLOC_SYSCTL_VM_OVERCOMMIT static bool os_overcommits_sysctl(void) { @@ -300,8 +383,17 @@ os_overcommits_proc(void) { } #endif -void +bool pages_boot(void) { + os_page = os_page_detect(); + if (os_page > PAGE) { + malloc_write(": Unsupported system page size\n"); + if (opt_abort) { + abort(); + } + return true; + } + #ifndef _WIN32 mmap_flags = MAP_PRIVATE | MAP_ANON; #endif @@ -318,4 +410,6 @@ pages_boot(void) { #else os_overcommits = false; #endif + + return false; } diff --git a/test/unit/pack.c b/test/unit/pack.c index 5da4ae12..edfc548f 100644 --- a/test/unit/pack.c +++ b/test/unit/pack.c @@ -6,7 +6,7 @@ #if LG_PAGE <= 14 #define SZ (ZU(1) << (LG_PAGE - 2)) #else -#define SZ 4096 +#define SZ ZU(4096) #endif /* diff --git a/test/unit/pages.c b/test/unit/pages.c index 30d69592..4457f369 100644 --- a/test/unit/pages.c +++ b/test/unit/pages.c @@ -7,7 +7,7 @@ TEST_BEGIN(test_pages_huge) { alloc_size = HUGEPAGE * 2 - PAGE; commit = true; - pages = pages_map(NULL, alloc_size, &commit); + pages = pages_map(NULL, alloc_size, PAGE, &commit); assert_ptr_not_null(pages, "Unexpected pages_map() error"); hugepage = (void *)(ALIGNMENT_CEILING((uintptr_t)pages, HUGEPAGE)); -- GitLab From acf4c8ae33539a219711791c3556016b853b7d09 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 18 Apr 2017 15:00:14 -0700 Subject: [PATCH 427/544] Output 4 counters for bin mutexes instead of just 2. --- src/stats.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/stats.c b/src/stats.c index bbba4679..435dfb9f 100644 --- a/src/stats.c +++ b/src/stats.c @@ -126,19 +126,21 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\"bins\": [\n"); } else { + char *mutex_counters = " n_lock_ops n_waiting" + " n_spin_acq max_wait_ns\n"; if (config_tcache) { malloc_cprintf(write_cb, cbopaque, "bins: size ind allocated nmalloc" " ndalloc nrequests curregs" " curslabs regs pgs util nfills" - " nflushes newslabs reslabs" - " contention max_wait_ns\n"); + " nflushes newslabs reslabs%s", + mutex ? mutex_counters : "\n"); } else { malloc_cprintf(write_cb, cbopaque, "bins: size ind allocated nmalloc" " ndalloc nrequests curregs" " curslabs regs pgs util newslabs" - " reslabs contention max_wait_ns\n"); + " reslabs%s", mutex ? mutex_counters : "\n"); } } for (j = 0, in_gap = false; j < nbins; j++) { @@ -245,6 +247,10 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, &max_wait, uint64_t); CTL_M2_M4_GET("stats.arenas.0.bins.0.mutex.num_ops", i, j, &num_ops, uint64_t); + uint64_t mutex_stats[num_mutex_prof_counters]; + if (mutex) { + read_arena_bin_mutex_stats(i, j, mutex_stats); + } char rate[6]; if (get_rate_str(num_wait, num_ops, rate)) { @@ -259,22 +265,32 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, "%20zu %3u %12zu %12"FMTu64 " %12"FMTu64" %12"FMTu64" %12zu" " %12zu %4u %3zu %-5s %12"FMTu64 - " %12"FMTu64" %12"FMTu64" %12"FMTu64 - " %12s %12"FMTu64"\n", + " %12"FMTu64" %12"FMTu64" %12"FMTu64, reg_size, j, curregs * reg_size, nmalloc, ndalloc, nrequests, curregs, curslabs, nregs, slab_size / page, util, nfills, - nflushes, nslabs, nreslabs, rate, max_wait); + nflushes, nslabs, nreslabs); } else { malloc_cprintf(write_cb, cbopaque, "%20zu %3u %12zu %12"FMTu64 " %12"FMTu64" %12"FMTu64" %12zu" " %12zu %4u %3zu %-5s %12"FMTu64 - " %12"FMTu64" %12s %12"FMTu64"\n", + " %12"FMTu64, reg_size, j, curregs * reg_size, nmalloc, ndalloc, nrequests, curregs, curslabs, nregs, slab_size / page, util, nslabs, - nreslabs, rate, max_wait); + nreslabs); + } + if (mutex) { + malloc_cprintf(write_cb, cbopaque, + " %12"FMTu64" %12"FMTu64" %12"FMTu64 + " %12"FMTu64"\n", + mutex_stats[mutex_counter_num_ops], + mutex_stats[mutex_counter_num_wait], + mutex_stats[mutex_counter_num_spin_acq], + mutex_stats[mutex_counter_max_wait_time]); + } else { + malloc_cprintf(write_cb, cbopaque, "\n"); } } } -- GitLab From fed9a880c811fc56f7563efcb0a70c6ffe401c5f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 19 Apr 2017 16:14:54 -0700 Subject: [PATCH 428/544] Trim before commit in extent_recycle(). This avoids creating clean committed pages as a side effect of aligned allocation. For configurations that decommit memory, purged pages are decommitted, and decommitted extents cannot be coalesced with committed extents. Unless the clean committed pages happen to be selected during allocation, they cause unnecessary permanent extent fragmentation. This resolves #766. --- src/extent.c | 8 ++++++-- src/extent_mmap.c | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/extent.c b/src/extent.c index 6b7da3f9..d08ccdb3 100644 --- a/src/extent.c +++ b/src/extent.c @@ -829,12 +829,16 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + bool committed = false; extent_t *extent = extent_recycle_extract(tsdn, arena, r_extent_hooks, rtree_ctx, extents, false, new_addr, size, pad, alignment, slab, - zero, commit); + zero, &committed); if (extent == NULL) { return NULL; } + if (committed) { + *commit = true; + } extent = extent_recycle_split(tsdn, arena, r_extent_hooks, rtree_ctx, extents, new_addr, size, pad, alignment, slab, szind, extent); @@ -996,7 +1000,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, assert(new_addr == NULL || leadsize == 0); assert(alloc_size >= leadsize + esize); size_t trailsize = alloc_size - leadsize - esize; - if (extent_zeroed_get(extent)) { + if (extent_zeroed_get(extent) && extent_committed_get(extent)) { *zero = true; } if (extent_committed_get(extent)) { diff --git a/src/extent_mmap.c b/src/extent_mmap.c index b1862753..be099373 100644 --- a/src/extent_mmap.c +++ b/src/extent_mmap.c @@ -15,7 +15,9 @@ extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, return NULL; } assert(ret != NULL); - *zero = true; + if (*commit) { + *zero = true; + } return ret; } -- GitLab From 5aa46f027df42636d4aa1fb70d1078a6c5f96420 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Thu, 20 Apr 2017 15:19:02 -0700 Subject: [PATCH 429/544] Bypass extent tracking for auto arenas. Tracking extents is required by arena_reset. To support this, the extent linkage was used for tracking 1) large allocations, and 2) full slabs. However modifying the extent linkage could be an expensive operation as it likely incurs cache misses. Since we forbid arena_reset on auto arenas, let's bypass the linkage operations for auto arenas. --- .../internal/jemalloc_internal_inlines_a.h | 1 + .../internal/jemalloc_internal_inlines_b.h | 6 ++++ .../internal/jemalloc_internal_inlines_c.h | 9 ++--- src/arena.c | 33 ++++++++++++------- src/ctl.c | 7 +--- src/large.c | 25 +++++++++----- 6 files changed, 49 insertions(+), 32 deletions(-) diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_a.h b/include/jemalloc/internal/jemalloc_internal_inlines_a.h index 0d922f12..38fa3c70 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_a.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_a.h @@ -24,6 +24,7 @@ size_t sa2u(size_t size, size_t alignment); arena_t *arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal); arena_t *arena_choose(tsd_t *tsd, arena_t *arena); arena_t *arena_ichoose(tsd_t *tsd, arena_t *arena); +bool arena_is_auto(arena_t *arena); arena_tdata_t *arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing); arena_t *arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing); diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_b.h b/include/jemalloc/internal/jemalloc_internal_inlines_b.h index f22708a5..ab54a598 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_b.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_b.h @@ -70,6 +70,12 @@ arena_ichoose(tsd_t *tsd, arena_t *arena) { return arena_choose_impl(tsd, arena, true); } +JEMALLOC_INLINE bool +arena_is_auto(arena_t *arena) { + assert(narenas_auto > 0); + return (arena_ind_get(arena) < narenas_auto); +} + JEMALLOC_ALWAYS_INLINE extent_t * iealloc(tsdn_t *tsdn, const void *ptr) { rtree_ctx_t rtree_ctx_fallback; diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_c.h b/include/jemalloc/internal/jemalloc_internal_inlines_c.h index 8c793819..70ac6669 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_c.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_c.h @@ -54,8 +54,7 @@ iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, assert(size != 0); assert(!is_internal || tcache == NULL); - assert(!is_internal || arena == NULL || arena_ind_get(arena) < - narenas_auto); + assert(!is_internal || arena == NULL || arena_is_auto(arena)); witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); ret = arena_malloc(tsdn, arena, size, ind, zero, tcache, slow_path); @@ -79,8 +78,7 @@ ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, assert(usize != 0); assert(usize == sa2u(usize, alignment)); assert(!is_internal || tcache == NULL); - assert(!is_internal || arena == NULL || arena_ind_get(arena) < - narenas_auto); + assert(!is_internal || arena == NULL || arena_is_auto(arena)); witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); ret = arena_palloc(tsdn, arena, usize, alignment, zero, tcache); @@ -113,8 +111,7 @@ idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, alloc_ctx_t *alloc_ctx, bool is_internal, bool slow_path) { assert(ptr != NULL); assert(!is_internal || tcache == NULL); - assert(!is_internal || arena_ind_get(iaalloc(tsdn, ptr)) < - narenas_auto); + assert(!is_internal || arena_is_auto(iaalloc(tsdn, ptr))); witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); if (config_stats && is_internal) { arena_internal_sub(iaalloc(tsdn, ptr), isalloc(tsdn, ptr)); diff --git a/src/arena.c b/src/arena.c index bb45a90c..94a4b5ef 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1032,13 +1032,24 @@ arena_bin_slabs_nonfull_tryget(arena_bin_t *bin) { } static void -arena_bin_slabs_full_insert(arena_bin_t *bin, extent_t *slab) { +arena_bin_slabs_full_insert(arena_t *arena, arena_bin_t *bin, extent_t *slab) { assert(extent_nfree_get(slab) == 0); + /* + * Tracking extents is required by arena_reset, which is not allowed + * for auto arenas. Bypass this step to avoid touching the extent + * linkage (often results in cache misses) for auto arenas. + */ + if (arena_is_auto(arena)) { + return; + } extent_list_append(&bin->slabs_full, slab); } static void -arena_bin_slabs_full_remove(arena_bin_t *bin, extent_t *slab) { +arena_bin_slabs_full_remove(arena_t *arena, arena_bin_t *bin, extent_t *slab) { + if (arena_is_auto(arena)) { + return; + } extent_list_remove(&bin->slabs_full, slab); } @@ -1106,7 +1117,7 @@ arena_reset(tsd_t *tsd, arena_t *arena) { } for (slab = extent_list_first(&bin->slabs_full); slab != NULL; slab = extent_list_first(&bin->slabs_full)) { - arena_bin_slabs_full_remove(bin, slab); + arena_bin_slabs_full_remove(arena, bin, slab); malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); arena_slab_dalloc(tsd_tsdn(tsd), arena, slab); malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); @@ -1285,8 +1296,8 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, extent_t *slab; bin_info = &arena_bin_info[binind]; - if (bin->slabcur != NULL) { - arena_bin_slabs_full_insert(bin, bin->slabcur); + if (!arena_is_auto(arena) && bin->slabcur != NULL) { + arena_bin_slabs_full_insert(arena, bin, bin->slabcur); bin->slabcur = NULL; } slab = arena_bin_nonfull_slab_get(tsdn, arena, bin, binind); @@ -1319,7 +1330,7 @@ arena_bin_malloc_hard(tsdn_t *tsdn, arena_t *arena, arena_bin_t *bin, return ret; } - arena_bin_slabs_full_insert(bin, bin->slabcur); + arena_bin_slabs_full_insert(arena, bin, bin->slabcur); bin->slabcur = NULL; } @@ -1559,7 +1570,7 @@ arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache, } static void -arena_dissociate_bin_slab(extent_t *slab, arena_bin_t *bin) { +arena_dissociate_bin_slab(arena_t *arena, extent_t *slab, arena_bin_t *bin) { /* Dissociate slab from bin. */ if (slab == bin->slabcur) { bin->slabcur = NULL; @@ -1573,7 +1584,7 @@ arena_dissociate_bin_slab(extent_t *slab, arena_bin_t *bin) { * into the non-full slabs heap. */ if (bin_info->nregs == 1) { - arena_bin_slabs_full_remove(bin, slab); + arena_bin_slabs_full_remove(arena, bin, slab); } else { arena_bin_slabs_nonfull_remove(bin, slab); } @@ -1611,7 +1622,7 @@ arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, if (extent_nfree_get(bin->slabcur) > 0) { arena_bin_slabs_nonfull_insert(bin, bin->slabcur); } else { - arena_bin_slabs_full_insert(bin, bin->slabcur); + arena_bin_slabs_full_insert(arena, bin, bin->slabcur); } bin->slabcur = slab; if (config_stats) { @@ -1637,10 +1648,10 @@ arena_dalloc_bin_locked_impl(tsdn_t *tsdn, arena_t *arena, extent_t *slab, arena_slab_reg_dalloc(tsdn, slab, slab_data, ptr); unsigned nfree = extent_nfree_get(slab); if (nfree == bin_info->nregs) { - arena_dissociate_bin_slab(slab, bin); + arena_dissociate_bin_slab(arena, slab, bin); arena_dalloc_bin_slab(tsdn, arena, slab, bin); } else if (nfree == 1 && slab != bin->slabcur) { - arena_bin_slabs_full_remove(bin, slab); + arena_bin_slabs_full_remove(arena, bin, slab); arena_bin_lower_slab(tsdn, arena, slab, bin); } diff --git a/src/ctl.c b/src/ctl.c index 069e5356..1b0ee053 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1846,13 +1846,8 @@ arena_i_reset_destroy_helper(tsd_t *tsd, const size_t *mib, size_t miblen, WRITEONLY(); MIB_UNSIGNED(*arena_ind, 1); - if (*arena_ind < narenas_auto) { - ret = EFAULT; - goto label_return; - } - *arena = arena_get(tsd_tsdn(tsd), *arena_ind, false); - if (*arena == NULL) { + if (*arena == NULL || arena_is_auto(*arena)) { ret = EFAULT; goto label_return; } diff --git a/src/large.c b/src/large.c index 629656d0..36e8be91 100644 --- a/src/large.c +++ b/src/large.c @@ -46,10 +46,13 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, return NULL; } - /* Insert extent into large. */ - malloc_mutex_lock(tsdn, &arena->large_mtx); - extent_list_append(&arena->large, extent); - malloc_mutex_unlock(tsdn, &arena->large_mtx); + /* See comments in arena_bin_slabs_full_insert(). */ + if (!arena_is_auto(arena)) { + /* Insert extent into large. */ + malloc_mutex_lock(tsdn, &arena->large_mtx); + extent_list_append(&arena->large, extent); + malloc_mutex_unlock(tsdn, &arena->large_mtx); + } if (config_prof && arena_prof_accum(tsdn, arena, usize)) { prof_idump(tsdn); } @@ -318,16 +321,20 @@ large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, static void large_dalloc_prep_impl(tsdn_t *tsdn, arena_t *arena, extent_t *extent, bool junked_locked) { - if (!junked_locked) { - malloc_mutex_lock(tsdn, &arena->large_mtx); - extent_list_remove(&arena->large, extent); - malloc_mutex_unlock(tsdn, &arena->large_mtx); + /* See comments in arena_bin_slabs_full_insert(). */ + if (!arena_is_auto(arena)) { + malloc_mutex_lock(tsdn, &arena->large_mtx); + extent_list_remove(&arena->large, extent); + malloc_mutex_unlock(tsdn, &arena->large_mtx); + } large_dalloc_maybe_junk(extent_addr_get(extent), extent_usize_get(extent)); } else { malloc_mutex_assert_owner(tsdn, &arena->large_mtx); - extent_list_remove(&arena->large, extent); + if (!arena_is_auto(arena)) { + extent_list_remove(&arena->large, extent); + } } arena_extent_dalloc_large_prep(tsdn, arena, extent); } -- GitLab From 4403c9ab441eabb6c55d93b99836f7126e46be75 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 20 Apr 2017 17:21:37 -0700 Subject: [PATCH 430/544] Remove --disable-tcache. Simplify configuration by removing the --disable-tcache option, but replace the testing for that configuration with --with-malloc-conf=tcache:false. Fix the thread.arena and thread.tcache.flush mallctls to work correctly if tcache is disabled. This partially resolves #580. --- .travis.yml | 14 +-- INSTALL | 5 - configure.ac | 17 --- doc/jemalloc.xml.in | 34 +----- include/jemalloc/internal/arena_inlines_a.h | 2 +- .../internal/jemalloc_internal_defs.h.in | 7 -- .../internal/jemalloc_internal_inlines_a.h | 19 ++- .../internal/jemalloc_internal_inlines_b.h | 2 +- .../jemalloc/internal/jemalloc_preamble.h.in | 7 -- include/jemalloc/internal/tcache_inlines.h | 5 - include/jemalloc/internal/tcache_structs.h | 9 -- scripts/gen_run_tests.py | 2 +- scripts/gen_travis.py | 15 ++- src/arena.c | 56 ++++----- src/ctl.c | 66 +++------- src/jemalloc.c | 13 +- src/stats.c | 114 +++++------------- src/tcache.c | 44 ++----- test/integration/thread_tcache_enabled.c | 25 +--- test/test.sh.in | 1 - test/unit/decay.c | 109 ++++++++--------- test/unit/decay.sh | 5 +- test/unit/mallctl.c | 9 +- test/unit/prof_idump.sh | 8 +- test/unit/stats.c | 20 +-- 25 files changed, 192 insertions(+), 416 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2235206d..4838cb37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,7 @@ matrix: - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx @@ -31,7 +31,7 @@ matrix: - os: osx env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=clang CXX=clang++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" addons: @@ -45,7 +45,7 @@ matrix: - os: linux env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-tcache" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds" addons: @@ -65,7 +65,7 @@ matrix: packages: - gcc-multilib - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--disable-tcache" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" addons: apt: packages: @@ -75,13 +75,13 @@ matrix: - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-tcache" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-tcache" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux - env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --disable-tcache" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" before_script: diff --git a/INSTALL b/INSTALL index 705f0ff5..f2c0fa8b 100644 --- a/INSTALL +++ b/INSTALL @@ -153,11 +153,6 @@ any of the following arguments (not a definitive list) to 'configure': Statically link against the specified libunwind.a rather than dynamically linking with -lunwind. ---disable-tcache - Disable thread-specific caches for small objects. Objects are cached and - released in bulk, thus reducing the total number of mutex operations. See - the "opt.tcache" option for usage details. - --disable-munmap Disable virtual memory deallocation via munmap(2); instead keep track of the virtual memory for later use. munmap() is disabled by default (i.e. diff --git a/configure.ac b/configure.ac index f6d08ccd..669c1b38 100644 --- a/configure.ac +++ b/configure.ac @@ -1137,22 +1137,6 @@ if test "x$enable_prof" = "x1" ; then fi AC_SUBST([enable_prof]) -dnl Enable thread-specific caching by default. -AC_ARG_ENABLE([tcache], - [AS_HELP_STRING([--disable-tcache], [Disable per thread caches])], -[if test "x$enable_tcache" = "xno" ; then - enable_tcache="0" -else - enable_tcache="1" -fi -], -[enable_tcache="1"] -) -if test "x$enable_tcache" = "x1" ; then - AC_DEFINE([JEMALLOC_TCACHE], [ ]) -fi -AC_SUBST([enable_tcache]) - dnl Indicate whether adjacent virtual memory mappings automatically coalesce dnl (and fragment on demand). if test "x${maps_coalesce}" = "x1" ; then @@ -2181,7 +2165,6 @@ AC_MSG_RESULT([prof : ${enable_prof}]) AC_MSG_RESULT([prof-libunwind : ${enable_prof_libunwind}]) AC_MSG_RESULT([prof-libgcc : ${enable_prof_libgcc}]) AC_MSG_RESULT([prof-gcc : ${enable_prof_gcc}]) -AC_MSG_RESULT([tcache : ${enable_tcache}]) AC_MSG_RESULT([fill : ${enable_fill}]) AC_MSG_RESULT([utrace : ${enable_utrace}]) AC_MSG_RESULT([xmalloc : ${enable_xmalloc}]) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 3b98395d..2b321a7c 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -510,13 +510,12 @@ for (i = 0; i < nbins; i++) { sense to reduce the number of arenas if an application does not make much use of the allocation functions. - In addition to multiple arenas, unless - is specified during configuration, this - allocator supports thread-specific caching, in order to make it possible to - completely avoid synchronization for most allocation requests. Such caching - allows very fast allocation in the common case, but it increases memory - usage and fragmentation, since a bounded number of objects can remain - allocated in each thread cache. + In addition to multiple arenas, this allocator supports + thread-specific caching, in order to make it possible to completely avoid + synchronization for most allocation requests. Such caching allows very fast + allocation in the common case, but it increases memory usage and + fragmentation, since a bounded number of objects can remain allocated in + each thread cache. Memory is conceptually broken into extents. Extents are always aligned to multiples of the page size. This alignment makes it possible to @@ -839,16 +838,6 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", build configuration. - - - config.tcache - (bool) - r- - - was not specified - during build configuration. - - config.tls @@ -1095,7 +1084,6 @@ malloc_conf = "xmalloc:true";]]> opt.tcache (bool) r- - [] Thread-specific caching (tcache) enabled/disabled. When there are multiple threads, each thread uses a tcache for objects up to @@ -1112,7 +1100,6 @@ malloc_conf = "xmalloc:true";]]> opt.lg_tcache_max (size_t) r- - [] Maximum size class (log base 2) to cache in the thread-specific cache (tcache). At a minimum, all small size classes @@ -1370,7 +1357,6 @@ malloc_conf = "xmalloc:true";]]> thread.tcache.enabled (bool) rw - [] Enable/disable calling thread's tcache. The tcache is implicitly flushed as a side effect of becoming @@ -1384,7 +1370,6 @@ malloc_conf = "xmalloc:true";]]> thread.tcache.flush (void) -- - [] Flush calling thread's thread-specific cache (tcache). This interface releases all cached objects and internal data structures @@ -1440,7 +1425,6 @@ malloc_conf = "xmalloc:true";]]> tcache.create (unsigned) r- - [] Create an explicit thread-specific cache (tcache) and return an identifier that can be passed to the tcache.flush (unsigned) -w - [] Flush the specified thread-specific cache (tcache). The same considerations apply to this interface as to tcache.destroy (unsigned) -w - [] Flush the specified thread-specific cache (tcache) and make the identifier available for use during a future tcache creation. @@ -1873,7 +1855,6 @@ struct extent_hooks_s { arenas.tcache_max (size_t) r- - [] Maximum thread-cached size class. @@ -1892,7 +1873,6 @@ struct extent_hooks_s { arenas.nhbins (unsigned) r- - [] Total number of thread cache bin size classes. @@ -2575,7 +2555,6 @@ struct extent_hooks_s { stats.arenas.<i>.bins.<j>.nfills (uint64_t) r- - [ ] Cumulative number of tcache fills. @@ -2585,7 +2564,6 @@ struct extent_hooks_s { stats.arenas.<i>.bins.<j>.nflushes (uint64_t) r- - [ ] Cumulative number of tcache flushes. diff --git a/include/jemalloc/internal/arena_inlines_a.h b/include/jemalloc/internal/arena_inlines_a.h index cf92342b..2bd5ce75 100644 --- a/include/jemalloc/internal/arena_inlines_a.h +++ b/include/jemalloc/internal/arena_inlines_a.h @@ -58,7 +58,7 @@ percpu_arena_update(tsd_t *tsd, unsigned cpu) { /* Set new arena/tcache associations. */ arena_migrate(tsd, oldind, newind); tcache_t *tcache = tcache_get(tsd); - if (config_tcache && tcache) { + if (tcache != NULL) { tcache_arena_reassociate(tsd_tsdn(tsd), tcache, newarena); } diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 28eb0b34..d3d76944 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -154,13 +154,6 @@ /* Use gcc intrinsics for profile backtracing if defined. */ #undef JEMALLOC_PROF_GCC -/* - * JEMALLOC_TCACHE enables a thread-specific caching layer for small objects. - * This makes it possible to allocate/deallocate objects without any locking - * when the cache is in the steady state. - */ -#undef JEMALLOC_TCACHE - /* * JEMALLOC_DSS enables use of sbrk(2) to allocate extents from the data storage * segment (DSS). diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_a.h b/include/jemalloc/internal/jemalloc_internal_inlines_a.h index 38fa3c70..c28bd7cf 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_a.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_a.h @@ -323,7 +323,8 @@ malloc_getcpu(void) { JEMALLOC_ALWAYS_INLINE unsigned percpu_arena_choose(void) { unsigned arena_ind; - assert(have_percpu_arena && (percpu_arena_mode != percpu_arena_disabled)); + assert(have_percpu_arena && (percpu_arena_mode != + percpu_arena_disabled)); malloc_cpuid_t cpuid = malloc_getcpu(); assert(cpuid >= 0); @@ -420,19 +421,16 @@ tcache_large_bin_get(tcache_t *tcache, szind_t binind) { JEMALLOC_ALWAYS_INLINE bool tcache_available(tsd_t *tsd) { - cassert(config_tcache); - /* * Thread specific auto tcache might be unavailable if: 1) during tcache * initialization, or 2) disabled through thread.tcache.enabled mallctl * or config options. This check covers all cases. */ - if (likely(tsd_tcache_enabled_get(tsd) == true)) { - /* Associated arena == null implies tcache init in progress. */ - if (tsd_tcachep_get(tsd)->arena != NULL) { - assert(tcache_small_bin_get(tsd_tcachep_get(tsd), - 0)->avail != NULL); - } + if (likely(tsd_tcache_enabled_get(tsd))) { + /* Associated arena == NULL implies tcache init in progress. */ + assert(tsd_tcachep_get(tsd)->arena == NULL || + tcache_small_bin_get(tsd_tcachep_get(tsd), 0)->avail != + NULL); return true; } @@ -441,9 +439,6 @@ tcache_available(tsd_t *tsd) { JEMALLOC_ALWAYS_INLINE tcache_t * tcache_get(tsd_t *tsd) { - if (!config_tcache) { - return NULL; - } if (!tcache_available(tsd)) { return NULL; } diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_b.h b/include/jemalloc/internal/jemalloc_internal_inlines_b.h index ab54a598..2fd371c3 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_b.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_b.h @@ -24,7 +24,7 @@ arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { if (unlikely(ret == NULL)) { ret = arena_choose_hard(tsd, internal); assert(ret); - if (config_tcache && tcache_available(tsd)) { + if (tcache_available(tsd)) { tcache_t *tcache = tcache_get(tsd); if (tcache->arena != NULL) { /* See comments in tcache_data_init().*/ diff --git a/include/jemalloc/internal/jemalloc_preamble.h.in b/include/jemalloc/internal/jemalloc_preamble.h.in index 7c796c61..0e2ce312 100644 --- a/include/jemalloc/internal/jemalloc_preamble.h.in +++ b/include/jemalloc/internal/jemalloc_preamble.h.in @@ -111,13 +111,6 @@ static const bool config_stats = false #endif ; -static const bool config_tcache = -#ifdef JEMALLOC_TCACHE - true -#else - false -#endif - ; static const bool config_tls = #ifdef JEMALLOC_TLS true diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index d425b82a..67d35b58 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -6,7 +6,6 @@ #ifndef JEMALLOC_ENABLE_INLINE void tcache_event(tsd_t *tsd, tcache_t *tcache); -void tcache_flush(void); bool tcache_enabled_get(tsd_t *tsd); tcache_t *tcache_get(tsd_t *tsd); void tcache_enabled_set(tsd_t *tsd, bool enabled); @@ -25,15 +24,11 @@ tcache_t *tcaches_get(tsd_t *tsd, unsigned ind); #if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TCACHE_C_)) JEMALLOC_INLINE bool tcache_enabled_get(tsd_t *tsd) { - cassert(config_tcache); - return tsd_tcache_enabled_get(tsd); } JEMALLOC_INLINE void tcache_enabled_set(tsd_t *tsd, bool enabled) { - cassert(config_tcache); - bool was_enabled = tsd_tcache_enabled_get(tsd); if (!was_enabled && enabled) { diff --git a/include/jemalloc/internal/tcache_structs.h b/include/jemalloc/internal/tcache_structs.h index c43e59b7..fe27f362 100644 --- a/include/jemalloc/internal/tcache_structs.h +++ b/include/jemalloc/internal/tcache_structs.h @@ -40,23 +40,14 @@ struct tcache_s { * element of tbins is initialized to point to the proper offset within * this array. */ -#ifdef JEMALLOC_TCACHE tcache_bin_t tbins_small[NBINS]; -#else - tcache_bin_t tbins_small[0]; -#endif /* Data accessed less often below. */ ql_elm(tcache_t) link; /* Used for aggregating stats. */ arena_t *arena; /* Associated arena. */ szind_t next_gc_bin; /* Next bin to GC. */ -#ifdef JEMALLOC_TCACHE /* For small bins, fill (ncached_max >> lg_fill_div). */ uint8_t lg_fill_div[NBINS]; tcache_bin_t tbins_large[NSIZES-NBINS]; -#else - uint8_t lg_fill_div[0]; - tcache_bin_t tbins_large[0]; -#endif }; /* Linkage for list of available (previously used) explicit tcache IDs. */ diff --git a/scripts/gen_run_tests.py b/scripts/gen_run_tests.py index 729ecb1a..9e46ba90 100755 --- a/scripts/gen_run_tests.py +++ b/scripts/gen_run_tests.py @@ -18,7 +18,7 @@ possible_config_opts = [ '--enable-debug', '--enable-prof', '--disable-stats', - '--disable-tcache', + '--with-malloc-conf=tcache:false', ] print 'set -e' diff --git a/scripts/gen_travis.py b/scripts/gen_travis.py index 35a10ee6..4649cb71 100755 --- a/scripts/gen_travis.py +++ b/scripts/gen_travis.py @@ -24,11 +24,11 @@ script: # The 'default' configuration is gcc, on linux, with no compiler or configure # flags. We also test with clang, -m32, --enable-debug, --enable-prof, -# --disable-stats, and --disable-tcache. To avoid abusing travis though, we -# don't test all 2**7 = 128 possible combinations of these; instead, we only -# test combinations of up to 2 'unusual' settings, under the hope that bugs -# involving interactions of such settings are rare. -# things at once, for C(7, 0) + C(7, 1) + C(7, 2) = 29 +# --disable-stats, and --with-malloc-conf=tcache:false. To avoid abusing +# travis though, we don't test all 2**7 = 128 possible combinations of these; +# instead, we only test combinations of up to 2 'unusual' settings, under the +# hope that bugs involving interactions of such settings are rare. +# Things at once, for C(7, 0) + C(7, 1) + C(7, 2) = 29 MAX_UNUSUAL_OPTIONS = 2 os_default = 'linux' @@ -40,7 +40,10 @@ compilers_unusual = 'CC=clang CXX=clang++' compiler_flag_unusuals = ['-m32'] configure_flag_unusuals = [ - '--enable-debug', '--enable-prof', '--disable-stats', '--disable-tcache', + '--enable-debug', + '--enable-prof', + '--disable-stats', + '--with-malloc-conf=tcache:false', ] all_unusuals = ( diff --git a/src/arena.c b/src/arena.c index 94a4b5ef..c2eca449 100644 --- a/src/arena.c +++ b/src/arena.c @@ -283,31 +283,27 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, arena_stats_unlock(tsdn, &arena->stats); - if (config_tcache) { - tcache_bin_t *tbin; - tcache_t *tcache; - - /* tcache_bytes counts currently cached bytes. */ - atomic_store_zu(&astats->tcache_bytes, 0, ATOMIC_RELAXED); - malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx); - ql_foreach(tcache, &arena->tcache_ql, link) { - szind_t i = 0; - for (; i < NBINS; i++) { - tbin = tcache_small_bin_get(tcache, i); - arena_stats_accum_zu(&astats->tcache_bytes, - tbin->ncached * index2size(i)); - } - for (; i < nhbins; i++) { - tbin = tcache_large_bin_get(tcache, i); - arena_stats_accum_zu(&astats->tcache_bytes, - tbin->ncached * index2size(i)); - } + /* tcache_bytes counts currently cached bytes. */ + atomic_store_zu(&astats->tcache_bytes, 0, ATOMIC_RELAXED); + malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx); + tcache_t *tcache; + ql_foreach(tcache, &arena->tcache_ql, link) { + szind_t i = 0; + for (; i < NBINS; i++) { + tcache_bin_t *tbin = tcache_small_bin_get(tcache, i); + arena_stats_accum_zu(&astats->tcache_bytes, + tbin->ncached * index2size(i)); + } + for (; i < nhbins; i++) { + tcache_bin_t *tbin = tcache_large_bin_get(tcache, i); + arena_stats_accum_zu(&astats->tcache_bytes, + tbin->ncached * index2size(i)); } - malloc_mutex_prof_read(tsdn, - &astats->mutex_prof_data[arena_prof_mutex_tcache_list], - &arena->tcache_ql_mtx); - malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx); } + malloc_mutex_prof_read(tsdn, + &astats->mutex_prof_data[arena_prof_mutex_tcache_list], + &arena->tcache_ql_mtx); + malloc_mutex_unlock(tsdn, &arena->tcache_ql_mtx); #define READ_ARENA_MUTEX_PROF_DATA(mtx, ind) \ malloc_mutex_lock(tsdn, &arena->mtx); \ @@ -342,10 +338,8 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, bstats[i].ndalloc += bin->stats.ndalloc; bstats[i].nrequests += bin->stats.nrequests; bstats[i].curregs += bin->stats.curregs; - if (config_tcache) { - bstats[i].nfills += bin->stats.nfills; - bstats[i].nflushes += bin->stats.nflushes; - } + bstats[i].nfills += bin->stats.nfills; + bstats[i].nflushes += bin->stats.nflushes; bstats[i].nslabs += bin->stats.nslabs; bstats[i].reslabs += bin->stats.reslabs; bstats[i].curslabs += bin->stats.curslabs; @@ -1867,9 +1861,7 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { if (arena_stats_init(tsdn, &arena->stats)) { goto label_error; } - } - if (config_stats && config_tcache) { ql_new(&arena->tcache_ql); if (malloc_mutex_init(&arena->tcache_ql_mtx, "tcache_ql", WITNESS_RANK_TCACHE_QL)) { @@ -2007,7 +1999,7 @@ arena_prefork0(tsdn_t *tsdn, arena_t *arena) { void arena_prefork1(tsdn_t *tsdn, arena_t *arena) { - if (config_stats && config_tcache) { + if (config_stats) { malloc_mutex_prefork(tsdn, &arena->tcache_ql_mtx); } } @@ -2056,7 +2048,7 @@ arena_postfork_parent(tsdn_t *tsdn, arena_t *arena) { extents_postfork_parent(tsdn, &arena->extents_retained); malloc_mutex_postfork_parent(tsdn, &arena->decay_dirty.mtx); malloc_mutex_postfork_parent(tsdn, &arena->decay_muzzy.mtx); - if (config_stats && config_tcache) { + if (config_stats) { malloc_mutex_postfork_parent(tsdn, &arena->tcache_ql_mtx); } } @@ -2076,7 +2068,7 @@ arena_postfork_child(tsdn_t *tsdn, arena_t *arena) { extents_postfork_child(tsdn, &arena->extents_retained); malloc_mutex_postfork_child(tsdn, &arena->decay_dirty.mtx); malloc_mutex_postfork_child(tsdn, &arena->decay_muzzy.mtx); - if (config_stats && config_tcache) { + if (config_stats) { malloc_mutex_postfork_child(tsdn, &arena->tcache_ql_mtx); } } diff --git a/src/ctl.c b/src/ctl.c index 1b0ee053..a1842956 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -70,7 +70,6 @@ CTL_PROTO(config_prof) CTL_PROTO(config_prof_libgcc) CTL_PROTO(config_prof_libunwind) CTL_PROTO(config_stats) -CTL_PROTO(config_tcache) CTL_PROTO(config_tls) CTL_PROTO(config_utrace) CTL_PROTO(config_xmalloc) @@ -255,7 +254,6 @@ static const ctl_named_node_t config_node[] = { {NAME("prof_libgcc"), CTL(config_prof_libgcc)}, {NAME("prof_libunwind"), CTL(config_prof_libunwind)}, {NAME("stats"), CTL(config_stats)}, - {NAME("tcache"), CTL(config_tcache)}, {NAME("tls"), CTL(config_tls)}, {NAME("utrace"), CTL(config_utrace)}, {NAME("xmalloc"), CTL(config_xmalloc)} @@ -777,10 +775,8 @@ ARENA_PROF_MUTEXES accum_arena_stats_u64(&sdstats->astats.nrequests_large, &astats->astats.nrequests_large); - if (config_tcache) { - accum_atomic_zu(&sdstats->astats.tcache_bytes, - &astats->astats.tcache_bytes); - } + accum_atomic_zu(&sdstats->astats.tcache_bytes, + &astats->astats.tcache_bytes); for (i = 0; i < NBINS; i++) { sdstats->bstats[i].nmalloc += astats->bstats[i].nmalloc; @@ -793,12 +789,9 @@ ARENA_PROF_MUTEXES } else { assert(astats->bstats[i].curregs == 0); } - if (config_tcache) { - sdstats->bstats[i].nfills += - astats->bstats[i].nfills; - sdstats->bstats[i].nflushes += - astats->bstats[i].nflushes; - } + sdstats->bstats[i].nfills += astats->bstats[i].nfills; + sdstats->bstats[i].nflushes += + astats->bstats[i].nflushes; sdstats->bstats[i].nslabs += astats->bstats[i].nslabs; sdstats->bstats[i].reslabs += astats->bstats[i].reslabs; if (!destroyed) { @@ -1457,7 +1450,6 @@ CTL_RO_CONFIG_GEN(config_prof, bool) CTL_RO_CONFIG_GEN(config_prof_libgcc, bool) CTL_RO_CONFIG_GEN(config_prof_libunwind, bool) CTL_RO_CONFIG_GEN(config_stats, bool) -CTL_RO_CONFIG_GEN(config_tcache, bool) CTL_RO_CONFIG_GEN(config_tls, bool) CTL_RO_CONFIG_GEN(config_utrace, bool) CTL_RO_CONFIG_GEN(config_xmalloc, bool) @@ -1475,8 +1467,8 @@ CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *) CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool) CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool) CTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool) -CTL_RO_NL_CGEN(config_tcache, opt_tcache, opt_tcache, bool) -CTL_RO_NL_CGEN(config_tcache, opt_lg_tcache_max, opt_lg_tcache_max, ssize_t) +CTL_RO_NL_GEN(opt_tcache, opt_tcache, bool) +CTL_RO_NL_GEN(opt_lg_tcache_max, opt_lg_tcache_max, ssize_t) CTL_RO_NL_CGEN(config_prof, opt_prof, opt_prof, bool) CTL_RO_NL_CGEN(config_prof, opt_prof_prefix, opt_prof_prefix, const char *) CTL_RO_NL_CGEN(config_prof, opt_prof_active, opt_prof_active, bool) @@ -1536,12 +1528,9 @@ thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, } /* Set new arena/tcache associations. */ arena_migrate(tsd, oldind, newind); - if (config_tcache) { - tcache_t *tcache = tsd_tcachep_get(tsd); - if (tcache != NULL) { - tcache_arena_reassociate(tsd_tsdn(tsd), tcache, - newarena); - } + if (tcache_available(tsd)) { + tcache_arena_reassociate(tsd_tsdn(tsd), + tsd_tcachep_get(tsd), newarena); } } @@ -1565,10 +1554,6 @@ thread_tcache_enabled_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, int ret; bool oldval; - if (!config_tcache) { - return ENOENT; - } - oldval = tcache_enabled_get(tsd); if (newp != NULL) { if (newlen != sizeof(bool)) { @@ -1589,8 +1574,9 @@ thread_tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int ret; - if (!config_tcache) { - return ENOENT; + if (!tcache_available(tsd)) { + ret = EFAULT; + goto label_return; } READONLY(); @@ -1670,10 +1656,6 @@ tcache_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, int ret; unsigned tcache_ind; - if (!config_tcache) { - return ENOENT; - } - READONLY(); if (tcaches_create(tsd, &tcache_ind)) { ret = EFAULT; @@ -1692,10 +1674,6 @@ tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, int ret; unsigned tcache_ind; - if (!config_tcache) { - return ENOENT; - } - WRITEONLY(); tcache_ind = UINT_MAX; WRITE(tcache_ind, unsigned); @@ -1716,10 +1694,6 @@ tcache_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, int ret; unsigned tcache_ind; - if (!config_tcache) { - return ENOENT; - } - WRITEONLY(); tcache_ind = UINT_MAX; WRITE(tcache_ind, unsigned); @@ -2150,9 +2124,9 @@ arenas_muzzy_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, CTL_RO_NL_GEN(arenas_quantum, QUANTUM, size_t) CTL_RO_NL_GEN(arenas_page, PAGE, size_t) -CTL_RO_NL_CGEN(config_tcache, arenas_tcache_max, tcache_maxclass, size_t) +CTL_RO_NL_GEN(arenas_tcache_max, tcache_maxclass, size_t) CTL_RO_NL_GEN(arenas_nbins, NBINS, unsigned) -CTL_RO_NL_CGEN(config_tcache, arenas_nhbins, nhbins, unsigned) +CTL_RO_NL_GEN(arenas_nhbins, nhbins, unsigned) CTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[2]].reg_size, size_t) CTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t) CTL_RO_NL_GEN(arenas_bin_i_slab_size, arena_bin_info[mib[2]].slab_size, size_t) @@ -2380,7 +2354,7 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_base, CTL_RO_CGEN(config_stats, stats_arenas_i_internal, atomic_load_zu(&arenas_i(mib[2])->astats->astats.internal, ATOMIC_RELAXED), size_t) -CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_tcache_bytes, +CTL_RO_CGEN(config_stats, stats_arenas_i_tcache_bytes, atomic_load_zu(&arenas_i(mib[2])->astats->astats.tcache_bytes, ATOMIC_RELAXED), size_t) CTL_RO_CGEN(config_stats, stats_arenas_i_resident, @@ -2480,9 +2454,7 @@ stats_mutexes_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, MUTEX_PROF_RESET(arena->extents_retained.mtx); MUTEX_PROF_RESET(arena->decay_dirty.mtx); MUTEX_PROF_RESET(arena->decay_muzzy.mtx); - if (config_tcache) { - MUTEX_PROF_RESET(arena->tcache_ql_mtx); - } + MUTEX_PROF_RESET(arena->tcache_ql_mtx); MUTEX_PROF_RESET(arena->base->mtx); for (szind_t i = 0; i < NBINS; i++) { @@ -2502,9 +2474,9 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nrequests, arenas_i(mib[2])->astats->bstats[mib[4]].nrequests, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curregs, arenas_i(mib[2])->astats->bstats[mib[4]].curregs, size_t) -CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nfills, +CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nfills, arenas_i(mib[2])->astats->bstats[mib[4]].nfills, uint64_t) -CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nflushes, +CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nflushes, arenas_i(mib[2])->astats->bstats[mib[4]].nflushes, uint64_t) CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nslabs, arenas_i(mib[2])->astats->bstats[mib[4]].nslabs, uint64_t) diff --git a/src/jemalloc.c b/src/jemalloc.c index ea632c2e..e08226c9 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -682,7 +682,7 @@ arenas_tdata_cleanup(tsd_t *tsd) { static void stats_print_atexit(void) { - if (config_tcache && config_stats) { + if (config_stats) { tsdn_t *tsdn; unsigned narenas, i; @@ -1106,12 +1106,9 @@ malloc_conf_init(void) { if (config_xmalloc) { CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc", true) } - if (config_tcache) { - CONF_HANDLE_BOOL(opt_tcache, "tcache", true) - CONF_HANDLE_SSIZE_T(opt_lg_tcache_max, - "lg_tcache_max", -1, - (sizeof(size_t) << 3) - 1) - } + CONF_HANDLE_BOOL(opt_tcache, "tcache", true) + CONF_HANDLE_SSIZE_T(opt_lg_tcache_max, "lg_tcache_max", + -1, (sizeof(size_t) << 3) - 1) if (strncmp("percpu_arena", k, klen) == 0) { int i; bool match = false; @@ -1236,7 +1233,7 @@ malloc_init_hard_a0_locked() { prof_boot1(); } arena_boot(); - if (config_tcache && tcache_boot(TSDN_NULL)) { + if (tcache_boot(TSDN_NULL)) { return true; } if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS)) { diff --git a/src/stats.c b/src/stats.c index 435dfb9f..4074c940 100644 --- a/src/stats.c +++ b/src/stats.c @@ -128,20 +128,11 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, } else { char *mutex_counters = " n_lock_ops n_waiting" " n_spin_acq max_wait_ns\n"; - if (config_tcache) { - malloc_cprintf(write_cb, cbopaque, - "bins: size ind allocated nmalloc" - " ndalloc nrequests curregs" - " curslabs regs pgs util nfills" - " nflushes newslabs reslabs%s", - mutex ? mutex_counters : "\n"); - } else { - malloc_cprintf(write_cb, cbopaque, - "bins: size ind allocated nmalloc" - " ndalloc nrequests curregs" - " curslabs regs pgs util newslabs" - " reslabs%s", mutex ? mutex_counters : "\n"); - } + malloc_cprintf(write_cb, cbopaque, + "bins: size ind allocated nmalloc" + " ndalloc nrequests curregs curslabs regs" + " pgs util nfills nflushes newslabs" + " reslabs%s", mutex ? mutex_counters : "\n"); } for (j = 0, in_gap = false; j < nbins; j++) { uint64_t nslabs; @@ -173,12 +164,10 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, size_t); CTL_M2_M4_GET("stats.arenas.0.bins.0.nrequests", i, j, &nrequests, uint64_t); - if (config_tcache) { - CTL_M2_M4_GET("stats.arenas.0.bins.0.nfills", i, j, - &nfills, uint64_t); - CTL_M2_M4_GET("stats.arenas.0.bins.0.nflushes", i, j, - &nflushes, uint64_t); - } + CTL_M2_M4_GET("stats.arenas.0.bins.0.nfills", i, j, &nfills, + uint64_t); + CTL_M2_M4_GET("stats.arenas.0.bins.0.nflushes", i, j, &nflushes, + uint64_t); CTL_M2_M4_GET("stats.arenas.0.bins.0.nreslabs", i, j, &nreslabs, uint64_t); CTL_M2_M4_GET("stats.arenas.0.bins.0.curslabs", i, j, &curslabs, @@ -190,23 +179,13 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, "\t\t\t\t\t\t\"nmalloc\": %"FMTu64",\n" "\t\t\t\t\t\t\"ndalloc\": %"FMTu64",\n" "\t\t\t\t\t\t\"curregs\": %zu,\n" - "\t\t\t\t\t\t\"nrequests\": %"FMTu64",\n", - nmalloc, - ndalloc, - curregs, - nrequests); - if (config_tcache) { - malloc_cprintf(write_cb, cbopaque, - "\t\t\t\t\t\t\"nfills\": %"FMTu64",\n" - "\t\t\t\t\t\t\"nflushes\": %"FMTu64",\n", - nfills, - nflushes); - } - malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\t\t\"nrequests\": %"FMTu64",\n" + "\t\t\t\t\t\t\"nfills\": %"FMTu64",\n" + "\t\t\t\t\t\t\"nflushes\": %"FMTu64",\n" "\t\t\t\t\t\t\"nreslabs\": %"FMTu64",\n" "\t\t\t\t\t\t\"curslabs\": %zu%s\n", - nreslabs, curslabs, mutex ? "," : ""); - + nmalloc, ndalloc, curregs, nrequests, nfills, + nflushes, nreslabs, curslabs, mutex ? "," : ""); if (mutex) { uint64_t mutex_stats[num_mutex_prof_counters]; read_arena_bin_mutex_stats(i, j, mutex_stats); @@ -260,27 +239,13 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, } } - if (config_tcache) { - malloc_cprintf(write_cb, cbopaque, - "%20zu %3u %12zu %12"FMTu64 - " %12"FMTu64" %12"FMTu64" %12zu" - " %12zu %4u %3zu %-5s %12"FMTu64 - " %12"FMTu64" %12"FMTu64" %12"FMTu64, - reg_size, j, curregs * reg_size, nmalloc, - ndalloc, nrequests, curregs, curslabs, - nregs, slab_size / page, util, nfills, - nflushes, nslabs, nreslabs); - } else { - malloc_cprintf(write_cb, cbopaque, - "%20zu %3u %12zu %12"FMTu64 - " %12"FMTu64" %12"FMTu64" %12zu" - " %12zu %4u %3zu %-5s %12"FMTu64 - " %12"FMTu64, - reg_size, j, curregs * reg_size, nmalloc, - ndalloc, nrequests, curregs, curslabs, - nregs, slab_size / page, util, nslabs, - nreslabs); - } + malloc_cprintf(write_cb, cbopaque, "%20zu %3u %12zu %12" + FMTu64" %12"FMTu64" %12"FMTu64" %12zu %12zu %4u" + " %3zu %-5s %12"FMTu64" %12"FMTu64" %12"FMTu64 + " %12"FMTu64, reg_size, j, curregs * reg_size, + nmalloc, ndalloc, nrequests, curregs, curslabs, + nregs, slab_size / page, util, nfills, nflushes, + nslabs, nreslabs); if (mutex) { malloc_cprintf(write_cb, cbopaque, " %12"FMTu64" %12"FMTu64" %12"FMTu64 @@ -423,14 +388,7 @@ stats_arena_mutexes_print(void (*write_cb)(void *, const char *), malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\"mutexes\": {\n"); arena_prof_mutex_ind_t i, last_mutex; last_mutex = num_arena_prof_mutexes - 1; - if (!config_tcache) { - last_mutex--; - } for (i = 0; i < num_arena_prof_mutexes; i++) { - if (!config_tcache && - i == arena_prof_mutex_tcache_list) { - continue; - } mutex_stats_output_json(write_cb, cbopaque, arena_mutex_names[i], mutex_stats[i], "\t\t\t\t\t", (i == last_mutex)); @@ -440,10 +398,6 @@ stats_arena_mutexes_print(void (*write_cb)(void *, const char *), } else { arena_prof_mutex_ind_t i; for (i = 0; i < num_arena_prof_mutexes; i++) { - if (!config_tcache && - i == arena_prof_mutex_tcache_list) { - continue; - } mutex_stats_output(write_cb, cbopaque, arena_mutex_names[i], mutex_stats[i], i == 0); } @@ -659,16 +613,13 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, "internal: %12zu\n", internal); } - if (config_tcache) { - CTL_M2_GET("stats.arenas.0.tcache_bytes", i, &tcache_bytes, - size_t); - if (json) { - malloc_cprintf(write_cb, cbopaque, - "\t\t\t\t\"tcache\": %zu,\n", tcache_bytes); - } else { - malloc_cprintf(write_cb, cbopaque, - "tcache: %12zu\n", tcache_bytes); - } + CTL_M2_GET("stats.arenas.0.tcache_bytes", i, &tcache_bytes, size_t); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"tcache\": %zu,\n", tcache_bytes); + } else { + malloc_cprintf(write_cb, cbopaque, + "tcache: %12zu\n", tcache_bytes); } CTL_M2_GET("stats.arenas.0.resident", i, &resident, size_t); @@ -761,7 +712,6 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, CONFIG_WRITE_BOOL_JSON(prof_libgcc, ",") CONFIG_WRITE_BOOL_JSON(prof_libunwind, ",") CONFIG_WRITE_BOOL_JSON(stats, ",") - CONFIG_WRITE_BOOL_JSON(tcache, ",") CONFIG_WRITE_BOOL_JSON(tls, ",") CONFIG_WRITE_BOOL_JSON(utrace, ",") CONFIG_WRITE_BOOL_JSON(xmalloc, "") @@ -959,11 +909,9 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "\t\t\t\"nbins\": %u,\n", nbins); - if (config_tcache) { - CTL_GET("arenas.nhbins", &uv, unsigned); - malloc_cprintf(write_cb, cbopaque, - "\t\t\t\"nhbins\": %u,\n", uv); - } + CTL_GET("arenas.nhbins", &uv, unsigned); + malloc_cprintf(write_cb, cbopaque, "\t\t\t\"nhbins\": %u,\n", + uv); malloc_cprintf(write_cb, cbopaque, "\t\t\t\"bin\": [\n"); diff --git a/src/tcache.c b/src/tcache.c index 971c016b..72d1e47f 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -7,13 +7,7 @@ /******************************************************************************/ /* Data. */ -bool opt_tcache = -#ifdef JEMALLOC_TCACHE - true -#else - false -#endif - ; +bool opt_tcache = true; ssize_t opt_lg_tcache_max = LG_TCACHE_MAXCLASS_DEFAULT; tcache_bin_info_t *tcache_bin_info; @@ -93,7 +87,7 @@ tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, tcache_bin_t *tbin, szind_t binind, bool *tcache_success) { void *ret; - assert(tcache->arena); + assert(tcache->arena != NULL); arena_tcache_fill_small(tsdn, arena, tcache, tbin, binind, config_prof ? tcache->prof_accumbytes : 0); if (config_prof) { @@ -304,7 +298,7 @@ tcache_arena_associate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena) { static void tcache_arena_dissociate(tsdn_t *tsdn, tcache_t *tcache) { arena_t *arena = tcache->arena; - assert(arena); + assert(arena != NULL); if (config_stats) { /* Unlink from list of extant tcaches. */ malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx); @@ -383,10 +377,6 @@ tcache_init(tsd_t *tsd, tcache_t *tcache, void *avail_stack) { /* Initialize auto tcache (embedded in TSD). */ bool tsd_tcache_data_init(tsd_t *tsd) { - if (!config_tcache) { - return false; - } - tcache_t *tcache = &tsd->tcache; assert(tcache_small_bin_get(tcache, 0)->avail == NULL); size_t size = stack_nelms * sizeof(void *); @@ -458,9 +448,9 @@ tcache_create_explicit(tsd_t *tsd) { static void tcache_flush_cache(tsd_t *tsd, tcache_t *tcache) { - unsigned i; + assert(tcache->arena != NULL); - for (i = 0; i < NBINS; i++) { + for (unsigned i = 0; i < NBINS; i++) { tcache_bin_t *tbin = tcache_small_bin_get(tcache, i); tcache_bin_flush_small(tsd, tcache, tbin, i, 0); @@ -468,7 +458,7 @@ tcache_flush_cache(tsd_t *tsd, tcache_t *tcache) { assert(tbin->tstats.nrequests == 0); } } - for (; i < nhbins; i++) { + for (unsigned i = NBINS; i < nhbins; i++) { tcache_bin_t *tbin = tcache_large_bin_get(tcache, i); tcache_bin_flush_large(tsd, tbin, i, 0, tcache); @@ -477,20 +467,17 @@ tcache_flush_cache(tsd_t *tsd, tcache_t *tcache) { } } - arena_t *arena = tcache->arena; - if (config_prof && arena && tcache->prof_accumbytes > 0 && - arena_prof_accum(tsd_tsdn(tsd), arena, tcache->prof_accumbytes)) { + if (config_prof && tcache->prof_accumbytes > 0 && + arena_prof_accum(tsd_tsdn(tsd), tcache->arena, + tcache->prof_accumbytes)) { prof_idump(tsd_tsdn(tsd)); } } void tcache_flush(void) { - tsd_t *tsd; - - cassert(config_tcache); - - tsd = tsd_fetch(); + tsd_t *tsd = tsd_fetch(); + assert(tcache_available(tsd)); tcache_flush_cache(tsd, tsd_tcachep_get(tsd)); } @@ -514,10 +501,6 @@ tcache_destroy(tsd_t *tsd, tcache_t *tcache, bool tsd_tcache) { /* For auto tcache (embedded in TSD) only. */ void tcache_cleanup(tsd_t *tsd) { - if (!config_tcache) { - return; - } - tcache_t *tcache = tsd_tcachep_get(tsd); if (!tcache_available(tsd)) { assert(tsd_tcache_enabled_get(tsd) == false); @@ -660,10 +643,6 @@ tcaches_destroy(tsd_t *tsd, unsigned ind) { bool tcache_boot(tsdn_t *tsdn) { - cassert(config_tcache); - - unsigned i; - /* If necessary, clamp opt_lg_tcache_max. */ if (opt_lg_tcache_max < 0 || (ZU(1) << opt_lg_tcache_max) < SMALL_MAXCLASS) { @@ -685,6 +664,7 @@ tcache_boot(tsdn_t *tsdn) { return true; } stack_nelms = 0; + unsigned i; for (i = 0; i < NBINS; i++) { if ((arena_bin_info[i].nregs << 1) <= TCACHE_NSLOTS_SMALL_MIN) { tcache_bin_info[i].ncached_max = diff --git a/test/integration/thread_tcache_enabled.c b/test/integration/thread_tcache_enabled.c index a0ba56b4..0c343a6c 100644 --- a/test/integration/thread_tcache_enabled.c +++ b/test/integration/thread_tcache_enabled.c @@ -1,29 +1,11 @@ #include "test/jemalloc_test.h" -static const bool config_tcache = -#ifdef JEMALLOC_TCACHE - true -#else - false -#endif - ; - void * thd_start(void *arg) { - int err; - size_t sz; bool e0, e1; - - sz = sizeof(bool); - if ((err = mallctl("thread.tcache.enabled", (void *)&e0, &sz, NULL, - 0))) { - if (err == ENOENT) { - assert_false(config_tcache, - "ENOENT should only be returned if tcache is " - "disabled"); - } - goto label_ENOENT; - } + size_t sz = sizeof(bool); + assert_d_eq(mallctl("thread.tcache.enabled", (void *)&e0, &sz, NULL, + 0), 0, "Unexpected mallctl failure"); if (e0) { e1 = false; @@ -78,7 +60,6 @@ thd_start(void *arg) { free(malloc(1)); return NULL; -label_ENOENT: test_skip("\"thread.tcache.enabled\" mallctl not available"); return NULL; } diff --git a/test/test.sh.in b/test/test.sh.in index f0f0f979..4d0e0df6 100644 --- a/test/test.sh.in +++ b/test/test.sh.in @@ -43,7 +43,6 @@ for t in $@; do # per test shell script to ignore the @JEMALLOC_CPREFIX@ detail). $(enable_fill=@enable_fill@ \ enable_prof=@enable_prof@ \ - enable_tcache=@enable_tcache@ \ . @srcroot@${t}.sh && \ export_malloc_conf && \ ${t}@exe@ @abs_srcroot@ @abs_objroot@) diff --git a/test/unit/decay.c b/test/unit/decay.c index 471a558c..26359faf 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -174,16 +174,15 @@ TEST_BEGIN(test_decay_ticks) { assert_d_eq(mallctl("arenas.lextent.0.size", (void *)&large0, &sz, NULL, 0), 0, "Unexpected mallctl failure"); - int err; /* Set up a manually managed arena for test. */ arena_ind = do_arena_create(0, 0); /* Migrate to the new arena, and get the ticker. */ unsigned old_arena_ind; size_t sz_arena_ind = sizeof(old_arena_ind); - err = mallctl("thread.arena", (void *)&old_arena_ind, &sz_arena_ind, - (void *)&arena_ind, sizeof(arena_ind)); - assert_d_eq(err, 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, + &sz_arena_ind, (void *)&arena_ind, sizeof(arena_ind)), 0, + "Unexpected mallctl() failure"); decay_ticker = decay_ticker_get(tsd_fetch(), arena_ind); assert_ptr_not_null(decay_ticker, "Unexpected failure getting decay ticker"); @@ -310,51 +309,48 @@ TEST_BEGIN(test_decay_ticks) { * Test tcache fill/flush interactions for large and small size classes, * using an explicit tcache. */ - if (config_tcache) { - unsigned tcache_ind, i; - size_t tcache_sizes[2]; - tcache_sizes[0] = large0; - tcache_sizes[1] = 1; - - size_t tcache_max, sz_tcache_max; - sz_tcache_max = sizeof(tcache_max); - err = mallctl("arenas.tcache_max", (void *)&tcache_max, - &sz_tcache_max, NULL, 0); - assert_d_eq(err, 0, "Unexpected mallctl() failure"); - - sz = sizeof(unsigned); - assert_d_eq(mallctl("tcache.create", (void *)&tcache_ind, &sz, - NULL, 0), 0, "Unexpected mallctl failure"); - - for (i = 0; i < sizeof(tcache_sizes) / sizeof(size_t); i++) { - sz = tcache_sizes[i]; - - /* tcache fill. */ - tick0 = ticker_read(decay_ticker); - p = mallocx(sz, MALLOCX_TCACHE(tcache_ind)); - assert_ptr_not_null(p, "Unexpected mallocx() failure"); - tick1 = ticker_read(decay_ticker); + unsigned tcache_ind, i; + size_t tcache_sizes[2]; + tcache_sizes[0] = large0; + tcache_sizes[1] = 1; + + size_t tcache_max, sz_tcache_max; + sz_tcache_max = sizeof(tcache_max); + assert_d_eq(mallctl("arenas.tcache_max", (void *)&tcache_max, + &sz_tcache_max, NULL, 0), 0, "Unexpected mallctl() failure"); + + sz = sizeof(unsigned); + assert_d_eq(mallctl("tcache.create", (void *)&tcache_ind, &sz, + NULL, 0), 0, "Unexpected mallctl failure"); + + for (i = 0; i < sizeof(tcache_sizes) / sizeof(size_t); i++) { + sz = tcache_sizes[i]; + + /* tcache fill. */ + tick0 = ticker_read(decay_ticker); + p = mallocx(sz, MALLOCX_TCACHE(tcache_ind)); + assert_ptr_not_null(p, "Unexpected mallocx() failure"); + tick1 = ticker_read(decay_ticker); + assert_u32_ne(tick1, tick0, + "Expected ticker to tick during tcache fill " + "(sz=%zu)", sz); + /* tcache flush. */ + dallocx(p, MALLOCX_TCACHE(tcache_ind)); + tick0 = ticker_read(decay_ticker); + assert_d_eq(mallctl("tcache.flush", NULL, NULL, + (void *)&tcache_ind, sizeof(unsigned)), 0, + "Unexpected mallctl failure"); + tick1 = ticker_read(decay_ticker); + + /* Will only tick if it's in tcache. */ + if (sz <= tcache_max) { assert_u32_ne(tick1, tick0, - "Expected ticker to tick during tcache fill " - "(sz=%zu)", sz); - /* tcache flush. */ - dallocx(p, MALLOCX_TCACHE(tcache_ind)); - tick0 = ticker_read(decay_ticker); - assert_d_eq(mallctl("tcache.flush", NULL, NULL, - (void *)&tcache_ind, sizeof(unsigned)), 0, - "Unexpected mallctl failure"); - tick1 = ticker_read(decay_ticker); - - /* Will only tick if it's in tcache. */ - if (sz <= tcache_max) { - assert_u32_ne(tick1, tick0, - "Expected ticker to tick during tcache " - "flush (sz=%zu)", sz); - } else { - assert_u32_eq(tick1, tick0, - "Unexpected ticker tick during tcache " - "flush (sz=%zu)", sz); - } + "Expected ticker to tick during tcache " + "flush (sz=%zu)", sz); + } else { + assert_u32_eq(tick1, tick0, + "Unexpected ticker tick during tcache " + "flush (sz=%zu)", sz); } } } @@ -422,18 +418,11 @@ TEST_BEGIN(test_decay_ticker) { * the ticker triggers purging. */ - if (config_tcache) { - size_t tcache_max; - - size_t sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.tcache_max", (void *)&tcache_max, - &sz, NULL, 0), 0, "Unexpected mallctl failure"); - large = nallocx(tcache_max + 1, flags); - } else { - size_t sz = sizeof(size_t); - assert_d_eq(mallctl("arenas.lextent.0.size", &large, &sz, NULL, - 0), 0, "Unexpected mallctl failure"); - } + size_t tcache_max; + size_t sz = sizeof(size_t); + assert_d_eq(mallctl("arenas.tcache_max", (void *)&tcache_max, &sz, NULL, + 0), 0, "Unexpected mallctl failure"); + large = nallocx(tcache_max + 1, flags); do_purge(arena_ind); uint64_t dirty_npurge0 = get_arena_dirty_npurge(arena_ind); diff --git a/test/unit/decay.sh b/test/unit/decay.sh index 0df17884..a41489b0 100644 --- a/test/unit/decay.sh +++ b/test/unit/decay.sh @@ -1,6 +1,3 @@ #!/bin/sh -export MALLOC_CONF="dirty_decay_time:1,muzzy_decay_time:1" -if [ "x${enable_tcache}" = "x1" ] ; then - export MALLOC_CONF="${MALLOC_CONF},lg_tcache_max:0" -fi +export MALLOC_CONF="dirty_decay_time:1,muzzy_decay_time:1,lg_tcache_max:0" diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index b8c6a255..945d8290 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -136,7 +136,6 @@ TEST_BEGIN(test_mallctl_config) { TEST_MALLCTL_CONFIG(prof_libgcc, bool); TEST_MALLCTL_CONFIG(prof_libunwind, bool); TEST_MALLCTL_CONFIG(stats, bool); - TEST_MALLCTL_CONFIG(tcache, bool); TEST_MALLCTL_CONFIG(tls, bool); TEST_MALLCTL_CONFIG(utrace, bool); TEST_MALLCTL_CONFIG(xmalloc, bool); @@ -170,8 +169,8 @@ TEST_BEGIN(test_mallctl_opt) { TEST_MALLCTL_OPT(bool, zero, fill); TEST_MALLCTL_OPT(bool, utrace, utrace); TEST_MALLCTL_OPT(bool, xmalloc, xmalloc); - TEST_MALLCTL_OPT(bool, tcache, tcache); - TEST_MALLCTL_OPT(size_t, lg_tcache_max, tcache); + TEST_MALLCTL_OPT(bool, tcache, always); + TEST_MALLCTL_OPT(size_t, lg_tcache_max, always); TEST_MALLCTL_OPT(bool, prof, prof); TEST_MALLCTL_OPT(const char *, prof_prefix, prof); TEST_MALLCTL_OPT(bool, prof_active, prof); @@ -213,8 +212,6 @@ TEST_END TEST_BEGIN(test_tcache_none) { void *p0, *q, *p1; - test_skip_if(!config_tcache); - /* Allocate p and q. */ p0 = mallocx(42, 0); assert_ptr_not_null(p0, "Unexpected mallocx() failure"); @@ -243,8 +240,6 @@ TEST_BEGIN(test_tcache) { unsigned i; size_t sz, psz, qsz; - test_skip_if(!config_tcache); - psz = 42; qsz = nallocx(psz, 0) + 1; diff --git a/test/unit/prof_idump.sh b/test/unit/prof_idump.sh index fdb5813f..4dc599a3 100644 --- a/test/unit/prof_idump.sh +++ b/test/unit/prof_idump.sh @@ -1,12 +1,8 @@ #!/bin/sh +export MALLOC_CONF="tcache:false" if [ "x${enable_prof}" = "x1" ] ; then - export MALLOC_CONF="prof:true,prof_accum:true,prof_active:false,lg_prof_sample:0,lg_prof_interval:0" - if [ "x${enable_tcache}" = "x1" ] ; then - export MALLOC_CONF="${MALLOC_CONF},tcache:false" - fi -elif [ "x${enable_tcache}" = "x1" ] ; then - export MALLOC_CONF="tcache:false" + export MALLOC_CONF="${MALLOC_CONF},prof:true,prof_accum:true,prof_active:false,lg_prof_sample:0,lg_prof_interval:0" fi diff --git a/test/unit/stats.c b/test/unit/stats.c index 1619f5b6..f5ee1287 100644 --- a/test/unit/stats.c +++ b/test/unit/stats.c @@ -83,7 +83,7 @@ TEST_BEGIN(test_stats_arenas_summary) { dallocx(large, 0); assert_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), - config_tcache ? 0 : ENOENT, "Unexpected mallctl() result"); + opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result"); assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0, "Unexpected mallctl() failure"); @@ -150,7 +150,7 @@ TEST_BEGIN(test_stats_arenas_small) { assert_ptr_not_null(p, "Unexpected mallocx() failure"); assert_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), - config_tcache ? 0 : ENOENT, "Unexpected mallctl() result"); + opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result"); assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), 0, "Unexpected mallctl() failure"); @@ -230,6 +230,10 @@ TEST_BEGIN(test_stats_arenas_bins) { uint64_t nslabs, nreslabs; int expected = config_stats ? 0 : ENOENT; + /* Make sure allocation below isn't satisfied by tcache. */ + assert_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), + opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result"); + unsigned arena_ind, old_arena_ind; sz = sizeof(unsigned); assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), @@ -243,7 +247,7 @@ TEST_BEGIN(test_stats_arenas_bins) { assert_ptr_not_null(p, "Unexpected malloc() failure"); assert_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), - config_tcache ? 0 : ENOENT, "Unexpected mallctl() result"); + opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result"); assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)), 0, "Unexpected mallctl() failure"); @@ -266,11 +270,11 @@ TEST_BEGIN(test_stats_arenas_bins) { sz = sizeof(uint64_t); gen_mallctl_str(cmd, "nfills", arena_ind); - assert_d_eq(mallctl(cmd, (void *)&nfills, &sz, NULL, 0), - config_tcache ? expected : ENOENT, "Unexpected mallctl() result"); + assert_d_eq(mallctl(cmd, (void *)&nfills, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); gen_mallctl_str(cmd, "nflushes", arena_ind); - assert_d_eq(mallctl(cmd, (void *)&nflushes, &sz, NULL, 0), - config_tcache ? expected : ENOENT, "Unexpected mallctl() result"); + assert_d_eq(mallctl(cmd, (void *)&nflushes, &sz, NULL, 0), expected, + "Unexpected mallctl() result"); gen_mallctl_str(cmd, "nslabs", arena_ind); assert_d_eq(mallctl(cmd, (void *)&nslabs, &sz, NULL, 0), expected, @@ -292,7 +296,7 @@ TEST_BEGIN(test_stats_arenas_bins) { "nrequests should be greater than zero"); assert_zu_gt(curregs, 0, "allocated should be greater than zero"); - if (config_tcache) { + if (opt_tcache) { assert_u64_gt(nfills, 0, "At least one fill should have occurred"); assert_u64_gt(nflushes, 0, -- GitLab From ae248a216098add2d91358a49758b181bcbb4d35 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Wed, 19 Apr 2017 15:22:10 -0400 Subject: [PATCH 431/544] Use openat syscall if available Some architectures like AArch64 may not have the open syscall because it was superseded by the openat syscall, so check and use SYS_openat if SYS_open is not available. Additionally, Android headers for AArch64 define SYS_open to __NR_open, even though __NR_open is undefined. Undefine SYS_open in that case so SYS_openat is used. --- include/jemalloc/internal/jemalloc_internal_decls.h | 5 +++++ src/pages.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/include/jemalloc/internal/jemalloc_internal_decls.h b/include/jemalloc/internal/jemalloc_internal_decls.h index 21a4183d..d75de0b9 100644 --- a/include/jemalloc/internal/jemalloc_internal_decls.h +++ b/include/jemalloc/internal/jemalloc_internal_decls.h @@ -14,6 +14,11 @@ # if !defined(SYS_write) && defined(__NR_write) # define SYS_write __NR_write # endif +# if defined(SYS_open) && defined(__aarch64__) + /* Android headers may define SYS_open to __NR_open even though + * __NR_open may not exist on AArch64 (superseded by __NR_openat). */ +# undef SYS_open +# endif # include # endif # include diff --git a/src/pages.c b/src/pages.c index 46c307b8..86907aa5 100644 --- a/src/pages.c +++ b/src/pages.c @@ -351,6 +351,9 @@ os_overcommits_proc(void) { #if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_open) fd = (int)syscall(SYS_open, "/proc/sys/vm/overcommit_memory", O_RDONLY); +#elif defined(JEMALLOC_USE_SYSCALL) && defined(SYS_openat) + fd = (int)syscall(SYS_openat, + AT_FDCWD, "/proc/sys/vm/overcommit_memory", O_RDONLY); #else fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY); #endif -- GitLab From b2a8453a3fa653dc71f82ac9df64b012917f6b8c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 21 Apr 2017 10:07:01 -0700 Subject: [PATCH 432/544] Remove --disable-tls. This option is no longer useful, because TLS is correctly configured automatically on all supported platforms. This partially resolves #580. --- INSTALL | 5 ----- configure.ac | 27 ++++----------------------- doc/jemalloc.xml.in | 10 ---------- src/ctl.c | 3 --- src/stats.c | 1 - test/unit/mallctl.c | 1 - 6 files changed, 4 insertions(+), 43 deletions(-) diff --git a/INSTALL b/INSTALL index f2c0fa8b..2800df46 100644 --- a/INSTALL +++ b/INSTALL @@ -186,11 +186,6 @@ any of the following arguments (not a definitive list) to 'configure': practice, this feature usually has little impact on performance unless thread-specific caching is disabled. ---disable-tls - Disable thread-local storage (TLS), which allows for fast access to - thread-local variables via the __thread keyword. If TLS is available, - jemalloc uses it for several purposes. - --disable-cache-oblivious Disable cache-oblivious large allocation alignment for large allocation requests with no alignment constraints. If this feature is disabled, all diff --git a/configure.ac b/configure.ac index 669c1b38..4709e27c 100644 --- a/configure.ac +++ b/configure.ac @@ -1670,27 +1670,14 @@ if test "x$enable_lazy_lock" = "x1" ; then fi AC_SUBST([enable_lazy_lock]) -AC_ARG_ENABLE([tls], - [AS_HELP_STRING([--disable-tls], [Disable thread-local storage (__thread keyword)])], -if test "x$enable_tls" = "xno" ; then +dnl Automatically configure TLS. +if test "x${force_tls}" = "x1" ; then + enable_tls="1" +elif test "x${force_tls}" = "x0" ; then enable_tls="0" else enable_tls="1" fi -, -enable_tls="" -) -if test "x${enable_tls}" = "x" ; then - if test "x${force_tls}" = "x1" ; then - AC_MSG_RESULT([Forcing TLS to avoid allocator/threading bootstrap issues]) - enable_tls="1" - elif test "x${force_tls}" = "x0" ; then - AC_MSG_RESULT([Forcing no TLS to avoid allocator/threading bootstrap issues]) - enable_tls="0" - else - enable_tls="1" - fi -fi if test "x${enable_tls}" = "x1" ; then AC_MSG_CHECKING([for TLS]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM( @@ -1709,12 +1696,7 @@ else fi AC_SUBST([enable_tls]) if test "x${enable_tls}" = "x1" ; then - if test "x${force_tls}" = "x0" ; then - AC_MSG_WARN([TLS enabled despite being marked unusable on this platform]) - fi AC_DEFINE_UNQUOTED([JEMALLOC_TLS], [ ]) -elif test "x${force_tls}" = "x1" ; then - AC_MSG_WARN([TLS disabled despite being marked critical on this platform]) fi dnl ============================================================================ @@ -2170,7 +2152,6 @@ AC_MSG_RESULT([utrace : ${enable_utrace}]) AC_MSG_RESULT([xmalloc : ${enable_xmalloc}]) AC_MSG_RESULT([munmap : ${enable_munmap}]) AC_MSG_RESULT([lazy_lock : ${enable_lazy_lock}]) -AC_MSG_RESULT([tls : ${enable_tls}]) AC_MSG_RESULT([cache-oblivious : ${enable_cache_oblivious}]) AC_MSG_RESULT([cxx : ${enable_cxx}]) AC_MSG_RESULT([===============================================================================]) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 2b321a7c..7dace367 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -838,16 +838,6 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", build configuration. - - - config.tls - (bool) - r- - - was not specified during - build configuration. - - config.utrace diff --git a/src/ctl.c b/src/ctl.c index a1842956..e9143dd4 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -70,7 +70,6 @@ CTL_PROTO(config_prof) CTL_PROTO(config_prof_libgcc) CTL_PROTO(config_prof_libunwind) CTL_PROTO(config_stats) -CTL_PROTO(config_tls) CTL_PROTO(config_utrace) CTL_PROTO(config_xmalloc) CTL_PROTO(opt_abort) @@ -254,7 +253,6 @@ static const ctl_named_node_t config_node[] = { {NAME("prof_libgcc"), CTL(config_prof_libgcc)}, {NAME("prof_libunwind"), CTL(config_prof_libunwind)}, {NAME("stats"), CTL(config_stats)}, - {NAME("tls"), CTL(config_tls)}, {NAME("utrace"), CTL(config_utrace)}, {NAME("xmalloc"), CTL(config_xmalloc)} }; @@ -1450,7 +1448,6 @@ CTL_RO_CONFIG_GEN(config_prof, bool) CTL_RO_CONFIG_GEN(config_prof_libgcc, bool) CTL_RO_CONFIG_GEN(config_prof_libunwind, bool) CTL_RO_CONFIG_GEN(config_stats, bool) -CTL_RO_CONFIG_GEN(config_tls, bool) CTL_RO_CONFIG_GEN(config_utrace, bool) CTL_RO_CONFIG_GEN(config_xmalloc, bool) diff --git a/src/stats.c b/src/stats.c index 4074c940..71c9a94d 100644 --- a/src/stats.c +++ b/src/stats.c @@ -712,7 +712,6 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, CONFIG_WRITE_BOOL_JSON(prof_libgcc, ",") CONFIG_WRITE_BOOL_JSON(prof_libunwind, ",") CONFIG_WRITE_BOOL_JSON(stats, ",") - CONFIG_WRITE_BOOL_JSON(tls, ",") CONFIG_WRITE_BOOL_JSON(utrace, ",") CONFIG_WRITE_BOOL_JSON(xmalloc, "") diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 945d8290..8afd25ab 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -136,7 +136,6 @@ TEST_BEGIN(test_mallctl_config) { TEST_MALLCTL_CONFIG(prof_libgcc, bool); TEST_MALLCTL_CONFIG(prof_libunwind, bool); TEST_MALLCTL_CONFIG(stats, bool); - TEST_MALLCTL_CONFIG(tls, bool); TEST_MALLCTL_CONFIG(utrace, bool); TEST_MALLCTL_CONFIG(xmalloc, bool); -- GitLab From 3823effe126ec602c438b02eb70d4c258a2f0e3f Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 21 Apr 2017 11:00:36 -0700 Subject: [PATCH 433/544] Remove --enable-ivsalloc. Continue to use ivsalloc() when --enable-debug is specified (and add assertions to guard against 0 size), but stop providing a documented explicit semantics-changing band-aid to dodge undefined behavior in sallocx() and malloc_usable_size(). ivsalloc() remains compiled in, unlike when #211 restored --enable-ivsalloc, and if JEMALLOC_FORCE_IVSALLOC is defined during compilation, sallocx() and malloc_usable_size() will still use ivsalloc(). This partially resolves #580. --- INSTALL | 7 ------- configure.ac | 19 +------------------ .../internal/jemalloc_internal_defs.h.in | 6 ------ .../jemalloc/internal/jemalloc_preamble.h.in | 18 +++++++++++------- src/jemalloc.c | 15 +++++++++++---- 5 files changed, 23 insertions(+), 42 deletions(-) diff --git a/INSTALL b/INSTALL index 2800df46..6c53bfc0 100644 --- a/INSTALL +++ b/INSTALL @@ -104,7 +104,6 @@ any of the following arguments (not a definitive list) to 'configure': --enable-debug Enable assertions and validation code. This incurs a substantial performance hit, but is very useful during application development. - Implies --enable-ivsalloc. --enable-code-coverage Enable code coverage support, for use during jemalloc test development. @@ -123,12 +122,6 @@ any of the following arguments (not a definitive list) to 'configure': Disable statistics gathering functionality. See the "opt.stats_print" option documentation for usage details. ---enable-ivsalloc - Enable validation code for malloc_usable_size() and sallocx(), which - verifies that pointers reside within jemalloc-owned extents before - dereferencing metadata. This incurs a minor performance hit, and causes - the functions to return 0 for failed lookups. - --enable-prof Enable heap profiling and leak detection functionality. See the "opt.prof" option documentation for usage details. When enabled, there are several diff --git a/configure.ac b/configure.ac index 4709e27c..73450b4c 100644 --- a/configure.ac +++ b/configure.ac @@ -958,7 +958,7 @@ fi dnl Do not compile with debugging by default. AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug], - [Build debugging code (implies --enable-ivsalloc)])], + [Build debugging code])], [if test "x$enable_debug" = "xno" ; then enable_debug="0" else @@ -972,26 +972,9 @@ if test "x$enable_debug" = "x1" ; then fi if test "x$enable_debug" = "x1" ; then AC_DEFINE([JEMALLOC_DEBUG], [ ]) - enable_ivsalloc="1" fi AC_SUBST([enable_debug]) -dnl Do not validate pointers by default. -AC_ARG_ENABLE([ivsalloc], - [AS_HELP_STRING([--enable-ivsalloc], - [Validate pointers passed through the public API])], -[if test "x$enable_ivsalloc" = "xno" ; then - enable_ivsalloc="0" -else - enable_ivsalloc="1" -fi -], -[enable_ivsalloc="0"] -) -if test "x$enable_ivsalloc" = "x1" ; then - AC_DEFINE([JEMALLOC_IVSALLOC], [ ]) -fi - dnl Only optimize if not debugging. if test "x$enable_debug" = "x0" ; then if test "x$GCC" = "xyes" ; then diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index d3d76944..44896ae2 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -224,12 +224,6 @@ #undef JEMALLOC_INTERNAL_FFSL #undef JEMALLOC_INTERNAL_FFS -/* - * JEMALLOC_IVSALLOC enables ivsalloc(), which verifies that pointers reside - * within jemalloc-owned extents before dereferencing them. - */ -#undef JEMALLOC_IVSALLOC - /* * If defined, explicitly attempt to more uniformly distribute large allocation * pointer alignments across all cache indices. diff --git a/include/jemalloc/internal/jemalloc_preamble.h.in b/include/jemalloc/internal/jemalloc_preamble.h.in index 0e2ce312..dc21cf49 100644 --- a/include/jemalloc/internal/jemalloc_preamble.h.in +++ b/include/jemalloc/internal/jemalloc_preamble.h.in @@ -132,13 +132,6 @@ static const bool config_xmalloc = false #endif ; -static const bool config_ivsalloc = -#ifdef JEMALLOC_IVSALLOC - true -#else - false -#endif - ; static const bool config_cache_oblivious = #ifdef JEMALLOC_CACHE_OBLIVIOUS true @@ -164,5 +157,16 @@ static const bool have_percpu_arena = false #endif ; +/* + * Undocumented, and not recommended; the application should take full + * responsibility for tracking provenance. + */ +static const bool force_ivsalloc = +#ifdef JEMALLOC_FORCE_IVSALLOC + true +#else + false +#endif + ; #endif /* JEMALLOC_PREAMBLE_H */ diff --git a/src/jemalloc.c b/src/jemalloc.c index e08226c9..27a9fd7b 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -2678,12 +2678,14 @@ je_sallocx(const void *ptr, int flags) { tsdn_t *tsdn; assert(malloc_initialized() || IS_INITIALIZER); + assert(ptr != NULL); tsdn = tsdn_fetch(); witness_assert_lockless(tsdn); - if (config_ivsalloc) { + if (config_debug || force_ivsalloc) { usize = ivsalloc(tsdn, ptr); + assert(force_ivsalloc || usize != 0); } else { usize = isalloc(tsdn, ptr); } @@ -2885,10 +2887,15 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) { tsdn = tsdn_fetch(); witness_assert_lockless(tsdn); - if (config_ivsalloc) { - ret = ivsalloc(tsdn, ptr); + if (unlikely(ptr == NULL)) { + ret = 0; } else { - ret = (ptr == NULL) ? 0 : isalloc(tsdn, ptr); + if (config_debug || force_ivsalloc) { + ret = ivsalloc(tsdn, ptr); + assert(force_ivsalloc || ret != 0); + } else { + ret = isalloc(tsdn, ptr); + } } witness_assert_lockless(tsdn); -- GitLab From 425253e2cd64e23585f557bfa82789a5208d06e1 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Fri, 21 Apr 2017 13:47:49 -0700 Subject: [PATCH 434/544] Enable -Wundef, when supported. This can catch bugs in which one header defines a numeric constant, and another uses it without including the defining header. Undefined preprocessor symbols expand to '0', so that this will compile fine, silently doing the math wrong. --- configure.ac | 5 ++++- include/jemalloc/internal/jemalloc_internal_defs.h.in | 3 +++ include/jemalloc/internal/jemalloc_preamble.h.in | 1 + src/jemalloc.c | 10 +--------- src/nstime.c | 6 +++--- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index 73450b4c..0a717255 100644 --- a/configure.ac +++ b/configure.ac @@ -241,6 +241,7 @@ if test "x$GCC" = "xyes" ; then JE_CFLAGS_ADD([-Wall]) JE_CFLAGS_ADD([-Wshorten-64-to-32]) JE_CFLAGS_ADD([-Wsign-compare]) + JE_CFLAGS_ADD([-Wundef]) JE_CFLAGS_ADD([-pipe]) JE_CFLAGS_ADD([-g3]) elif test "x$je_cv_msvc" = "xyes" ; then @@ -824,7 +825,9 @@ else JEMALLOC_PREFIX="je_" fi] ) -if test "x$JEMALLOC_PREFIX" != "x" ; then +if test "x$JEMALLOC_PREFIX" = "x" ; then + AC_DEFINE([JEMALLOC_IS_MALLOC]) +else JEMALLOC_CPREFIX=`echo ${JEMALLOC_PREFIX} | tr "a-z" "A-Z"` AC_DEFINE_UNQUOTED([JEMALLOC_PREFIX], ["$JEMALLOC_PREFIX"]) AC_DEFINE_UNQUOTED([JEMALLOC_CPREFIX], ["$JEMALLOC_CPREFIX"]) diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 44896ae2..1bec2c93 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -312,4 +312,7 @@ /* config.malloc_conf options string. */ #undef JEMALLOC_CONFIG_MALLOC_CONF +/* If defined, jemalloc takes the malloc/free/etc. symbol names. */ +#undef JEMALLOC_IS_MALLOC + #endif /* JEMALLOC_INTERNAL_DEFS_H_ */ diff --git a/include/jemalloc/internal/jemalloc_preamble.h.in b/include/jemalloc/internal/jemalloc_preamble.h.in index dc21cf49..79827fc4 100644 --- a/include/jemalloc/internal/jemalloc_preamble.h.in +++ b/include/jemalloc/internal/jemalloc_preamble.h.in @@ -10,6 +10,7 @@ #define JEMALLOC_NO_DEMANGLE #ifdef JEMALLOC_JET +# undef JEMALLOC_IS_MALLOC # define JEMALLOC_N(n) jet_##n # include "jemalloc/internal/public_namespace.h" # define JEMALLOC_NO_RENAME diff --git a/src/jemalloc.c b/src/jemalloc.c index 27a9fd7b..de858e36 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -2285,15 +2285,7 @@ je_valloc(size_t size) { } #endif -/* - * is_malloc(je_malloc) is some macro magic to detect if jemalloc_defs.h has - * #define je_malloc malloc - */ -#define malloc_is_malloc 1 -#define is_malloc_(a) malloc_is_ ## a -#define is_malloc(a) is_malloc_(a) - -#if ((is_malloc(je_malloc) == 1) && defined(JEMALLOC_GLIBC_MALLOC_HOOK)) +#if defined(JEMALLOC_IS_MALLOC) && defined(JEMALLOC_GLIBC_MALLOC_HOOK) /* * glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible * to inconsistently reference libc's malloc(3)-compatible functions diff --git a/src/nstime.c b/src/nstime.c index 9f5d192d..20c00422 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -96,7 +96,7 @@ nstime_get(nstime_t *time) { nstime_init(time, ticks_100ns * 100); } -#elif JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE +#elif defined(JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE) # define NSTIME_MONOTONIC true static void nstime_get(nstime_t *time) { @@ -105,7 +105,7 @@ nstime_get(nstime_t *time) { clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); nstime_init2(time, ts.tv_sec, ts.tv_nsec); } -#elif JEMALLOC_HAVE_CLOCK_MONOTONIC +#elif defined(JEMALLOC_HAVE_CLOCK_MONOTONIC) # define NSTIME_MONOTONIC true static void nstime_get(nstime_t *time) { @@ -114,7 +114,7 @@ nstime_get(nstime_t *time) { clock_gettime(CLOCK_MONOTONIC, &ts); nstime_init2(time, ts.tv_sec, ts.tv_nsec); } -#elif JEMALLOC_HAVE_MACH_ABSOLUTE_TIME +#elif defined(JEMALLOC_HAVE_MACH_ABSOLUTE_TIME) # define NSTIME_MONOTONIC true static void nstime_get(nstime_t *time) { -- GitLab From 3aac709029f053e3329302771ad2069724f461e7 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 21 Apr 2017 14:49:17 -0700 Subject: [PATCH 435/544] Output MALLOC_CONF and debug cmd when test failure happens. --- test/test.sh.in | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/test/test.sh.in b/test/test.sh.in index 4d0e0df6..39302fff 100644 --- a/test/test.sh.in +++ b/test/test.sh.in @@ -41,15 +41,15 @@ for t in $@; do # execute the test. This allows the shell script to set MALLOC_CONF, which # is then used to set @JEMALLOC_CPREFIX@MALLOC_CONF (thus allowing the # per test shell script to ignore the @JEMALLOC_CPREFIX@ detail). - $(enable_fill=@enable_fill@ \ - enable_prof=@enable_prof@ \ - . @srcroot@${t}.sh && \ - export_malloc_conf && \ - ${t}@exe@ @abs_srcroot@ @abs_objroot@) + enable_fill=@enable_fill@ \ + enable_prof=@enable_prof@ \ + . @srcroot@${t}.sh && \ + export_malloc_conf && \ + $JEMALLOC_TEST_PREFIX ${t}@exe@ @abs_srcroot@ @abs_objroot@ else - $(export MALLOC_CONF= && \ - export_malloc_conf && - ${t}@exe@ @abs_srcroot@ @abs_objroot@) + export MALLOC_CONF= && \ + export_malloc_conf && \ + $JEMALLOC_TEST_PREFIX ${t}@exe@ @abs_srcroot@ @abs_objroot@ fi result_code=$? case ${result_code} in @@ -63,7 +63,8 @@ for t in $@; do fail_count=$((fail_count+1)) ;; *) - echo "Test harness error" 1>&2 + echo "Test harness error: ${t} w/ MALLOC_CONF=\"${MALLOC_CONF}\"" 1>&2 + echo "Use prefix to debug, e.g. JEMALLOC_TEST_PREFIX=\"gdb --args\" sh test/test.sh ${t}" 1>&2 exit 1 esac done -- GitLab From 7d86c92c61c60b771cdf146f6187c1550a089ad1 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 24 Apr 2017 09:14:31 -0700 Subject: [PATCH 436/544] Add missing 'test' to LG_SIZEOF_PTR tests. This fixes a bug/regression introduced by a01f99307719dcc8ca27cc70f0f0011beff914fa (Only disable munmap(2) by default on 64-bit Linux.). --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 0a717255..42cabad3 100644 --- a/configure.ac +++ b/configure.ac @@ -558,7 +558,7 @@ case "${host}" in AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) AC_DEFINE([JEMALLOC_C11_ATOMICS]) force_tls="0" - if "${LG_SIZEOF_PTR}" = "3"; then + if test "${LG_SIZEOF_PTR}" = "3"; then default_munmap="0" fi ;; @@ -571,7 +571,7 @@ case "${host}" in AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ]) AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) AC_DEFINE([JEMALLOC_USE_CXX_THROW], [ ]) - if "${LG_SIZEOF_PTR}" = "3"; then + if test "${LG_SIZEOF_PTR}" = "3"; then default_munmap="0" fi ;; @@ -596,7 +596,7 @@ case "${host}" in JE_APPEND_VS(LIBS, -lposix4 -lsocket -lnsl) ;; *-ibm-aix*) - if "${LG_SIZEOF_PTR}" = "3"; then + if test "${LG_SIZEOF_PTR}" = "3"; then dnl 64bit AIX LD_PRELOAD_VAR="LDR_PRELOAD64" else -- GitLab From 4d2e4bf5ebb1e37a9348fdbf51af0b63304d7c98 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Fri, 21 Apr 2017 09:37:34 -0700 Subject: [PATCH 437/544] Get rid of most of the various inline macros. --- include/jemalloc/internal/arena_inlines_a.h | 25 +-- include/jemalloc/internal/arena_inlines_b.h | 32 +--- include/jemalloc/internal/base_inlines.h | 8 +- include/jemalloc/internal/bitmap_inlines.h | 25 +-- include/jemalloc/internal/extent_inlines.h | 160 ++++++------------ include/jemalloc/internal/hash_inlines.h | 32 ++-- .../internal/jemalloc_internal_inlines_a.h | 60 ++----- .../internal/jemalloc_internal_inlines_b.h | 14 +- .../internal/jemalloc_internal_inlines_c.h | 31 ---- .../internal/jemalloc_internal_macros.h | 34 +--- include/jemalloc/internal/mutex_inlines.h | 30 +--- include/jemalloc/internal/prng_inlines.h | 18 -- include/jemalloc/internal/prof_inlines_a.h | 12 +- include/jemalloc/internal/prof_inlines_b.h | 24 --- include/jemalloc/internal/rtree_inlines.h | 74 ++------ include/jemalloc/internal/tcache_inlines.h | 23 +-- include/jemalloc/internal/ticker_inlines.h | 20 +-- include/jemalloc/internal/tsd_inlines.h | 26 +-- include/jemalloc/internal/witness_inlines.h | 30 +--- src/arena.c | 6 +- src/ckh.c | 12 +- src/ctl.c | 6 +- src/jemalloc.c | 32 ++-- src/jemalloc_cpp.cpp | 1 - src/prof.c | 12 +- test/include/test/SFMT-alti.h | 12 +- test/include/test/SFMT-sse2.h | 12 +- test/include/test/SFMT.h | 35 ++-- test/include/test/math.h | 20 +-- test/src/SFMT.c | 74 ++++---- test/stress/microbench.c | 2 +- 31 files changed, 233 insertions(+), 669 deletions(-) diff --git a/include/jemalloc/internal/arena_inlines_a.h b/include/jemalloc/internal/arena_inlines_a.h index 2bd5ce75..da587706 100644 --- a/include/jemalloc/internal/arena_inlines_a.h +++ b/include/jemalloc/internal/arena_inlines_a.h @@ -1,38 +1,27 @@ #ifndef JEMALLOC_INTERNAL_ARENA_INLINES_A_H #define JEMALLOC_INTERNAL_ARENA_INLINES_A_H -#ifndef JEMALLOC_ENABLE_INLINE -unsigned arena_ind_get(const arena_t *arena); -void arena_internal_add(arena_t *arena, size_t size); -void arena_internal_sub(arena_t *arena, size_t size); -size_t arena_internal_get(arena_t *arena); -bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes); -void percpu_arena_update(tsd_t *tsd, unsigned cpu); -#endif /* JEMALLOC_ENABLE_INLINE */ - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) - -JEMALLOC_INLINE unsigned +static inline unsigned arena_ind_get(const arena_t *arena) { return base_ind_get(arena->base); } -JEMALLOC_INLINE void +static inline void arena_internal_add(arena_t *arena, size_t size) { atomic_fetch_add_zu(&arena->stats.internal, size, ATOMIC_RELAXED); } -JEMALLOC_INLINE void +static inline void arena_internal_sub(arena_t *arena, size_t size) { atomic_fetch_sub_zu(&arena->stats.internal, size, ATOMIC_RELAXED); } -JEMALLOC_INLINE size_t +static inline size_t arena_internal_get(arena_t *arena) { return atomic_load_zu(&arena->stats.internal, ATOMIC_RELAXED); } -JEMALLOC_INLINE bool +static inline bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) { cassert(config_prof); @@ -43,7 +32,7 @@ arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes) { return prof_accum_add(tsdn, &arena->prof_accum, accumbytes); } -JEMALLOC_INLINE void +static inline void percpu_arena_update(tsd_t *tsd, unsigned cpu) { assert(have_percpu_arena); arena_t *oldarena = tsd_arena_get(tsd); @@ -65,6 +54,4 @@ percpu_arena_update(tsd_t *tsd, unsigned cpu) { } } -#endif /* (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) */ - #endif /* JEMALLOC_INTERNAL_ARENA_INLINES_A_H */ diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 4264f4b3..526103bc 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -3,30 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_types.h" -#ifndef JEMALLOC_ENABLE_INLINE -szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin); -prof_tctx_t *arena_prof_tctx_get(tsdn_t *tsdn, const void *ptr, - alloc_ctx_t *ctx); -void arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, - alloc_ctx_t *ctx, prof_tctx_t *tctx); -void arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx); -void arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks); -void arena_decay_tick(tsdn_t *tsdn, arena_t *arena); -void *arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, - bool zero, tcache_t *tcache, bool slow_path); -arena_t *arena_aalloc(tsdn_t *tsdn, const void *ptr); -size_t arena_salloc(tsdn_t *tsdn, const void *ptr); -size_t arena_vsalloc(tsdn_t *tsdn, const void *ptr); -void arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr); -void arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, - alloc_ctx_t *alloc_ctx, bool slow_path); -void arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size); -void arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - alloc_ctx_t *alloc_ctx, bool slow_path); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) -JEMALLOC_INLINE szind_t +static inline szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin) { szind_t binind = (szind_t)(bin - arena->bins); assert(binind < NBINS); @@ -71,7 +48,7 @@ arena_prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, } } -JEMALLOC_INLINE void +static inline void arena_prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx) { cassert(config_prof); assert(ptr != NULL); @@ -182,7 +159,7 @@ arena_vsalloc(tsdn_t *tsdn, const void *ptr) { return index2size(szind); } -JEMALLOC_INLINE void +static inline void arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) { assert(ptr != NULL); @@ -264,7 +241,7 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache, } } -JEMALLOC_INLINE void +static inline void arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) { assert(ptr != NULL); assert(size <= LARGE_MAXCLASS); @@ -376,5 +353,4 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, } } -#endif /* (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_)) */ #endif /* JEMALLOC_INTERNAL_ARENA_INLINES_B_H */ diff --git a/include/jemalloc/internal/base_inlines.h b/include/jemalloc/internal/base_inlines.h index aa8306ac..931560bf 100644 --- a/include/jemalloc/internal/base_inlines.h +++ b/include/jemalloc/internal/base_inlines.h @@ -1,15 +1,9 @@ #ifndef JEMALLOC_INTERNAL_BASE_INLINES_H #define JEMALLOC_INTERNAL_BASE_INLINES_H -#ifndef JEMALLOC_ENABLE_INLINE -unsigned base_ind_get(const base_t *base); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BASE_C_)) -JEMALLOC_INLINE unsigned +static inline unsigned base_ind_get(const base_t *base) { return base->ind; } -#endif #endif /* JEMALLOC_INTERNAL_BASE_INLINES_H */ diff --git a/include/jemalloc/internal/bitmap_inlines.h b/include/jemalloc/internal/bitmap_inlines.h index c2362018..84425b34 100644 --- a/include/jemalloc/internal/bitmap_inlines.h +++ b/include/jemalloc/internal/bitmap_inlines.h @@ -3,18 +3,7 @@ #include "jemalloc/internal/bit_util.h" -#ifndef JEMALLOC_ENABLE_INLINE -bool bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo); -bool bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); -void bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); -size_t bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, - size_t min_bit); -size_t bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo); -void bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BITMAP_C_)) -JEMALLOC_INLINE bool +static inline bool bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) { #ifdef BITMAP_USE_TREE size_t rgoff = binfo->levels[binfo->nlevels].group_offset - 1; @@ -33,7 +22,7 @@ bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) { #endif } -JEMALLOC_INLINE bool +static inline bool bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { size_t goff; bitmap_t g; @@ -44,7 +33,7 @@ bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { return !(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); } -JEMALLOC_INLINE void +static inline void bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { size_t goff; bitmap_t *gp; @@ -80,7 +69,7 @@ bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { } /* ffu: find first unset >= bit. */ -JEMALLOC_INLINE size_t +static inline size_t bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) { assert(min_bit < binfo->nbits); @@ -139,7 +128,7 @@ bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) { } /* sfu: set first unset. */ -JEMALLOC_INLINE size_t +static inline size_t bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) { size_t bit; bitmap_t g; @@ -169,7 +158,7 @@ bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) { return bit; } -JEMALLOC_INLINE void +static inline void bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { size_t goff; bitmap_t *gp; @@ -208,6 +197,4 @@ bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { #endif /* BITMAP_USE_TREE */ } -#endif - #endif /* JEMALLOC_INTERNAL_BITMAP_INLINES_H */ diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index fbe51e47..22d45ce1 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -3,64 +3,7 @@ #include "jemalloc/internal/ql.h" -#ifndef JEMALLOC_ENABLE_INLINE -arena_t *extent_arena_get(const extent_t *extent); -szind_t extent_szind_get_maybe_invalid(const extent_t *extent); -szind_t extent_szind_get(const extent_t *extent); -size_t extent_usize_get(const extent_t *extent); -size_t extent_sn_get(const extent_t *extent); -extent_state_t extent_state_get(const extent_t *extent); -bool extent_zeroed_get(const extent_t *extent); -bool extent_committed_get(const extent_t *extent); -bool extent_slab_get(const extent_t *extent); -unsigned extent_nfree_get(const extent_t *extent); -void *extent_base_get(const extent_t *extent); -void *extent_addr_get(const extent_t *extent); -size_t extent_size_get(const extent_t *extent); -size_t extent_esn_get(const extent_t *extent); -size_t extent_bsize_get(const extent_t *extent); -void *extent_before_get(const extent_t *extent); -void *extent_last_get(const extent_t *extent); -void *extent_past_get(const extent_t *extent); -arena_slab_data_t *extent_slab_data_get(extent_t *extent); -const arena_slab_data_t *extent_slab_data_get_const(const extent_t *extent); -prof_tctx_t *extent_prof_tctx_get(const extent_t *extent); -void extent_arena_set(extent_t *extent, arena_t *arena); -void extent_addr_set(extent_t *extent, void *addr); -void extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment); -void extent_size_set(extent_t *extent, size_t size); -void extent_esn_set(extent_t *extent, size_t esn); -void extent_bsize_set(extent_t *extent, size_t bsize); -void extent_szind_set(extent_t *extent, szind_t szind); -void extent_nfree_set(extent_t *extent, unsigned nfree); -void extent_nfree_inc(extent_t *extent); -void extent_nfree_dec(extent_t *extent); -void extent_sn_set(extent_t *extent, size_t sn); -void extent_state_set(extent_t *extent, extent_state_t state); -void extent_zeroed_set(extent_t *extent, bool zeroed); -void extent_committed_set(extent_t *extent, bool committed); -void extent_slab_set(extent_t *extent, bool slab); -void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx); -void extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, - bool slab, szind_t szind, size_t sn, extent_state_t state, bool zeroed, - bool committed); -void extent_binit(extent_t *extent, void *addr, size_t size, size_t sn); -void extent_list_init(extent_list_t *list); -extent_t *extent_list_first(const extent_list_t *list); -extent_t *extent_list_last(const extent_list_t *list); -void extent_list_append(extent_list_t *list, extent_t *extent); -void extent_list_replace(extent_list_t *list, extent_t *to_remove, - extent_t *to_insert); -void extent_list_remove(extent_list_t *list, extent_t *extent); -int extent_sn_comp(const extent_t *a, const extent_t *b); -int extent_esn_comp(const extent_t *a, const extent_t *b); -int extent_ad_comp(const extent_t *a, const extent_t *b); -int extent_snad_comp(const extent_t *a, const extent_t *b); -int extent_esnead_comp(const extent_t *a, const extent_t *b); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_)) -JEMALLOC_INLINE arena_t * +static inline arena_t * extent_arena_get(const extent_t *extent) { unsigned arena_ind = (unsigned)((extent->e_bits & EXTENT_BITS_ARENA_MASK) >> EXTENT_BITS_ARENA_SHIFT); @@ -75,7 +18,7 @@ extent_arena_get(const extent_t *extent) { return (arena_t *)atomic_load_p(&arenas[arena_ind], ATOMIC_ACQUIRE); } -JEMALLOC_INLINE szind_t +static inline szind_t extent_szind_get_maybe_invalid(const extent_t *extent) { szind_t szind = (szind_t)((extent->e_bits & EXTENT_BITS_SZIND_MASK) >> EXTENT_BITS_SZIND_SHIFT); @@ -83,120 +26,120 @@ extent_szind_get_maybe_invalid(const extent_t *extent) { return szind; } -JEMALLOC_INLINE szind_t +static inline szind_t extent_szind_get(const extent_t *extent) { szind_t szind = extent_szind_get_maybe_invalid(extent); assert(szind < NSIZES); /* Never call when "invalid". */ return szind; } -JEMALLOC_INLINE size_t +static inline size_t extent_usize_get(const extent_t *extent) { return index2size(extent_szind_get(extent)); } -JEMALLOC_INLINE size_t +static inline size_t extent_sn_get(const extent_t *extent) { return (size_t)((extent->e_bits & EXTENT_BITS_SN_MASK) >> EXTENT_BITS_SN_SHIFT); } -JEMALLOC_INLINE extent_state_t +static inline extent_state_t extent_state_get(const extent_t *extent) { return (extent_state_t)((extent->e_bits & EXTENT_BITS_STATE_MASK) >> EXTENT_BITS_STATE_SHIFT); } -JEMALLOC_INLINE bool +static inline bool extent_zeroed_get(const extent_t *extent) { return (bool)((extent->e_bits & EXTENT_BITS_ZEROED_MASK) >> EXTENT_BITS_ZEROED_SHIFT); } -JEMALLOC_INLINE bool +static inline bool extent_committed_get(const extent_t *extent) { return (bool)((extent->e_bits & EXTENT_BITS_COMMITTED_MASK) >> EXTENT_BITS_COMMITTED_SHIFT); } -JEMALLOC_INLINE bool +static inline bool extent_slab_get(const extent_t *extent) { return (bool)((extent->e_bits & EXTENT_BITS_SLAB_MASK) >> EXTENT_BITS_SLAB_SHIFT); } -JEMALLOC_INLINE unsigned +static inline unsigned extent_nfree_get(const extent_t *extent) { assert(extent_slab_get(extent)); return (unsigned)((extent->e_bits & EXTENT_BITS_NFREE_MASK) >> EXTENT_BITS_NFREE_SHIFT); } -JEMALLOC_INLINE void * +static inline void * extent_base_get(const extent_t *extent) { assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || !extent_slab_get(extent)); return PAGE_ADDR2BASE(extent->e_addr); } -JEMALLOC_INLINE void * +static inline void * extent_addr_get(const extent_t *extent) { assert(extent->e_addr == PAGE_ADDR2BASE(extent->e_addr) || !extent_slab_get(extent)); return extent->e_addr; } -JEMALLOC_INLINE size_t +static inline size_t extent_size_get(const extent_t *extent) { return (extent->e_size_esn & EXTENT_SIZE_MASK); } -JEMALLOC_INLINE size_t +static inline size_t extent_esn_get(const extent_t *extent) { return (extent->e_size_esn & EXTENT_ESN_MASK); } -JEMALLOC_INLINE size_t +static inline size_t extent_bsize_get(const extent_t *extent) { return extent->e_bsize; } -JEMALLOC_INLINE void * +static inline void * extent_before_get(const extent_t *extent) { return (void *)((uintptr_t)extent_base_get(extent) - PAGE); } -JEMALLOC_INLINE void * +static inline void * extent_last_get(const extent_t *extent) { return (void *)((uintptr_t)extent_base_get(extent) + extent_size_get(extent) - PAGE); } -JEMALLOC_INLINE void * +static inline void * extent_past_get(const extent_t *extent) { return (void *)((uintptr_t)extent_base_get(extent) + extent_size_get(extent)); } -JEMALLOC_INLINE arena_slab_data_t * +static inline arena_slab_data_t * extent_slab_data_get(extent_t *extent) { assert(extent_slab_get(extent)); return &extent->e_slab_data; } -JEMALLOC_INLINE const arena_slab_data_t * +static inline const arena_slab_data_t * extent_slab_data_get_const(const extent_t *extent) { assert(extent_slab_get(extent)); return &extent->e_slab_data; } -JEMALLOC_INLINE prof_tctx_t * +static inline prof_tctx_t * extent_prof_tctx_get(const extent_t *extent) { return (prof_tctx_t *)atomic_load_p(&extent->e_prof_tctx, ATOMIC_ACQUIRE); } -JEMALLOC_INLINE void +static inline void extent_arena_set(extent_t *extent, arena_t *arena) { unsigned arena_ind = (arena != NULL) ? arena_ind_get(arena) : ((1U << MALLOCX_ARENA_BITS) - 1); @@ -204,12 +147,12 @@ extent_arena_set(extent_t *extent, arena_t *arena) { ((uint64_t)arena_ind << EXTENT_BITS_ARENA_SHIFT); } -JEMALLOC_INLINE void +static inline void extent_addr_set(extent_t *extent, void *addr) { extent->e_addr = addr; } -JEMALLOC_INLINE void +static inline void extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment) { assert(extent_base_get(extent) == extent_addr_get(extent)); @@ -228,85 +171,85 @@ extent_addr_randomize(tsdn_t *tsdn, extent_t *extent, size_t alignment) { } } -JEMALLOC_INLINE void +static inline void extent_size_set(extent_t *extent, size_t size) { assert((size & ~EXTENT_SIZE_MASK) == 0); extent->e_size_esn = size | (extent->e_size_esn & ~EXTENT_SIZE_MASK); } -JEMALLOC_INLINE void +static inline void extent_esn_set(extent_t *extent, size_t esn) { extent->e_size_esn = (extent->e_size_esn & ~EXTENT_ESN_MASK) | (esn & EXTENT_ESN_MASK); } -JEMALLOC_INLINE void +static inline void extent_bsize_set(extent_t *extent, size_t bsize) { extent->e_bsize = bsize; } -JEMALLOC_INLINE void +static inline void extent_szind_set(extent_t *extent, szind_t szind) { assert(szind <= NSIZES); /* NSIZES means "invalid". */ extent->e_bits = (extent->e_bits & ~EXTENT_BITS_SZIND_MASK) | ((uint64_t)szind << EXTENT_BITS_SZIND_SHIFT); } -JEMALLOC_INLINE void +static inline void extent_nfree_set(extent_t *extent, unsigned nfree) { assert(extent_slab_get(extent)); extent->e_bits = (extent->e_bits & ~EXTENT_BITS_NFREE_MASK) | ((uint64_t)nfree << EXTENT_BITS_NFREE_SHIFT); } -JEMALLOC_INLINE void +static inline void extent_nfree_inc(extent_t *extent) { assert(extent_slab_get(extent)); extent->e_bits += ((uint64_t)1U << EXTENT_BITS_NFREE_SHIFT); } -JEMALLOC_INLINE void +static inline void extent_nfree_dec(extent_t *extent) { assert(extent_slab_get(extent)); extent->e_bits -= ((uint64_t)1U << EXTENT_BITS_NFREE_SHIFT); } -JEMALLOC_INLINE void +static inline void extent_sn_set(extent_t *extent, size_t sn) { extent->e_bits = (extent->e_bits & ~EXTENT_BITS_SN_MASK) | ((uint64_t)sn << EXTENT_BITS_SN_SHIFT); } -JEMALLOC_INLINE void +static inline void extent_state_set(extent_t *extent, extent_state_t state) { extent->e_bits = (extent->e_bits & ~EXTENT_BITS_STATE_MASK) | ((uint64_t)state << EXTENT_BITS_STATE_SHIFT); } -JEMALLOC_INLINE void +static inline void extent_zeroed_set(extent_t *extent, bool zeroed) { extent->e_bits = (extent->e_bits & ~EXTENT_BITS_ZEROED_MASK) | ((uint64_t)zeroed << EXTENT_BITS_ZEROED_SHIFT); } -JEMALLOC_INLINE void +static inline void extent_committed_set(extent_t *extent, bool committed) { extent->e_bits = (extent->e_bits & ~EXTENT_BITS_COMMITTED_MASK) | ((uint64_t)committed << EXTENT_BITS_COMMITTED_SHIFT); } -JEMALLOC_INLINE void +static inline void extent_slab_set(extent_t *extent, bool slab) { extent->e_bits = (extent->e_bits & ~EXTENT_BITS_SLAB_MASK) | ((uint64_t)slab << EXTENT_BITS_SLAB_SHIFT); } -JEMALLOC_INLINE void +static inline void extent_prof_tctx_set(extent_t *extent, prof_tctx_t *tctx) { atomic_store_p(&extent->e_prof_tctx, tctx, ATOMIC_RELEASE); } -JEMALLOC_INLINE void +static inline void extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, bool slab, szind_t szind, size_t sn, extent_state_t state, bool zeroed, bool committed) { @@ -327,7 +270,7 @@ extent_init(extent_t *extent, arena_t *arena, void *addr, size_t size, } } -JEMALLOC_INLINE void +static inline void extent_binit(extent_t *extent, void *addr, size_t bsize, size_t sn) { extent_arena_set(extent, NULL); extent_addr_set(extent, addr); @@ -340,39 +283,39 @@ extent_binit(extent_t *extent, void *addr, size_t bsize, size_t sn) { extent_committed_set(extent, true); } -JEMALLOC_INLINE void +static inline void extent_list_init(extent_list_t *list) { ql_new(list); } -JEMALLOC_INLINE extent_t * +static inline extent_t * extent_list_first(const extent_list_t *list) { return ql_first(list); } -JEMALLOC_INLINE extent_t * +static inline extent_t * extent_list_last(const extent_list_t *list) { return ql_last(list, ql_link); } -JEMALLOC_INLINE void +static inline void extent_list_append(extent_list_t *list, extent_t *extent) { ql_tail_insert(list, extent, ql_link); } -JEMALLOC_INLINE void +static inline void extent_list_replace(extent_list_t *list, extent_t *to_remove, extent_t *to_insert) { ql_after_insert(to_remove, to_insert, ql_link); ql_remove(list, to_remove, ql_link); } -JEMALLOC_INLINE void +static inline void extent_list_remove(extent_list_t *list, extent_t *extent) { ql_remove(list, extent, ql_link); } -JEMALLOC_INLINE int +static inline int extent_sn_comp(const extent_t *a, const extent_t *b) { size_t a_sn = extent_sn_get(a); size_t b_sn = extent_sn_get(b); @@ -380,7 +323,7 @@ extent_sn_comp(const extent_t *a, const extent_t *b) { return (a_sn > b_sn) - (a_sn < b_sn); } -JEMALLOC_INLINE int +static inline int extent_esn_comp(const extent_t *a, const extent_t *b) { size_t a_esn = extent_esn_get(a); size_t b_esn = extent_esn_get(b); @@ -388,7 +331,7 @@ extent_esn_comp(const extent_t *a, const extent_t *b) { return (a_esn > b_esn) - (a_esn < b_esn); } -JEMALLOC_INLINE int +static inline int extent_ad_comp(const extent_t *a, const extent_t *b) { uintptr_t a_addr = (uintptr_t)extent_addr_get(a); uintptr_t b_addr = (uintptr_t)extent_addr_get(b); @@ -396,7 +339,7 @@ extent_ad_comp(const extent_t *a, const extent_t *b) { return (a_addr > b_addr) - (a_addr < b_addr); } -JEMALLOC_INLINE int +static inline int extent_ead_comp(const extent_t *a, const extent_t *b) { uintptr_t a_eaddr = (uintptr_t)a; uintptr_t b_eaddr = (uintptr_t)b; @@ -404,7 +347,7 @@ extent_ead_comp(const extent_t *a, const extent_t *b) { return (a_eaddr > b_eaddr) - (a_eaddr < b_eaddr); } -JEMALLOC_INLINE int +static inline int extent_snad_comp(const extent_t *a, const extent_t *b) { int ret; @@ -417,7 +360,7 @@ extent_snad_comp(const extent_t *a, const extent_t *b) { return ret; } -JEMALLOC_INLINE int +static inline int extent_esnead_comp(const extent_t *a, const extent_t *b) { int ret; @@ -429,6 +372,5 @@ extent_esnead_comp(const extent_t *a, const extent_t *b) { ret = extent_ead_comp(a, b); return ret; } -#endif #endif /* JEMALLOC_INTERNAL_EXTENT_INLINES_H */ diff --git a/include/jemalloc/internal/hash_inlines.h b/include/jemalloc/internal/hash_inlines.h index 321c17cc..2cd7e3ee 100644 --- a/include/jemalloc/internal/hash_inlines.h +++ b/include/jemalloc/internal/hash_inlines.h @@ -9,30 +9,19 @@ * details. */ -#ifndef JEMALLOC_ENABLE_INLINE -uint32_t hash_x86_32(const void *key, int len, uint32_t seed); -void hash_x86_128(const void *key, const int len, uint32_t seed, - uint64_t r_out[2]); -void hash_x64_128(const void *key, const int len, const uint32_t seed, - uint64_t r_out[2]); -void hash(const void *key, size_t len, const uint32_t seed, - size_t r_hash[2]); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_HASH_C_)) /******************************************************************************/ /* Internal implementation. */ -JEMALLOC_INLINE uint32_t +static inline uint32_t hash_rotl_32(uint32_t x, int8_t r) { return ((x << r) | (x >> (32 - r))); } -JEMALLOC_INLINE uint64_t +static inline uint64_t hash_rotl_64(uint64_t x, int8_t r) { return ((x << r) | (x >> (64 - r))); } -JEMALLOC_INLINE uint32_t +static inline uint32_t hash_get_block_32(const uint32_t *p, int i) { /* Handle unaligned read. */ if (unlikely((uintptr_t)p & (sizeof(uint32_t)-1)) != 0) { @@ -45,7 +34,7 @@ hash_get_block_32(const uint32_t *p, int i) { return p[i]; } -JEMALLOC_INLINE uint64_t +static inline uint64_t hash_get_block_64(const uint64_t *p, int i) { /* Handle unaligned read. */ if (unlikely((uintptr_t)p & (sizeof(uint64_t)-1)) != 0) { @@ -58,7 +47,7 @@ hash_get_block_64(const uint64_t *p, int i) { return p[i]; } -JEMALLOC_INLINE uint32_t +static inline uint32_t hash_fmix_32(uint32_t h) { h ^= h >> 16; h *= 0x85ebca6b; @@ -69,7 +58,7 @@ hash_fmix_32(uint32_t h) { return h; } -JEMALLOC_INLINE uint64_t +static inline uint64_t hash_fmix_64(uint64_t k) { k ^= k >> 33; k *= KQU(0xff51afd7ed558ccd); @@ -80,7 +69,7 @@ hash_fmix_64(uint64_t k) { return k; } -JEMALLOC_INLINE uint32_t +static inline uint32_t hash_x86_32(const void *key, int len, uint32_t seed) { const uint8_t *data = (const uint8_t *) key; const int nblocks = len / 4; @@ -130,7 +119,7 @@ hash_x86_32(const void *key, int len, uint32_t seed) { return h1; } -UNUSED JEMALLOC_INLINE void +UNUSED static inline void hash_x86_128(const void *key, const int len, uint32_t seed, uint64_t r_out[2]) { const uint8_t * data = (const uint8_t *) key; @@ -231,7 +220,7 @@ hash_x86_128(const void *key, const int len, uint32_t seed, r_out[1] = (((uint64_t) h4) << 32) | h3; } -UNUSED JEMALLOC_INLINE void +UNUSED static inline void hash_x64_128(const void *key, const int len, const uint32_t seed, uint64_t r_out[2]) { const uint8_t *data = (const uint8_t *) key; @@ -310,7 +299,7 @@ hash_x64_128(const void *key, const int len, const uint32_t seed, /******************************************************************************/ /* API. */ -JEMALLOC_INLINE void +static inline void hash(const void *key, size_t len, const uint32_t seed, size_t r_hash[2]) { assert(len <= INT_MAX); /* Unfortunate implementation limitation. */ @@ -325,6 +314,5 @@ hash(const void *key, size_t len, const uint32_t seed, size_t r_hash[2]) { } #endif } -#endif #endif /* JEMALLOC_INTERNAL_HASH_INLINES_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_a.h b/include/jemalloc/internal/jemalloc_internal_inlines_a.h index c28bd7cf..9cb933c2 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_a.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_a.h @@ -5,42 +5,6 @@ #include "jemalloc/internal/bit_util.h" #include "jemalloc/internal/jemalloc_internal_types.h" -#ifndef JEMALLOC_ENABLE_INLINE -pszind_t psz2ind(size_t psz); -size_t pind2sz_compute(pszind_t pind); -size_t pind2sz_lookup(pszind_t pind); -size_t pind2sz(pszind_t pind); -size_t psz2u(size_t psz); -szind_t size2index_compute(size_t size); -szind_t size2index_lookup(size_t size); -szind_t size2index(size_t size); -size_t index2size_compute(szind_t index); -size_t index2size_lookup(szind_t index); -size_t index2size(szind_t index); -size_t s2u_compute(size_t size); -size_t s2u_lookup(size_t size); -size_t s2u(size_t size); -size_t sa2u(size_t size, size_t alignment); -arena_t *arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal); -arena_t *arena_choose(tsd_t *tsd, arena_t *arena); -arena_t *arena_ichoose(tsd_t *tsd, arena_t *arena); -bool arena_is_auto(arena_t *arena); -arena_tdata_t *arena_tdata_get(tsd_t *tsd, unsigned ind, - bool refresh_if_missing); -arena_t *arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing); -ticker_t *decay_ticker_get(tsd_t *tsd, unsigned ind); -bool tcache_available(tsd_t *tsd); -tcache_bin_t *tcache_small_bin_get(tcache_t *tcache, szind_t binind); -tcache_bin_t *tcache_large_bin_get(tcache_t *tcache, szind_t binind); -tcache_t *tcache_get(tsd_t *tsd); -malloc_cpuid_t malloc_getcpu(void); -unsigned percpu_arena_choose(void); -unsigned percpu_arena_ind_limit(void); -void pre_reentrancy(tsd_t *tsd); -void post_reentrancy(tsd_t *tsd); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) JEMALLOC_ALWAYS_INLINE pszind_t psz2ind(size_t psz) { if (unlikely(psz > LARGE_MAXCLASS)) { @@ -64,7 +28,7 @@ psz2ind(size_t psz) { } } -JEMALLOC_INLINE size_t +static inline size_t pind2sz_compute(pszind_t pind) { if (unlikely(pind == NPSIZES)) { return LARGE_MAXCLASS + PAGE; @@ -86,20 +50,20 @@ pind2sz_compute(pszind_t pind) { } } -JEMALLOC_INLINE size_t +static inline size_t pind2sz_lookup(pszind_t pind) { size_t ret = (size_t)pind2sz_tab[pind]; assert(ret == pind2sz_compute(pind)); return ret; } -JEMALLOC_INLINE size_t +static inline size_t pind2sz(pszind_t pind) { assert(pind < NPSIZES+1); return pind2sz_lookup(pind); } -JEMALLOC_INLINE size_t +static inline size_t psz2u(size_t psz) { if (unlikely(psz > LARGE_MAXCLASS)) { return LARGE_MAXCLASS + PAGE; @@ -115,7 +79,7 @@ psz2u(size_t psz) { } } -JEMALLOC_INLINE szind_t +static inline szind_t size2index_compute(size_t size) { if (unlikely(size > LARGE_MAXCLASS)) { return NSIZES; @@ -164,7 +128,7 @@ size2index(size_t size) { return size2index_compute(size); } -JEMALLOC_INLINE size_t +static inline size_t index2size_compute(szind_t index) { #if (NTBINS > 0) if (index < NTBINS) { @@ -355,7 +319,7 @@ percpu_arena_ind_limit(void) { } } -JEMALLOC_INLINE arena_tdata_t * +static inline arena_tdata_t * arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing) { arena_tdata_t *tdata; arena_tdata_t *arenas_tdata = tsd_arenas_tdata_get(tsd); @@ -380,7 +344,7 @@ arena_tdata_get(tsd_t *tsd, unsigned ind, bool refresh_if_missing) { return arena_tdata_get_hard(tsd, ind); } -JEMALLOC_INLINE arena_t * +static inline arena_t * arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing) { arena_t *ret; @@ -396,7 +360,7 @@ arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing) { return ret; } -JEMALLOC_INLINE ticker_t * +static inline ticker_t * decay_ticker_get(tsd_t *tsd, unsigned ind) { arena_tdata_t *tdata; @@ -446,7 +410,7 @@ tcache_get(tsd_t *tsd) { return tsd_tcachep_get(tsd); } -JEMALLOC_INLINE void +static inline void pre_reentrancy(tsd_t *tsd) { bool fast = tsd_fast(tsd); ++*tsd_reentrancy_levelp_get(tsd); @@ -457,7 +421,7 @@ pre_reentrancy(tsd_t *tsd) { } } -JEMALLOC_INLINE void +static inline void post_reentrancy(tsd_t *tsd) { int8_t *reentrancy_level = tsd_reentrancy_levelp_get(tsd); assert(*reentrancy_level > 0); @@ -466,6 +430,4 @@ post_reentrancy(tsd_t *tsd) { } } -#endif - #endif /* JEMALLOC_INTERNAL_INLINES_A_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_b.h b/include/jemalloc/internal/jemalloc_internal_inlines_b.h index 2fd371c3..cfc52094 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_b.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_b.h @@ -1,13 +1,8 @@ #ifndef JEMALLOC_INTERNAL_INLINES_B_H #define JEMALLOC_INTERNAL_INLINES_B_H -#ifndef JEMALLOC_ENABLE_INLINE -extent_t *iealloc(tsdn_t *tsdn, const void *ptr); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) /* Choose an arena based on a per-thread value. */ -JEMALLOC_INLINE arena_t * +static inline arena_t * arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { arena_t *ret; @@ -60,17 +55,17 @@ arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { return ret; } -JEMALLOC_INLINE arena_t * +static inline arena_t * arena_choose(tsd_t *tsd, arena_t *arena) { return arena_choose_impl(tsd, arena, false); } -JEMALLOC_INLINE arena_t * +static inline arena_t * arena_ichoose(tsd_t *tsd, arena_t *arena) { return arena_choose_impl(tsd, arena, true); } -JEMALLOC_INLINE bool +static inline bool arena_is_auto(arena_t *arena) { assert(narenas_auto > 0); return (arena_ind_get(arena) < narenas_auto); @@ -84,6 +79,5 @@ iealloc(tsdn_t *tsdn, const void *ptr) { return rtree_extent_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, true); } -#endif #endif /* JEMALLOC_INTERNAL_INLINES_B_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_c.h b/include/jemalloc/internal/jemalloc_internal_inlines_c.h index 70ac6669..415c503b 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_c.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_c.h @@ -3,36 +3,6 @@ #include "jemalloc/internal/jemalloc_internal_types.h" -#ifndef JEMALLOC_ENABLE_INLINE -arena_t *iaalloc(tsdn_t *tsdn, const void *ptr); -size_t isalloc(tsdn_t *tsdn, const void *ptr); -void *iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, - tcache_t *tcache, bool is_internal, arena_t *arena, bool slow_path); -void *ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, - bool slow_path); -void *ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, - tcache_t *tcache, bool is_internal, arena_t *arena); -void *ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, - tcache_t *tcache, arena_t *arena); -void *ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero); -size_t ivsalloc(tsdn_t *tsdn, const void *ptr); -void idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, - alloc_ctx_t *alloc_ctx, bool is_internal, bool slow_path); -void idalloc(tsd_t *tsd, void *ptr); -void isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, - alloc_ctx_t *alloc_ctx, bool slow_path); -void *iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, - size_t extra, size_t alignment, bool zero, tcache_t *tcache, - arena_t *arena); -void *iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, - size_t alignment, bool zero, tcache_t *tcache, arena_t *arena); -void *iralloc(tsd_t *tsd, void *ptr, size_t oldsize, size_t size, - size_t alignment, bool zero); -bool ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, - size_t alignment, bool zero); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_C_)) JEMALLOC_ALWAYS_INLINE arena_t * iaalloc(tsdn_t *tsdn, const void *ptr) { assert(ptr != NULL); @@ -214,6 +184,5 @@ ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, return arena_ralloc_no_move(tsdn, ptr, oldsize, size, extra, zero); } -#endif #endif /* JEMALLOC_INTERNAL_INLINES_C_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_macros.h b/include/jemalloc/internal/jemalloc_internal_macros.h index c5dd9b39..1b2802a8 100644 --- a/include/jemalloc/internal/jemalloc_internal_macros.h +++ b/include/jemalloc/internal/jemalloc_internal_macros.h @@ -1,37 +1,13 @@ #ifndef JEMALLOC_INTERNAL_MACROS_H #define JEMALLOC_INTERNAL_MACROS_H -/* - * JEMALLOC_ALWAYS_INLINE and JEMALLOC_INLINE are used within header files for - * functions that are static inline functions if inlining is enabled, and - * single-definition library-private functions if inlining is disabled. - * - * JEMALLOC_ALWAYS_INLINE_C and JEMALLOC_INLINE_C are for use in .c files, in - * which case the denoted functions are always static, regardless of whether - * inlining is enabled. - */ #if defined(JEMALLOC_DEBUG) || defined(JEMALLOC_CODE_COVERAGE) - /* Disable inlining to make debugging/profiling easier. */ -# define JEMALLOC_ALWAYS_INLINE -# define JEMALLOC_ALWAYS_INLINE_C static -# define JEMALLOC_INLINE -# define JEMALLOC_INLINE_C static +# define JEMALLOC_ALWAYS_INLINE static inline #else -# define JEMALLOC_ENABLE_INLINE -# ifdef JEMALLOC_HAVE_ATTR -# define JEMALLOC_ALWAYS_INLINE \ - static inline JEMALLOC_ATTR(unused) JEMALLOC_ATTR(always_inline) -# define JEMALLOC_ALWAYS_INLINE_C \ - static inline JEMALLOC_ATTR(always_inline) -# else -# define JEMALLOC_ALWAYS_INLINE static inline -# define JEMALLOC_ALWAYS_INLINE_C static inline -# endif -# define JEMALLOC_INLINE static inline -# define JEMALLOC_INLINE_C static inline -# ifdef _MSC_VER -# define inline _inline -# endif +# define JEMALLOC_ALWAYS_INLINE JEMALLOC_ATTR(always_inline) static inline +#endif +#ifdef _MSC_VER +# define inline _inline #endif #ifdef JEMALLOC_CC_SILENCE diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index 5ec439f7..2856d844 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -5,31 +5,19 @@ void malloc_mutex_lock_slow(malloc_mutex_t *mutex); -#ifndef JEMALLOC_ENABLE_INLINE -void malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex); -bool malloc_mutex_trylock(malloc_mutex_t *mutex); -void malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex); -void malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); -void malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex); -void malloc_mutex_prof_read(tsdn_t *tsdn, mutex_prof_data_t *data, - malloc_mutex_t *mutex); -void malloc_mutex_prof_merge(mutex_prof_data_t *sum, mutex_prof_data_t *data); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) -JEMALLOC_INLINE void +static inline void malloc_mutex_lock_final(malloc_mutex_t *mutex) { MALLOC_MUTEX_LOCK(mutex); } /* Trylock: return false if the lock is successfully acquired. */ -JEMALLOC_INLINE bool +static inline bool malloc_mutex_trylock(malloc_mutex_t *mutex) { return MALLOC_MUTEX_TRYLOCK(mutex); } /* Aggregate lock prof data. */ -JEMALLOC_INLINE void +static inline void malloc_mutex_prof_merge(mutex_prof_data_t *sum, mutex_prof_data_t *data) { nstime_add(&sum->tot_wait_time, &data->tot_wait_time); if (nstime_compare(&sum->max_wait_time, &data->max_wait_time) < 0) { @@ -52,7 +40,7 @@ malloc_mutex_prof_merge(mutex_prof_data_t *sum, mutex_prof_data_t *data) { sum->n_lock_ops += data->n_lock_ops; } -JEMALLOC_INLINE void +static inline void malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) { witness_assert_not_owner(tsdn, &mutex->witness); if (isthreaded) { @@ -72,7 +60,7 @@ malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) { witness_lock(tsdn, &mutex->witness); } -JEMALLOC_INLINE void +static inline void malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) { witness_unlock(tsdn, &mutex->witness); if (isthreaded) { @@ -80,18 +68,18 @@ malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) { } } -JEMALLOC_INLINE void +static inline void malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { witness_assert_owner(tsdn, &mutex->witness); } -JEMALLOC_INLINE void +static inline void malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { witness_assert_not_owner(tsdn, &mutex->witness); } /* Copy the prof data from mutex for processing. */ -JEMALLOC_INLINE void +static inline void malloc_mutex_prof_read(tsdn_t *tsdn, mutex_prof_data_t *data, malloc_mutex_t *mutex) { mutex_prof_data_t *source = &mutex->prof_data; @@ -108,6 +96,4 @@ malloc_mutex_prof_read(tsdn_t *tsdn, mutex_prof_data_t *data, atomic_store_u32(&data->n_waiting_thds, 0, ATOMIC_RELAXED); } -#endif - #endif /* JEMALLOC_INTERNAL_MUTEX_INLINES_H */ diff --git a/include/jemalloc/internal/prng_inlines.h b/include/jemalloc/internal/prng_inlines.h index c39c63f5..0275dfc4 100644 --- a/include/jemalloc/internal/prng_inlines.h +++ b/include/jemalloc/internal/prng_inlines.h @@ -4,23 +4,6 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/bit_util.h" -#ifndef JEMALLOC_ENABLE_INLINE -uint32_t prng_state_next_u32(uint32_t state); -uint64_t prng_state_next_u64(uint64_t state); -size_t prng_state_next_zu(size_t state); - -uint32_t prng_lg_range_u32(atomic_u32_t *state, unsigned lg_range, - bool atomic); -uint64_t prng_lg_range_u64(uint64_t *state, unsigned lg_range); -size_t prng_lg_range_zu(atomic_zu_t *state, unsigned lg_range, bool atomic); - -uint32_t prng_range_u32(atomic_u32_t *state, uint32_t range, - bool atomic); -uint64_t prng_range_u64(uint64_t *state, uint64_t range); -size_t prng_range_zu(atomic_zu_t *state, size_t range, bool atomic); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PRNG_C_)) JEMALLOC_ALWAYS_INLINE uint32_t prng_state_next_u32(uint32_t state) { return (state * PRNG_A_32) + PRNG_C_32; @@ -156,6 +139,5 @@ prng_range_zu(atomic_zu_t *state, size_t range, bool atomic) { return ret; } -#endif #endif /* JEMALLOC_INTERNAL_PRNG_INLINES_H */ diff --git a/include/jemalloc/internal/prof_inlines_a.h b/include/jemalloc/internal/prof_inlines_a.h index d0d29685..6203cbd9 100644 --- a/include/jemalloc/internal/prof_inlines_a.h +++ b/include/jemalloc/internal/prof_inlines_a.h @@ -1,14 +1,7 @@ #ifndef JEMALLOC_INTERNAL_PROF_INLINES_A_H #define JEMALLOC_INTERNAL_PROF_INLINES_A_H -#ifndef JEMALLOC_ENABLE_INLINE -bool prof_accum_add(tsdn_t *tsdn, prof_accum_t *prof_accum, - uint64_t accumbytes); -void prof_accum_cancel(tsdn_t *tsdn, prof_accum_t *prof_accum, size_t usize); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PROF_C_)) -JEMALLOC_INLINE bool +static inline bool prof_accum_add(tsdn_t *tsdn, prof_accum_t *prof_accum, uint64_t accumbytes) { cassert(config_prof); @@ -46,7 +39,7 @@ prof_accum_add(tsdn_t *tsdn, prof_accum_t *prof_accum, uint64_t accumbytes) { return overflow; } -JEMALLOC_INLINE void +static inline void prof_accum_cancel(tsdn_t *tsdn, prof_accum_t *prof_accum, size_t usize) { cassert(config_prof); @@ -73,6 +66,5 @@ prof_accum_cancel(tsdn_t *tsdn, prof_accum_t *prof_accum, size_t usize) { malloc_mutex_unlock(tsdn, &prof_accum->mtx); #endif } -#endif #endif /* JEMALLOC_INTERNAL_PROF_INLINES_A_H */ diff --git a/include/jemalloc/internal/prof_inlines_b.h b/include/jemalloc/internal/prof_inlines_b.h index 6a79c01e..eba981b9 100644 --- a/include/jemalloc/internal/prof_inlines_b.h +++ b/include/jemalloc/internal/prof_inlines_b.h @@ -1,29 +1,6 @@ #ifndef JEMALLOC_INTERNAL_PROF_INLINES_B_H #define JEMALLOC_INTERNAL_PROF_INLINES_B_H -#ifndef JEMALLOC_ENABLE_INLINE -bool prof_active_get_unlocked(void); -bool prof_gdump_get_unlocked(void); -prof_tdata_t *prof_tdata_get(tsd_t *tsd, bool create); -prof_tctx_t *prof_tctx_get(tsdn_t *tsdn, const void *ptr, - alloc_ctx_t *alloc_ctx); -void prof_tctx_set(tsdn_t *tsdn, const void *ptr, size_t usize, - alloc_ctx_t *alloc_ctx, prof_tctx_t *tctx); -void prof_tctx_reset(tsdn_t *tsdn, const void *ptr, prof_tctx_t *tctx); -bool prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update, - prof_tdata_t **tdata_out); -prof_tctx_t *prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, - bool update); -void prof_malloc(tsdn_t *tsdn, const void *ptr, size_t usize, - alloc_ctx_t *alloc_ctx, prof_tctx_t *tctx); -void prof_realloc(tsd_t *tsd, const void *ptr, size_t usize, - prof_tctx_t *tctx, bool prof_active, bool updated, const void *old_ptr, - size_t old_usize, prof_tctx_t *old_tctx); -void prof_free(tsd_t *tsd, const void *ptr, size_t usize, - alloc_ctx_t *alloc_ctx); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_PROF_C_)) JEMALLOC_ALWAYS_INLINE bool prof_active_get_unlocked(void) { /* @@ -231,6 +208,5 @@ prof_free(tsd_t *tsd, const void *ptr, size_t usize, alloc_ctx_t *alloc_ctx) { prof_free_sampled_object(tsd, usize, tctx); } } -#endif #endif /* JEMALLOC_INTERNAL_PROF_INLINES_B_H */ diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 030e5787..f4f7c2ca 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -3,59 +3,6 @@ #include "jemalloc/internal/spin.h" -#ifndef JEMALLOC_ENABLE_INLINE -uintptr_t rtree_leafkey(uintptr_t key); -uintptr_t rtree_subkey(uintptr_t key, unsigned level); -# ifdef RTREE_LEAF_COMPACT -uintptr_t rtree_leaf_elm_bits_read(tsdn_t *tsdn, rtree_t *rtree, - rtree_leaf_elm_t *elm, bool acquired, bool dependent); -extent_t *rtree_leaf_elm_bits_extent_get(uintptr_t bits); -szind_t rtree_leaf_elm_bits_szind_get(uintptr_t bits); -bool rtree_leaf_elm_bits_slab_get(uintptr_t bits); -bool rtree_leaf_elm_bits_locked_get(uintptr_t bits); -# endif -extent_t *rtree_leaf_elm_extent_read(tsdn_t *tsdn, rtree_t *rtree, - rtree_leaf_elm_t *elm, bool acquired, bool dependent); -szind_t rtree_leaf_elm_szind_read(tsdn_t *tsdn, rtree_t *rtree, - rtree_leaf_elm_t *elm, bool acquired, bool dependent); -bool rtree_leaf_elm_slab_read(tsdn_t *tsdn, rtree_t *rtree, - rtree_leaf_elm_t *elm, bool acquired, bool dependent); -void rtree_leaf_elm_extent_write(tsdn_t *tsdn, rtree_t *rtree, - rtree_leaf_elm_t *elm, bool acquired, extent_t *extent); -void rtree_leaf_elm_szind_write(tsdn_t *tsdn, rtree_t *rtree, - rtree_leaf_elm_t *elm, bool acquired, szind_t szind); -void rtree_leaf_elm_slab_write(tsdn_t *tsdn, rtree_t *rtree, - rtree_leaf_elm_t *elm, bool acquired, bool slab); -void rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, - bool acquired, extent_t *extent, szind_t szind, bool slab); -void rtree_leaf_elm_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, - rtree_leaf_elm_t *elm, szind_t szind, bool slab); -rtree_leaf_elm_t *rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, - rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); -bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, - uintptr_t key, extent_t *extent, szind_t szind, bool slab); -rtree_leaf_elm_t *rtree_read(tsdn_t *tsdn, rtree_t *rtree, - rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent); -extent_t *rtree_extent_read(tsdn_t *tsdn, rtree_t *rtree, - rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent); -szind_t rtree_szind_read(tsdn_t *tsdn, rtree_t *rtree, - rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent); -bool rtree_extent_szind_read(tsdn_t *tsdn, rtree_t *rtree, - rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, extent_t **r_extent, - szind_t *r_szind); -bool rtree_szind_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, - uintptr_t key, bool dependent, szind_t *r_szind, bool *r_slab); -rtree_leaf_elm_t *rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, - rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); -void rtree_leaf_elm_release(tsdn_t *tsdn, rtree_t *rtree, - rtree_leaf_elm_t *elm); -void rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, - rtree_ctx_t *rtree_ctx, uintptr_t key, szind_t szind, bool slab); -void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, - uintptr_t key); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_RTREE_C_)) JEMALLOC_ALWAYS_INLINE uintptr_t rtree_leafkey(uintptr_t key) { unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR+3); @@ -194,7 +141,7 @@ rtree_leaf_elm_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, #endif } -JEMALLOC_INLINE void +static inline void rtree_leaf_elm_extent_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, bool acquired, extent_t *extent) { if (config_debug && acquired) { @@ -219,7 +166,7 @@ rtree_leaf_elm_extent_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, #endif } -JEMALLOC_INLINE void +static inline void rtree_leaf_elm_szind_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, bool acquired, szind_t szind) { if (config_debug && acquired) { @@ -241,7 +188,7 @@ rtree_leaf_elm_szind_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, #endif } -JEMALLOC_INLINE void +static inline void rtree_leaf_elm_slab_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, bool acquired, bool slab) { if (config_debug && acquired) { @@ -261,7 +208,7 @@ rtree_leaf_elm_slab_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, #endif } -JEMALLOC_INLINE void +static inline void rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, bool acquired, extent_t *extent, szind_t szind, bool slab) { if (config_debug && acquired) { @@ -287,7 +234,7 @@ rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, #endif } -JEMALLOC_INLINE void +static inline void rtree_leaf_elm_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, szind_t szind, bool slab) { assert(!slab || szind < NBINS); @@ -384,7 +331,7 @@ rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, dependent, init_missing); } -JEMALLOC_INLINE bool +static inline bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, extent_t *extent, szind_t szind, bool slab) { /* Use rtree_clear() to set the extent to NULL. */ @@ -471,7 +418,7 @@ rtree_szind_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, return false; } -JEMALLOC_INLINE rtree_leaf_elm_t * +static inline rtree_leaf_elm_t * rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing) { rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, @@ -511,7 +458,7 @@ rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, return elm; } -JEMALLOC_INLINE void +static inline void rtree_leaf_elm_release(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm) { extent_t *extent = rtree_leaf_elm_extent_read(tsdn, rtree, elm, true, true); @@ -521,7 +468,7 @@ rtree_leaf_elm_release(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm) { } } -JEMALLOC_INLINE void +static inline void rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, szind_t szind, bool slab) { assert(!slab || szind < NBINS); @@ -530,7 +477,7 @@ rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, rtree_leaf_elm_szind_slab_update(tsdn, rtree, elm, szind, slab); } -JEMALLOC_INLINE void +static inline void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key) { rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true); @@ -538,6 +485,5 @@ rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, NULL); rtree_leaf_elm_write(tsdn, rtree, elm, false, NULL, NSIZES, false); } -#endif #endif /* JEMALLOC_INTERNAL_RTREE_INLINES_H */ diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index 67d35b58..8b42af66 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -4,30 +4,12 @@ #include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/util.h" -#ifndef JEMALLOC_ENABLE_INLINE -void tcache_event(tsd_t *tsd, tcache_t *tcache); -bool tcache_enabled_get(tsd_t *tsd); -tcache_t *tcache_get(tsd_t *tsd); -void tcache_enabled_set(tsd_t *tsd, bool enabled); -void *tcache_alloc_easy(tcache_bin_t *tbin, bool *tcache_success); -void *tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, - size_t size, szind_t ind, bool zero, bool slow_path); -void *tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, - size_t size, szind_t ind, bool zero, bool slow_path); -void tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, - szind_t binind, bool slow_path); -void tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, - szind_t binind, bool slow_path); -tcache_t *tcaches_get(tsd_t *tsd, unsigned ind); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TCACHE_C_)) -JEMALLOC_INLINE bool +static inline bool tcache_enabled_get(tsd_t *tsd) { return tsd_tcache_enabled_get(tsd); } -JEMALLOC_INLINE void +static inline void tcache_enabled_set(tsd_t *tsd, bool enabled) { bool was_enabled = tsd_tcache_enabled_get(tsd); @@ -261,6 +243,5 @@ tcaches_get(tsd_t *tsd, unsigned ind) { } return elm->tcache; } -#endif #endif /* JEMALLOC_INTERNAL_TCACHE_INLINES_H */ diff --git a/include/jemalloc/internal/ticker_inlines.h b/include/jemalloc/internal/ticker_inlines.h index 9102ba6d..cd5821f9 100644 --- a/include/jemalloc/internal/ticker_inlines.h +++ b/include/jemalloc/internal/ticker_inlines.h @@ -1,32 +1,23 @@ #ifndef JEMALLOC_INTERNAL_TICKER_INLINES_H #define JEMALLOC_INTERNAL_TICKER_INLINES_H -#ifndef JEMALLOC_ENABLE_INLINE -void ticker_init(ticker_t *ticker, int32_t nticks); -void ticker_copy(ticker_t *ticker, const ticker_t *other); -int32_t ticker_read(const ticker_t *ticker); -bool ticker_ticks(ticker_t *ticker, int32_t nticks); -bool ticker_tick(ticker_t *ticker); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TICKER_C_)) -JEMALLOC_INLINE void +static inline void ticker_init(ticker_t *ticker, int32_t nticks) { ticker->tick = nticks; ticker->nticks = nticks; } -JEMALLOC_INLINE void +static inline void ticker_copy(ticker_t *ticker, const ticker_t *other) { *ticker = *other; } -JEMALLOC_INLINE int32_t +static inline int32_t ticker_read(const ticker_t *ticker) { return ticker->tick; } -JEMALLOC_INLINE bool +static inline bool ticker_ticks(ticker_t *ticker, int32_t nticks) { if (unlikely(ticker->tick < nticks)) { ticker->tick = ticker->nticks; @@ -36,10 +27,9 @@ ticker_ticks(ticker_t *ticker, int32_t nticks) { return(false); } -JEMALLOC_INLINE bool +static inline bool ticker_tick(ticker_t *ticker) { return ticker_ticks(ticker, 1); } -#endif #endif /* JEMALLOC_INTERNAL_TICKER_INLINES_H */ diff --git a/include/jemalloc/internal/tsd_inlines.h b/include/jemalloc/internal/tsd_inlines.h index 93469bca..f0f77e48 100644 --- a/include/jemalloc/internal/tsd_inlines.h +++ b/include/jemalloc/internal/tsd_inlines.h @@ -1,29 +1,6 @@ #ifndef JEMALLOC_INTERNAL_TSD_INLINES_H #define JEMALLOC_INTERNAL_TSD_INLINES_H -#ifndef JEMALLOC_ENABLE_INLINE -malloc_tsd_protos(JEMALLOC_ATTR(unused), , tsd_t) - -tsd_t *tsd_fetch_impl(bool init); -tsd_t *tsd_fetch(void); -tsdn_t *tsd_tsdn(tsd_t *tsd); -bool tsd_nominal(tsd_t *tsd); -#define O(n, t, gs, i, c) \ -t *tsd_##n##p_get(tsd_t *tsd); \ -t tsd_##n##_get(tsd_t *tsd); \ -void tsd_##n##_set(tsd_t *tsd, t n); -MALLOC_TSD -#undef O -tsdn_t *tsdn_fetch(void); -bool tsdn_null(const tsdn_t *tsdn); -tsd_t *tsdn_tsd(tsdn_t *tsdn); -rtree_ctx_t *tsd_rtree_ctx(tsd_t *tsd); -rtree_ctx_t *tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback); -bool tsd_fast(tsd_t *tsd); -bool tsd_assert_fast(tsd_t *tsd); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_TSD_C_)) malloc_tsd_externs(, tsd_t) malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, , tsd_t, tsd_initializer, tsd_cleanup) @@ -97,7 +74,7 @@ tsd_tsdn(tsd_t *tsd) { return (tsdn_t *)tsd; } -JEMALLOC_INLINE bool +static inline bool tsd_nominal(tsd_t *tsd) { return (tsd->state <= tsd_state_nominal_max); } @@ -140,6 +117,5 @@ tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback) { } return tsd_rtree_ctx(tsdn_tsd(tsdn)); } -#endif #endif /* JEMALLOC_INTERNAL_TSD_INLINES_H */ diff --git a/include/jemalloc/internal/witness_inlines.h b/include/jemalloc/internal/witness_inlines.h index c5027f11..51d1af38 100644 --- a/include/jemalloc/internal/witness_inlines.h +++ b/include/jemalloc/internal/witness_inlines.h @@ -3,21 +3,8 @@ #include "jemalloc/internal/ql.h" -#ifndef JEMALLOC_ENABLE_INLINE -bool witness_owner(tsd_t *tsd, const witness_t *witness); -void witness_assert_owner(tsdn_t *tsdn, const witness_t *witness); -void witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness); -void witness_assert_depth_to_rank(tsdn_t *tsdn, witness_rank_t rank_inclusive, - unsigned depth); -void witness_assert_depth(tsdn_t *tsdn, unsigned depth); -void witness_assert_lockless(tsdn_t *tsdn); -void witness_lock(tsdn_t *tsdn, witness_t *witness); -void witness_unlock(tsdn_t *tsdn, witness_t *witness); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_MUTEX_C_)) /* Helper, not intended for direct use. */ -JEMALLOC_INLINE bool +static inline bool witness_owner(tsd_t *tsd, const witness_t *witness) { witness_list_t *witnesses; witness_t *w; @@ -34,7 +21,7 @@ witness_owner(tsd_t *tsd, const witness_t *witness) { return false; } -JEMALLOC_INLINE void +static inline void witness_assert_owner(tsdn_t *tsdn, const witness_t *witness) { tsd_t *tsd; @@ -56,7 +43,7 @@ witness_assert_owner(tsdn_t *tsdn, const witness_t *witness) { witness_owner_error(witness); } -JEMALLOC_INLINE void +static inline void witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness) { tsd_t *tsd; witness_list_t *witnesses; @@ -82,7 +69,7 @@ witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness) { } } -JEMALLOC_INLINE void +static inline void witness_assert_depth_to_rank(tsdn_t *tsdn, witness_rank_t rank_inclusive, unsigned depth) { tsd_t *tsd; @@ -115,17 +102,17 @@ witness_assert_depth_to_rank(tsdn_t *tsdn, witness_rank_t rank_inclusive, } } -JEMALLOC_INLINE void +static inline void witness_assert_depth(tsdn_t *tsdn, unsigned depth) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_MIN, depth); } -JEMALLOC_INLINE void +static inline void witness_assert_lockless(tsdn_t *tsdn) { witness_assert_depth(tsdn, 0); } -JEMALLOC_INLINE void +static inline void witness_lock(tsdn_t *tsdn, witness_t *witness) { tsd_t *tsd; witness_list_t *witnesses; @@ -168,7 +155,7 @@ witness_lock(tsdn_t *tsdn, witness_t *witness) { ql_tail_insert(witnesses, witness, link); } -JEMALLOC_INLINE void +static inline void witness_unlock(tsdn_t *tsdn, witness_t *witness) { tsd_t *tsd; witness_list_t *witnesses; @@ -197,6 +184,5 @@ witness_unlock(tsdn_t *tsdn, witness_t *witness) { witness_assert_owner(tsdn, witness); } } -#endif #endif /* JEMALLOC_INTERNAL_WITNESS_INLINES_H */ diff --git a/src/arena.c b/src/arena.c index c2eca449..40561c03 100644 --- a/src/arena.c +++ b/src/arena.c @@ -359,7 +359,7 @@ arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena, } } -JEMALLOC_INLINE_C void * +static void * arena_slab_reg_alloc(tsdn_t *tsdn, extent_t *slab, const arena_bin_info_t *bin_info) { void *ret; @@ -377,7 +377,7 @@ arena_slab_reg_alloc(tsdn_t *tsdn, extent_t *slab, } #ifndef JEMALLOC_JET -JEMALLOC_INLINE_C +static #endif size_t arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr) { @@ -414,7 +414,7 @@ arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr) { return regind; } -JEMALLOC_INLINE_C void +static void arena_slab_reg_dalloc(tsdn_t *tsdn, extent_t *slab, arena_slab_data_t *slab_data, void *ptr) { szind_t binind = extent_szind_get(slab); diff --git a/src/ckh.c b/src/ckh.c index aaa97924..6576740b 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -54,7 +54,7 @@ static void ckh_shrink(tsd_t *tsd, ckh_t *ckh); * Search bucket for key and return the cell number if found; SIZE_T_MAX * otherwise. */ -JEMALLOC_INLINE_C size_t +static size_t ckh_bucket_search(ckh_t *ckh, size_t bucket, const void *key) { ckhc_t *cell; unsigned i; @@ -72,7 +72,7 @@ ckh_bucket_search(ckh_t *ckh, size_t bucket, const void *key) { /* * Search table for key and return cell number if found; SIZE_T_MAX otherwise. */ -JEMALLOC_INLINE_C size_t +static size_t ckh_isearch(ckh_t *ckh, const void *key) { size_t hashes[2], bucket, cell; @@ -93,7 +93,7 @@ ckh_isearch(ckh_t *ckh, const void *key) { return cell; } -JEMALLOC_INLINE_C bool +static bool ckh_try_bucket_insert(ckh_t *ckh, size_t bucket, const void *key, const void *data) { ckhc_t *cell; @@ -125,7 +125,7 @@ ckh_try_bucket_insert(ckh_t *ckh, size_t bucket, const void *key, * eviction/relocation procedure until either success or detection of an * eviction/relocation bucket cycle. */ -JEMALLOC_INLINE_C bool +static bool ckh_evict_reloc_insert(ckh_t *ckh, size_t argbucket, void const **argkey, void const **argdata) { const void *key, *data, *tkey, *tdata; @@ -196,7 +196,7 @@ ckh_evict_reloc_insert(ckh_t *ckh, size_t argbucket, void const **argkey, } } -JEMALLOC_INLINE_C bool +static bool ckh_try_insert(ckh_t *ckh, void const**argkey, void const**argdata) { size_t hashes[2], bucket; const void *key = *argkey; @@ -226,7 +226,7 @@ ckh_try_insert(ckh_t *ckh, void const**argkey, void const**argdata) { * Try to rebuild the hash table from scratch by inserting all items from the * old table into the new. */ -JEMALLOC_INLINE_C bool +static bool ckh_rebuild(ckh_t *ckh, ckhc_t *aTab) { size_t count, i, nins; const void *key, *data; diff --git a/src/ctl.c b/src/ctl.c index e9143dd4..72372d55 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -21,19 +21,19 @@ static ctl_arenas_t *ctl_arenas; /******************************************************************************/ /* Helpers for named and indexed nodes. */ -JEMALLOC_INLINE_C const ctl_named_node_t * +static const ctl_named_node_t * ctl_named_node(const ctl_node_t *node) { return ((node->named) ? (const ctl_named_node_t *)node : NULL); } -JEMALLOC_INLINE_C const ctl_named_node_t * +static const ctl_named_node_t * ctl_named_children(const ctl_named_node_t *node, size_t index) { const ctl_named_node_t *children = ctl_named_node(node->children); return (children ? &children[index] : NULL); } -JEMALLOC_INLINE_C const ctl_indexed_node_t * +static const ctl_indexed_node_t * ctl_indexed_node(const ctl_node_t *node) { return (!node->named ? (const ctl_indexed_node_t *)node : NULL); } diff --git a/src/jemalloc.c b/src/jemalloc.c index de858e36..51194992 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -288,7 +288,7 @@ malloc_initialized(void) { return (malloc_init_state == malloc_init_initialized); } -JEMALLOC_ALWAYS_INLINE_C bool +JEMALLOC_ALWAYS_INLINE bool malloc_init_a0(void) { if (unlikely(malloc_init_state == malloc_init_uninitialized)) { return malloc_init_hard_a0(); @@ -296,7 +296,7 @@ malloc_init_a0(void) { return false; } -JEMALLOC_ALWAYS_INLINE_C bool +JEMALLOC_ALWAYS_INLINE bool malloc_init(void) { if (unlikely(!malloc_initialized()) && malloc_init_hard()) { return true; @@ -1490,7 +1490,7 @@ struct static_opts_s { bool slow; }; -JEMALLOC_ALWAYS_INLINE_C void +JEMALLOC_ALWAYS_INLINE void static_opts_init(static_opts_t *static_opts) { static_opts->may_overflow = false; static_opts->bump_empty_alloc = false; @@ -1523,7 +1523,7 @@ struct dynamic_opts_s { unsigned arena_ind; }; -JEMALLOC_ALWAYS_INLINE_C void +JEMALLOC_ALWAYS_INLINE void dynamic_opts_init(dynamic_opts_t *dynamic_opts) { dynamic_opts->result = NULL; dynamic_opts->num_items = 0; @@ -1535,7 +1535,7 @@ dynamic_opts_init(dynamic_opts_t *dynamic_opts) { } /* ind is ignored if dopts->alignment > 0. */ -JEMALLOC_ALWAYS_INLINE_C void * +JEMALLOC_ALWAYS_INLINE void * imalloc_no_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd, size_t size, size_t usize, szind_t ind) { tcache_t *tcache; @@ -1577,7 +1577,7 @@ imalloc_no_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd, arena, sopts->slow); } -JEMALLOC_ALWAYS_INLINE_C void * +JEMALLOC_ALWAYS_INLINE void * imalloc_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd, size_t usize, szind_t ind) { void *ret; @@ -1611,7 +1611,7 @@ imalloc_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd, * Returns true if the allocation will overflow, and false otherwise. Sets * *size to the product either way. */ -JEMALLOC_ALWAYS_INLINE_C bool +JEMALLOC_ALWAYS_INLINE bool compute_size_with_overflow(bool may_overflow, dynamic_opts_t *dopts, size_t *size) { /* @@ -1649,7 +1649,7 @@ compute_size_with_overflow(bool may_overflow, dynamic_opts_t *dopts, return true; } -JEMALLOC_ALWAYS_INLINE_C int +JEMALLOC_ALWAYS_INLINE int imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) { /* Where the actual allocated memory will live. */ void *allocation = NULL; @@ -1850,7 +1850,7 @@ label_invalid_alignment: } /* Returns the errno-style error code of the allocation. */ -JEMALLOC_ALWAYS_INLINE_C int +JEMALLOC_ALWAYS_INLINE int imalloc(static_opts_t *sopts, dynamic_opts_t *dopts) { if (unlikely(!malloc_initialized()) && unlikely(malloc_init())) { if (config_xmalloc && unlikely(opt_xmalloc)) { @@ -2011,7 +2011,7 @@ irealloc_prof_sample(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize, return p; } -JEMALLOC_ALWAYS_INLINE_C void * +JEMALLOC_ALWAYS_INLINE void * irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize, alloc_ctx_t *alloc_ctx) { void *p; @@ -2036,7 +2036,7 @@ irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize, return p; } -JEMALLOC_ALWAYS_INLINE_C void +JEMALLOC_ALWAYS_INLINE void ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { assert(slow_path || tsd_assert_fast(tsd)); if (tsd_reentrancy_level_get(tsd) == 0) { @@ -2074,7 +2074,7 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { } } -JEMALLOC_ALWAYS_INLINE_C void +JEMALLOC_ALWAYS_INLINE void isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) { assert(slow_path || tsd_assert_fast(tsd)); if (tsd_reentrancy_level_get(tsd) == 0) { @@ -2403,7 +2403,7 @@ irallocx_prof_sample(tsdn_t *tsdn, void *old_ptr, size_t old_usize, return p; } -JEMALLOC_ALWAYS_INLINE_C void * +JEMALLOC_ALWAYS_INLINE void * irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size, size_t alignment, size_t *usize, bool zero, tcache_t *tcache, arena_t *arena, alloc_ctx_t *alloc_ctx) { @@ -2528,7 +2528,7 @@ label_oom: return NULL; } -JEMALLOC_ALWAYS_INLINE_C size_t +JEMALLOC_ALWAYS_INLINE size_t ixallocx_helper(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size, size_t extra, size_t alignment, bool zero) { size_t usize; @@ -2555,7 +2555,7 @@ ixallocx_prof_sample(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size, return usize; } -JEMALLOC_ALWAYS_INLINE_C size_t +JEMALLOC_ALWAYS_INLINE size_t ixallocx_prof(tsd_t *tsd, void *ptr, size_t old_usize, size_t size, size_t extra, size_t alignment, bool zero, alloc_ctx_t *alloc_ctx) { size_t usize_max, usize; @@ -2727,7 +2727,7 @@ je_dallocx(void *ptr, int flags) { witness_assert_lockless(tsd_tsdn(tsd)); } -JEMALLOC_ALWAYS_INLINE_C size_t +JEMALLOC_ALWAYS_INLINE size_t inallocx(tsdn_t *tsdn, size_t size, int flags) { witness_assert_lockless(tsdn); diff --git a/src/jemalloc_cpp.cpp b/src/jemalloc_cpp.cpp index 71999a8a..844ab398 100644 --- a/src/jemalloc_cpp.cpp +++ b/src/jemalloc_cpp.cpp @@ -40,7 +40,6 @@ void operator delete[](void *ptr, std::size_t size) noexcept; #endif template -JEMALLOC_INLINE void * newImpl(std::size_t size) noexcept(IsNoExcept) { void *ptr = je_malloc(size); diff --git a/src/prof.c b/src/prof.c index f2b21f72..99a4c8f0 100644 --- a/src/prof.c +++ b/src/prof.c @@ -145,7 +145,7 @@ static char *prof_thread_name_alloc(tsdn_t *tsdn, const char *thread_name); /******************************************************************************/ /* Red-black trees. */ -JEMALLOC_INLINE_C int +static int prof_tctx_comp(const prof_tctx_t *a, const prof_tctx_t *b) { uint64_t a_thr_uid = a->thr_uid; uint64_t b_thr_uid = b->thr_uid; @@ -168,7 +168,7 @@ prof_tctx_comp(const prof_tctx_t *a, const prof_tctx_t *b) { rb_gen(static UNUSED, tctx_tree_, prof_tctx_tree_t, prof_tctx_t, tctx_link, prof_tctx_comp) -JEMALLOC_INLINE_C int +static int prof_gctx_comp(const prof_gctx_t *a, const prof_gctx_t *b) { unsigned a_len = a->bt.len; unsigned b_len = b->bt.len; @@ -183,7 +183,7 @@ prof_gctx_comp(const prof_gctx_t *a, const prof_gctx_t *b) { rb_gen(static UNUSED, gctx_tree_, prof_gctx_tree_t, prof_gctx_t, dump_link, prof_gctx_comp) -JEMALLOC_INLINE_C int +static int prof_tdata_comp(const prof_tdata_t *a, const prof_tdata_t *b) { int ret; uint64_t a_uid = a->thr_uid; @@ -273,7 +273,7 @@ bt_init(prof_bt_t *bt, void **vec) { bt->len = 0; } -JEMALLOC_INLINE_C void +static void prof_enter(tsd_t *tsd, prof_tdata_t *tdata) { cassert(config_prof); assert(tdata == prof_tdata_get(tsd, false)); @@ -286,7 +286,7 @@ prof_enter(tsd_t *tsd, prof_tdata_t *tdata) { malloc_mutex_lock(tsd_tsdn(tsd), &bt2gctx_mtx); } -JEMALLOC_INLINE_C void +static void prof_leave(tsd_t *tsd, prof_tdata_t *tdata) { cassert(config_prof); assert(tdata == prof_tdata_get(tsd, false)); @@ -1884,7 +1884,7 @@ prof_bt_keycomp(const void *k1, const void *k2) { return (memcmp(bt1->vec, bt2->vec, bt1->len * sizeof(void *)) == 0); } -JEMALLOC_INLINE_C uint64_t +static uint64_t prof_thr_uid_alloc(tsdn_t *tsdn) { uint64_t thr_uid; diff --git a/test/include/test/SFMT-alti.h b/test/include/test/SFMT-alti.h index 0005df6b..a1885dbf 100644 --- a/test/include/test/SFMT-alti.h +++ b/test/include/test/SFMT-alti.h @@ -33,8 +33,8 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** - * @file SFMT-alti.h +/** + * @file SFMT-alti.h * * @brief SIMD oriented Fast Mersenne Twister(SFMT) * pseudorandom number generator @@ -95,7 +95,7 @@ vector unsigned int vec_recursion(vector unsigned int a, * This function fills the internal state array with pseudorandom * integers. */ -JEMALLOC_INLINE void gen_rand_all(sfmt_t *ctx) { +static inline void gen_rand_all(sfmt_t *ctx) { int i; vector unsigned int r, r1, r2; @@ -119,10 +119,10 @@ JEMALLOC_INLINE void gen_rand_all(sfmt_t *ctx) { * This function fills the user-specified array with pseudorandom * integers. * - * @param array an 128-bit array to be filled by pseudorandom numbers. + * @param array an 128-bit array to be filled by pseudorandom numbers. * @param size number of 128-bit pesudorandom numbers to be generated. */ -JEMALLOC_INLINE void gen_rand_array(sfmt_t *ctx, w128_t *array, int size) { +static inline void gen_rand_array(sfmt_t *ctx, w128_t *array, int size) { int i, j; vector unsigned int r, r1, r2; @@ -173,7 +173,7 @@ JEMALLOC_INLINE void gen_rand_array(sfmt_t *ctx, w128_t *array, int size) { * @param array an 128-bit array to be swaped. * @param size size of 128-bit array. */ -JEMALLOC_INLINE void swap(w128_t *array, int size) { +static inline void swap(w128_t *array, int size) { int i; const vector unsigned char perm = ALTI_SWAP; diff --git a/test/include/test/SFMT-sse2.h b/test/include/test/SFMT-sse2.h index 0314a163..169ad558 100644 --- a/test/include/test/SFMT-sse2.h +++ b/test/include/test/SFMT-sse2.h @@ -33,7 +33,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** +/** * @file SFMT-sse2.h * @brief SIMD oriented Fast Mersenne Twister(SFMT) for Intel SSE2 * @@ -60,10 +60,10 @@ * @param mask 128-bit mask * @return output */ -JEMALLOC_ALWAYS_INLINE __m128i mm_recursion(__m128i *a, __m128i *b, +JEMALLOC_ALWAYS_INLINE __m128i mm_recursion(__m128i *a, __m128i *b, __m128i c, __m128i d, __m128i mask) { __m128i v, x, y, z; - + x = _mm_load_si128(a); y = _mm_srli_epi32(*b, SR1); z = _mm_srli_si128(c, SR2); @@ -81,7 +81,7 @@ JEMALLOC_ALWAYS_INLINE __m128i mm_recursion(__m128i *a, __m128i *b, * This function fills the internal state array with pseudorandom * integers. */ -JEMALLOC_INLINE void gen_rand_all(sfmt_t *ctx) { +static inline void gen_rand_all(sfmt_t *ctx) { int i; __m128i r, r1, r2, mask; mask = _mm_set_epi32(MSK4, MSK3, MSK2, MSK1); @@ -108,10 +108,10 @@ JEMALLOC_INLINE void gen_rand_all(sfmt_t *ctx) { * This function fills the user-specified array with pseudorandom * integers. * - * @param array an 128-bit array to be filled by pseudorandom numbers. + * @param array an 128-bit array to be filled by pseudorandom numbers. * @param size number of 128-bit pesudorandom numbers to be generated. */ -JEMALLOC_INLINE void gen_rand_array(sfmt_t *ctx, w128_t *array, int size) { +static inline void gen_rand_array(sfmt_t *ctx, w128_t *array, int size) { int i, j; __m128i r, r1, r2, mask; mask = _mm_set_epi32(MSK4, MSK3, MSK2, MSK1); diff --git a/test/include/test/SFMT.h b/test/include/test/SFMT.h index 4ad7484a..863fc55e 100644 --- a/test/include/test/SFMT.h +++ b/test/include/test/SFMT.h @@ -81,76 +81,62 @@ const char *get_idstring(void); int get_min_array_size32(void); int get_min_array_size64(void); -#ifndef JEMALLOC_ENABLE_INLINE -double to_real1(uint32_t v); -double genrand_real1(sfmt_t *ctx); -double to_real2(uint32_t v); -double genrand_real2(sfmt_t *ctx); -double to_real3(uint32_t v); -double genrand_real3(sfmt_t *ctx); -double to_res53(uint64_t v); -double to_res53_mix(uint32_t x, uint32_t y); -double genrand_res53(sfmt_t *ctx); -double genrand_res53_mix(sfmt_t *ctx); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(SFMT_C_)) /* These real versions are due to Isaku Wada */ /** generates a random number on [0,1]-real-interval */ -JEMALLOC_INLINE double to_real1(uint32_t v) { +static inline double to_real1(uint32_t v) { return v * (1.0/4294967295.0); /* divided by 2^32-1 */ } /** generates a random number on [0,1]-real-interval */ -JEMALLOC_INLINE double genrand_real1(sfmt_t *ctx) { +static inline double genrand_real1(sfmt_t *ctx) { return to_real1(gen_rand32(ctx)); } /** generates a random number on [0,1)-real-interval */ -JEMALLOC_INLINE double to_real2(uint32_t v) { +static inline double to_real2(uint32_t v) { return v * (1.0/4294967296.0); /* divided by 2^32 */ } /** generates a random number on [0,1)-real-interval */ -JEMALLOC_INLINE double genrand_real2(sfmt_t *ctx) { +static inline double genrand_real2(sfmt_t *ctx) { return to_real2(gen_rand32(ctx)); } /** generates a random number on (0,1)-real-interval */ -JEMALLOC_INLINE double to_real3(uint32_t v) { +static inline double to_real3(uint32_t v) { return (((double)v) + 0.5)*(1.0/4294967296.0); /* divided by 2^32 */ } /** generates a random number on (0,1)-real-interval */ -JEMALLOC_INLINE double genrand_real3(sfmt_t *ctx) { +static inline double genrand_real3(sfmt_t *ctx) { return to_real3(gen_rand32(ctx)); } /** These real versions are due to Isaku Wada */ /** generates a random number on [0,1) with 53-bit resolution*/ -JEMALLOC_INLINE double to_res53(uint64_t v) { +static inline double to_res53(uint64_t v) { return v * (1.0/18446744073709551616.0L); } /** generates a random number on [0,1) with 53-bit resolution from two * 32 bit integers */ -JEMALLOC_INLINE double to_res53_mix(uint32_t x, uint32_t y) { +static inline double to_res53_mix(uint32_t x, uint32_t y) { return to_res53(x | ((uint64_t)y << 32)); } /** generates a random number on [0,1) with 53-bit resolution */ -JEMALLOC_INLINE double genrand_res53(sfmt_t *ctx) { +static inline double genrand_res53(sfmt_t *ctx) { return to_res53(gen_rand64(ctx)); } /** generates a random number on [0,1) with 53-bit resolution using 32bit integer. */ -JEMALLOC_INLINE double genrand_res53_mix(sfmt_t *ctx) { +static inline double genrand_res53_mix(sfmt_t *ctx) { uint32_t x, y; x = gen_rand32(ctx); @@ -158,4 +144,3 @@ JEMALLOC_INLINE double genrand_res53_mix(sfmt_t *ctx) { return to_res53_mix(x, y); } #endif -#endif diff --git a/test/include/test/math.h b/test/include/test/math.h index 94173bad..efba086d 100644 --- a/test/include/test/math.h +++ b/test/include/test/math.h @@ -1,12 +1,3 @@ -#ifndef JEMALLOC_ENABLE_INLINE -double ln_gamma(double x); -double i_gamma(double x, double p, double ln_gamma_p); -double pt_norm(double p); -double pt_chi2(double p, double df, double ln_gamma_df_2); -double pt_gamma(double p, double shape, double scale, double ln_gamma_shape); -#endif - -#if (defined(JEMALLOC_ENABLE_INLINE) || defined(MATH_C_)) /* * Compute the natural log of Gamma(x), accurate to 10 decimal places. * @@ -15,7 +6,7 @@ double pt_gamma(double p, double shape, double scale, double ln_gamma_shape); * Pike, M.C., I.D. Hill (1966) Algorithm 291: Logarithm of Gamma function * [S14]. Communications of the ACM 9(9):684. */ -JEMALLOC_INLINE double +static inline double ln_gamma(double x) { double f, z; @@ -50,7 +41,7 @@ ln_gamma(double x) { * Bhattacharjee, G.P. (1970) Algorithm AS 32: The incomplete Gamma integral. * Applied Statistics 19:285-287. */ -JEMALLOC_INLINE double +static inline double i_gamma(double x, double p, double ln_gamma_p) { double acu, factor, oflo, gin, term, rn, a, b, an, dif; double pn[6]; @@ -134,7 +125,7 @@ i_gamma(double x, double p, double ln_gamma_p) { * Wichura, M.J. (1988) Algorithm AS 241: The percentage points of the normal * distribution. Applied Statistics 37(3):477-484. */ -JEMALLOC_INLINE double +static inline double pt_norm(double p) { double q, r, ret; @@ -222,7 +213,7 @@ pt_norm(double p) { * Shea, B.L. (1991) Algorithm AS R85: A remark on AS 91: The percentage * points of the Chi^2 distribution. Applied Statistics 40(1):233-235. */ -JEMALLOC_INLINE double +static inline double pt_chi2(double p, double df, double ln_gamma_df_2) { double e, aa, xx, c, ch, a, q, p1, p2, t, x, b, s1, s2, s3, s4, s5, s6; unsigned i; @@ -309,8 +300,7 @@ pt_chi2(double p, double df, double ln_gamma_df_2) { * compute the upper limit on the definite integral from [0..z] that satisfies * p. */ -JEMALLOC_INLINE double +static inline double pt_gamma(double p, double shape, double scale, double ln_gamma_shape) { return pt_chi2(p, shape * 2.0, ln_gamma_shape) * 0.5 * scale; } -#endif diff --git a/test/src/SFMT.c b/test/src/SFMT.c index 4dc32599..c05e2183 100644 --- a/test/src/SFMT.c +++ b/test/src/SFMT.c @@ -33,7 +33,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/** +/** * @file SFMT.c * @brief SIMD oriented Fast Mersenne Twister(SFMT) * @@ -108,7 +108,7 @@ struct sfmt_s { /*-------------------------------------- FILE GLOBAL VARIABLES - internal state, index counter and flag + internal state, index counter and flag --------------------------------------*/ /** a parity check vector which certificate the period of 2^{MEXP} */ @@ -117,18 +117,18 @@ static uint32_t parity[4] = {PARITY1, PARITY2, PARITY3, PARITY4}; /*---------------- STATIC FUNCTIONS ----------------*/ -JEMALLOC_INLINE_C int idxof(int i); +static inline int idxof(int i); #if (!defined(HAVE_ALTIVEC)) && (!defined(HAVE_SSE2)) -JEMALLOC_INLINE_C void rshift128(w128_t *out, w128_t const *in, int shift); -JEMALLOC_INLINE_C void lshift128(w128_t *out, w128_t const *in, int shift); +static inline void rshift128(w128_t *out, w128_t const *in, int shift); +static inline void lshift128(w128_t *out, w128_t const *in, int shift); #endif -JEMALLOC_INLINE_C void gen_rand_all(sfmt_t *ctx); -JEMALLOC_INLINE_C void gen_rand_array(sfmt_t *ctx, w128_t *array, int size); -JEMALLOC_INLINE_C uint32_t func1(uint32_t x); -JEMALLOC_INLINE_C uint32_t func2(uint32_t x); +static inline void gen_rand_all(sfmt_t *ctx); +static inline void gen_rand_array(sfmt_t *ctx, w128_t *array, int size); +static inline uint32_t func1(uint32_t x); +static inline uint32_t func2(uint32_t x); static void period_certification(sfmt_t *ctx); #if defined(BIG_ENDIAN64) && !defined(ONLY64) -JEMALLOC_INLINE_C void swap(w128_t *array, int size); +static inline void swap(w128_t *array, int size); #endif #if defined(HAVE_ALTIVEC) @@ -138,15 +138,15 @@ JEMALLOC_INLINE_C void swap(w128_t *array, int size); #endif /** - * This function simulate a 64-bit index of LITTLE ENDIAN + * This function simulate a 64-bit index of LITTLE ENDIAN * in BIG ENDIAN machine. */ #ifdef ONLY64 -JEMALLOC_INLINE_C int idxof(int i) { +static inline int idxof(int i) { return i ^ 1; } #else -JEMALLOC_INLINE_C int idxof(int i) { +static inline int idxof(int i) { return i; } #endif @@ -160,7 +160,7 @@ JEMALLOC_INLINE_C int idxof(int i) { */ #if (!defined(HAVE_ALTIVEC)) && (!defined(HAVE_SSE2)) #ifdef ONLY64 -JEMALLOC_INLINE_C void rshift128(w128_t *out, w128_t const *in, int shift) { +static inline void rshift128(w128_t *out, w128_t const *in, int shift) { uint64_t th, tl, oh, ol; th = ((uint64_t)in->u[2] << 32) | ((uint64_t)in->u[3]); @@ -175,7 +175,7 @@ JEMALLOC_INLINE_C void rshift128(w128_t *out, w128_t const *in, int shift) { out->u[3] = (uint32_t)oh; } #else -JEMALLOC_INLINE_C void rshift128(w128_t *out, w128_t const *in, int shift) { +static inline void rshift128(w128_t *out, w128_t const *in, int shift) { uint64_t th, tl, oh, ol; th = ((uint64_t)in->u[3] << 32) | ((uint64_t)in->u[2]); @@ -199,7 +199,7 @@ JEMALLOC_INLINE_C void rshift128(w128_t *out, w128_t const *in, int shift) { * @param shift the shift value */ #ifdef ONLY64 -JEMALLOC_INLINE_C void lshift128(w128_t *out, w128_t const *in, int shift) { +static inline void lshift128(w128_t *out, w128_t const *in, int shift) { uint64_t th, tl, oh, ol; th = ((uint64_t)in->u[2] << 32) | ((uint64_t)in->u[3]); @@ -214,7 +214,7 @@ JEMALLOC_INLINE_C void lshift128(w128_t *out, w128_t const *in, int shift) { out->u[3] = (uint32_t)oh; } #else -JEMALLOC_INLINE_C void lshift128(w128_t *out, w128_t const *in, int shift) { +static inline void lshift128(w128_t *out, w128_t const *in, int shift) { uint64_t th, tl, oh, ol; th = ((uint64_t)in->u[3] << 32) | ((uint64_t)in->u[2]); @@ -241,37 +241,37 @@ JEMALLOC_INLINE_C void lshift128(w128_t *out, w128_t const *in, int shift) { */ #if (!defined(HAVE_ALTIVEC)) && (!defined(HAVE_SSE2)) #ifdef ONLY64 -JEMALLOC_INLINE_C void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c, +static inline void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c, w128_t *d) { w128_t x; w128_t y; lshift128(&x, a, SL2); rshift128(&y, c, SR2); - r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SR1) & MSK2) ^ y.u[0] + r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SR1) & MSK2) ^ y.u[0] ^ (d->u[0] << SL1); - r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SR1) & MSK1) ^ y.u[1] + r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SR1) & MSK1) ^ y.u[1] ^ (d->u[1] << SL1); - r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SR1) & MSK4) ^ y.u[2] + r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SR1) & MSK4) ^ y.u[2] ^ (d->u[2] << SL1); - r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SR1) & MSK3) ^ y.u[3] + r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SR1) & MSK3) ^ y.u[3] ^ (d->u[3] << SL1); } #else -JEMALLOC_INLINE_C void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c, +static inline void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c, w128_t *d) { w128_t x; w128_t y; lshift128(&x, a, SL2); rshift128(&y, c, SR2); - r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SR1) & MSK1) ^ y.u[0] + r->u[0] = a->u[0] ^ x.u[0] ^ ((b->u[0] >> SR1) & MSK1) ^ y.u[0] ^ (d->u[0] << SL1); - r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SR1) & MSK2) ^ y.u[1] + r->u[1] = a->u[1] ^ x.u[1] ^ ((b->u[1] >> SR1) & MSK2) ^ y.u[1] ^ (d->u[1] << SL1); - r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SR1) & MSK3) ^ y.u[2] + r->u[2] = a->u[2] ^ x.u[2] ^ ((b->u[2] >> SR1) & MSK3) ^ y.u[2] ^ (d->u[2] << SL1); - r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SR1) & MSK4) ^ y.u[3] + r->u[3] = a->u[3] ^ x.u[3] ^ ((b->u[3] >> SR1) & MSK4) ^ y.u[3] ^ (d->u[3] << SL1); } #endif @@ -282,7 +282,7 @@ JEMALLOC_INLINE_C void do_recursion(w128_t *r, w128_t *a, w128_t *b, w128_t *c, * This function fills the internal state array with pseudorandom * integers. */ -JEMALLOC_INLINE_C void gen_rand_all(sfmt_t *ctx) { +static inline void gen_rand_all(sfmt_t *ctx) { int i; w128_t *r1, *r2; @@ -306,10 +306,10 @@ JEMALLOC_INLINE_C void gen_rand_all(sfmt_t *ctx) { * This function fills the user-specified array with pseudorandom * integers. * - * @param array an 128-bit array to be filled by pseudorandom numbers. + * @param array an 128-bit array to be filled by pseudorandom numbers. * @param size number of 128-bit pseudorandom numbers to be generated. */ -JEMALLOC_INLINE_C void gen_rand_array(sfmt_t *ctx, w128_t *array, int size) { +static inline void gen_rand_array(sfmt_t *ctx, w128_t *array, int size) { int i, j; w128_t *r1, *r2; @@ -343,7 +343,7 @@ JEMALLOC_INLINE_C void gen_rand_array(sfmt_t *ctx, w128_t *array, int size) { #endif #if defined(BIG_ENDIAN64) && !defined(ONLY64) && !defined(HAVE_ALTIVEC) -JEMALLOC_INLINE_C void swap(w128_t *array, int size) { +static inline void swap(w128_t *array, int size) { int i; uint32_t x, y; @@ -476,7 +476,7 @@ uint32_t gen_rand32_range(sfmt_t *ctx, uint32_t limit) { * This function generates and returns 64-bit pseudorandom number. * init_gen_rand or init_by_array must be called before this function. * The function gen_rand64 should not be called after gen_rand32, - * unless an initialization is again executed. + * unless an initialization is again executed. * @return 64-bit pseudorandom number */ uint64_t gen_rand64(sfmt_t *ctx) { @@ -618,7 +618,7 @@ sfmt_t *init_gen_rand(uint32_t seed) { psfmt32[idxof(0)] = seed; for (i = 1; i < N32; i++) { - psfmt32[idxof(i)] = 1812433253UL * (psfmt32[idxof(i - 1)] + psfmt32[idxof(i)] = 1812433253UL * (psfmt32[idxof(i - 1)] ^ (psfmt32[idxof(i - 1)] >> 30)) + i; } @@ -668,7 +668,7 @@ sfmt_t *init_by_array(uint32_t *init_key, int key_length) { } else { count = N32; } - r = func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid)] + r = func1(psfmt32[idxof(0)] ^ psfmt32[idxof(mid)] ^ psfmt32[idxof(N32 - 1)]); psfmt32[idxof(mid)] += r; r += key_length; @@ -677,7 +677,7 @@ sfmt_t *init_by_array(uint32_t *init_key, int key_length) { count--; for (i = 1, j = 0; (j < count) && (j < key_length); j++) { - r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % N32)] + r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % N32)] ^ psfmt32[idxof((i + N32 - 1) % N32)]); psfmt32[idxof((i + mid) % N32)] += r; r += init_key[j] + i; @@ -686,7 +686,7 @@ sfmt_t *init_by_array(uint32_t *init_key, int key_length) { i = (i + 1) % N32; } for (; j < count; j++) { - r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % N32)] + r = func1(psfmt32[idxof(i)] ^ psfmt32[idxof((i + mid) % N32)] ^ psfmt32[idxof((i + N32 - 1) % N32)]); psfmt32[idxof((i + mid) % N32)] += r; r += i; @@ -695,7 +695,7 @@ sfmt_t *init_by_array(uint32_t *init_key, int key_length) { i = (i + 1) % N32; } for (j = 0; j < N32; j++) { - r = func2(psfmt32[idxof(i)] + psfmt32[idxof((i + mid) % N32)] + r = func2(psfmt32[idxof(i)] + psfmt32[idxof((i + mid) % N32)] + psfmt32[idxof((i + N32 - 1) % N32)]); psfmt32[idxof((i + mid) % N32)] ^= r; r -= i; diff --git a/test/stress/microbench.c b/test/stress/microbench.c index 73cbcab0..988b7938 100644 --- a/test/stress/microbench.c +++ b/test/stress/microbench.c @@ -1,6 +1,6 @@ #include "test/jemalloc_test.h" -JEMALLOC_INLINE_C void +static inline void time_func(timedelta_t *timer, uint64_t nwarmup, uint64_t niter, void (*func)(void)) { uint64_t i; -- GitLab From fa3ad730c492c50f19fc68050ea5d5175b1df3cb Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 19 Apr 2017 12:48:50 -0700 Subject: [PATCH 438/544] Header refactoring: prng module - remove from the catchall and unify. --- include/jemalloc/internal/extent_inlines.h | 1 + .../internal/jemalloc_internal_includes.h | 2 - .../internal/{prng_inlines.h => prng.h} | 50 +++++++++++++++++-- include/jemalloc/internal/prng_types.h | 29 ----------- include/jemalloc/internal/prof_structs.h | 1 + src/ckh.c | 1 + 6 files changed, 49 insertions(+), 35 deletions(-) rename include/jemalloc/internal/{prng_inlines.h => prng.h} (65%) delete mode 100644 include/jemalloc/internal/prng_types.h diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index 22d45ce1..a73b6530 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -1,6 +1,7 @@ #ifndef JEMALLOC_INTERNAL_EXTENT_INLINES_H #define JEMALLOC_INTERNAL_EXTENT_INLINES_H +#include "jemalloc/internal/prng.h" #include "jemalloc/internal/ql.h" static inline arena_t * diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 669194d0..5e80f96c 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -40,7 +40,6 @@ /* TYPES */ /******************************************************************************/ -#include "jemalloc/internal/prng_types.h" #include "jemalloc/internal/ticker_types.h" #include "jemalloc/internal/ckh_types.h" #include "jemalloc/internal/size_classes.h" @@ -108,7 +107,6 @@ /* INLINES */ /******************************************************************************/ -#include "jemalloc/internal/prng_inlines.h" #include "jemalloc/internal/ticker_inlines.h" #include "jemalloc/internal/tsd_inlines.h" #include "jemalloc/internal/witness_inlines.h" diff --git a/include/jemalloc/internal/prng_inlines.h b/include/jemalloc/internal/prng.h similarity index 65% rename from include/jemalloc/internal/prng_inlines.h rename to include/jemalloc/internal/prng.h index 0275dfc4..15cc2d18 100644 --- a/include/jemalloc/internal/prng_inlines.h +++ b/include/jemalloc/internal/prng.h @@ -1,9 +1,37 @@ -#ifndef JEMALLOC_INTERNAL_PRNG_INLINES_H -#define JEMALLOC_INTERNAL_PRNG_INLINES_H +#ifndef JEMALLOC_INTERNAL_PRNG_H +#define JEMALLOC_INTERNAL_PRNG_H #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/bit_util.h" +/* + * Simple linear congruential pseudo-random number generator: + * + * prng(y) = (a*x + c) % m + * + * where the following constants ensure maximal period: + * + * a == Odd number (relatively prime to 2^n), and (a-1) is a multiple of 4. + * c == Odd number (relatively prime to 2^n). + * m == 2^32 + * + * See Knuth's TAOCP 3rd Ed., Vol. 2, pg. 17 for details on these constraints. + * + * This choice of m has the disadvantage that the quality of the bits is + * proportional to bit position. For example, the lowest bit has a cycle of 2, + * the next has a cycle of 4, etc. For this reason, we prefer to use the upper + * bits. + */ + +/******************************************************************************/ +/* INTERNAL DEFINITIONS -- IGNORE */ +/******************************************************************************/ +#define PRNG_A_32 UINT32_C(1103515241) +#define PRNG_C_32 UINT32_C(12347) + +#define PRNG_A_64 UINT64_C(6364136223846793005) +#define PRNG_C_64 UINT64_C(1442695040888963407) + JEMALLOC_ALWAYS_INLINE uint32_t prng_state_next_u32(uint32_t state) { return (state * PRNG_A_32) + PRNG_C_32; @@ -25,6 +53,16 @@ prng_state_next_zu(size_t state) { #endif } +/******************************************************************************/ +/* BEGIN PUBLIC API */ +/******************************************************************************/ + +/* + * The prng_lg_range functions give a uniform int in the half-open range [0, + * 2**lg_range). If atomic is true, they do so safely from multiple threads. + * Multithreaded 64-bit prngs aren't supported. + */ + JEMALLOC_ALWAYS_INLINE uint32_t prng_lg_range_u32(atomic_u32_t *state, unsigned lg_range, bool atomic) { uint32_t ret, state0, state1; @@ -48,7 +86,6 @@ prng_lg_range_u32(atomic_u32_t *state, unsigned lg_range, bool atomic) { return ret; } -/* 64-bit atomic operations cannot be supported on all relevant platforms. */ JEMALLOC_ALWAYS_INLINE uint64_t prng_lg_range_u64(uint64_t *state, unsigned lg_range) { uint64_t ret, state1; @@ -86,6 +123,11 @@ prng_lg_range_zu(atomic_zu_t *state, unsigned lg_range, bool atomic) { return ret; } +/* + * The prng_range functions behave like the prng_lg_range, but return a result + * in [0, range) instead of [0, 2**lg_range). + */ + JEMALLOC_ALWAYS_INLINE uint32_t prng_range_u32(atomic_u32_t *state, uint32_t range, bool atomic) { uint32_t ret; @@ -140,4 +182,4 @@ prng_range_zu(atomic_zu_t *state, size_t range, bool atomic) { return ret; } -#endif /* JEMALLOC_INTERNAL_PRNG_INLINES_H */ +#endif /* JEMALLOC_INTERNAL_PRNG_H */ diff --git a/include/jemalloc/internal/prng_types.h b/include/jemalloc/internal/prng_types.h deleted file mode 100644 index 3e8e1834..00000000 --- a/include/jemalloc/internal/prng_types.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_PRNG_TYPES_H -#define JEMALLOC_INTERNAL_PRNG_TYPES_H - -/* - * Simple linear congruential pseudo-random number generator: - * - * prng(y) = (a*x + c) % m - * - * where the following constants ensure maximal period: - * - * a == Odd number (relatively prime to 2^n), and (a-1) is a multiple of 4. - * c == Odd number (relatively prime to 2^n). - * m == 2^32 - * - * See Knuth's TAOCP 3rd Ed., Vol. 2, pg. 17 for details on these constraints. - * - * This choice of m has the disadvantage that the quality of the bits is - * proportional to bit position. For example, the lowest bit has a cycle of 2, - * the next has a cycle of 4, etc. For this reason, we prefer to use the upper - * bits. - */ - -#define PRNG_A_32 UINT32_C(1103515241) -#define PRNG_C_32 UINT32_C(12347) - -#define PRNG_A_64 UINT64_C(6364136223846793005) -#define PRNG_C_64 UINT64_C(1442695040888963407) - -#endif /* JEMALLOC_INTERNAL_PRNG_TYPES_H */ diff --git a/include/jemalloc/internal/prof_structs.h b/include/jemalloc/internal/prof_structs.h index e1936769..82080aa1 100644 --- a/include/jemalloc/internal/prof_structs.h +++ b/include/jemalloc/internal/prof_structs.h @@ -1,6 +1,7 @@ #ifndef JEMALLOC_INTERNAL_PROF_STRUCTS_H #define JEMALLOC_INTERNAL_PROF_STRUCTS_H +#include "jemalloc/internal/prng.h" #include "jemalloc/internal/rb.h" struct prof_bt_s { diff --git a/src/ckh.c b/src/ckh.c index 6576740b..db52a845 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -40,6 +40,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/malloc_io.h" +#include "jemalloc/internal/prng.h" #include "jemalloc/internal/util.h" /******************************************************************************/ -- GitLab From bf2dc7e67840807fb90451ab34e7150401f7f7c4 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 19 Apr 2017 13:39:33 -0700 Subject: [PATCH 439/544] Header refactoring: ticker module - remove from the catchall and unify. --- include/jemalloc/internal/arena_inlines_b.h | 1 + include/jemalloc/internal/arena_structs_b.h | 1 + .../internal/jemalloc_internal_includes.h | 3 --- .../internal/jemalloc_internal_inlines_a.h | 1 + include/jemalloc/internal/tcache_inlines.h | 1 + include/jemalloc/internal/tcache_structs.h | 1 + .../internal/{ticker_inlines.h => ticker.h} | 19 ++++++++++++++++--- include/jemalloc/internal/ticker_structs.h | 9 --------- include/jemalloc/internal/ticker_types.h | 6 ------ src/jemalloc.c | 1 + test/unit/decay.c | 2 ++ test/unit/ticker.c | 2 ++ 12 files changed, 26 insertions(+), 21 deletions(-) rename include/jemalloc/internal/{ticker_inlines.h => ticker.h} (52%) delete mode 100644 include/jemalloc/internal/ticker_structs.h delete mode 100644 include/jemalloc/internal/ticker_types.h diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 526103bc..054757d4 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_ARENA_INLINES_B_H #include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/ticker.h" static inline szind_t arena_bin_index(arena_t *arena, arena_bin_t *bin) { diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index f2195f68..7b133f2e 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -4,6 +4,7 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/nstime.h" #include "jemalloc/internal/ql.h" +#include "jemalloc/internal/ticker.h" /* * Read-only information associated with each element of arena_t's bins array diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 5e80f96c..8ce7864f 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -40,7 +40,6 @@ /* TYPES */ /******************************************************************************/ -#include "jemalloc/internal/ticker_types.h" #include "jemalloc/internal/ckh_types.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/smoothstep.h" @@ -63,7 +62,6 @@ /* STRUCTS */ /******************************************************************************/ -#include "jemalloc/internal/ticker_structs.h" #include "jemalloc/internal/ckh_structs.h" #include "jemalloc/internal/witness_structs.h" #include "jemalloc/internal/mutex_structs.h" @@ -107,7 +105,6 @@ /* INLINES */ /******************************************************************************/ -#include "jemalloc/internal/ticker_inlines.h" #include "jemalloc/internal/tsd_inlines.h" #include "jemalloc/internal/witness_inlines.h" #include "jemalloc/internal/mutex_inlines.h" diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_a.h b/include/jemalloc/internal/jemalloc_internal_inlines_a.h index 9cb933c2..06a5c717 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_a.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_a.h @@ -4,6 +4,7 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/bit_util.h" #include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/ticker.h" JEMALLOC_ALWAYS_INLINE pszind_t psz2ind(size_t psz) { diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index 8b42af66..25931d82 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_TCACHE_INLINES_H #include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/ticker.h" #include "jemalloc/internal/util.h" static inline bool diff --git a/include/jemalloc/internal/tcache_structs.h b/include/jemalloc/internal/tcache_structs.h index fe27f362..c01098f1 100644 --- a/include/jemalloc/internal/tcache_structs.h +++ b/include/jemalloc/internal/tcache_structs.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_TCACHE_STRUCTS_H #include "jemalloc/internal/ql.h" +#include "jemalloc/internal/ticker.h" /* * Read-only information associated with each element of tcache_t's tbins array diff --git a/include/jemalloc/internal/ticker_inlines.h b/include/jemalloc/internal/ticker.h similarity index 52% rename from include/jemalloc/internal/ticker_inlines.h rename to include/jemalloc/internal/ticker.h index cd5821f9..faaac91d 100644 --- a/include/jemalloc/internal/ticker_inlines.h +++ b/include/jemalloc/internal/ticker.h @@ -1,5 +1,18 @@ -#ifndef JEMALLOC_INTERNAL_TICKER_INLINES_H -#define JEMALLOC_INTERNAL_TICKER_INLINES_H +#ifndef JEMALLOC_INTERNAL_TICKER_H +#define JEMALLOC_INTERNAL_TICKER_H + +/** + * A ticker makes it easy to count-down events until some limit. You + * ticker_init the ticker to trigger every nticks events. You then notify it + * that an event has occurred with calls to ticker_tick (or that nticks events + * have occurred with a call to ticker_ticks), which will return true (and reset + * the counter) if the countdown hit zero. + */ + +typedef struct { + int32_t tick; + int32_t nticks; +} ticker_t; static inline void ticker_init(ticker_t *ticker, int32_t nticks) { @@ -32,4 +45,4 @@ ticker_tick(ticker_t *ticker) { return ticker_ticks(ticker, 1); } -#endif /* JEMALLOC_INTERNAL_TICKER_INLINES_H */ +#endif /* JEMALLOC_INTERNAL_TICKER_H */ diff --git a/include/jemalloc/internal/ticker_structs.h b/include/jemalloc/internal/ticker_structs.h deleted file mode 100644 index e30c4e21..00000000 --- a/include/jemalloc/internal/ticker_structs.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_TICKER_STRUCTS_H -#define JEMALLOC_INTERNAL_TICKER_STRUCTS_H - -struct ticker_s { - int32_t tick; - int32_t nticks; -}; - -#endif /* JEMALLOC_INTERNAL_TICKER_STRUCTS_H */ diff --git a/include/jemalloc/internal/ticker_types.h b/include/jemalloc/internal/ticker_types.h deleted file mode 100644 index 62d67f3d..00000000 --- a/include/jemalloc/internal/ticker_types.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_TICKER_TYPES_H -#define JEMALLOC_INTERNAL_TICKER_TYPES_H - -typedef struct ticker_s ticker_t; - -#endif /* JEMALLOC_INTERNAL_TICKER_TYPES_H */ diff --git a/src/jemalloc.c b/src/jemalloc.c index 51194992..108258bd 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -7,6 +7,7 @@ #include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/malloc_io.h" #include "jemalloc/internal/spin.h" +#include "jemalloc/internal/ticker.h" #include "jemalloc/internal/util.h" /******************************************************************************/ diff --git a/test/unit/decay.c b/test/unit/decay.c index 26359faf..389f6e06 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -1,5 +1,7 @@ #include "test/jemalloc_test.h" +#include "jemalloc/internal/ticker.h" + static nstime_monotonic_t *nstime_monotonic_orig; static nstime_update_t *nstime_update_orig; diff --git a/test/unit/ticker.c b/test/unit/ticker.c index c2ad7295..e5790a31 100644 --- a/test/unit/ticker.c +++ b/test/unit/ticker.c @@ -1,5 +1,7 @@ #include "test/jemalloc_test.h" +#include "jemalloc/internal/ticker.h" + TEST_BEGIN(test_ticker_tick) { #define NREPS 2 #define NTICKS 3 -- GitLab From 68da2361d2cbb4cc34a784093bd2bee94bede543 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 19 Apr 2017 14:56:42 -0700 Subject: [PATCH 440/544] Header refactoring: ckh module - remove from the catchall and unify. --- include/jemalloc/internal/ckh.h | 101 ++++++++++++++++++ include/jemalloc/internal/ckh_externs.h | 18 ---- include/jemalloc/internal/ckh_structs.h | 41 ------- include/jemalloc/internal/ckh_types.h | 22 ---- .../internal/jemalloc_internal_includes.h | 3 - include/jemalloc/internal/prof_structs.h | 1 + src/ckh.c | 3 + src/prof.c | 1 + 8 files changed, 106 insertions(+), 84 deletions(-) create mode 100644 include/jemalloc/internal/ckh.h delete mode 100644 include/jemalloc/internal/ckh_externs.h delete mode 100644 include/jemalloc/internal/ckh_structs.h delete mode 100644 include/jemalloc/internal/ckh_types.h diff --git a/include/jemalloc/internal/ckh.h b/include/jemalloc/internal/ckh.h new file mode 100644 index 00000000..96922e04 --- /dev/null +++ b/include/jemalloc/internal/ckh.h @@ -0,0 +1,101 @@ +#ifndef JEMALLOC_INTERNAL_CKH_H +#define JEMALLOC_INTERNAL_CKH_H + +#include "jemalloc/internal/tsd_types.h" + +/* Cuckoo hashing implementation. Skip to the end for the interface. */ + +/******************************************************************************/ +/* INTERNAL DEFINITIONS -- IGNORE */ +/******************************************************************************/ + +/* Maintain counters used to get an idea of performance. */ +/* #define CKH_COUNT */ +/* Print counter values in ckh_delete() (requires CKH_COUNT). */ +/* #define CKH_VERBOSE */ + +/* + * There are 2^LG_CKH_BUCKET_CELLS cells in each hash table bucket. Try to fit + * one bucket per L1 cache line. + */ +#define LG_CKH_BUCKET_CELLS (LG_CACHELINE - LG_SIZEOF_PTR - 1) + +/* Typedefs to allow easy function pointer passing. */ +typedef void ckh_hash_t (const void *, size_t[2]); +typedef bool ckh_keycomp_t (const void *, const void *); + +/* Hash table cell. */ +typedef struct { + const void *key; + const void *data; +} ckhc_t; + +/* The hash table itself. */ +typedef struct { +#ifdef CKH_COUNT + /* Counters used to get an idea of performance. */ + uint64_t ngrows; + uint64_t nshrinks; + uint64_t nshrinkfails; + uint64_t ninserts; + uint64_t nrelocs; +#endif + + /* Used for pseudo-random number generation. */ + uint64_t prng_state; + + /* Total number of items. */ + size_t count; + + /* + * Minimum and current number of hash table buckets. There are + * 2^LG_CKH_BUCKET_CELLS cells per bucket. + */ + unsigned lg_minbuckets; + unsigned lg_curbuckets; + + /* Hash and comparison functions. */ + ckh_hash_t *hash; + ckh_keycomp_t *keycomp; + + /* Hash table with 2^lg_curbuckets buckets. */ + ckhc_t *tab; +} ckh_t; + +/******************************************************************************/ +/* BEGIN PUBLIC API */ +/******************************************************************************/ + +/* Lifetime management. Minitems is the initial capacity. */ +bool ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, + ckh_keycomp_t *keycomp); +void ckh_delete(tsd_t *tsd, ckh_t *ckh); + +/* Get the number of elements in the set. */ +size_t ckh_count(ckh_t *ckh); + +/* + * To iterate over the elements in the table, initialize *tabind to 0 and call + * this function until it returns true. Each call that returns false will + * update *key and *data to the next element in the table, assuming the pointers + * are non-NULL. + */ +bool ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data); + +/* + * Basic hash table operations -- insert, removal, lookup. For ckh_remove and + * ckh_search, key or data can be NULL. The hash-table only stores pointers to + * the key and value, and doesn't do any lifetime management. + */ +bool ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data); +bool ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key, + void **data); +bool ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data); + +/* Some useful hash and comparison functions for strings and pointers. */ +void ckh_string_hash(const void *key, size_t r_hash[2]); +bool ckh_string_keycomp(const void *k1, const void *k2); +void ckh_pointer_hash(const void *key, size_t r_hash[2]); +bool ckh_pointer_keycomp(const void *k1, const void *k2); + +#endif /* JEMALLOC_INTERNAL_CKH_H */ diff --git a/include/jemalloc/internal/ckh_externs.h b/include/jemalloc/internal/ckh_externs.h deleted file mode 100644 index c912f72b..00000000 --- a/include/jemalloc/internal/ckh_externs.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_CKH_EXTERNS_H -#define JEMALLOC_INTERNAL_CKH_EXTERNS_H - -bool ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, - ckh_keycomp_t *keycomp); -void ckh_delete(tsd_t *tsd, ckh_t *ckh); -size_t ckh_count(ckh_t *ckh); -bool ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data); -bool ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data); -bool ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key, - void **data); -bool ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data); -void ckh_string_hash(const void *key, size_t r_hash[2]); -bool ckh_string_keycomp(const void *k1, const void *k2); -void ckh_pointer_hash(const void *key, size_t r_hash[2]); -bool ckh_pointer_keycomp(const void *k1, const void *k2); - -#endif /* JEMALLOC_INTERNAL_CKH_EXTERNS_H */ diff --git a/include/jemalloc/internal/ckh_structs.h b/include/jemalloc/internal/ckh_structs.h deleted file mode 100644 index a800cbc2..00000000 --- a/include/jemalloc/internal/ckh_structs.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_CKH_STRUCTS_H -#define JEMALLOC_INTERNAL_CKH_STRUCTS_H - -/* Hash table cell. */ -struct ckhc_s { - const void *key; - const void *data; -}; - -struct ckh_s { -#ifdef CKH_COUNT - /* Counters used to get an idea of performance. */ - uint64_t ngrows; - uint64_t nshrinks; - uint64_t nshrinkfails; - uint64_t ninserts; - uint64_t nrelocs; -#endif - - /* Used for pseudo-random number generation. */ - uint64_t prng_state; - - /* Total number of items. */ - size_t count; - - /* - * Minimum and current number of hash table buckets. There are - * 2^LG_CKH_BUCKET_CELLS cells per bucket. - */ - unsigned lg_minbuckets; - unsigned lg_curbuckets; - - /* Hash and comparison functions. */ - ckh_hash_t *hash; - ckh_keycomp_t *keycomp; - - /* Hash table with 2^lg_curbuckets buckets. */ - ckhc_t *tab; -}; - -#endif /* JEMALLOC_INTERNAL_CKH_STRUCTS_H */ diff --git a/include/jemalloc/internal/ckh_types.h b/include/jemalloc/internal/ckh_types.h deleted file mode 100644 index b5911db4..00000000 --- a/include/jemalloc/internal/ckh_types.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_CKH_TYPES_H -#define JEMALLOC_INTERNAL_CKH_TYPES_H - -typedef struct ckh_s ckh_t; -typedef struct ckhc_s ckhc_t; - -/* Typedefs to allow easy function pointer passing. */ -typedef void ckh_hash_t (const void *, size_t[2]); -typedef bool ckh_keycomp_t (const void *, const void *); - -/* Maintain counters used to get an idea of performance. */ -/* #define CKH_COUNT */ -/* Print counter values in ckh_delete() (requires CKH_COUNT). */ -/* #define CKH_VERBOSE */ - -/* - * There are 2^LG_CKH_BUCKET_CELLS cells in each hash table bucket. Try to fit - * one bucket per L1 cache line. - */ -#define LG_CKH_BUCKET_CELLS (LG_CACHELINE - LG_SIZEOF_PTR - 1) - -#endif /* JEMALLOC_INTERNAL_CKH_TYPES_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 8ce7864f..f4a19862 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -40,7 +40,6 @@ /* TYPES */ /******************************************************************************/ -#include "jemalloc/internal/ckh_types.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/smoothstep.h" #include "jemalloc/internal/stats_types.h" @@ -62,7 +61,6 @@ /* STRUCTS */ /******************************************************************************/ -#include "jemalloc/internal/ckh_structs.h" #include "jemalloc/internal/witness_structs.h" #include "jemalloc/internal/mutex_structs.h" #include "jemalloc/internal/stats_structs.h" @@ -83,7 +81,6 @@ /******************************************************************************/ #include "jemalloc/internal/jemalloc_internal_externs.h" -#include "jemalloc/internal/ckh_externs.h" #include "jemalloc/internal/stats_externs.h" #include "jemalloc/internal/ctl_externs.h" #include "jemalloc/internal/witness_externs.h" diff --git a/include/jemalloc/internal/prof_structs.h b/include/jemalloc/internal/prof_structs.h index 82080aa1..a26a0420 100644 --- a/include/jemalloc/internal/prof_structs.h +++ b/include/jemalloc/internal/prof_structs.h @@ -1,6 +1,7 @@ #ifndef JEMALLOC_INTERNAL_PROF_STRUCTS_H #define JEMALLOC_INTERNAL_PROF_STRUCTS_H +#include "jemalloc/internal/ckh.h" #include "jemalloc/internal/prng.h" #include "jemalloc/internal/rb.h" diff --git a/src/ckh.c b/src/ckh.c index db52a845..8f0bac07 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -36,6 +36,9 @@ ******************************************************************************/ #define JEMALLOC_CKH_C_ #include "jemalloc/internal/jemalloc_preamble.h" + +#include "jemalloc/internal/ckh.h" + #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" diff --git a/src/prof.c b/src/prof.c index 99a4c8f0..a8f6aed2 100644 --- a/src/prof.c +++ b/src/prof.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/ckh.h" #include "jemalloc/internal/malloc_io.h" /******************************************************************************/ -- GitLab From 31b43219dbf397f273350a66a3a594fdfbaa1e00 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 19 Apr 2017 15:09:01 -0700 Subject: [PATCH 441/544] Header refactoring: size_classes module - remove from the catchall --- include/jemalloc/internal/arena_externs.h | 2 ++ include/jemalloc/internal/arena_inlines_b.h | 1 + include/jemalloc/internal/arena_structs_b.h | 2 ++ include/jemalloc/internal/base_structs.h | 3 +++ include/jemalloc/internal/bitmap_types.h | 2 ++ include/jemalloc/internal/ctl_structs.h | 2 ++ include/jemalloc/internal/extent_structs.h | 1 + include/jemalloc/internal/jemalloc_internal_includes.h | 1 - include/jemalloc/internal/jemalloc_internal_inlines_a.h | 1 + include/jemalloc/internal/rtree_inlines.h | 1 + include/jemalloc/internal/rtree_types.h | 2 ++ include/jemalloc/internal/stats_structs.h | 1 + include/jemalloc/internal/tcache_externs.h | 2 ++ include/jemalloc/internal/tcache_inlines.h | 1 + include/jemalloc/internal/tcache_structs.h | 1 + include/jemalloc/internal/tcache_types.h | 2 ++ src/arena.c | 1 + src/ctl.c | 1 + src/jemalloc.c | 1 + src/tcache.c | 1 + 20 files changed, 28 insertions(+), 1 deletion(-) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 0f86dc05..241165ec 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_ARENA_EXTERNS_H #define JEMALLOC_INTERNAL_ARENA_EXTERNS_H +#include "jemalloc/internal/size_classes.h" + static const size_t large_pad = #ifdef JEMALLOC_CACHE_OBLIVIOUS PAGE diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 054757d4..ca7af7fd 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_ARENA_INLINES_B_H #include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/ticker.h" static inline szind_t diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 7b133f2e..dbff7876 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -2,8 +2,10 @@ #define JEMALLOC_INTERNAL_ARENA_STRUCTS_B_H #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/nstime.h" #include "jemalloc/internal/ql.h" +#include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/ticker.h" /* diff --git a/include/jemalloc/internal/base_structs.h b/include/jemalloc/internal/base_structs.h index d79f38ee..1d0a1f3a 100644 --- a/include/jemalloc/internal/base_structs.h +++ b/include/jemalloc/internal/base_structs.h @@ -1,6 +1,9 @@ #ifndef JEMALLOC_INTERNAL_BASE_STRUCTS_H #define JEMALLOC_INTERNAL_BASE_STRUCTS_H +#include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/size_classes.h" + /* Embedded at the beginning of every block of base-managed virtual memory. */ struct base_block_s { /* Total size of block's virtual memory mapping. */ diff --git a/include/jemalloc/internal/bitmap_types.h b/include/jemalloc/internal/bitmap_types.h index b334769f..95f0dd12 100644 --- a/include/jemalloc/internal/bitmap_types.h +++ b/include/jemalloc/internal/bitmap_types.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_BITMAP_TYPES_H #define JEMALLOC_INTERNAL_BITMAP_TYPES_H +#include "jemalloc/internal/size_classes.h" + /* Maximum bitmap bit count is 2^LG_BITMAP_MAXBITS. */ #if LG_SLAB_MAXREGS > LG_CEIL_NSIZES /* Maximum bitmap bit count is determined by maximum regions per slab. */ diff --git a/include/jemalloc/internal/ctl_structs.h b/include/jemalloc/internal/ctl_structs.h index 2b48a68e..b0c37c9e 100644 --- a/include/jemalloc/internal/ctl_structs.h +++ b/include/jemalloc/internal/ctl_structs.h @@ -1,7 +1,9 @@ #ifndef JEMALLOC_INTERNAL_CTL_STRUCTS_H #define JEMALLOC_INTERNAL_CTL_STRUCTS_H +#include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/ql.h" +#include "jemalloc/internal/size_classes.h" struct ctl_node_s { bool named; diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 7066b8f6..aa0a3a75 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -5,6 +5,7 @@ #include "jemalloc/internal/ql.h" #include "jemalloc/internal/rb.h" #include "jemalloc/internal/ph.h" +#include "jemalloc/internal/size_classes.h" typedef enum { extent_state_active = 0, diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index f4a19862..3794c34c 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -40,7 +40,6 @@ /* TYPES */ /******************************************************************************/ -#include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/smoothstep.h" #include "jemalloc/internal/stats_types.h" #include "jemalloc/internal/ctl_types.h" diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_a.h b/include/jemalloc/internal/jemalloc_internal_inlines_a.h index 06a5c717..1755c3ac 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_a.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_a.h @@ -4,6 +4,7 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/bit_util.h" #include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/ticker.h" JEMALLOC_ALWAYS_INLINE pszind_t diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index f4f7c2ca..7bc52383 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -1,6 +1,7 @@ #ifndef JEMALLOC_INTERNAL_RTREE_INLINES_H #define JEMALLOC_INTERNAL_RTREE_INLINES_H +#include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/spin.h" JEMALLOC_ALWAYS_INLINE uintptr_t diff --git a/include/jemalloc/internal/rtree_types.h b/include/jemalloc/internal/rtree_types.h index d9a4cf4d..402f741c 100644 --- a/include/jemalloc/internal/rtree_types.h +++ b/include/jemalloc/internal/rtree_types.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_RTREE_TYPES_H #define JEMALLOC_INTERNAL_RTREE_TYPES_H +#include "jemalloc/internal/size_classes.h" + /* * This radix tree implementation is tailored to the singular purpose of * associating metadata with extents that are currently owned by jemalloc. diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats_structs.h index dc994b52..3693a854 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats_structs.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_STATS_STRUCTS_H #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/size_classes.h" #ifdef JEMALLOC_ATOMIC_U64 typedef atomic_u64_t arena_stats_u64_t; diff --git a/include/jemalloc/internal/tcache_externs.h b/include/jemalloc/internal/tcache_externs.h index 75ff3214..abe133fa 100644 --- a/include/jemalloc/internal/tcache_externs.h +++ b/include/jemalloc/internal/tcache_externs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_TCACHE_EXTERNS_H #define JEMALLOC_INTERNAL_TCACHE_EXTERNS_H +#include "jemalloc/internal/size_classes.h" + extern bool opt_tcache; extern ssize_t opt_lg_tcache_max; diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index 25931d82..8a65ba2b 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_TCACHE_INLINES_H #include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/ticker.h" #include "jemalloc/internal/util.h" diff --git a/include/jemalloc/internal/tcache_structs.h b/include/jemalloc/internal/tcache_structs.h index c01098f1..cd0cea55 100644 --- a/include/jemalloc/internal/tcache_structs.h +++ b/include/jemalloc/internal/tcache_structs.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_TCACHE_STRUCTS_H #include "jemalloc/internal/ql.h" +#include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/ticker.h" /* diff --git a/include/jemalloc/internal/tcache_types.h b/include/jemalloc/internal/tcache_types.h index a60db6ff..1155d62c 100644 --- a/include/jemalloc/internal/tcache_types.h +++ b/include/jemalloc/internal/tcache_types.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_TCACHE_TYPES_H #define JEMALLOC_INTERNAL_TCACHE_TYPES_H +#include "jemalloc/internal/size_classes.h" + typedef struct tcache_bin_info_s tcache_bin_info_t; typedef struct tcache_bin_s tcache_bin_t; typedef struct tcache_s tcache_t; diff --git a/src/arena.c b/src/arena.c index 40561c03..77f72828 100644 --- a/src/arena.c +++ b/src/arena.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/util.h" /******************************************************************************/ diff --git a/src/ctl.c b/src/ctl.c index 72372d55..c054ded6 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/nstime.h" +#include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/util.h" /******************************************************************************/ diff --git a/src/jemalloc.c b/src/jemalloc.c index 108258bd..602cf677 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -6,6 +6,7 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/malloc_io.h" +#include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/spin.h" #include "jemalloc/internal/ticker.h" #include "jemalloc/internal/util.h" diff --git a/src/tcache.c b/src/tcache.c index 72d1e47f..c272a3c4 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/size_classes.h" /******************************************************************************/ /* Data. */ -- GitLab From 36abf78aa924f5f038f94443357e89ae86ae3510 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 19 Apr 2017 15:15:57 -0700 Subject: [PATCH 442/544] Header refactoring: move smoothstep.h out of the catchall. --- include/jemalloc/internal/arena_structs_b.h | 1 + include/jemalloc/internal/jemalloc_internal_includes.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index dbff7876..8a7d7a12 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -6,6 +6,7 @@ #include "jemalloc/internal/nstime.h" #include "jemalloc/internal/ql.h" #include "jemalloc/internal/size_classes.h" +#include "jemalloc/internal/smoothstep.h" #include "jemalloc/internal/ticker.h" /* diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 3794c34c..8b650fbf 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -40,7 +40,6 @@ /* TYPES */ /******************************************************************************/ -#include "jemalloc/internal/smoothstep.h" #include "jemalloc/internal/stats_types.h" #include "jemalloc/internal/ctl_types.h" #include "jemalloc/internal/witness_types.h" -- GitLab From d6b5c7e0f6973fa95d398cb9df3f48ac205e1fc3 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Thu, 20 Apr 2017 13:38:12 -0700 Subject: [PATCH 443/544] Header refactoring: stats - unify and remove from catchall --- include/jemalloc/internal/arena_externs.h | 1 + include/jemalloc/internal/arena_structs_b.h | 1 + include/jemalloc/internal/ctl_structs.h | 1 + .../internal/jemalloc_internal_includes.h | 3 -- .../internal/{stats_structs.h => stats.h} | 38 ++++++++++++------- include/jemalloc/internal/stats_externs.h | 9 ----- include/jemalloc/internal/stats_types.h | 10 ----- include/jemalloc/internal/tcache_structs.h | 1 + 8 files changed, 29 insertions(+), 35 deletions(-) rename include/jemalloc/internal/{stats_structs.h => stats.h} (81%) delete mode 100644 include/jemalloc/internal/stats_externs.h delete mode 100644 include/jemalloc/internal/stats_types.h diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 241165ec..1e13efd3 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_ARENA_EXTERNS_H #include "jemalloc/internal/size_classes.h" +#include "jemalloc/internal/stats.h" static const size_t large_pad = #ifdef JEMALLOC_CACHE_OBLIVIOUS diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 8a7d7a12..bef73aaf 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -7,6 +7,7 @@ #include "jemalloc/internal/ql.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/smoothstep.h" +#include "jemalloc/internal/stats.h" #include "jemalloc/internal/ticker.h" /* diff --git a/include/jemalloc/internal/ctl_structs.h b/include/jemalloc/internal/ctl_structs.h index b0c37c9e..c64820d2 100644 --- a/include/jemalloc/internal/ctl_structs.h +++ b/include/jemalloc/internal/ctl_structs.h @@ -4,6 +4,7 @@ #include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/ql.h" #include "jemalloc/internal/size_classes.h" +#include "jemalloc/internal/stats.h" struct ctl_node_s { bool named; diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 8b650fbf..0cb6183d 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -40,7 +40,6 @@ /* TYPES */ /******************************************************************************/ -#include "jemalloc/internal/stats_types.h" #include "jemalloc/internal/ctl_types.h" #include "jemalloc/internal/witness_types.h" #include "jemalloc/internal/mutex_types.h" @@ -61,7 +60,6 @@ #include "jemalloc/internal/witness_structs.h" #include "jemalloc/internal/mutex_structs.h" -#include "jemalloc/internal/stats_structs.h" #include "jemalloc/internal/ctl_structs.h" #include "jemalloc/internal/bitmap_structs.h" #include "jemalloc/internal/arena_structs_a.h" @@ -79,7 +77,6 @@ /******************************************************************************/ #include "jemalloc/internal/jemalloc_internal_externs.h" -#include "jemalloc/internal/stats_externs.h" #include "jemalloc/internal/ctl_externs.h" #include "jemalloc/internal/witness_externs.h" #include "jemalloc/internal/mutex_externs.h" diff --git a/include/jemalloc/internal/stats_structs.h b/include/jemalloc/internal/stats.h similarity index 81% rename from include/jemalloc/internal/stats_structs.h rename to include/jemalloc/internal/stats.h index 3693a854..9414200f 100644 --- a/include/jemalloc/internal/stats_structs.h +++ b/include/jemalloc/internal/stats.h @@ -1,9 +1,21 @@ -#ifndef JEMALLOC_INTERNAL_STATS_STRUCTS_H -#define JEMALLOC_INTERNAL_STATS_STRUCTS_H +#ifndef JEMALLOC_INTERNAL_STATS_H +#define JEMALLOC_INTERNAL_STATS_H #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/size_classes.h" +/* The opt.stats_print storage. */ +extern bool opt_stats_print; + +/* Implements je_malloc_stats_print. */ +void stats_print(void (*write_cb)(void *, const char *), void *cbopaque, + const char *opts); + +/* + * In those architectures that support 64-bit atomics, we use atomic updates for + * our 64-bit values. Otherwise, we use a plain uint64_t and synchronize + * externally. + */ #ifdef JEMALLOC_ATOMIC_U64 typedef atomic_u64_t arena_stats_u64_t; #else @@ -11,15 +23,15 @@ typedef atomic_u64_t arena_stats_u64_t; typedef uint64_t arena_stats_u64_t; #endif -struct tcache_bin_stats_s { +typedef struct tcache_bin_stats_s { /* * Number of allocation requests that corresponded to the size of this * bin. */ uint64_t nrequests; -}; +} tcache_bin_stats_t; -struct malloc_bin_stats_s { +typedef struct malloc_bin_stats_s { /* * Total number of allocation/deallocation requests served directly by * the bin. Note that tcache may allocate an object, then recycle it @@ -61,9 +73,9 @@ struct malloc_bin_stats_s { size_t curslabs; mutex_prof_data_t mutex_data; -}; +} malloc_bin_stats_t; -struct malloc_large_stats_s { +typedef struct malloc_large_stats_s { /* * Total number of allocation/deallocation requests served directly by * the arena. @@ -80,23 +92,23 @@ struct malloc_large_stats_s { /* Current number of allocations of this size class. */ size_t curlextents; /* Derived. */ -}; +} malloc_large_stats_t; -struct decay_stats_s { +typedef struct decay_stats_s { /* Total number of purge sweeps. */ arena_stats_u64_t npurge; /* Total number of madvise calls made. */ arena_stats_u64_t nmadvise; /* Total number of pages purged. */ arena_stats_u64_t purged; -}; +} decay_stats_t; /* * Arena stats. Note that fields marked "derived" are not directly maintained * within the arena code; rather their values are derived during stats merge * requests. */ -struct arena_stats_s { +typedef struct arena_stats_s { #ifndef JEMALLOC_ATOMIC_U64 malloc_mutex_t mtx; #endif @@ -131,6 +143,6 @@ struct arena_stats_s { /* One element for each large size class. */ malloc_large_stats_t lstats[NSIZES - NBINS]; -}; +} arena_stats_t; -#endif /* JEMALLOC_INTERNAL_STATS_STRUCTS_H */ +#endif /* JEMALLOC_INTERNAL_STATS_H */ diff --git a/include/jemalloc/internal/stats_externs.h b/include/jemalloc/internal/stats_externs.h deleted file mode 100644 index 519441c9..00000000 --- a/include/jemalloc/internal/stats_externs.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_STATS_EXTERNS_H -#define JEMALLOC_INTERNAL_STATS_EXTERNS_H - -extern bool opt_stats_print; - -void stats_print(void (*write_cb)(void *, const char *), void *cbopaque, - const char *opts); - -#endif /* JEMALLOC_INTERNAL_STATS_EXTERNS_H */ diff --git a/include/jemalloc/internal/stats_types.h b/include/jemalloc/internal/stats_types.h deleted file mode 100644 index 48483388..00000000 --- a/include/jemalloc/internal/stats_types.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_STATS_TYPES_H -#define JEMALLOC_INTERNAL_STATS_TYPES_H - -typedef struct tcache_bin_stats_s tcache_bin_stats_t; -typedef struct malloc_bin_stats_s malloc_bin_stats_t; -typedef struct malloc_large_stats_s malloc_large_stats_t; -typedef struct decay_stats_s decay_stats_t; -typedef struct arena_stats_s arena_stats_t; - -#endif /* JEMALLOC_INTERNAL_STATS_TYPES_H */ diff --git a/include/jemalloc/internal/tcache_structs.h b/include/jemalloc/internal/tcache_structs.h index cd0cea55..7c0afb0a 100644 --- a/include/jemalloc/internal/tcache_structs.h +++ b/include/jemalloc/internal/tcache_structs.h @@ -3,6 +3,7 @@ #include "jemalloc/internal/ql.h" #include "jemalloc/internal/size_classes.h" +#include "jemalloc/internal/stats.h" #include "jemalloc/internal/ticker.h" /* -- GitLab From 120c7a747fe9a94bd3bac88080789b7c98a760d1 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Thu, 20 Apr 2017 14:32:24 -0700 Subject: [PATCH 444/544] Header refactoring: bitmap - unify and remove from catchall. --- include/jemalloc/internal/arena_structs_a.h | 2 + include/jemalloc/internal/arena_structs_b.h | 1 + include/jemalloc/internal/bitmap.h | 369 ++++++++++++++++++ include/jemalloc/internal/bitmap_externs.h | 8 - include/jemalloc/internal/bitmap_inlines.h | 200 ---------- include/jemalloc/internal/bitmap_structs.h | 28 -- include/jemalloc/internal/bitmap_types.h | 147 ------- include/jemalloc/internal/extent_structs.h | 1 + .../internal/jemalloc_internal_includes.h | 4 - 9 files changed, 373 insertions(+), 387 deletions(-) create mode 100644 include/jemalloc/internal/bitmap.h delete mode 100644 include/jemalloc/internal/bitmap_externs.h delete mode 100644 include/jemalloc/internal/bitmap_inlines.h delete mode 100644 include/jemalloc/internal/bitmap_structs.h delete mode 100644 include/jemalloc/internal/bitmap_types.h diff --git a/include/jemalloc/internal/arena_structs_a.h b/include/jemalloc/internal/arena_structs_a.h index 07013a06..46aa77c8 100644 --- a/include/jemalloc/internal/arena_structs_a.h +++ b/include/jemalloc/internal/arena_structs_a.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_ARENA_STRUCTS_A_H #define JEMALLOC_INTERNAL_ARENA_STRUCTS_A_H +#include "jemalloc/internal/bitmap.h" + struct arena_slab_data_s { /* Per region allocated/deallocated bitmap. */ bitmap_t bitmap[BITMAP_GROUPS_MAX]; diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index bef73aaf..ecc59d3b 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_ARENA_STRUCTS_B_H #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/bitmap.h" #include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/nstime.h" #include "jemalloc/internal/ql.h" diff --git a/include/jemalloc/internal/bitmap.h b/include/jemalloc/internal/bitmap.h new file mode 100644 index 00000000..f6374e14 --- /dev/null +++ b/include/jemalloc/internal/bitmap.h @@ -0,0 +1,369 @@ +#ifndef JEMALLOC_INTERNAL_BITMAP_H +#define JEMALLOC_INTERNAL_BITMAP_H + +#include "jemalloc/internal/arena_types.h" +#include "jemalloc/internal/bit_util.h" +#include "jemalloc/internal/size_classes.h" + +typedef unsigned long bitmap_t; +#define LG_SIZEOF_BITMAP LG_SIZEOF_LONG + +/* Maximum bitmap bit count is 2^LG_BITMAP_MAXBITS. */ +#if LG_SLAB_MAXREGS > LG_CEIL_NSIZES +/* Maximum bitmap bit count is determined by maximum regions per slab. */ +# define LG_BITMAP_MAXBITS LG_SLAB_MAXREGS +#else +/* Maximum bitmap bit count is determined by number of extent size classes. */ +# define LG_BITMAP_MAXBITS LG_CEIL_NSIZES +#endif +#define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS) + +/* Number of bits per group. */ +#define LG_BITMAP_GROUP_NBITS (LG_SIZEOF_BITMAP + 3) +#define BITMAP_GROUP_NBITS (1U << LG_BITMAP_GROUP_NBITS) +#define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1) + +/* + * Do some analysis on how big the bitmap is before we use a tree. For a brute + * force linear search, if we would have to call ffs_lu() more than 2^3 times, + * use a tree instead. + */ +#if LG_BITMAP_MAXBITS - LG_BITMAP_GROUP_NBITS > 3 +# define BITMAP_USE_TREE +#endif + +/* Number of groups required to store a given number of bits. */ +#define BITMAP_BITS2GROUPS(nbits) \ + (((nbits) + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS) + +/* + * Number of groups required at a particular level for a given number of bits. + */ +#define BITMAP_GROUPS_L0(nbits) \ + BITMAP_BITS2GROUPS(nbits) +#define BITMAP_GROUPS_L1(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits)) +#define BITMAP_GROUPS_L2(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))) +#define BITMAP_GROUPS_L3(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ + BITMAP_BITS2GROUPS((nbits))))) +#define BITMAP_GROUPS_L4(nbits) \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ + BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))))) + +/* + * Assuming the number of levels, number of groups required for a given number + * of bits. + */ +#define BITMAP_GROUPS_1_LEVEL(nbits) \ + BITMAP_GROUPS_L0(nbits) +#define BITMAP_GROUPS_2_LEVEL(nbits) \ + (BITMAP_GROUPS_1_LEVEL(nbits) + BITMAP_GROUPS_L1(nbits)) +#define BITMAP_GROUPS_3_LEVEL(nbits) \ + (BITMAP_GROUPS_2_LEVEL(nbits) + BITMAP_GROUPS_L2(nbits)) +#define BITMAP_GROUPS_4_LEVEL(nbits) \ + (BITMAP_GROUPS_3_LEVEL(nbits) + BITMAP_GROUPS_L3(nbits)) +#define BITMAP_GROUPS_5_LEVEL(nbits) \ + (BITMAP_GROUPS_4_LEVEL(nbits) + BITMAP_GROUPS_L4(nbits)) + +/* + * Maximum number of groups required to support LG_BITMAP_MAXBITS. + */ +#ifdef BITMAP_USE_TREE + +#if LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_1_LEVEL(nbits) +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_1_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 2 +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_2_LEVEL(nbits) +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_2_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 3 +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_3_LEVEL(nbits) +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_3_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 4 +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_4_LEVEL(nbits) +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_4_LEVEL(BITMAP_MAXBITS) +#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 5 +# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_5_LEVEL(nbits) +# define BITMAP_GROUPS_MAX BITMAP_GROUPS_5_LEVEL(BITMAP_MAXBITS) +#else +# error "Unsupported bitmap size" +#endif + +/* + * Maximum number of levels possible. This could be statically computed based + * on LG_BITMAP_MAXBITS: + * + * #define BITMAP_MAX_LEVELS \ + * (LG_BITMAP_MAXBITS / LG_SIZEOF_BITMAP) \ + * + !!(LG_BITMAP_MAXBITS % LG_SIZEOF_BITMAP) + * + * However, that would not allow the generic BITMAP_INFO_INITIALIZER() macro, so + * instead hardcode BITMAP_MAX_LEVELS to the largest number supported by the + * various cascading macros. The only additional cost this incurs is some + * unused trailing entries in bitmap_info_t structures; the bitmaps themselves + * are not impacted. + */ +#define BITMAP_MAX_LEVELS 5 + +#define BITMAP_INFO_INITIALIZER(nbits) { \ + /* nbits. */ \ + nbits, \ + /* nlevels. */ \ + (BITMAP_GROUPS_L0(nbits) > BITMAP_GROUPS_L1(nbits)) + \ + (BITMAP_GROUPS_L1(nbits) > BITMAP_GROUPS_L2(nbits)) + \ + (BITMAP_GROUPS_L2(nbits) > BITMAP_GROUPS_L3(nbits)) + \ + (BITMAP_GROUPS_L3(nbits) > BITMAP_GROUPS_L4(nbits)) + 1, \ + /* levels. */ \ + { \ + {0}, \ + {BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) + \ + BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L3(nbits) + BITMAP_GROUPS_L2(nbits) + \ + BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \ + {BITMAP_GROUPS_L4(nbits) + BITMAP_GROUPS_L3(nbits) + \ + BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) \ + + BITMAP_GROUPS_L0(nbits)} \ + } \ +} + +#else /* BITMAP_USE_TREE */ + +#define BITMAP_GROUPS(nbits) BITMAP_BITS2GROUPS(nbits) +#define BITMAP_GROUPS_MAX BITMAP_BITS2GROUPS(BITMAP_MAXBITS) + +#define BITMAP_INFO_INITIALIZER(nbits) { \ + /* nbits. */ \ + nbits, \ + /* ngroups. */ \ + BITMAP_BITS2GROUPS(nbits) \ +} + +#endif /* BITMAP_USE_TREE */ + +typedef struct bitmap_level_s { + /* Offset of this level's groups within the array of groups. */ + size_t group_offset; +} bitmap_level_t; + +typedef struct bitmap_info_s { + /* Logical number of bits in bitmap (stored at bottom level). */ + size_t nbits; + +#ifdef BITMAP_USE_TREE + /* Number of levels necessary for nbits. */ + unsigned nlevels; + + /* + * Only the first (nlevels+1) elements are used, and levels are ordered + * bottom to top (e.g. the bottom level is stored in levels[0]). + */ + bitmap_level_t levels[BITMAP_MAX_LEVELS+1]; +#else /* BITMAP_USE_TREE */ + /* Number of groups necessary for nbits. */ + size_t ngroups; +#endif /* BITMAP_USE_TREE */ +} bitmap_info_t; + +void bitmap_info_init(bitmap_info_t *binfo, size_t nbits); +void bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo, bool fill); +size_t bitmap_size(const bitmap_info_t *binfo); + +static inline bool +bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) { +#ifdef BITMAP_USE_TREE + size_t rgoff = binfo->levels[binfo->nlevels].group_offset - 1; + bitmap_t rg = bitmap[rgoff]; + /* The bitmap is full iff the root group is 0. */ + return (rg == 0); +#else + size_t i; + + for (i = 0; i < binfo->ngroups; i++) { + if (bitmap[i] != 0) { + return false; + } + } + return true; +#endif +} + +static inline bool +bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { + size_t goff; + bitmap_t g; + + assert(bit < binfo->nbits); + goff = bit >> LG_BITMAP_GROUP_NBITS; + g = bitmap[goff]; + return !(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); +} + +static inline void +bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { + size_t goff; + bitmap_t *gp; + bitmap_t g; + + assert(bit < binfo->nbits); + assert(!bitmap_get(bitmap, binfo, bit)); + goff = bit >> LG_BITMAP_GROUP_NBITS; + gp = &bitmap[goff]; + g = *gp; + assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); + g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); + *gp = g; + assert(bitmap_get(bitmap, binfo, bit)); +#ifdef BITMAP_USE_TREE + /* Propagate group state transitions up the tree. */ + if (g == 0) { + unsigned i; + for (i = 1; i < binfo->nlevels; i++) { + bit = goff; + goff = bit >> LG_BITMAP_GROUP_NBITS; + gp = &bitmap[binfo->levels[i].group_offset + goff]; + g = *gp; + assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); + g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); + *gp = g; + if (g != 0) { + break; + } + } + } +#endif +} + +/* ffu: find first unset >= bit. */ +static inline size_t +bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) { + assert(min_bit < binfo->nbits); + +#ifdef BITMAP_USE_TREE + size_t bit = 0; + for (unsigned level = binfo->nlevels; level--;) { + size_t lg_bits_per_group = (LG_BITMAP_GROUP_NBITS * (level + + 1)); + bitmap_t group = bitmap[binfo->levels[level].group_offset + (bit + >> lg_bits_per_group)]; + unsigned group_nmask = ((min_bit > bit) ? (min_bit - bit) : 0) + >> (lg_bits_per_group - LG_BITMAP_GROUP_NBITS); + assert(group_nmask <= BITMAP_GROUP_NBITS); + bitmap_t group_mask = ~((1LU << group_nmask) - 1); + bitmap_t group_masked = group & group_mask; + if (group_masked == 0LU) { + if (group == 0LU) { + return binfo->nbits; + } + /* + * min_bit was preceded by one or more unset bits in + * this group, but there are no other unset bits in this + * group. Try again starting at the first bit of the + * next sibling. This will recurse at most once per + * non-root level. + */ + size_t sib_base = bit + (1U << lg_bits_per_group); + assert(sib_base > min_bit); + assert(sib_base > bit); + if (sib_base >= binfo->nbits) { + return binfo->nbits; + } + return bitmap_ffu(bitmap, binfo, sib_base); + } + bit += (ffs_lu(group_masked) - 1) << (lg_bits_per_group - + LG_BITMAP_GROUP_NBITS); + } + assert(bit >= min_bit); + assert(bit < binfo->nbits); + return bit; +#else + size_t i = min_bit >> LG_BITMAP_GROUP_NBITS; + bitmap_t g = bitmap[i] & ~((1LU << (min_bit & BITMAP_GROUP_NBITS_MASK)) + - 1); + size_t bit; + do { + bit = ffs_lu(g); + if (bit != 0) { + return (i << LG_BITMAP_GROUP_NBITS) + (bit - 1); + } + i++; + g = bitmap[i]; + } while (i < binfo->ngroups); + return binfo->nbits; +#endif +} + +/* sfu: set first unset. */ +static inline size_t +bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) { + size_t bit; + bitmap_t g; + unsigned i; + + assert(!bitmap_full(bitmap, binfo)); + +#ifdef BITMAP_USE_TREE + i = binfo->nlevels - 1; + g = bitmap[binfo->levels[i].group_offset]; + bit = ffs_lu(g) - 1; + while (i > 0) { + i--; + g = bitmap[binfo->levels[i].group_offset + bit]; + bit = (bit << LG_BITMAP_GROUP_NBITS) + (ffs_lu(g) - 1); + } +#else + i = 0; + g = bitmap[0]; + while ((bit = ffs_lu(g)) == 0) { + i++; + g = bitmap[i]; + } + bit = (i << LG_BITMAP_GROUP_NBITS) + (bit - 1); +#endif + bitmap_set(bitmap, binfo, bit); + return bit; +} + +static inline void +bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { + size_t goff; + bitmap_t *gp; + bitmap_t g; + UNUSED bool propagate; + + assert(bit < binfo->nbits); + assert(bitmap_get(bitmap, binfo, bit)); + goff = bit >> LG_BITMAP_GROUP_NBITS; + gp = &bitmap[goff]; + g = *gp; + propagate = (g == 0); + assert((g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))) == 0); + g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); + *gp = g; + assert(!bitmap_get(bitmap, binfo, bit)); +#ifdef BITMAP_USE_TREE + /* Propagate group state transitions up the tree. */ + if (propagate) { + unsigned i; + for (i = 1; i < binfo->nlevels; i++) { + bit = goff; + goff = bit >> LG_BITMAP_GROUP_NBITS; + gp = &bitmap[binfo->levels[i].group_offset + goff]; + g = *gp; + propagate = (g == 0); + assert((g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))) + == 0); + g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); + *gp = g; + if (!propagate) { + break; + } + } + } +#endif /* BITMAP_USE_TREE */ +} + +#endif /* JEMALLOC_INTERNAL_BITMAP_H */ diff --git a/include/jemalloc/internal/bitmap_externs.h b/include/jemalloc/internal/bitmap_externs.h deleted file mode 100644 index 034a4e6b..00000000 --- a/include/jemalloc/internal/bitmap_externs.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_BITMAP_EXTERNS_H -#define JEMALLOC_INTERNAL_BITMAP_EXTERNS_H - -void bitmap_info_init(bitmap_info_t *binfo, size_t nbits); -void bitmap_init(bitmap_t *bitmap, const bitmap_info_t *binfo, bool fill); -size_t bitmap_size(const bitmap_info_t *binfo); - -#endif /* JEMALLOC_INTERNAL_BITMAP_EXTERNS_H */ diff --git a/include/jemalloc/internal/bitmap_inlines.h b/include/jemalloc/internal/bitmap_inlines.h deleted file mode 100644 index 84425b34..00000000 --- a/include/jemalloc/internal/bitmap_inlines.h +++ /dev/null @@ -1,200 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_BITMAP_INLINES_H -#define JEMALLOC_INTERNAL_BITMAP_INLINES_H - -#include "jemalloc/internal/bit_util.h" - -static inline bool -bitmap_full(bitmap_t *bitmap, const bitmap_info_t *binfo) { -#ifdef BITMAP_USE_TREE - size_t rgoff = binfo->levels[binfo->nlevels].group_offset - 1; - bitmap_t rg = bitmap[rgoff]; - /* The bitmap is full iff the root group is 0. */ - return (rg == 0); -#else - size_t i; - - for (i = 0; i < binfo->ngroups; i++) { - if (bitmap[i] != 0) { - return false; - } - } - return true; -#endif -} - -static inline bool -bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { - size_t goff; - bitmap_t g; - - assert(bit < binfo->nbits); - goff = bit >> LG_BITMAP_GROUP_NBITS; - g = bitmap[goff]; - return !(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); -} - -static inline void -bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { - size_t goff; - bitmap_t *gp; - bitmap_t g; - - assert(bit < binfo->nbits); - assert(!bitmap_get(bitmap, binfo, bit)); - goff = bit >> LG_BITMAP_GROUP_NBITS; - gp = &bitmap[goff]; - g = *gp; - assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); - g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); - *gp = g; - assert(bitmap_get(bitmap, binfo, bit)); -#ifdef BITMAP_USE_TREE - /* Propagate group state transitions up the tree. */ - if (g == 0) { - unsigned i; - for (i = 1; i < binfo->nlevels; i++) { - bit = goff; - goff = bit >> LG_BITMAP_GROUP_NBITS; - gp = &bitmap[binfo->levels[i].group_offset + goff]; - g = *gp; - assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); - g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); - *gp = g; - if (g != 0) { - break; - } - } - } -#endif -} - -/* ffu: find first unset >= bit. */ -static inline size_t -bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) { - assert(min_bit < binfo->nbits); - -#ifdef BITMAP_USE_TREE - size_t bit = 0; - for (unsigned level = binfo->nlevels; level--;) { - size_t lg_bits_per_group = (LG_BITMAP_GROUP_NBITS * (level + - 1)); - bitmap_t group = bitmap[binfo->levels[level].group_offset + (bit - >> lg_bits_per_group)]; - unsigned group_nmask = ((min_bit > bit) ? (min_bit - bit) : 0) - >> (lg_bits_per_group - LG_BITMAP_GROUP_NBITS); - assert(group_nmask <= BITMAP_GROUP_NBITS); - bitmap_t group_mask = ~((1LU << group_nmask) - 1); - bitmap_t group_masked = group & group_mask; - if (group_masked == 0LU) { - if (group == 0LU) { - return binfo->nbits; - } - /* - * min_bit was preceded by one or more unset bits in - * this group, but there are no other unset bits in this - * group. Try again starting at the first bit of the - * next sibling. This will recurse at most once per - * non-root level. - */ - size_t sib_base = bit + (1U << lg_bits_per_group); - assert(sib_base > min_bit); - assert(sib_base > bit); - if (sib_base >= binfo->nbits) { - return binfo->nbits; - } - return bitmap_ffu(bitmap, binfo, sib_base); - } - bit += (ffs_lu(group_masked) - 1) << (lg_bits_per_group - - LG_BITMAP_GROUP_NBITS); - } - assert(bit >= min_bit); - assert(bit < binfo->nbits); - return bit; -#else - size_t i = min_bit >> LG_BITMAP_GROUP_NBITS; - bitmap_t g = bitmap[i] & ~((1LU << (min_bit & BITMAP_GROUP_NBITS_MASK)) - - 1); - size_t bit; - do { - bit = ffs_lu(g); - if (bit != 0) { - return (i << LG_BITMAP_GROUP_NBITS) + (bit - 1); - } - i++; - g = bitmap[i]; - } while (i < binfo->ngroups); - return binfo->nbits; -#endif -} - -/* sfu: set first unset. */ -static inline size_t -bitmap_sfu(bitmap_t *bitmap, const bitmap_info_t *binfo) { - size_t bit; - bitmap_t g; - unsigned i; - - assert(!bitmap_full(bitmap, binfo)); - -#ifdef BITMAP_USE_TREE - i = binfo->nlevels - 1; - g = bitmap[binfo->levels[i].group_offset]; - bit = ffs_lu(g) - 1; - while (i > 0) { - i--; - g = bitmap[binfo->levels[i].group_offset + bit]; - bit = (bit << LG_BITMAP_GROUP_NBITS) + (ffs_lu(g) - 1); - } -#else - i = 0; - g = bitmap[0]; - while ((bit = ffs_lu(g)) == 0) { - i++; - g = bitmap[i]; - } - bit = (i << LG_BITMAP_GROUP_NBITS) + (bit - 1); -#endif - bitmap_set(bitmap, binfo, bit); - return bit; -} - -static inline void -bitmap_unset(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { - size_t goff; - bitmap_t *gp; - bitmap_t g; - UNUSED bool propagate; - - assert(bit < binfo->nbits); - assert(bitmap_get(bitmap, binfo, bit)); - goff = bit >> LG_BITMAP_GROUP_NBITS; - gp = &bitmap[goff]; - g = *gp; - propagate = (g == 0); - assert((g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))) == 0); - g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); - *gp = g; - assert(!bitmap_get(bitmap, binfo, bit)); -#ifdef BITMAP_USE_TREE - /* Propagate group state transitions up the tree. */ - if (propagate) { - unsigned i; - for (i = 1; i < binfo->nlevels; i++) { - bit = goff; - goff = bit >> LG_BITMAP_GROUP_NBITS; - gp = &bitmap[binfo->levels[i].group_offset + goff]; - g = *gp; - propagate = (g == 0); - assert((g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))) - == 0); - g ^= ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK); - *gp = g; - if (!propagate) { - break; - } - } - } -#endif /* BITMAP_USE_TREE */ -} - -#endif /* JEMALLOC_INTERNAL_BITMAP_INLINES_H */ diff --git a/include/jemalloc/internal/bitmap_structs.h b/include/jemalloc/internal/bitmap_structs.h deleted file mode 100644 index 297ae669..00000000 --- a/include/jemalloc/internal/bitmap_structs.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_BITMAP_STRUCTS_H -#define JEMALLOC_INTERNAL_BITMAP_STRUCTS_H - -struct bitmap_level_s { - /* Offset of this level's groups within the array of groups. */ - size_t group_offset; -}; - -struct bitmap_info_s { - /* Logical number of bits in bitmap (stored at bottom level). */ - size_t nbits; - -#ifdef BITMAP_USE_TREE - /* Number of levels necessary for nbits. */ - unsigned nlevels; - - /* - * Only the first (nlevels+1) elements are used, and levels are ordered - * bottom to top (e.g. the bottom level is stored in levels[0]). - */ - bitmap_level_t levels[BITMAP_MAX_LEVELS+1]; -#else /* BITMAP_USE_TREE */ - /* Number of groups necessary for nbits. */ - size_t ngroups; -#endif /* BITMAP_USE_TREE */ -}; - -#endif /* JEMALLOC_INTERNAL_BITMAP_STRUCTS_H */ diff --git a/include/jemalloc/internal/bitmap_types.h b/include/jemalloc/internal/bitmap_types.h deleted file mode 100644 index 95f0dd12..00000000 --- a/include/jemalloc/internal/bitmap_types.h +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_BITMAP_TYPES_H -#define JEMALLOC_INTERNAL_BITMAP_TYPES_H - -#include "jemalloc/internal/size_classes.h" - -/* Maximum bitmap bit count is 2^LG_BITMAP_MAXBITS. */ -#if LG_SLAB_MAXREGS > LG_CEIL_NSIZES -/* Maximum bitmap bit count is determined by maximum regions per slab. */ -# define LG_BITMAP_MAXBITS LG_SLAB_MAXREGS -#else -/* Maximum bitmap bit count is determined by number of extent size classes. */ -# define LG_BITMAP_MAXBITS LG_CEIL_NSIZES -#endif -#define BITMAP_MAXBITS (ZU(1) << LG_BITMAP_MAXBITS) - -typedef struct bitmap_level_s bitmap_level_t; -typedef struct bitmap_info_s bitmap_info_t; -typedef unsigned long bitmap_t; -#define LG_SIZEOF_BITMAP LG_SIZEOF_LONG - -/* Number of bits per group. */ -#define LG_BITMAP_GROUP_NBITS (LG_SIZEOF_BITMAP + 3) -#define BITMAP_GROUP_NBITS (1U << LG_BITMAP_GROUP_NBITS) -#define BITMAP_GROUP_NBITS_MASK (BITMAP_GROUP_NBITS-1) - -/* - * Do some analysis on how big the bitmap is before we use a tree. For a brute - * force linear search, if we would have to call ffs_lu() more than 2^3 times, - * use a tree instead. - */ -#if LG_BITMAP_MAXBITS - LG_BITMAP_GROUP_NBITS > 3 -# define BITMAP_USE_TREE -#endif - -/* Number of groups required to store a given number of bits. */ -#define BITMAP_BITS2GROUPS(nbits) \ - (((nbits) + BITMAP_GROUP_NBITS_MASK) >> LG_BITMAP_GROUP_NBITS) - -/* - * Number of groups required at a particular level for a given number of bits. - */ -#define BITMAP_GROUPS_L0(nbits) \ - BITMAP_BITS2GROUPS(nbits) -#define BITMAP_GROUPS_L1(nbits) \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits)) -#define BITMAP_GROUPS_L2(nbits) \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))) -#define BITMAP_GROUPS_L3(nbits) \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ - BITMAP_BITS2GROUPS((nbits))))) -#define BITMAP_GROUPS_L4(nbits) \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \ - BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))))) - -/* - * Assuming the number of levels, number of groups required for a given number - * of bits. - */ -#define BITMAP_GROUPS_1_LEVEL(nbits) \ - BITMAP_GROUPS_L0(nbits) -#define BITMAP_GROUPS_2_LEVEL(nbits) \ - (BITMAP_GROUPS_1_LEVEL(nbits) + BITMAP_GROUPS_L1(nbits)) -#define BITMAP_GROUPS_3_LEVEL(nbits) \ - (BITMAP_GROUPS_2_LEVEL(nbits) + BITMAP_GROUPS_L2(nbits)) -#define BITMAP_GROUPS_4_LEVEL(nbits) \ - (BITMAP_GROUPS_3_LEVEL(nbits) + BITMAP_GROUPS_L3(nbits)) -#define BITMAP_GROUPS_5_LEVEL(nbits) \ - (BITMAP_GROUPS_4_LEVEL(nbits) + BITMAP_GROUPS_L4(nbits)) - -/* - * Maximum number of groups required to support LG_BITMAP_MAXBITS. - */ -#ifdef BITMAP_USE_TREE - -#if LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS -# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_1_LEVEL(nbits) -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_1_LEVEL(BITMAP_MAXBITS) -#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 2 -# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_2_LEVEL(nbits) -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_2_LEVEL(BITMAP_MAXBITS) -#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 3 -# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_3_LEVEL(nbits) -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_3_LEVEL(BITMAP_MAXBITS) -#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 4 -# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_4_LEVEL(nbits) -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_4_LEVEL(BITMAP_MAXBITS) -#elif LG_BITMAP_MAXBITS <= LG_BITMAP_GROUP_NBITS * 5 -# define BITMAP_GROUPS(nbits) BITMAP_GROUPS_5_LEVEL(nbits) -# define BITMAP_GROUPS_MAX BITMAP_GROUPS_5_LEVEL(BITMAP_MAXBITS) -#else -# error "Unsupported bitmap size" -#endif - -/* - * Maximum number of levels possible. This could be statically computed based - * on LG_BITMAP_MAXBITS: - * - * #define BITMAP_MAX_LEVELS \ - * (LG_BITMAP_MAXBITS / LG_SIZEOF_BITMAP) \ - * + !!(LG_BITMAP_MAXBITS % LG_SIZEOF_BITMAP) - * - * However, that would not allow the generic BITMAP_INFO_INITIALIZER() macro, so - * instead hardcode BITMAP_MAX_LEVELS to the largest number supported by the - * various cascading macros. The only additional cost this incurs is some - * unused trailing entries in bitmap_info_t structures; the bitmaps themselves - * are not impacted. - */ -#define BITMAP_MAX_LEVELS 5 - -#define BITMAP_INFO_INITIALIZER(nbits) { \ - /* nbits. */ \ - nbits, \ - /* nlevels. */ \ - (BITMAP_GROUPS_L0(nbits) > BITMAP_GROUPS_L1(nbits)) + \ - (BITMAP_GROUPS_L1(nbits) > BITMAP_GROUPS_L2(nbits)) + \ - (BITMAP_GROUPS_L2(nbits) > BITMAP_GROUPS_L3(nbits)) + \ - (BITMAP_GROUPS_L3(nbits) > BITMAP_GROUPS_L4(nbits)) + 1, \ - /* levels. */ \ - { \ - {0}, \ - {BITMAP_GROUPS_L0(nbits)}, \ - {BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \ - {BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) + \ - BITMAP_GROUPS_L0(nbits)}, \ - {BITMAP_GROUPS_L3(nbits) + BITMAP_GROUPS_L2(nbits) + \ - BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \ - {BITMAP_GROUPS_L4(nbits) + BITMAP_GROUPS_L3(nbits) + \ - BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) \ - + BITMAP_GROUPS_L0(nbits)} \ - } \ -} - -#else /* BITMAP_USE_TREE */ - -#define BITMAP_GROUPS(nbits) BITMAP_BITS2GROUPS(nbits) -#define BITMAP_GROUPS_MAX BITMAP_BITS2GROUPS(BITMAP_MAXBITS) - -#define BITMAP_INFO_INITIALIZER(nbits) { \ - /* nbits. */ \ - nbits, \ - /* ngroups. */ \ - BITMAP_BITS2GROUPS(nbits) \ -} - -#endif /* BITMAP_USE_TREE */ - -#endif /* JEMALLOC_INTERNAL_BITMAP_TYPES_H */ diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index aa0a3a75..5d8c3a20 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_EXTENT_STRUCTS_H #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/bitmap.h" #include "jemalloc/internal/ql.h" #include "jemalloc/internal/rb.h" #include "jemalloc/internal/ph.h" diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 0cb6183d..f98a1b27 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -48,7 +48,6 @@ #include "jemalloc/internal/extent_dss_types.h" #include "jemalloc/internal/base_types.h" #include "jemalloc/internal/arena_types.h" -#include "jemalloc/internal/bitmap_types.h" #include "jemalloc/internal/rtree_types.h" #include "jemalloc/internal/pages_types.h" #include "jemalloc/internal/tcache_types.h" @@ -61,7 +60,6 @@ #include "jemalloc/internal/witness_structs.h" #include "jemalloc/internal/mutex_structs.h" #include "jemalloc/internal/ctl_structs.h" -#include "jemalloc/internal/bitmap_structs.h" #include "jemalloc/internal/arena_structs_a.h" #include "jemalloc/internal/extent_structs.h" #include "jemalloc/internal/extent_dss_structs.h" @@ -80,7 +78,6 @@ #include "jemalloc/internal/ctl_externs.h" #include "jemalloc/internal/witness_externs.h" #include "jemalloc/internal/mutex_externs.h" -#include "jemalloc/internal/bitmap_externs.h" #include "jemalloc/internal/extent_externs.h" #include "jemalloc/internal/extent_dss_externs.h" #include "jemalloc/internal/extent_mmap_externs.h" @@ -103,7 +100,6 @@ #include "jemalloc/internal/jemalloc_internal_inlines_a.h" #include "jemalloc/internal/rtree_inlines.h" #include "jemalloc/internal/base_inlines.h" -#include "jemalloc/internal/bitmap_inlines.h" /* * Include portions of arena code interleaved with tcache code in order to * resolve circular dependencies. -- GitLab From b54530020fb31b47376a0248aa3b73a51e9a5927 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 21 Apr 2017 14:49:31 -0700 Subject: [PATCH 445/544] Remove --with-lg-size-class-group. Four size classes per size doubling has proven to be a universally good choice for the entire 4.x release series, so there's little point to preserving this configurability. This partially resolves #580. --- INSTALL | 32 +------------------------------- configure.ac | 9 +-------- 2 files changed, 2 insertions(+), 39 deletions(-) diff --git a/INSTALL b/INSTALL index 6c53bfc0..ffc3767b 100644 --- a/INSTALL +++ b/INSTALL @@ -220,35 +220,6 @@ any of the following arguments (not a definitive list) to 'configure': when cross compiling, or when overriding the default for systems that do not explicitly support huge pages. ---with-lg-size-class-group= - Specify the base 2 log of how many size classes to use for each doubling in - size. By default jemalloc uses =2, which results in - e.g. the following size classes: - - [...], 64, - 80, 96, 112, 128, - 160, [...] - - =3 results in e.g. the following size classes: - - [...], 64, - 72, 80, 88, 96, 104, 112, 120, 128, - 144, [...] - - The minimal =0 causes jemalloc to only provide size - classes that are powers of 2: - - [...], - 64, - 128, - 256, - [...] - - An implementation detail currently limits the total number of small size - classes to 255, and a compilation error will result if the - you specify cannot be supported. The limit is - roughly =4, depending on page size. - --with-lg-quantum= Specify the base 2 log of the minimum allocation alignment. jemalloc needs to know the minimum alignment that meets the following C standard @@ -272,8 +243,7 @@ any of the following arguments (not a definitive list) to 'configure': this allocator noncompliance means that it is generally safe in practice to let jemalloc's minimum alignment follow glibc's lead. If you specify --with-lg-quantum=3 during configuration, jemalloc will provide additional - size classes that are not 16-byte-aligned (24, 40, and 56, assuming - --with-lg-size-class-group=2). + size classes that are not 16-byte-aligned (24, 40, and 56). --with-lg-tiny-min= Specify the base 2 log of the minimum tiny size class to support. Tiny diff --git a/configure.ac b/configure.ac index 42cabad3..2e233712 100644 --- a/configure.ac +++ b/configure.ac @@ -1401,12 +1401,6 @@ AC_ARG_WITH([lg_page_sizes], [Base 2 logs of system page sizes to support])], [LG_PAGE_SIZES="$with_lg_page_sizes"], [LG_PAGE_SIZES="$LG_PAGE"]) -AC_ARG_WITH([lg_size_class_group], - [AS_HELP_STRING([--with-lg-size-class-group=], - [Base 2 log of size classes per doubling])], - [LG_SIZE_CLASS_GROUP="$with_lg_size_class_group"], - [LG_SIZE_CLASS_GROUP="2"]) - dnl ============================================================================ dnl jemalloc configuration. dnl @@ -2022,7 +2016,7 @@ AC_CONFIG_COMMANDS([include/jemalloc/internal/public_unnamespace.h], [ ]) AC_CONFIG_COMMANDS([include/jemalloc/internal/size_classes.h], [ mkdir -p "${objroot}include/jemalloc/internal" - "${SHELL}" "${srcdir}/include/jemalloc/internal/size_classes.sh" "${LG_QUANTA}" ${LG_TINY_MIN} "${LG_PAGE_SIZES}" ${LG_SIZE_CLASS_GROUP} > "${objroot}include/jemalloc/internal/size_classes.h" + "${SHELL}" "${srcdir}/include/jemalloc/internal/size_classes.sh" "${LG_QUANTA}" ${LG_TINY_MIN} "${LG_PAGE_SIZES}" 2 > "${objroot}include/jemalloc/internal/size_classes.h" ], [ SHELL="${SHELL}" srcdir="${srcdir}" @@ -2030,7 +2024,6 @@ AC_CONFIG_COMMANDS([include/jemalloc/internal/size_classes.h], [ LG_QUANTA="${LG_QUANTA}" LG_TINY_MIN=${LG_TINY_MIN} LG_PAGE_SIZES="${LG_PAGE_SIZES}" - LG_SIZE_CLASS_GROUP=${LG_SIZE_CLASS_GROUP} ]) AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_protos_jet.h], [ mkdir -p "${objroot}include/jemalloc" -- GitLab From af76f0e5d28cd6f0ce8e6c8c6a2a78ba4089868a Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 21 Apr 2017 15:35:54 -0700 Subject: [PATCH 446/544] Remove --with-lg-tiny-min. This option isn't useful in practice. This partially resolves #580. --- INSTALL | 37 ++++--------------- configure.ac | 10 +---- .../internal/jemalloc_internal_defs.h.in | 3 -- include/jemalloc/internal/size_classes.sh | 2 + 4 files changed, 11 insertions(+), 41 deletions(-) diff --git a/INSTALL b/INSTALL index ffc3767b..d4ddba2b 100644 --- a/INSTALL +++ b/INSTALL @@ -233,38 +233,17 @@ any of the following arguments (not a definitive list) to 'configure': This setting is architecture-specific, and although jemalloc includes known safe values for the most commonly used modern architectures, there is a wrinkle related to GNU libc (glibc) that may impact your choice of - . On most modern architectures, this mandates 16-byte alignment - (=4), but the glibc developers chose not to meet this + . On most modern architectures, this mandates 16-byte + alignment (=4), but the glibc developers chose not to meet this requirement for performance reasons. An old discussion can be found at https://sourceware.org/bugzilla/show_bug.cgi?id=206 . Unlike glibc, jemalloc does follow the C standard by default (caveat: jemalloc - technically cheats if --with-lg-tiny-min is smaller than - --with-lg-quantum), but the fact that Linux systems already work around - this allocator noncompliance means that it is generally safe in practice to - let jemalloc's minimum alignment follow glibc's lead. If you specify - --with-lg-quantum=3 during configuration, jemalloc will provide additional - size classes that are not 16-byte-aligned (24, 40, and 56). - ---with-lg-tiny-min= - Specify the base 2 log of the minimum tiny size class to support. Tiny - size classes are powers of 2 less than the quantum, and are only - incorporated if is less than (see - --with-lg-quantum). Tiny size classes technically violate the C standard - requirement for minimum alignment, and crashes could conceivably result if - the compiler were to generate instructions that made alignment assumptions, - both because illegal instruction traps could result, and because accesses - could straddle page boundaries and cause segmentation faults due to - accessing unmapped addresses. - - The default of =3 works well in practice even on architectures - that technically require 16-byte alignment, probably for the same reason - --with-lg-quantum=3 works. Smaller tiny size classes can, and will, cause - crashes (see https://bugzilla.mozilla.org/show_bug.cgi?id=691003 for an - example). - - This option is rarely useful, and is mainly provided as documentation of a - subtle implementation detail. If you do use this option, specify a - value in [3, ..., ]. + technically cheats for size classes smaller than the quantum), but the fact + that Linux systems already work around this allocator noncompliance means + that it is generally safe in practice to let jemalloc's minimum alignment + follow glibc's lead. If you specify --with-lg-quantum=3 during + configuration, jemalloc will provide additional size classes that are not + 16-byte-aligned (24, 40, and 56). The following environment variables (not a definitive list) impact configure's behavior: diff --git a/configure.ac b/configure.ac index 2e233712..a950a23a 100644 --- a/configure.ac +++ b/configure.ac @@ -1296,13 +1296,6 @@ else fi fi -AC_ARG_WITH([lg_tiny_min], - [AS_HELP_STRING([--with-lg-tiny-min=], - [Base 2 log of minimum tiny size class to support])], - [LG_TINY_MIN="$with_lg_tiny_min"], - [LG_TINY_MIN="3"]) -AC_DEFINE_UNQUOTED([LG_TINY_MIN], [$LG_TINY_MIN]) - AC_ARG_WITH([lg_quantum], [AS_HELP_STRING([--with-lg-quantum=], [Base 2 log of minimum allocation alignment])], @@ -2016,13 +2009,12 @@ AC_CONFIG_COMMANDS([include/jemalloc/internal/public_unnamespace.h], [ ]) AC_CONFIG_COMMANDS([include/jemalloc/internal/size_classes.h], [ mkdir -p "${objroot}include/jemalloc/internal" - "${SHELL}" "${srcdir}/include/jemalloc/internal/size_classes.sh" "${LG_QUANTA}" ${LG_TINY_MIN} "${LG_PAGE_SIZES}" 2 > "${objroot}include/jemalloc/internal/size_classes.h" + "${SHELL}" "${srcdir}/include/jemalloc/internal/size_classes.sh" "${LG_QUANTA}" 3 "${LG_PAGE_SIZES}" 2 > "${objroot}include/jemalloc/internal/size_classes.h" ], [ SHELL="${SHELL}" srcdir="${srcdir}" objroot="${objroot}" LG_QUANTA="${LG_QUANTA}" - LG_TINY_MIN=${LG_TINY_MIN} LG_PAGE_SIZES="${LG_PAGE_SIZES}" ]) AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_protos_jet.h], [ diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 1bec2c93..7e83e7b7 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -172,9 +172,6 @@ /* Support lazy locking (avoid locking unless a second thread is launched). */ #undef JEMALLOC_LAZY_LOCK -/* Minimum size class to support is 2^LG_TINY_MIN bytes. */ -#undef LG_TINY_MIN - /* * Minimum allocation alignment is 2^LG_QUANTUM bytes (ignoring tiny size * classes). diff --git a/include/jemalloc/internal/size_classes.sh b/include/jemalloc/internal/size_classes.sh index da1e006c..dd562db1 100755 --- a/include/jemalloc/internal/size_classes.sh +++ b/include/jemalloc/internal/size_classes.sh @@ -285,6 +285,7 @@ cat < Date: Fri, 21 Apr 2017 15:05:43 -0700 Subject: [PATCH 447/544] Implement malloc_mutex_trylock() w/ proper stats update. --- include/jemalloc/internal/mutex_inlines.h | 42 +++++++++++++------ include/jemalloc/internal/private_symbols.txt | 4 ++ src/mutex.c | 4 +- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index 2856d844..6da21cf6 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -10,12 +10,38 @@ malloc_mutex_lock_final(malloc_mutex_t *mutex) { MALLOC_MUTEX_LOCK(mutex); } -/* Trylock: return false if the lock is successfully acquired. */ static inline bool -malloc_mutex_trylock(malloc_mutex_t *mutex) { +malloc_mutex_trylock_final(malloc_mutex_t *mutex) { return MALLOC_MUTEX_TRYLOCK(mutex); } +static inline void +mutex_owner_stats_update(tsdn_t *tsdn, malloc_mutex_t *mutex) { + if (config_stats) { + mutex_prof_data_t *data = &mutex->prof_data; + data->n_lock_ops++; + if (data->prev_owner != tsdn) { + data->prev_owner = tsdn; + data->n_owner_switches++; + } + } +} + +/* Trylock: return false if the lock is successfully acquired. */ +static inline bool +malloc_mutex_trylock(tsdn_t *tsdn, malloc_mutex_t *mutex) { + witness_assert_not_owner(tsdn, &mutex->witness); + if (isthreaded) { + if (malloc_mutex_trylock_final(mutex)) { + return true; + } + mutex_owner_stats_update(tsdn, mutex); + } + witness_lock(tsdn, &mutex->witness); + + return false; +} + /* Aggregate lock prof data. */ static inline void malloc_mutex_prof_merge(mutex_prof_data_t *sum, mutex_prof_data_t *data) { @@ -44,18 +70,10 @@ static inline void malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) { witness_assert_not_owner(tsdn, &mutex->witness); if (isthreaded) { - if (malloc_mutex_trylock(mutex)) { + if (malloc_mutex_trylock_final(mutex)) { malloc_mutex_lock_slow(mutex); } - /* We own the lock now. Update a few counters. */ - if (config_stats) { - mutex_prof_data_t *data = &mutex->prof_data; - data->n_lock_ops++; - if (data->prev_owner != tsdn) { - data->prev_owner = tsdn; - data->n_owner_switches++; - } - } + mutex_owner_stats_update(tsdn, mutex); } witness_lock(tsdn, &mutex->witness); } diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 649a689f..50590957 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -292,10 +292,13 @@ malloc_mutex_assert_owner malloc_mutex_boot malloc_mutex_init malloc_mutex_lock +malloc_mutex_lock_final malloc_mutex_lock_slow malloc_mutex_postfork_child malloc_mutex_postfork_parent malloc_mutex_prefork +malloc_mutex_trylock +malloc_mutex_trylock_final malloc_mutex_unlock malloc_printf malloc_slow @@ -309,6 +312,7 @@ malloc_tsd_malloc malloc_vcprintf malloc_vsnprintf malloc_write +mutex_owner_stats_update narenas_auto narenas_total_get ncpus diff --git a/src/mutex.c b/src/mutex.c index 3bb5ce1d..3eec970f 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -81,7 +81,7 @@ malloc_mutex_lock_slow(malloc_mutex_t *mutex) { int cnt = 0, max_cnt = MALLOC_MUTEX_MAX_SPIN; do { CPU_SPINWAIT; - if (!malloc_mutex_trylock(mutex)) { + if (!malloc_mutex_trylock_final(mutex)) { data->n_spin_acquired++; return; } @@ -100,7 +100,7 @@ label_spin_done: uint32_t n_thds = atomic_fetch_add_u32(&data->n_waiting_thds, 1, ATOMIC_RELAXED) + 1; /* One last try as above two calls may take quite some cycles. */ - if (!malloc_mutex_trylock(mutex)) { + if (!malloc_mutex_trylock_final(mutex)) { atomic_fetch_sub_u32(&data->n_waiting_thds, 1, ATOMIC_RELAXED); data->n_spin_acquired++; return; -- GitLab From cf6035e1ee60dd9245b119aadb2ccec592dde27d Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 21 Apr 2017 15:23:14 -0700 Subject: [PATCH 448/544] Use trylock in arena_decay_impl(). If another thread is working on decay, we don't have to wait for the mutex. --- src/arena.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/arena.c b/src/arena.c index 77f72828..1288b7ba 100644 --- a/src/arena.c +++ b/src/arena.c @@ -47,7 +47,7 @@ const arena_bin_info_t arena_bin_info[NBINS] = { static void arena_decay_to_limit(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, extents_t *extents, bool all, size_t npages_limit); -static void arena_decay_dirty(tsdn_t *tsdn, arena_t *arena, bool all); +static bool arena_decay_dirty(tsdn_t *tsdn, arena_t *arena, bool all); static void arena_dalloc_bin_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, arena_bin_t *bin); static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, extent_t *slab, @@ -965,33 +965,41 @@ arena_decay_to_limit(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, decay->purging = false; } -static void +static bool arena_decay_impl(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, extents_t *extents, bool all) { - malloc_mutex_lock(tsdn, &decay->mtx); if (all) { + malloc_mutex_lock(tsdn, &decay->mtx); arena_decay_to_limit(tsdn, arena, decay, extents, all, 0); } else { + if (malloc_mutex_trylock(tsdn, &decay->mtx)) { + /* No need to wait if another thread is in progress. */ + return true; + } arena_maybe_decay(tsdn, arena, decay, extents); } malloc_mutex_unlock(tsdn, &decay->mtx); + + return false; } -static void +static bool arena_decay_dirty(tsdn_t *tsdn, arena_t *arena, bool all) { - arena_decay_impl(tsdn, arena, &arena->decay_dirty, + return arena_decay_impl(tsdn, arena, &arena->decay_dirty, &arena->extents_dirty, all); } -static void +static bool arena_decay_muzzy(tsdn_t *tsdn, arena_t *arena, bool all) { - arena_decay_impl(tsdn, arena, &arena->decay_muzzy, + return arena_decay_impl(tsdn, arena, &arena->decay_muzzy, &arena->extents_muzzy, all); } void arena_decay(tsdn_t *tsdn, arena_t *arena, bool all) { - arena_decay_dirty(tsdn, arena, all); + if (arena_decay_dirty(tsdn, arena, all)) { + return; + } arena_decay_muzzy(tsdn, arena, all); } -- GitLab From 0f63396b2317dd1a456008819fbedecc372abf13 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 24 Apr 2017 11:47:10 -0700 Subject: [PATCH 449/544] Remove --disable-cc-silence. The explicit compiler warning suppression controlled by this option is universally desirable, so remove the ability to disable suppression. This partially resolves #580. --- INSTALL | 5 ---- configure.ac | 27 +++---------------- .../internal/jemalloc_internal_defs.h.in | 3 --- .../internal/jemalloc_internal_macros.h | 6 +---- include/jemalloc/internal/util.h | 6 +---- 5 files changed, 6 insertions(+), 41 deletions(-) diff --git a/INSTALL b/INSTALL index d4ddba2b..c14dd377 100644 --- a/INSTALL +++ b/INSTALL @@ -96,11 +96,6 @@ any of the following arguments (not a definitive list) to 'configure': --with-malloc-conf=decay_time:30 ---disable-cc-silence - Disable code that silences non-useful compiler warnings. This is mainly - useful during development when auditing the set of warnings that are being - silenced. - --enable-debug Enable assertions and validation code. This incurs a substantial performance hit, but is very useful during application development. diff --git a/configure.ac b/configure.ac index a950a23a..2baead74 100644 --- a/configure.ac +++ b/configure.ac @@ -258,12 +258,10 @@ if test "x$je_cv_cray" = "xyes" ; then JE_CFLAGS_ADD([-hipa2]) JE_CFLAGS_ADD([-hnognu]) fi - if test "x$enable_cc_silence" != "xno" ; then - dnl ignore unreachable code warning - JE_CFLAGS_ADD([-hnomessage=128]) - dnl ignore redefinition of "malloc", "free", etc warning - JE_CFLAGS_ADD([-hnomessage=1357]) - fi + dnl ignore unreachable code warning + JE_CFLAGS_ADD([-hnomessage=128]) + dnl ignore redefinition of "malloc", "free", etc warning + JE_CFLAGS_ADD([-hnomessage=1357]) fi AC_SUBST([CONFIGURE_CFLAGS]) AC_SUBST([SPECIFIED_CFLAGS]) @@ -942,22 +940,6 @@ cfghdrs_tup="include/jemalloc/jemalloc_defs.h:include/jemalloc/jemalloc_defs.h.i cfghdrs_tup="${cfghdrs_tup} include/jemalloc/internal/jemalloc_internal_defs.h:include/jemalloc/internal/jemalloc_internal_defs.h.in" cfghdrs_tup="${cfghdrs_tup} test/include/test/jemalloc_test_defs.h:test/include/test/jemalloc_test_defs.h.in" -dnl Silence irrelevant compiler warnings by default. -AC_ARG_ENABLE([cc-silence], - [AS_HELP_STRING([--disable-cc-silence], - [Do not silence irrelevant compiler warnings])], -[if test "x$enable_cc_silence" = "xno" ; then - enable_cc_silence="0" -else - enable_cc_silence="1" -fi -], -[enable_cc_silence="1"] -) -if test "x$enable_cc_silence" = "x1" ; then - AC_DEFINE([JEMALLOC_CC_SILENCE], [ ]) -fi - dnl Do not compile with debugging by default. AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug], @@ -2110,7 +2092,6 @@ AC_MSG_RESULT([ : ${JEMALLOC_PRIVATE_NAMESPACE}]) AC_MSG_RESULT([install_suffix : ${install_suffix}]) AC_MSG_RESULT([malloc_conf : ${config_malloc_conf}]) AC_MSG_RESULT([autogen : ${enable_autogen}]) -AC_MSG_RESULT([cc-silence : ${enable_cc_silence}]) AC_MSG_RESULT([debug : ${enable_debug}]) AC_MSG_RESULT([code-coverage : ${enable_code_coverage}]) AC_MSG_RESULT([stats : ${enable_stats}]) diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 7e83e7b7..dbcbf26a 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -127,9 +127,6 @@ /* Non-empty if the tls_model attribute is supported. */ #undef JEMALLOC_TLS_MODEL -/* JEMALLOC_CC_SILENCE enables code that silences unuseful compiler warnings. */ -#undef JEMALLOC_CC_SILENCE - /* JEMALLOC_CODE_COVERAGE enables test code coverage analysis. */ #undef JEMALLOC_CODE_COVERAGE diff --git a/include/jemalloc/internal/jemalloc_internal_macros.h b/include/jemalloc/internal/jemalloc_internal_macros.h index 1b2802a8..317b2ab0 100644 --- a/include/jemalloc/internal/jemalloc_internal_macros.h +++ b/include/jemalloc/internal/jemalloc_internal_macros.h @@ -10,11 +10,7 @@ # define inline _inline #endif -#ifdef JEMALLOC_CC_SILENCE -# define UNUSED JEMALLOC_ATTR(unused) -#else -# define UNUSED -#endif +#define UNUSED JEMALLOC_ATTR(unused) #define ZU(z) ((size_t)z) #define ZD(z) ((ssize_t)z) diff --git a/include/jemalloc/internal/util.h b/include/jemalloc/internal/util.h index 88662e89..304cb545 100644 --- a/include/jemalloc/internal/util.h +++ b/include/jemalloc/internal/util.h @@ -26,11 +26,7 @@ * wherever the compiler fails to recognize that the variable is never used * uninitialized. */ -#ifdef JEMALLOC_CC_SILENCE -# define JEMALLOC_CC_SILENCE_INIT(v) = v -#else -# define JEMALLOC_CC_SILENCE_INIT(v) -#endif +#define JEMALLOC_CC_SILENCE_INIT(v) = v #ifdef __GNUC__ # define likely(x) __builtin_expect(!!(x), 1) -- GitLab From e2cc6280ed96e2e6a2754d4e7187296e377d9548 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 24 Apr 2017 15:22:03 -0700 Subject: [PATCH 450/544] Remove --enable-code-coverage. This option hasn't been particularly useful since the original pre-3.0.0 push to broaden test coverage. This partially resolves #580. --- INSTALL | 13 ----- Makefile.in | 50 ------------------- configure.ac | 26 ---------- coverage.sh | 16 ------ .../internal/jemalloc_internal_defs.h.in | 3 -- .../internal/jemalloc_internal_macros.h | 2 +- 6 files changed, 1 insertion(+), 109 deletions(-) delete mode 100755 coverage.sh diff --git a/INSTALL b/INSTALL index c14dd377..5d0cd21e 100644 --- a/INSTALL +++ b/INSTALL @@ -100,19 +100,6 @@ any of the following arguments (not a definitive list) to 'configure': Enable assertions and validation code. This incurs a substantial performance hit, but is very useful during application development. ---enable-code-coverage - Enable code coverage support, for use during jemalloc test development. - Additional testing targets are available if this option is enabled: - - coverage - coverage_unit - coverage_integration - coverage_stress - - These targets do not clear code coverage results from previous runs, and - there are interactions between the various coverage targets, so it is - usually advisable to run 'make clean' between repeated code coverage runs. - --disable-stats Disable statistics gathering functionality. See the "opt.stats_print" option documentation for usage details. diff --git a/Makefile.in b/Makefile.in index 26c811c8..418e92b4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -55,7 +55,6 @@ cfghdrs_out := @cfghdrs_out@ cfgoutputs_in := $(addprefix $(srcroot),@cfgoutputs_in@) cfgoutputs_out := @cfgoutputs_out@ enable_autogen := @enable_autogen@ -enable_code_coverage := @enable_code_coverage@ enable_prof := @enable_prof@ enable_zone_allocator := @enable_zone_allocator@ MALLOC_CONF := @JEMALLOC_CPREFIX@MALLOC_CONF @@ -452,38 +451,6 @@ stress: tests_stress stress_dir $(SHELL) $(objroot)test/test.sh $(TESTS_STRESS:$(srcroot)%.c=$(objroot)%) check: check_unit check_integration check_integration_decay check_integration_prof -ifeq ($(enable_code_coverage), 1) -coverage_unit: check_unit - $(SHELL) $(srcroot)coverage.sh $(srcroot)src jet $(C_JET_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)test/src unit $(C_TESTLIB_UNIT_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)test/unit unit $(TESTS_UNIT_OBJS) - -coverage_integration: check_integration - $(SHELL) $(srcroot)coverage.sh $(srcroot)src pic $(C_PIC_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)src integration $(C_UTIL_INTEGRATION_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)test/src integration $(C_TESTLIB_INTEGRATION_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)test/integration integration $(TESTS_INTEGRATION_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)test/integration/cpp integration $(TESTS_INTEGRATION_CPP_OBJS) - -coverage_stress: stress - $(SHELL) $(srcroot)coverage.sh $(srcroot)src pic $(C_PIC_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)src jet $(C_JET_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)test/src stress $(C_TESTLIB_STRESS_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)test/stress stress $(TESTS_STRESS_OBJS) - -coverage: check - $(SHELL) $(srcroot)coverage.sh $(srcroot)src pic $(C_PIC_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)src jet $(C_JET_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)src integration $(C_UTIL_INTEGRATION_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)test/src unit $(C_TESTLIB_UNIT_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)test/src integration $(C_TESTLIB_INTEGRATION_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)test/src stress $(C_TESTLIB_STRESS_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)test/unit unit $(TESTS_UNIT_OBJS) $(TESTS_UNIT_AUX_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)test/integration integration $(TESTS_INTEGRATION_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)test/integration/cpp integration $(TESTS_INTEGRATION_CPP_OBJS) - $(SHELL) $(srcroot)coverage.sh $(srcroot)test/stress integration $(TESTS_STRESS_OBJS) -endif - clean: rm -f $(C_OBJS) rm -f $(CPP_OBJS) @@ -492,37 +459,20 @@ clean: rm -f $(C_JET_OBJS) rm -f $(C_TESTLIB_OBJS) rm -f $(C_OBJS:%.$(O)=%.d) - rm -f $(C_OBJS:%.$(O)=%.gcda) - rm -f $(C_OBJS:%.$(O)=%.gcno) rm -f $(CPP_OBJS:%.$(O)=%.d) - rm -f $(CPP_OBJS:%.$(O)=%.gcda) - rm -f $(CPP_OBJS:%.$(O)=%.gcno) rm -f $(C_PIC_OBJS:%.$(O)=%.d) - rm -f $(C_PIC_OBJS:%.$(O)=%.gcda) - rm -f $(C_PIC_OBJS:%.$(O)=%.gcno) rm -f $(CPP_PIC_OBJS:%.$(O)=%.d) - rm -f $(CPP_PIC_OBJS:%.$(O)=%.gcda) - rm -f $(CPP_PIC_OBJS:%.$(O)=%.gcno) rm -f $(C_JET_OBJS:%.$(O)=%.d) - rm -f $(C_JET_OBJS:%.$(O)=%.gcda) - rm -f $(C_JET_OBJS:%.$(O)=%.gcno) rm -f $(C_TESTLIB_OBJS:%.$(O)=%.d) - rm -f $(C_TESTLIB_OBJS:%.$(O)=%.gcda) - rm -f $(C_TESTLIB_OBJS:%.$(O)=%.gcno) rm -f $(TESTS_OBJS:%.$(O)=%$(EXE)) rm -f $(TESTS_OBJS) rm -f $(TESTS_OBJS:%.$(O)=%.d) - rm -f $(TESTS_OBJS:%.$(O)=%.gcda) - rm -f $(TESTS_OBJS:%.$(O)=%.gcno) rm -f $(TESTS_OBJS:%.$(O)=%.out) rm -f $(TESTS_CPP_OBJS:%.$(O)=%$(EXE)) rm -f $(TESTS_CPP_OBJS) rm -f $(TESTS_CPP_OBJS:%.$(O)=%.d) - rm -f $(TESTS_CPP_OBJS:%.$(O)=%.gcda) - rm -f $(TESTS_CPP_OBJS:%.$(O)=%.gcno) rm -f $(TESTS_CPP_OBJS:%.$(O)=%.out) rm -f $(DSOS) $(STATIC_LIBS) - rm -f $(objroot)*.gcov.* distclean: clean rm -f $(objroot)bin/jemalloc-config diff --git a/configure.ac b/configure.ac index 2baead74..04952d89 100644 --- a/configure.ac +++ b/configure.ac @@ -783,31 +783,6 @@ AC_CHECK_FUNC([valloc], [AC_DEFINE([JEMALLOC_OVERRIDE_VALLOC], [ ]) public_syms="${public_syms} valloc"]) -dnl Do not compute test code coverage by default. -GCOV_FLAGS= -AC_ARG_ENABLE([code-coverage], - [AS_HELP_STRING([--enable-code-coverage], - [Enable code coverage])], -[if test "x$enable_code_coverage" = "xno" ; then - enable_code_coverage="0" -else - enable_code_coverage="1" -fi -], -[enable_code_coverage="0"] -) -if test "x$enable_code_coverage" = "x1" ; then - deoptimize="no" - echo "$CFLAGS $EXTRA_CFLAGS" | grep '\-O' >/dev/null || deoptimize="yes" - if test "x${deoptimize}" = "xyes" ; then - JE_CFLAGS_ADD([-O0]) - fi - JE_CFLAGS_ADD([-fprofile-arcs -ftest-coverage]) - EXTRA_LDFLAGS="$EXTRA_LDFLAGS -fprofile-arcs -ftest-coverage" - AC_DEFINE([JEMALLOC_CODE_COVERAGE], [ ]) -fi -AC_SUBST([enable_code_coverage]) - dnl Perform no name mangling by default. AC_ARG_WITH([mangling], [AS_HELP_STRING([--with-mangling=], [Mangle symbols in ])], @@ -2093,7 +2068,6 @@ AC_MSG_RESULT([install_suffix : ${install_suffix}]) AC_MSG_RESULT([malloc_conf : ${config_malloc_conf}]) AC_MSG_RESULT([autogen : ${enable_autogen}]) AC_MSG_RESULT([debug : ${enable_debug}]) -AC_MSG_RESULT([code-coverage : ${enable_code_coverage}]) AC_MSG_RESULT([stats : ${enable_stats}]) AC_MSG_RESULT([prof : ${enable_prof}]) AC_MSG_RESULT([prof-libunwind : ${enable_prof_libunwind}]) diff --git a/coverage.sh b/coverage.sh deleted file mode 100755 index 6d1362a8..00000000 --- a/coverage.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -set -e - -objdir=$1 -suffix=$2 -shift 2 -objs=$@ - -gcov -b -p -f -o "${objdir}" ${objs} - -# Move gcov outputs so that subsequent gcov invocations won't clobber results -# for the same sources with different compilation flags. -for f in `find . -maxdepth 1 -type f -name '*.gcov'` ; do - mv "${f}" "${f}.${suffix}" -done diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index dbcbf26a..c22e5302 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -127,9 +127,6 @@ /* Non-empty if the tls_model attribute is supported. */ #undef JEMALLOC_TLS_MODEL -/* JEMALLOC_CODE_COVERAGE enables test code coverage analysis. */ -#undef JEMALLOC_CODE_COVERAGE - /* * JEMALLOC_DEBUG enables assertions and other sanity checks, and disables * inline functions. diff --git a/include/jemalloc/internal/jemalloc_internal_macros.h b/include/jemalloc/internal/jemalloc_internal_macros.h index 317b2ab0..a1712cf5 100644 --- a/include/jemalloc/internal/jemalloc_internal_macros.h +++ b/include/jemalloc/internal/jemalloc_internal_macros.h @@ -1,7 +1,7 @@ #ifndef JEMALLOC_INTERNAL_MACROS_H #define JEMALLOC_INTERNAL_MACROS_H -#if defined(JEMALLOC_DEBUG) || defined(JEMALLOC_CODE_COVERAGE) +#ifdef JEMALLOC_DEBUG # define JEMALLOC_ALWAYS_INLINE static inline #else # define JEMALLOC_ALWAYS_INLINE JEMALLOC_ATTR(always_inline) static inline -- GitLab From c67c3e4a63277718b9d137a38663c6ae324c99aa Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 24 Apr 2017 17:28:55 -0700 Subject: [PATCH 451/544] Replace --disable-munmap with opt.munmap. Control use of munmap(2) via a run-time option rather than a compile-time option (with the same per platform default). The old behavior of --disable-munmap can be achieved with --with-malloc-conf=munmap:false. This partially resolves #580. --- INSTALL | 9 ----- configure.ac | 16 +------- doc/jemalloc.xml.in | 38 ++++++++++++------- include/jemalloc/internal/arena_structs_b.h | 8 ++-- .../jemalloc/internal/extent_mmap_externs.h | 2 + .../internal/jemalloc_internal_defs.h.in | 7 ++-- .../jemalloc/internal/jemalloc_preamble.h.in | 7 ---- src/arena.c | 4 +- src/ctl.c | 6 +-- src/extent.c | 2 +- src/extent_mmap.c | 15 +++++++- src/jemalloc.c | 38 ++++++++----------- src/large.c | 2 +- src/stats.c | 2 +- test/unit/arena_reset.c | 4 +- test/unit/mallctl.c | 2 +- 16 files changed, 77 insertions(+), 85 deletions(-) diff --git a/INSTALL b/INSTALL index 5d0cd21e..abf3290b 100644 --- a/INSTALL +++ b/INSTALL @@ -128,15 +128,6 @@ any of the following arguments (not a definitive list) to 'configure': Statically link against the specified libunwind.a rather than dynamically linking with -lunwind. ---disable-munmap - Disable virtual memory deallocation via munmap(2); instead keep track of - the virtual memory for later use. munmap() is disabled by default (i.e. - --disable-munmap is implied) on [64-bit] Linux, which has a quirk in its - virtual memory allocation algorithm that causes semi-permanent VM map holes - under normal jemalloc operation. Although munmap() causes issues on 32-bit - Linux as well, it is not disabled by default due to the practical - possibility of address space exhaustion. - --disable-fill Disable support for junk/zero filling of memory. See the "opt.junk" and "opt.zero" option documentation for usage details. diff --git a/configure.ac b/configure.ac index 04952d89..6447c51a 100644 --- a/configure.ac +++ b/configure.ac @@ -1086,21 +1086,10 @@ if test "x${maps_coalesce}" = "x1" ; then AC_DEFINE([JEMALLOC_MAPS_COALESCE], [ ]) fi -dnl Enable VM deallocation via munmap() by default. -AC_ARG_ENABLE([munmap], - [AS_HELP_STRING([--disable-munmap], [Disable VM deallocation via munmap(2)])], -[if test "x$enable_munmap" = "xno" ; then - enable_munmap="0" -else - enable_munmap="1" -fi -], -[enable_munmap="${default_munmap}"] -) -if test "x$enable_munmap" = "x1" ; then +dnl Indicate whether to use munmap() by default. +if test "x$default_munmap" = "x1" ; then AC_DEFINE([JEMALLOC_MUNMAP], [ ]) fi -AC_SUBST([enable_munmap]) dnl Enable allocation from DSS if supported by the OS. have_dss="1" @@ -2076,7 +2065,6 @@ AC_MSG_RESULT([prof-gcc : ${enable_prof_gcc}]) AC_MSG_RESULT([fill : ${enable_fill}]) AC_MSG_RESULT([utrace : ${enable_utrace}]) AC_MSG_RESULT([xmalloc : ${enable_xmalloc}]) -AC_MSG_RESULT([munmap : ${enable_munmap}]) AC_MSG_RESULT([lazy_lock : ${enable_lazy_lock}]) AC_MSG_RESULT([cache-oblivious : ${enable_cache_oblivious}]) AC_MSG_RESULT([cxx : ${enable_cxx}]) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 7dace367..66d8e5df 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -788,16 +788,6 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", during build configuration. - - - config.munmap - (bool) - r- - - was specified during - build configuration. - - config.prof @@ -873,6 +863,28 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", + + + opt.munmap + (bool) + r- + + If true, call + munmap + 2 or equivalent rather than + retaining unused virtual memory (see stats.retained for related details). + This option is enabled by default unless it is known to trigger + platform-specific performance problems, e.g. for [64-bit] Linux, which + has a quirk in its virtual memory allocation algorithm that causes + semi-permanent VM map holes under normal jemalloc operation. Although + munmap + 2 causes issues on 32-bit Linux as + well, it is not disabled by default due to the practical possibility of + address space exhaustion. + + + opt.dss @@ -2114,9 +2126,9 @@ struct extent_hooks_s { Total number of bytes in virtual memory mappings that were retained rather than being returned to the operating system via e.g. munmap - 2. Retained virtual memory is - typically untouched, decommitted, or purged, so it has no strongly - associated physical memory (see 2 or similar. Retained virtual + memory is typically untouched, decommitted, or purged, so it has no + strongly associated physical memory (see extent hooks for details). Retained memory is excluded from mapped memory statistics, e.g. stats.mapped. diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index ecc59d3b..6b83e526 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -230,10 +230,10 @@ struct arena_s { /* * Next extent size class in a growing series to use when satisfying a - * request via the extent hooks (only if !config_munmap). This limits - * the number of disjoint virtual memory ranges so that extent merging - * can be effective even if multiple arenas' extent allocation requests - * are highly interleaved. + * request via the extent hooks (only if !opt_munmap). This limits the + * number of disjoint virtual memory ranges so that extent merging can + * be effective even if multiple arenas' extent allocation requests are + * highly interleaved. * * Synchronization: atomic. */ diff --git a/include/jemalloc/internal/extent_mmap_externs.h b/include/jemalloc/internal/extent_mmap_externs.h index 5917b53d..e5bc8110 100644 --- a/include/jemalloc/internal/extent_mmap_externs.h +++ b/include/jemalloc/internal/extent_mmap_externs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_EXTENT_MMAP_EXTERNS_H #define JEMALLOC_INTERNAL_EXTENT_MMAP_EXTERNS_H +extern bool opt_munmap; + void *extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit); bool extent_dalloc_mmap(void *addr, size_t size); diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index c22e5302..8f7c42b8 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -192,9 +192,10 @@ #undef JEMALLOC_MAPS_COALESCE /* - * If defined, use munmap() to unmap freed extents, rather than storing them for - * later reuse. This is disabled by default on Linux because common sequences - * of mmap()/munmap() calls will cause virtual memory map holes. + * If defined, use munmap() to unmap freed extents by default, rather than + * storing them for later reuse. This is disabled on 64-bit Linux because + * common sequences of mmap()/munmap() calls will cause virtual memory map + * holes. */ #undef JEMALLOC_MUNMAP diff --git a/include/jemalloc/internal/jemalloc_preamble.h.in b/include/jemalloc/internal/jemalloc_preamble.h.in index 79827fc4..bc0ca641 100644 --- a/include/jemalloc/internal/jemalloc_preamble.h.in +++ b/include/jemalloc/internal/jemalloc_preamble.h.in @@ -98,13 +98,6 @@ static const bool maps_coalesce = false #endif ; -static const bool config_munmap = -#ifdef JEMALLOC_MUNMAP - true -#else - false -#endif - ; static const bool config_stats = #ifdef JEMALLOC_STATS true diff --git a/src/arena.c b/src/arena.c index 1288b7ba..3b94a20d 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1143,7 +1143,7 @@ arena_destroy_retained(tsdn_t *tsdn, arena_t *arena) { * opportunity to unmap all retained memory without having to keep its * own metadata structures, but if deallocation fails, that is the * application's decision/problem. In practice, retained extents are - * leaked here if !config_munmap unless the application provided custom + * leaked here if !opt_munmap unless the application provided custom * extent hooks, so best practice is to either enable munmap (and avoid * dss for arenas to be destroyed), or provide custom extent hooks that * either unmap retained extents or track them for later use. @@ -1947,7 +1947,7 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { goto label_error; } - if (!config_munmap) { + if (!opt_munmap) { atomic_store_u(&arena->extent_grow_next, psz2ind(HUGEPAGE), ATOMIC_RELAXED); } diff --git a/src/ctl.c b/src/ctl.c index c054ded6..8c2e7bc2 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -66,7 +66,6 @@ CTL_PROTO(config_debug) CTL_PROTO(config_fill) CTL_PROTO(config_lazy_lock) CTL_PROTO(config_malloc_conf) -CTL_PROTO(config_munmap) CTL_PROTO(config_prof) CTL_PROTO(config_prof_libgcc) CTL_PROTO(config_prof_libunwind) @@ -74,6 +73,7 @@ CTL_PROTO(config_stats) CTL_PROTO(config_utrace) CTL_PROTO(config_xmalloc) CTL_PROTO(opt_abort) +CTL_PROTO(opt_munmap) CTL_PROTO(opt_dss) CTL_PROTO(opt_narenas) CTL_PROTO(opt_percpu_arena) @@ -249,7 +249,6 @@ static const ctl_named_node_t config_node[] = { {NAME("fill"), CTL(config_fill)}, {NAME("lazy_lock"), CTL(config_lazy_lock)}, {NAME("malloc_conf"), CTL(config_malloc_conf)}, - {NAME("munmap"), CTL(config_munmap)}, {NAME("prof"), CTL(config_prof)}, {NAME("prof_libgcc"), CTL(config_prof_libgcc)}, {NAME("prof_libunwind"), CTL(config_prof_libunwind)}, @@ -260,6 +259,7 @@ static const ctl_named_node_t config_node[] = { static const ctl_named_node_t opt_node[] = { {NAME("abort"), CTL(opt_abort)}, + {NAME("munmap"), CTL(opt_munmap)}, {NAME("dss"), CTL(opt_dss)}, {NAME("narenas"), CTL(opt_narenas)}, {NAME("percpu_arena"), CTL(opt_percpu_arena)}, @@ -1444,7 +1444,6 @@ CTL_RO_CONFIG_GEN(config_debug, bool) CTL_RO_CONFIG_GEN(config_fill, bool) CTL_RO_CONFIG_GEN(config_lazy_lock, bool) CTL_RO_CONFIG_GEN(config_malloc_conf, const char *) -CTL_RO_CONFIG_GEN(config_munmap, bool) CTL_RO_CONFIG_GEN(config_prof, bool) CTL_RO_CONFIG_GEN(config_prof_libgcc, bool) CTL_RO_CONFIG_GEN(config_prof_libunwind, bool) @@ -1455,6 +1454,7 @@ CTL_RO_CONFIG_GEN(config_xmalloc, bool) /******************************************************************************/ CTL_RO_NL_GEN(opt_abort, opt_abort, bool) +CTL_RO_NL_GEN(opt_munmap, opt_munmap, bool) CTL_RO_NL_GEN(opt_dss, opt_dss, const char *) CTL_RO_NL_GEN(opt_narenas, opt_narenas, unsigned) CTL_RO_NL_GEN(opt_percpu_arena, opt_percpu_arena, const char *) diff --git a/src/extent.c b/src/extent.c index d08ccdb3..1ddaf240 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1123,7 +1123,7 @@ extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, extent_gdump_add(tsdn, extent); } } - if (!config_munmap && extent == NULL) { + if (!opt_munmap && extent == NULL) { extent = extent_grow_retained(tsdn, arena, r_extent_hooks, new_addr, size, pad, alignment, slab, szind, zero, commit); } diff --git a/src/extent_mmap.c b/src/extent_mmap.c index be099373..5fe82ee5 100644 --- a/src/extent_mmap.c +++ b/src/extent_mmap.c @@ -4,6 +4,17 @@ #include "jemalloc/internal/assert.h" +/******************************************************************************/ +/* Data. */ + +bool opt_munmap = +#ifdef JEMALLOC_MUNMAP + true +#else + false +#endif + ; + /******************************************************************************/ void * @@ -23,8 +34,8 @@ extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, bool extent_dalloc_mmap(void *addr, size_t size) { - if (config_munmap) { + if (opt_munmap) { pages_unmap(addr, size); } - return !config_munmap; + return !opt_munmap; } diff --git a/src/jemalloc.c b/src/jemalloc.c index 602cf677..5e1f0a72 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -947,7 +947,7 @@ malloc_conf_init(void) { (sizeof(n)-1 == klen && strncmp(n, k, klen) == 0) #define CONF_MATCH_VALUE(n) \ (sizeof(n)-1 == vlen && strncmp(n, v, vlen) == 0) -#define CONF_HANDLE_BOOL(o, n, cont) \ +#define CONF_HANDLE_BOOL(o, n) \ if (CONF_MATCH(n)) { \ if (CONF_MATCH_VALUE("true")) { \ o = true; \ @@ -958,9 +958,7 @@ malloc_conf_init(void) { "Invalid conf value", \ k, klen, v, vlen); \ } \ - if (cont) { \ - continue; \ - } \ + continue; \ } #define CONF_MIN_no(um, min) false #define CONF_MIN_yes(um, min) ((um) < (min)) @@ -1043,7 +1041,8 @@ malloc_conf_init(void) { continue; \ } - CONF_HANDLE_BOOL(opt_abort, "abort", true) + CONF_HANDLE_BOOL(opt_abort, "abort") + CONF_HANDLE_BOOL(opt_munmap, "munmap") if (strncmp("dss", k, klen) == 0) { int i; bool match = false; @@ -1074,7 +1073,7 @@ malloc_conf_init(void) { "dirty_decay_time", -1, NSTIME_SEC_MAX); CONF_HANDLE_SSIZE_T(opt_muzzy_decay_time, "muzzy_decay_time", -1, NSTIME_SEC_MAX); - CONF_HANDLE_BOOL(opt_stats_print, "stats_print", true) + CONF_HANDLE_BOOL(opt_stats_print, "stats_print") if (config_fill) { if (CONF_MATCH("junk")) { if (CONF_MATCH_VALUE("true")) { @@ -1100,15 +1099,15 @@ malloc_conf_init(void) { } continue; } - CONF_HANDLE_BOOL(opt_zero, "zero", true) + CONF_HANDLE_BOOL(opt_zero, "zero") } if (config_utrace) { - CONF_HANDLE_BOOL(opt_utrace, "utrace", true) + CONF_HANDLE_BOOL(opt_utrace, "utrace") } if (config_xmalloc) { - CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc", true) + CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc") } - CONF_HANDLE_BOOL(opt_tcache, "tcache", true) + CONF_HANDLE_BOOL(opt_tcache, "tcache") CONF_HANDLE_SSIZE_T(opt_lg_tcache_max, "lg_tcache_max", -1, (sizeof(size_t) << 3) - 1) if (strncmp("percpu_arena", k, klen) == 0) { @@ -1136,27 +1135,22 @@ malloc_conf_init(void) { continue; } if (config_prof) { - CONF_HANDLE_BOOL(opt_prof, "prof", true) + CONF_HANDLE_BOOL(opt_prof, "prof") CONF_HANDLE_CHAR_P(opt_prof_prefix, "prof_prefix", "jeprof") - CONF_HANDLE_BOOL(opt_prof_active, "prof_active", - true) + CONF_HANDLE_BOOL(opt_prof_active, "prof_active") CONF_HANDLE_BOOL(opt_prof_thread_active_init, - "prof_thread_active_init", true) + "prof_thread_active_init") CONF_HANDLE_SIZE_T(opt_lg_prof_sample, "lg_prof_sample", 0, (sizeof(uint64_t) << 3) - 1, no, yes, true) - CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum", - true) + CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum") CONF_HANDLE_SSIZE_T(opt_lg_prof_interval, "lg_prof_interval", -1, (sizeof(uint64_t) << 3) - 1) - CONF_HANDLE_BOOL(opt_prof_gdump, "prof_gdump", - true) - CONF_HANDLE_BOOL(opt_prof_final, "prof_final", - true) - CONF_HANDLE_BOOL(opt_prof_leak, "prof_leak", - true) + CONF_HANDLE_BOOL(opt_prof_gdump, "prof_gdump") + CONF_HANDLE_BOOL(opt_prof_final, "prof_final") + CONF_HANDLE_BOOL(opt_prof_leak, "prof_leak") } malloc_conf_error("Invalid conf pair", k, klen, v, vlen); diff --git a/src/large.c b/src/large.c index 36e8be91..4d515fbb 100644 --- a/src/large.c +++ b/src/large.c @@ -93,7 +93,7 @@ large_dalloc_maybe_junk(void *ptr, size_t size) { * Only bother junk filling if the extent isn't about to be * unmapped. */ - if (!config_munmap || (have_dss && extent_in_dss(ptr))) { + if (!opt_munmap || (have_dss && extent_in_dss(ptr))) { large_dalloc_junk(ptr, size); } } diff --git a/src/stats.c b/src/stats.c index 71c9a94d..ca9db89d 100644 --- a/src/stats.c +++ b/src/stats.c @@ -707,7 +707,6 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, "config.malloc_conf: \"%s\"\n", config_malloc_conf); } - CONFIG_WRITE_BOOL_JSON(munmap, ",") CONFIG_WRITE_BOOL_JSON(prof, ",") CONFIG_WRITE_BOOL_JSON(prof_libgcc, ",") CONFIG_WRITE_BOOL_JSON(prof_libunwind, ",") @@ -801,6 +800,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, "Run-time option settings:\n"); } OPT_WRITE_BOOL(abort, ",") + OPT_WRITE_BOOL(munmap, ",") OPT_WRITE_CHAR_P(dss, ",") OPT_WRITE_UNSIGNED(narenas, ",") OPT_WRITE_CHAR_P(percpu_arena, ",") diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 589c652c..0fa240b7 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -251,8 +251,8 @@ TEST_BEGIN(test_arena_destroy_hooks_default) { TEST_END /* - * Actually unmap extents, regardless of config_munmap, so that attempts to - * access a destroyed arena's memory will segfault. + * Actually unmap extents, regardless of opt_munmap, so that attempts to access + * a destroyed arena's memory will segfault. */ static bool extent_dalloc_unmap(extent_hooks_t *extent_hooks, void *addr, size_t size, diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 8afd25ab..51a5244e 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -131,7 +131,6 @@ TEST_BEGIN(test_mallctl_config) { TEST_MALLCTL_CONFIG(fill, bool); TEST_MALLCTL_CONFIG(lazy_lock, bool); TEST_MALLCTL_CONFIG(malloc_conf, const char *); - TEST_MALLCTL_CONFIG(munmap, bool); TEST_MALLCTL_CONFIG(prof, bool); TEST_MALLCTL_CONFIG(prof_libgcc, bool); TEST_MALLCTL_CONFIG(prof_libunwind, bool); @@ -158,6 +157,7 @@ TEST_BEGIN(test_mallctl_opt) { } while (0) TEST_MALLCTL_OPT(bool, abort, always); + TEST_MALLCTL_OPT(bool, munmap, always); TEST_MALLCTL_OPT(const char *, dss, always); TEST_MALLCTL_OPT(unsigned, narenas, always); TEST_MALLCTL_OPT(const char *, percpu_arena, always); -- GitLab From 89e2d3c12b573310e60b97beaf178007a71d83a3 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 24 Apr 2017 17:09:56 -0700 Subject: [PATCH 452/544] Header refactoring: ctl - unify and remove from catchall. In order to do this, we introduce the mutex_prof module, which breaks a circular dependency between ctl and prof. --- include/jemalloc/internal/ctl.h | 130 ++++++++++++++++++ include/jemalloc/internal/ctl_externs.h | 48 ------- include/jemalloc/internal/ctl_structs.h | 85 ------------ include/jemalloc/internal/ctl_types.h | 57 -------- .../internal/jemalloc_internal_includes.h | 3 - include/jemalloc/internal/mutex_prof.h | 84 +++++++++++ include/jemalloc/internal/mutex_structs.h | 34 +---- include/jemalloc/internal/stats.h | 2 +- src/ctl.c | 19 +-- src/jemalloc.c | 1 + src/stats.c | 58 ++++---- 11 files changed, 257 insertions(+), 264 deletions(-) create mode 100644 include/jemalloc/internal/ctl.h delete mode 100644 include/jemalloc/internal/ctl_externs.h delete mode 100644 include/jemalloc/internal/ctl_structs.h delete mode 100644 include/jemalloc/internal/ctl_types.h create mode 100644 include/jemalloc/internal/mutex_prof.h diff --git a/include/jemalloc/internal/ctl.h b/include/jemalloc/internal/ctl.h new file mode 100644 index 00000000..de74a75d --- /dev/null +++ b/include/jemalloc/internal/ctl.h @@ -0,0 +1,130 @@ +#ifndef JEMALLOC_INTERNAL_CTL_H +#define JEMALLOC_INTERNAL_CTL_H + +#include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/malloc_io.h" +#include "jemalloc/internal/mutex_prof.h" +#include "jemalloc/internal/ql.h" +#include "jemalloc/internal/size_classes.h" +#include "jemalloc/internal/stats.h" + +/* Maximum ctl tree depth. */ +#define CTL_MAX_DEPTH 7 + +typedef struct ctl_node_s { + bool named; +} ctl_node_t; + +typedef struct ctl_named_node_s { + ctl_node_t node; + const char *name; + /* If (nchildren == 0), this is a terminal node. */ + size_t nchildren; + const ctl_node_t *children; + int (*ctl)(tsd_t *, const size_t *, size_t, void *, size_t *, void *, + size_t); +} ctl_named_node_t; + +typedef struct ctl_indexed_node_s { + struct ctl_node_s node; + const ctl_named_node_t *(*index)(tsdn_t *, const size_t *, size_t, + size_t); +} ctl_indexed_node_t; + +typedef struct ctl_arena_stats_s { + arena_stats_t astats; + + /* Aggregate stats for small size classes, based on bin stats. */ + size_t allocated_small; + uint64_t nmalloc_small; + uint64_t ndalloc_small; + uint64_t nrequests_small; + + malloc_bin_stats_t bstats[NBINS]; + malloc_large_stats_t lstats[NSIZES - NBINS]; +} ctl_arena_stats_t; + +typedef struct ctl_stats_s { + size_t allocated; + size_t active; + size_t metadata; + size_t resident; + size_t mapped; + size_t retained; + + mutex_prof_data_t mutex_prof_data[mutex_prof_num_global_mutexes]; +} ctl_stats_t; + +typedef struct ctl_arena_s ctl_arena_t; +struct ctl_arena_s { + unsigned arena_ind; + bool initialized; + ql_elm(ctl_arena_t) destroyed_link; + + /* Basic stats, supported even if !config_stats. */ + unsigned nthreads; + const char *dss; + ssize_t dirty_decay_time; + ssize_t muzzy_decay_time; + size_t pactive; + size_t pdirty; + size_t pmuzzy; + + /* NULL if !config_stats. */ + ctl_arena_stats_t *astats; +}; + +typedef struct ctl_arenas_s { + uint64_t epoch; + unsigned narenas; + ql_head(ctl_arena_t) destroyed; + + /* + * Element 0 corresponds to merged stats for extant arenas (accessed via + * MALLCTL_ARENAS_ALL), element 1 corresponds to merged stats for + * destroyed arenas (accessed via MALLCTL_ARENAS_DESTROYED), and the + * remaining MALLOCX_ARENA_MAX+1 elements correspond to arenas. + */ + ctl_arena_t *arenas[MALLOCX_ARENA_MAX + 3]; +} ctl_arenas_t; + +int ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp, + void *newp, size_t newlen); +int ctl_nametomib(tsdn_t *tsdn, const char *name, size_t *mibp, + size_t *miblenp); + +int ctl_bymib(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, + size_t *oldlenp, void *newp, size_t newlen); +bool ctl_boot(void); +void ctl_prefork(tsdn_t *tsdn); +void ctl_postfork_parent(tsdn_t *tsdn); +void ctl_postfork_child(tsdn_t *tsdn); + +#define xmallctl(name, oldp, oldlenp, newp, newlen) do { \ + if (je_mallctl(name, oldp, oldlenp, newp, newlen) \ + != 0) { \ + malloc_printf( \ + ": Failure in xmallctl(\"%s\", ...)\n", \ + name); \ + abort(); \ + } \ +} while (0) + +#define xmallctlnametomib(name, mibp, miblenp) do { \ + if (je_mallctlnametomib(name, mibp, miblenp) != 0) { \ + malloc_printf(": Failure in " \ + "xmallctlnametomib(\"%s\", ...)\n", name); \ + abort(); \ + } \ +} while (0) + +#define xmallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) do { \ + if (je_mallctlbymib(mib, miblen, oldp, oldlenp, newp, \ + newlen) != 0) { \ + malloc_write( \ + ": Failure in xmallctlbymib()\n"); \ + abort(); \ + } \ +} while (0) + +#endif /* JEMALLOC_INTERNAL_CTL_H */ diff --git a/include/jemalloc/internal/ctl_externs.h b/include/jemalloc/internal/ctl_externs.h deleted file mode 100644 index 875a8101..00000000 --- a/include/jemalloc/internal/ctl_externs.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_CTL_EXTERNS_H -#define JEMALLOC_INTERNAL_CTL_EXTERNS_H - -#include "jemalloc/internal/malloc_io.h" - -/* Maximum ctl tree depth. */ -#define CTL_MAX_DEPTH 7 - -int ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp, - void *newp, size_t newlen); -int ctl_nametomib(tsdn_t *tsdn, const char *name, size_t *mibp, - size_t *miblenp); - -int ctl_bymib(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, - size_t *oldlenp, void *newp, size_t newlen); -bool ctl_boot(void); -void ctl_prefork(tsdn_t *tsdn); -void ctl_postfork_parent(tsdn_t *tsdn); -void ctl_postfork_child(tsdn_t *tsdn); - -#define xmallctl(name, oldp, oldlenp, newp, newlen) do { \ - if (je_mallctl(name, oldp, oldlenp, newp, newlen) \ - != 0) { \ - malloc_printf( \ - ": Failure in xmallctl(\"%s\", ...)\n", \ - name); \ - abort(); \ - } \ -} while (0) - -#define xmallctlnametomib(name, mibp, miblenp) do { \ - if (je_mallctlnametomib(name, mibp, miblenp) != 0) { \ - malloc_printf(": Failure in " \ - "xmallctlnametomib(\"%s\", ...)\n", name); \ - abort(); \ - } \ -} while (0) - -#define xmallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) do { \ - if (je_mallctlbymib(mib, miblen, oldp, oldlenp, newp, \ - newlen) != 0) { \ - malloc_write( \ - ": Failure in xmallctlbymib()\n"); \ - abort(); \ - } \ -} while (0) - -#endif /* JEMALLOC_INTERNAL_CTL_EXTERNS_H */ diff --git a/include/jemalloc/internal/ctl_structs.h b/include/jemalloc/internal/ctl_structs.h deleted file mode 100644 index c64820d2..00000000 --- a/include/jemalloc/internal/ctl_structs.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_CTL_STRUCTS_H -#define JEMALLOC_INTERNAL_CTL_STRUCTS_H - -#include "jemalloc/internal/jemalloc_internal_types.h" -#include "jemalloc/internal/ql.h" -#include "jemalloc/internal/size_classes.h" -#include "jemalloc/internal/stats.h" - -struct ctl_node_s { - bool named; -}; - -struct ctl_named_node_s { - struct ctl_node_s node; - const char *name; - /* If (nchildren == 0), this is a terminal node. */ - size_t nchildren; - const ctl_node_t *children; - int (*ctl)(tsd_t *, const size_t *, size_t, void *, - size_t *, void *, size_t); -}; - -struct ctl_indexed_node_s { - struct ctl_node_s node; - const ctl_named_node_t *(*index)(tsdn_t *, const size_t *, size_t, - size_t); -}; - -struct ctl_arena_stats_s { - arena_stats_t astats; - - /* Aggregate stats for small size classes, based on bin stats. */ - size_t allocated_small; - uint64_t nmalloc_small; - uint64_t ndalloc_small; - uint64_t nrequests_small; - - malloc_bin_stats_t bstats[NBINS]; - malloc_large_stats_t lstats[NSIZES - NBINS]; -}; - -struct ctl_stats_s { - size_t allocated; - size_t active; - size_t metadata; - size_t resident; - size_t mapped; - size_t retained; - - mutex_prof_data_t mutex_prof_data[num_global_prof_mutexes]; -}; - -struct ctl_arena_s { - unsigned arena_ind; - bool initialized; - ql_elm(ctl_arena_t) destroyed_link; - - /* Basic stats, supported even if !config_stats. */ - unsigned nthreads; - const char *dss; - ssize_t dirty_decay_time; - ssize_t muzzy_decay_time; - size_t pactive; - size_t pdirty; - size_t pmuzzy; - - /* NULL if !config_stats. */ - ctl_arena_stats_t *astats; -}; - -struct ctl_arenas_s { - uint64_t epoch; - unsigned narenas; - ql_head(ctl_arena_t) destroyed; - - /* - * Element 0 corresponds to merged stats for extant arenas (accessed via - * MALLCTL_ARENAS_ALL), element 1 corresponds to merged stats for - * destroyed arenas (accessed via MALLCTL_ARENAS_DESTROYED), and the - * remaining MALLOCX_ARENA_MAX+1 elements correspond to arenas. - */ - ctl_arena_t *arenas[MALLOCX_ARENA_MAX + 3]; -}; - -#endif /* JEMALLOC_INTERNAL_CTL_STRUCTS_H */ diff --git a/include/jemalloc/internal/ctl_types.h b/include/jemalloc/internal/ctl_types.h deleted file mode 100644 index e7986092..00000000 --- a/include/jemalloc/internal/ctl_types.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_CTL_TYPES_H -#define JEMALLOC_INTERNAL_CTL_TYPES_H - -#define GLOBAL_PROF_MUTEXES \ - OP(ctl) \ - OP(prof) - -typedef enum { -#define OP(mtx) global_prof_mutex_##mtx, - GLOBAL_PROF_MUTEXES -#undef OP - num_global_prof_mutexes -} global_prof_mutex_ind_t; - -#define ARENA_PROF_MUTEXES \ - OP(large) \ - OP(extent_avail) \ - OP(extents_dirty) \ - OP(extents_muzzy) \ - OP(extents_retained) \ - OP(decay_dirty) \ - OP(decay_muzzy) \ - OP(base) \ - OP(tcache_list) - -typedef enum { -#define OP(mtx) arena_prof_mutex_##mtx, - ARENA_PROF_MUTEXES -#undef OP - num_arena_prof_mutexes -} arena_prof_mutex_ind_t; - -#define MUTEX_PROF_COUNTERS \ - OP(num_ops, uint64_t) \ - OP(num_wait, uint64_t) \ - OP(num_spin_acq, uint64_t) \ - OP(num_owner_switch, uint64_t) \ - OP(total_wait_time, uint64_t) \ - OP(max_wait_time, uint64_t) \ - OP(max_num_thds, uint32_t) - -typedef enum { -#define OP(counter, type) mutex_counter_##counter, - MUTEX_PROF_COUNTERS -#undef OP - num_mutex_prof_counters -} mutex_prof_counter_ind_t; - -typedef struct ctl_node_s ctl_node_t; -typedef struct ctl_named_node_s ctl_named_node_t; -typedef struct ctl_indexed_node_s ctl_indexed_node_t; -typedef struct ctl_arena_stats_s ctl_arena_stats_t; -typedef struct ctl_stats_s ctl_stats_t; -typedef struct ctl_arena_s ctl_arena_t; -typedef struct ctl_arenas_s ctl_arenas_t; - -#endif /* JEMALLOC_INTERNAL_CTL_TYPES_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index f98a1b27..9000841e 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -40,7 +40,6 @@ /* TYPES */ /******************************************************************************/ -#include "jemalloc/internal/ctl_types.h" #include "jemalloc/internal/witness_types.h" #include "jemalloc/internal/mutex_types.h" #include "jemalloc/internal/tsd_types.h" @@ -59,7 +58,6 @@ #include "jemalloc/internal/witness_structs.h" #include "jemalloc/internal/mutex_structs.h" -#include "jemalloc/internal/ctl_structs.h" #include "jemalloc/internal/arena_structs_a.h" #include "jemalloc/internal/extent_structs.h" #include "jemalloc/internal/extent_dss_structs.h" @@ -75,7 +73,6 @@ /******************************************************************************/ #include "jemalloc/internal/jemalloc_internal_externs.h" -#include "jemalloc/internal/ctl_externs.h" #include "jemalloc/internal/witness_externs.h" #include "jemalloc/internal/mutex_externs.h" #include "jemalloc/internal/extent_externs.h" diff --git a/include/jemalloc/internal/mutex_prof.h b/include/jemalloc/internal/mutex_prof.h new file mode 100644 index 00000000..50c0af0a --- /dev/null +++ b/include/jemalloc/internal/mutex_prof.h @@ -0,0 +1,84 @@ +#ifndef JEMALLOC_INTERNAL_MUTEX_PROF_H +#define JEMALLOC_INTERNAL_MUTEX_PROF_H + +#include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/nstime.h" + +#define MUTEX_PROF_GLOBAL_MUTEXES \ + OP(ctl) \ + OP(prof) + +typedef enum { +#define OP(mtx) global_prof_mutex_##mtx, + MUTEX_PROF_GLOBAL_MUTEXES +#undef OP + mutex_prof_num_global_mutexes +} mutex_prof_global_ind_t; + +#define MUTEX_PROF_ARENA_MUTEXES \ + OP(large) \ + OP(extent_avail) \ + OP(extents_dirty) \ + OP(extents_muzzy) \ + OP(extents_retained) \ + OP(decay_dirty) \ + OP(decay_muzzy) \ + OP(base) \ + OP(tcache_list) + +typedef enum { +#define OP(mtx) arena_prof_mutex_##mtx, + MUTEX_PROF_ARENA_MUTEXES +#undef OP + mutex_prof_num_arena_mutexes +} mutex_prof_arena_ind_t; + +#define MUTEX_PROF_COUNTERS \ + OP(num_ops, uint64_t) \ + OP(num_wait, uint64_t) \ + OP(num_spin_acq, uint64_t) \ + OP(num_owner_switch, uint64_t) \ + OP(total_wait_time, uint64_t) \ + OP(max_wait_time, uint64_t) \ + OP(max_num_thds, uint32_t) + +typedef enum { +#define OP(counter, type) mutex_counter_##counter, + MUTEX_PROF_COUNTERS +#undef OP + mutex_prof_num_counters +} mutex_prof_counter_ind_t; + +typedef struct mutex_prof_data_s { + /* + * Counters touched on the slow path, i.e. when there is lock + * contention. We update them once we have the lock. + */ + /* Total time (in nano seconds) spent waiting on this mutex. */ + nstime_t tot_wait_time; + /* Max time (in nano seconds) spent on a single lock operation. */ + nstime_t max_wait_time; + /* # of times have to wait for this mutex (after spinning). */ + uint64_t n_wait_times; + /* # of times acquired the mutex through local spinning. */ + uint64_t n_spin_acquired; + /* Max # of threads waiting for the mutex at the same time. */ + uint32_t max_n_thds; + /* Current # of threads waiting on the lock. Atomic synced. */ + atomic_u32_t n_waiting_thds; + + /* + * Data touched on the fast path. These are modified right after we + * grab the lock, so it's placed closest to the end (i.e. right before + * the lock) so that we have a higher chance of them being on the same + * cacheline. + */ + /* # of times the mutex holder is different than the previous one. */ + uint64_t n_owner_switches; + /* Previous mutex holder, to facilitate n_owner_switches. */ + tsdn_t *prev_owner; + /* # of lock() operations in total. */ + uint64_t n_lock_ops; +} mutex_prof_data_t; + +#endif /* JEMALLOC_INTERNAL_MUTEX_PROF_H */ diff --git a/include/jemalloc/internal/mutex_structs.h b/include/jemalloc/internal/mutex_structs.h index dc755547..2691852d 100644 --- a/include/jemalloc/internal/mutex_structs.h +++ b/include/jemalloc/internal/mutex_structs.h @@ -2,39 +2,7 @@ #define JEMALLOC_INTERNAL_MUTEX_STRUCTS_H #include "jemalloc/internal/atomic.h" -#include "jemalloc/internal/nstime.h" - -struct mutex_prof_data_s { - /* - * Counters touched on the slow path, i.e. when there is lock - * contention. We update them once we have the lock. - */ - /* Total time (in nano seconds) spent waiting on this mutex. */ - nstime_t tot_wait_time; - /* Max time (in nano seconds) spent on a single lock operation. */ - nstime_t max_wait_time; - /* # of times have to wait for this mutex (after spinning). */ - uint64_t n_wait_times; - /* # of times acquired the mutex through local spinning. */ - uint64_t n_spin_acquired; - /* Max # of threads waiting for the mutex at the same time. */ - uint32_t max_n_thds; - /* Current # of threads waiting on the lock. Atomic synced. */ - atomic_u32_t n_waiting_thds; - - /* - * Data touched on the fast path. These are modified right after we - * grab the lock, so it's placed closest to the end (i.e. right before - * the lock) so that we have a higher chance of them being on the same - * cacheline. - */ - /* # of times the mutex holder is different than the previous one. */ - uint64_t n_owner_switches; - /* Previous mutex holder, to facilitate n_owner_switches. */ - tsdn_t *prev_owner; - /* # of lock() operations in total. */ - uint64_t n_lock_ops; -}; +#include "jemalloc/internal/mutex_prof.h" struct malloc_mutex_s { union { diff --git a/include/jemalloc/internal/stats.h b/include/jemalloc/internal/stats.h index 9414200f..301a50ab 100644 --- a/include/jemalloc/internal/stats.h +++ b/include/jemalloc/internal/stats.h @@ -139,7 +139,7 @@ typedef struct arena_stats_s { /* Number of bytes cached in tcache associated with this arena. */ atomic_zu_t tcache_bytes; /* Derived. */ - mutex_prof_data_t mutex_prof_data[num_arena_prof_mutexes]; + mutex_prof_data_t mutex_prof_data[mutex_prof_num_arena_mutexes]; /* One element for each large size class. */ malloc_large_stats_t lstats[NSIZES - NBINS]; diff --git a/src/ctl.c b/src/ctl.c index 8c2e7bc2..3591f891 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/ctl.h" #include "jemalloc/internal/nstime.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/util.h" @@ -193,12 +194,12 @@ CTL_PROTO(stats_##n##_max_num_thds) /* Global mutexes. */ #define OP(mtx) MUTEX_STATS_CTL_PROTO_GEN(mutexes_##mtx) -GLOBAL_PROF_MUTEXES +MUTEX_PROF_GLOBAL_MUTEXES #undef OP /* Per arena mutexes. */ #define OP(mtx) MUTEX_STATS_CTL_PROTO_GEN(arenas_i_mutexes_##mtx) -ARENA_PROF_MUTEXES +MUTEX_PROF_ARENA_MUTEXES #undef OP /* Arena bin mutexes. */ @@ -429,12 +430,12 @@ static const ctl_indexed_node_t stats_arenas_i_lextents_node[] = { }; #define OP(mtx) MUTEX_PROF_DATA_NODE(arenas_i_mutexes_##mtx) -ARENA_PROF_MUTEXES +MUTEX_PROF_ARENA_MUTEXES #undef OP static const ctl_named_node_t stats_arenas_i_mutexes_node[] = { #define OP(mtx) {NAME(#mtx), CHILD(named, stats_arenas_i_mutexes_##mtx)}, -ARENA_PROF_MUTEXES +MUTEX_PROF_ARENA_MUTEXES #undef OP }; @@ -473,12 +474,12 @@ static const ctl_indexed_node_t stats_arenas_node[] = { }; #define OP(mtx) MUTEX_PROF_DATA_NODE(mutexes_##mtx) -GLOBAL_PROF_MUTEXES +MUTEX_PROF_GLOBAL_MUTEXES #undef OP static const ctl_named_node_t stats_mutexes_node[] = { #define OP(mtx) {NAME(#mtx), CHILD(named, stats_mutexes_##mtx)}, -GLOBAL_PROF_MUTEXES +MUTEX_PROF_GLOBAL_MUTEXES #undef OP {NAME("reset"), CTL(stats_mutexes_reset)} }; @@ -737,7 +738,7 @@ ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena, arena_prof_mutex_##mtx]), \ &(astats->astats.mutex_prof_data[ \ arena_prof_mutex_##mtx])); -ARENA_PROF_MUTEXES +MUTEX_PROF_ARENA_MUTEXES #undef OP if (!destroyed) { accum_atomic_zu(&sdstats->astats.base, @@ -2401,13 +2402,13 @@ CTL_RO_CGEN(config_stats, stats_##n##_max_num_thds, \ #define OP(mtx) \ RO_MUTEX_CTL_GEN(mutexes_##mtx, \ ctl_stats->mutex_prof_data[global_prof_mutex_##mtx]) -GLOBAL_PROF_MUTEXES +MUTEX_PROF_GLOBAL_MUTEXES #undef OP /* Per arena mutexes */ #define OP(mtx) RO_MUTEX_CTL_GEN(arenas_i_mutexes_##mtx, \ arenas_i(mib[2])->astats->astats.mutex_prof_data[arena_prof_mutex_##mtx]) -ARENA_PROF_MUTEXES +MUTEX_PROF_ARENA_MUTEXES #undef OP /* tcache bin mutex */ diff --git a/src/jemalloc.c b/src/jemalloc.c index 5e1f0a72..42146004 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/ctl.h" #include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/malloc_io.h" #include "jemalloc/internal/size_classes.h" diff --git a/src/stats.c b/src/stats.c index ca9db89d..5d515186 100644 --- a/src/stats.c +++ b/src/stats.c @@ -3,16 +3,18 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/ctl.h" +#include "jemalloc/internal/mutex_prof.h" -const char *global_mutex_names[num_global_prof_mutexes] = { +const char *global_mutex_names[mutex_prof_num_global_mutexes] = { #define OP(mtx) #mtx, - GLOBAL_PROF_MUTEXES + MUTEX_PROF_GLOBAL_MUTEXES #undef OP }; -const char *arena_mutex_names[num_arena_prof_mutexes] = { +const char *arena_mutex_names[mutex_prof_num_arena_mutexes] = { #define OP(mtx) #mtx, - ARENA_PROF_MUTEXES + MUTEX_PROF_ARENA_MUTEXES #undef OP }; @@ -81,7 +83,7 @@ gen_mutex_ctl_str(char *str, size_t buf_len, const char *prefix, static void read_arena_bin_mutex_stats(unsigned arena_ind, unsigned bin_ind, - uint64_t results[num_mutex_prof_counters]) { + uint64_t results[mutex_prof_num_counters]) { char cmd[MUTEX_CTL_STR_MAX_LENGTH]; #define OP(c, t) \ gen_mutex_ctl_str(cmd, MUTEX_CTL_STR_MAX_LENGTH, \ @@ -94,7 +96,7 @@ MUTEX_PROF_COUNTERS static void mutex_stats_output_json(void (*write_cb)(void *, const char *), void *cbopaque, - const char *name, uint64_t stats[num_mutex_prof_counters], + const char *name, uint64_t stats[mutex_prof_num_counters], const char *json_indent, bool last) { malloc_cprintf(write_cb, cbopaque, "%s\"%s\": {\n", json_indent, name); @@ -105,7 +107,7 @@ mutex_stats_output_json(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, \ fmt_str[sizeof(t) / sizeof(uint32_t) - 1], \ json_indent, #c, (t)stats[mutex_counter_##c], \ - (++k == num_mutex_prof_counters) ? "" : ","); + (++k == mutex_prof_num_counters) ? "" : ","); MUTEX_PROF_COUNTERS #undef OP malloc_cprintf(write_cb, cbopaque, "%s}%s\n", json_indent, @@ -187,7 +189,7 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, nmalloc, ndalloc, curregs, nrequests, nfills, nflushes, nreslabs, curslabs, mutex ? "," : ""); if (mutex) { - uint64_t mutex_stats[num_mutex_prof_counters]; + uint64_t mutex_stats[mutex_prof_num_counters]; read_arena_bin_mutex_stats(i, j, mutex_stats); mutex_stats_output_json(write_cb, cbopaque, "mutex", mutex_stats, "\t\t\t\t\t\t", true); @@ -226,7 +228,7 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, &max_wait, uint64_t); CTL_M2_M4_GET("stats.arenas.0.bins.0.mutex.num_ops", i, j, &num_ops, uint64_t); - uint64_t mutex_stats[num_mutex_prof_counters]; + uint64_t mutex_stats[mutex_prof_num_counters]; if (mutex) { read_arena_bin_mutex_stats(i, j, mutex_stats); } @@ -336,11 +338,11 @@ stats_arena_lextents_print(void (*write_cb)(void *, const char *), static void read_arena_mutex_stats(unsigned arena_ind, - uint64_t results[num_arena_prof_mutexes][num_mutex_prof_counters]) { + uint64_t results[mutex_prof_num_arena_mutexes][mutex_prof_num_counters]) { char cmd[MUTEX_CTL_STR_MAX_LENGTH]; - arena_prof_mutex_ind_t i; - for (i = 0; i < num_arena_prof_mutexes; i++) { + mutex_prof_arena_ind_t i; + for (i = 0; i < mutex_prof_num_arena_mutexes; i++) { #define OP(c, t) \ gen_mutex_ctl_str(cmd, MUTEX_CTL_STR_MAX_LENGTH, \ "arenas.0.mutexes", arena_mutex_names[i], #c); \ @@ -353,7 +355,7 @@ MUTEX_PROF_COUNTERS static void mutex_stats_output(void (*write_cb)(void *, const char *), void *cbopaque, - const char *name, uint64_t stats[num_mutex_prof_counters], + const char *name, uint64_t stats[mutex_prof_num_counters], bool first_mutex) { if (first_mutex) { /* Print title. */ @@ -380,15 +382,15 @@ MUTEX_PROF_COUNTERS static void stats_arena_mutexes_print(void (*write_cb)(void *, const char *), void *cbopaque, bool json, bool json_end, unsigned arena_ind) { - uint64_t mutex_stats[num_arena_prof_mutexes][num_mutex_prof_counters]; + uint64_t mutex_stats[mutex_prof_num_arena_mutexes][mutex_prof_num_counters]; read_arena_mutex_stats(arena_ind, mutex_stats); /* Output mutex stats. */ if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\"mutexes\": {\n"); - arena_prof_mutex_ind_t i, last_mutex; - last_mutex = num_arena_prof_mutexes - 1; - for (i = 0; i < num_arena_prof_mutexes; i++) { + mutex_prof_arena_ind_t i, last_mutex; + last_mutex = mutex_prof_num_arena_mutexes - 1; + for (i = 0; i < mutex_prof_num_arena_mutexes; i++) { mutex_stats_output_json(write_cb, cbopaque, arena_mutex_names[i], mutex_stats[i], "\t\t\t\t\t", (i == last_mutex)); @@ -396,8 +398,8 @@ stats_arena_mutexes_print(void (*write_cb)(void *, const char *), malloc_cprintf(write_cb, cbopaque, "\t\t\t\t}%s\n", json_end ? "" : ","); } else { - arena_prof_mutex_ind_t i; - for (i = 0; i < num_arena_prof_mutexes; i++) { + mutex_prof_arena_ind_t i; + for (i = 0; i < mutex_prof_num_arena_mutexes; i++) { mutex_stats_output(write_cb, cbopaque, arena_mutex_names[i], mutex_stats[i], i == 0); } @@ -993,11 +995,11 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, static void read_global_mutex_stats( - uint64_t results[num_global_prof_mutexes][num_mutex_prof_counters]) { + uint64_t results[mutex_prof_num_global_mutexes][mutex_prof_num_counters]) { char cmd[MUTEX_CTL_STR_MAX_LENGTH]; - global_prof_mutex_ind_t i; - for (i = 0; i < num_global_prof_mutexes; i++) { + mutex_prof_global_ind_t i; + for (i = 0; i < mutex_prof_num_global_mutexes; i++) { #define OP(c, t) \ gen_mutex_ctl_str(cmd, MUTEX_CTL_STR_MAX_LENGTH, \ "mutexes", global_mutex_names[i], #c); \ @@ -1020,7 +1022,7 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, CTL_GET("stats.mapped", &mapped, size_t); CTL_GET("stats.retained", &retained, size_t); - uint64_t mutex_stats[num_global_prof_mutexes][num_mutex_prof_counters]; + uint64_t mutex_stats[mutex_prof_num_global_mutexes][mutex_prof_num_counters]; if (mutex) { read_global_mutex_stats(mutex_stats); } @@ -1044,12 +1046,12 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, if (mutex) { malloc_cprintf(write_cb, cbopaque, "\t\t\t\"mutexes\": {\n"); - global_prof_mutex_ind_t i; - for (i = 0; i < num_global_prof_mutexes; i++) { + mutex_prof_global_ind_t i; + for (i = 0; i < mutex_prof_num_global_mutexes; i++) { mutex_stats_output_json(write_cb, cbopaque, global_mutex_names[i], mutex_stats[i], "\t\t\t\t", - i == num_global_prof_mutexes - 1); + i == mutex_prof_num_global_mutexes - 1); } malloc_cprintf(write_cb, cbopaque, "\t\t\t}\n"); } @@ -1061,8 +1063,8 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, " resident: %zu, mapped: %zu, retained: %zu\n", allocated, active, metadata, resident, mapped, retained); if (mutex) { - global_prof_mutex_ind_t i; - for (i = 0; i < num_global_prof_mutexes; i++) { + mutex_prof_global_ind_t i; + for (i = 0; i < mutex_prof_num_global_mutexes; i++) { mutex_stats_output(write_cb, cbopaque, global_mutex_names[i], mutex_stats[i], i == 0); -- GitLab From dab4beb277f5fd82dd0f66324bb9a2c7458afe1c Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 24 Apr 2017 17:16:36 -0700 Subject: [PATCH 453/544] Header refactoring: hash - unify and remove from catchall. --- include/jemalloc/internal/{hash_inlines.h => hash.h} | 6 +++--- include/jemalloc/internal/jemalloc_internal_includes.h | 1 - src/ckh.c | 1 + src/prof.c | 1 + test/unit/hash.c | 1 + 5 files changed, 6 insertions(+), 4 deletions(-) rename include/jemalloc/internal/{hash_inlines.h => hash.h} (98%) diff --git a/include/jemalloc/internal/hash_inlines.h b/include/jemalloc/internal/hash.h similarity index 98% rename from include/jemalloc/internal/hash_inlines.h rename to include/jemalloc/internal/hash.h index 2cd7e3ee..188296cf 100644 --- a/include/jemalloc/internal/hash_inlines.h +++ b/include/jemalloc/internal/hash.h @@ -1,5 +1,5 @@ -#ifndef JEMALLOC_INTERNAL_HASH_INLINES_H -#define JEMALLOC_INTERNAL_HASH_INLINES_H +#ifndef JEMALLOC_INTERNAL_HASH_H +#define JEMALLOC_INTERNAL_HASH_H #include "jemalloc/internal/assert.h" @@ -315,4 +315,4 @@ hash(const void *key, size_t len, const uint32_t seed, size_t r_hash[2]) { #endif } -#endif /* JEMALLOC_INTERNAL_HASH_INLINES_H */ +#endif /* JEMALLOC_INTERNAL_HASH_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 9000841e..fb4105f0 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -107,7 +107,6 @@ #include "jemalloc/internal/jemalloc_internal_inlines_b.h" #include "jemalloc/internal/tcache_inlines.h" #include "jemalloc/internal/arena_inlines_b.h" -#include "jemalloc/internal/hash_inlines.h" #include "jemalloc/internal/jemalloc_internal_inlines_c.h" #include "jemalloc/internal/prof_inlines_b.h" diff --git a/src/ckh.c b/src/ckh.c index 8f0bac07..013b6249 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -42,6 +42,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/hash.h" #include "jemalloc/internal/malloc_io.h" #include "jemalloc/internal/prng.h" #include "jemalloc/internal/util.h" diff --git a/src/prof.c b/src/prof.c index a8f6aed2..a872afb1 100644 --- a/src/prof.c +++ b/src/prof.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/ckh.h" +#include "jemalloc/internal/hash.h" #include "jemalloc/internal/malloc_io.h" /******************************************************************************/ diff --git a/test/unit/hash.c b/test/unit/hash.c index 48507515..7cc034f8 100644 --- a/test/unit/hash.c +++ b/test/unit/hash.c @@ -28,6 +28,7 @@ */ #include "test/jemalloc_test.h" +#include "jemalloc/internal/hash.h" typedef enum { hash_variant_x86_32, -- GitLab From 268843ac680f688582044621434221bedf78719b Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 24 Apr 2017 18:05:15 -0700 Subject: [PATCH 454/544] Header refactoring: pages.h - unify and remove from catchall. --- include/jemalloc/internal/arena_externs.h | 1 + include/jemalloc/internal/extent_inlines.h | 1 + .../internal/jemalloc_internal_includes.h | 2 -- .../internal/{pages_types.h => pages.h} | 31 +++++++++++++++++-- include/jemalloc/internal/pages_externs.h | 29 ----------------- src/pages.c | 3 ++ 6 files changed, 33 insertions(+), 34 deletions(-) rename include/jemalloc/internal/{pages_types.h => pages.h} (68%) delete mode 100644 include/jemalloc/internal/pages_externs.h diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 1e13efd3..7d56e44b 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -1,6 +1,7 @@ #ifndef JEMALLOC_INTERNAL_ARENA_EXTERNS_H #define JEMALLOC_INTERNAL_ARENA_EXTERNS_H +#include "jemalloc/internal/pages.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/stats.h" diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index a73b6530..e1f8bd9e 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -1,6 +1,7 @@ #ifndef JEMALLOC_INTERNAL_EXTENT_INLINES_H #define JEMALLOC_INTERNAL_EXTENT_INLINES_H +#include "jemalloc/internal/pages.h" #include "jemalloc/internal/prng.h" #include "jemalloc/internal/ql.h" diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index fb4105f0..340cb1ce 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -48,7 +48,6 @@ #include "jemalloc/internal/base_types.h" #include "jemalloc/internal/arena_types.h" #include "jemalloc/internal/rtree_types.h" -#include "jemalloc/internal/pages_types.h" #include "jemalloc/internal/tcache_types.h" #include "jemalloc/internal/prof_types.h" @@ -81,7 +80,6 @@ #include "jemalloc/internal/base_externs.h" #include "jemalloc/internal/arena_externs.h" #include "jemalloc/internal/rtree_externs.h" -#include "jemalloc/internal/pages_externs.h" #include "jemalloc/internal/large_externs.h" #include "jemalloc/internal/tcache_externs.h" #include "jemalloc/internal/prof_externs.h" diff --git a/include/jemalloc/internal/pages_types.h b/include/jemalloc/internal/pages.h similarity index 68% rename from include/jemalloc/internal/pages_types.h rename to include/jemalloc/internal/pages.h index e44ee2a4..28383b7f 100644 --- a/include/jemalloc/internal/pages_types.h +++ b/include/jemalloc/internal/pages.h @@ -1,5 +1,5 @@ -#ifndef JEMALLOC_INTERNAL_PAGES_TYPES_H -#define JEMALLOC_INTERNAL_PAGES_TYPES_H +#ifndef JEMALLOC_INTERNAL_PAGES_EXTERNS_H +#define JEMALLOC_INTERNAL_PAGES_EXTERNS_H /* Page size. LG_PAGE is determined by the configure script. */ #ifdef PAGE_MASK @@ -43,4 +43,29 @@ # define PAGES_CAN_PURGE_FORCED #endif -#endif /* JEMALLOC_INTERNAL_PAGES_TYPES_H */ +static const bool pages_can_purge_lazy = +#ifdef PAGES_CAN_PURGE_LAZY + true +#else + false +#endif + ; +static const bool pages_can_purge_forced = +#ifdef PAGES_CAN_PURGE_FORCED + true +#else + false +#endif + ; + +void *pages_map(void *addr, size_t size, size_t alignment, bool *commit); +void pages_unmap(void *addr, size_t size); +bool pages_commit(void *addr, size_t size); +bool pages_decommit(void *addr, size_t size); +bool pages_purge_lazy(void *addr, size_t size); +bool pages_purge_forced(void *addr, size_t size); +bool pages_huge(void *addr, size_t size); +bool pages_nohuge(void *addr, size_t size); +bool pages_boot(void); + +#endif /* JEMALLOC_INTERNAL_PAGES_EXTERNS_H */ diff --git a/include/jemalloc/internal/pages_externs.h b/include/jemalloc/internal/pages_externs.h deleted file mode 100644 index af9a01b8..00000000 --- a/include/jemalloc/internal/pages_externs.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_PAGES_EXTERNS_H -#define JEMALLOC_INTERNAL_PAGES_EXTERNS_H - -static const bool pages_can_purge_lazy = -#ifdef PAGES_CAN_PURGE_LAZY - true -#else - false -#endif - ; -static const bool pages_can_purge_forced = -#ifdef PAGES_CAN_PURGE_FORCED - true -#else - false -#endif - ; - -void *pages_map(void *addr, size_t size, size_t alignment, bool *commit); -void pages_unmap(void *addr, size_t size); -bool pages_commit(void *addr, size_t size); -bool pages_decommit(void *addr, size_t size); -bool pages_purge_lazy(void *addr, size_t size); -bool pages_purge_forced(void *addr, size_t size); -bool pages_huge(void *addr, size_t size); -bool pages_nohuge(void *addr, size_t size); -bool pages_boot(void); - -#endif /* JEMALLOC_INTERNAL_PAGES_EXTERNS_H */ diff --git a/src/pages.c b/src/pages.c index 86907aa5..3a048e3b 100644 --- a/src/pages.c +++ b/src/pages.c @@ -1,5 +1,8 @@ #define JEMALLOC_PAGES_C_ #include "jemalloc/internal/jemalloc_preamble.h" + +#include "jemalloc/internal/pages.h" + #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" -- GitLab From 05775a37360c7f1d41dc57b73ed5c0f259024d9f Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 24 Apr 2017 18:14:57 -0700 Subject: [PATCH 455/544] Avoid prof_dump during reentrancy. --- include/jemalloc/internal/prof_inlines_b.h | 3 ++ src/prof.c | 32 ++++++++++++++-------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/include/jemalloc/internal/prof_inlines_b.h b/include/jemalloc/internal/prof_inlines_b.h index eba981b9..8cdea615 100644 --- a/include/jemalloc/internal/prof_inlines_b.h +++ b/include/jemalloc/internal/prof_inlines_b.h @@ -96,6 +96,9 @@ prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update, } return true; } else { + if (tsd->reentrancy_level > 0) { + return true; + } /* Compute new sample threshold. */ if (update) { prof_sample_threshold_update(tdata); diff --git a/src/prof.c b/src/prof.c index a872afb1..1e818ab4 100644 --- a/src/prof.c +++ b/src/prof.c @@ -1641,30 +1641,30 @@ label_write_error: static bool prof_dump(tsd_t *tsd, bool propagate_err, const char *filename, bool leakcheck) { - prof_tdata_t *tdata; - struct prof_tdata_merge_iter_arg_s prof_tdata_merge_iter_arg; - struct prof_gctx_merge_iter_arg_s prof_gctx_merge_iter_arg; - struct prof_gctx_dump_iter_arg_s prof_gctx_dump_iter_arg; - prof_gctx_tree_t gctxs; - bool err; - cassert(config_prof); + assert(tsd->reentrancy_level == 0); - tdata = prof_tdata_get(tsd, true); + prof_tdata_t * tdata = prof_tdata_get(tsd, true); if (tdata == NULL) { return true; } + pre_reentrancy(tsd); malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_mtx); + prof_gctx_tree_t gctxs; + struct prof_tdata_merge_iter_arg_s prof_tdata_merge_iter_arg; + struct prof_gctx_merge_iter_arg_s prof_gctx_merge_iter_arg; + struct prof_gctx_dump_iter_arg_s prof_gctx_dump_iter_arg; prof_dump_prep(tsd, tdata, &prof_tdata_merge_iter_arg, &prof_gctx_merge_iter_arg, &gctxs); - err = prof_dump_file(tsd, propagate_err, filename, leakcheck, tdata, + bool err = prof_dump_file(tsd, propagate_err, filename, leakcheck, tdata, &prof_tdata_merge_iter_arg, &prof_gctx_merge_iter_arg, &prof_gctx_dump_iter_arg, &gctxs); prof_gctx_finish(tsd, &gctxs); malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_mtx); + post_reentrancy(tsd); if (err) { return true; @@ -1757,6 +1757,7 @@ prof_fdump(void) { return; } tsd = tsd_fetch(); + assert(tsd->reentrancy_level == 0); malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_seq_mtx); prof_dump_filename(filename, 'f', VSEQ_INVALID); @@ -1791,6 +1792,10 @@ prof_idump(tsdn_t *tsdn) { return; } tsd = tsdn_tsd(tsdn); + if (tsd->reentrancy_level > 0) { + return; + } + tdata = prof_tdata_get(tsd, false); if (tdata == NULL) { return; @@ -1812,14 +1817,13 @@ prof_idump(tsdn_t *tsdn) { bool prof_mdump(tsd_t *tsd, const char *filename) { - char filename_buf[DUMP_FILENAME_BUFSIZE]; - cassert(config_prof); + assert(tsd->reentrancy_level == 0); if (!opt_prof || !prof_booted) { return true; } - + char filename_buf[DUMP_FILENAME_BUFSIZE]; if (filename == NULL) { /* No filename specified, so automatically generate one. */ if (opt_prof_prefix[0] == '\0') { @@ -1845,6 +1849,10 @@ prof_gdump(tsdn_t *tsdn) { return; } tsd = tsdn_tsd(tsdn); + if (tsd->reentrancy_level > 0) { + return; + } + tdata = prof_tdata_get(tsd, false); if (tdata == NULL) { return; -- GitLab From e2aad5e810853ebfa285b361563120bd1925ca19 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 25 Apr 2017 13:33:22 -0700 Subject: [PATCH 456/544] Remove redundant extent lookup in tcache_bin_flush_large. --- src/tcache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tcache.c b/src/tcache.c index c272a3c4..e2474a32 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -215,7 +215,7 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, for (unsigned i = 0; i < nflush; i++) { void *ptr = *(tbin->avail - 1 - i); assert(ptr != NULL); - extent = iealloc(tsd_tsdn(tsd), ptr); + extent = item_extent[i]; if (extent_arena_get(extent) == locked_arena) { large_dalloc_prep_junked_locked(tsd_tsdn(tsd), extent); -- GitLab From 8584adc451f31adfc4ab8693d9189cf3a7e5d858 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 25 Apr 2017 13:31:45 -0700 Subject: [PATCH 457/544] Use trylock in tcache_bin_flush when possible. During tcache gc, use tcache_bin_try_flush_small / _large so that we can skip items with their bins locked already. --- include/jemalloc/internal/tcache_externs.h | 30 ++-- include/jemalloc/internal/tcache_inlines.h | 4 +- src/tcache.c | 171 +++++++++++++++------ 3 files changed, 142 insertions(+), 63 deletions(-) diff --git a/include/jemalloc/internal/tcache_externs.h b/include/jemalloc/internal/tcache_externs.h index abe133fa..95dfe446 100644 --- a/include/jemalloc/internal/tcache_externs.h +++ b/include/jemalloc/internal/tcache_externs.h @@ -27,23 +27,27 @@ extern size_t tcache_maxclass; */ extern tcaches_t *tcaches; -size_t tcache_salloc(tsdn_t *tsdn, const void *ptr); -void tcache_event_hard(tsd_t *tsd, tcache_t *tcache); -void *tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, +size_t tcache_salloc(tsdn_t *tsdn, const void *ptr); +void tcache_event_hard(tsd_t *tsd, tcache_t *tcache); +void *tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, tcache_bin_t *tbin, szind_t binind, bool *tcache_success); -void tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, +void tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, szind_t binind, unsigned rem); -void tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, - unsigned rem, tcache_t *tcache); -void tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, +unsigned tcache_bin_try_flush_small(tsd_t *tsd, tcache_t *tcache, + tcache_bin_t *tbin, szind_t binind, unsigned rem); +void tcache_bin_flush_large(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, + szind_t binind, unsigned rem); +unsigned tcache_bin_try_flush_large(tsd_t *tsd, tcache_t *tcache, + tcache_bin_t *tbin, szind_t binind, unsigned rem); +void tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); tcache_t *tcache_create_explicit(tsd_t *tsd); -void tcache_cleanup(tsd_t *tsd); -void tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); -bool tcaches_create(tsd_t *tsd, unsigned *r_ind); -void tcaches_flush(tsd_t *tsd, unsigned ind); -void tcaches_destroy(tsd_t *tsd, unsigned ind); -bool tcache_boot(tsdn_t *tsdn); +void tcache_cleanup(tsd_t *tsd); +void tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); +bool tcaches_create(tsd_t *tsd, unsigned *r_ind); +void tcaches_flush(tsd_t *tsd, unsigned ind); +void tcaches_destroy(tsd_t *tsd, unsigned ind); +bool tcache_boot(tsdn_t *tsdn); void tcache_arena_associate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); void tcache_prefork(tsdn_t *tsdn); void tcache_postfork_parent(tsdn_t *tsdn); diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index 8a65ba2b..5e9a7a0f 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -227,8 +227,8 @@ tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, tbin = tcache_large_bin_get(tcache, binind); tbin_info = &tcache_bin_info[binind]; if (unlikely(tbin->ncached == tbin_info->ncached_max)) { - tcache_bin_flush_large(tsd, tbin, binind, - (tbin_info->ncached_max >> 1), tcache); + tcache_bin_flush_large(tsd, tcache, tbin, binind, + (tbin_info->ncached_max >> 1)); } assert(tbin->ncached < tbin_info->ncached_max); tbin->ncached++; diff --git a/src/tcache.c b/src/tcache.c index e2474a32..292c0176 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -45,14 +45,16 @@ tcache_event_hard(tsd_t *tsd, tcache_t *tcache) { } else { tbin = tcache_large_bin_get(tcache, binind); } + bool repeat_bin; if (tbin->low_water > 0) { /* * Flush (ceiling) 3/4 of the objects below the low water mark. */ + unsigned nflushed; if (binind < NBINS) { - tcache_bin_flush_small(tsd, tcache, tbin, binind, - tbin->ncached - tbin->low_water + (tbin->low_water - >> 2)); + nflushed = tcache_bin_try_flush_small(tsd, tcache, tbin, + binind, tbin->ncached - tbin->low_water + + (tbin->low_water >> 2)); /* * Reduce fill count by 2X. Limit lg_fill_div such that * the fill count is always at least 1. @@ -63,23 +65,29 @@ tcache_event_hard(tsd_t *tsd, tcache_t *tcache) { tcache->lg_fill_div[binind]++; } } else { - tcache_bin_flush_large(tsd, tbin, binind, tbin->ncached - - tbin->low_water + (tbin->low_water >> 2), tcache); + nflushed = tcache_bin_try_flush_large(tsd, tcache, tbin, + binind, tbin->ncached - tbin->low_water + + (tbin->low_water >> 2)); } - } else if (tbin->low_water < 0) { - /* - * Increase fill count by 2X for small bins. Make sure - * lg_fill_div stays greater than 0. - */ - if (binind < NBINS && tcache->lg_fill_div[binind] > 1) { - tcache->lg_fill_div[binind]--; + repeat_bin = (nflushed == 0); + } else { + if (tbin->low_water < 0) { + /* + * Increase fill count by 2X for small bins. Make sure + * lg_fill_div stays greater than 0. + */ + if (binind < NBINS && tcache->lg_fill_div[binind] > 1) { + tcache->lg_fill_div[binind]--; + } } + repeat_bin = false; } - tbin->low_water = tbin->ncached; - - tcache->next_gc_bin++; - if (tcache->next_gc_bin == nhbins) { - tcache->next_gc_bin = 0; + if (!repeat_bin) { + tcache->next_gc_bin++; + if (tcache->next_gc_bin == nhbins) { + tcache->next_gc_bin = 0; + } + tbin->low_water = tbin->ncached; } } @@ -99,11 +107,9 @@ tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, return ret; } -void -tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, - szind_t binind, unsigned rem) { - bool merged_stats = false; - +static unsigned +tcache_bin_flush_small_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, + szind_t binind, unsigned rem, bool must_flush) { assert(binind < NBINS); assert(rem <= tbin->ncached); @@ -116,9 +122,12 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, item_extent[i] = iealloc(tsd_tsdn(tsd), *(tbin->avail - 1 - i)); } + bool merged_stats = false; + unsigned nflushed = 0; + unsigned nskipped = 0; while (nflush > 0) { /* Lock the arena bin associated with the first object. */ - extent_t *extent = item_extent[0]; + extent_t *extent = item_extent[nskipped]; arena_t *bin_arena = extent_arena_get(extent); arena_bin_t *bin = &bin_arena->bins[binind]; @@ -130,7 +139,16 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, tcache->prof_accumbytes = 0; } - malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); + if (must_flush) { + malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); + } else { + /* Make best effort to flush w/o blocking. */ + if (malloc_mutex_trylock(tsd_tsdn(tsd), &bin->lock)) { + nskipped++; + nflush--; + continue; + } + } if (config_stats && bin_arena == arena) { assert(!merged_stats); merged_stats = true; @@ -139,7 +157,7 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, tbin->tstats.nrequests = 0; } unsigned ndeferred = 0; - for (unsigned i = 0; i < nflush; i++) { + for (unsigned i = nskipped; i < nflush; i++) { void *ptr = *(tbin->avail - 1 - i); extent = item_extent[i]; assert(ptr != NULL && extent != NULL); @@ -154,13 +172,14 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, * locked. Stash the object, so that it can be * handled in a future pass. */ - *(tbin->avail - 1 - ndeferred) = ptr; - item_extent[ndeferred] = extent; + *(tbin->avail - 1 - ndeferred - nskipped) = ptr; + item_extent[ndeferred + nskipped] = extent; ndeferred++; } } malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); arena_decay_ticks(tsd_tsdn(tsd), bin_arena, nflush - ndeferred); + nflushed += nflush - ndeferred; nflush = ndeferred; } if (config_stats && !merged_stats) { @@ -169,26 +188,49 @@ tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, * arena, so the stats didn't get merged. Manually do so now. */ arena_bin_t *bin = &arena->bins[binind]; - malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); - bin->stats.nflushes++; - bin->stats.nrequests += tbin->tstats.nrequests; - tbin->tstats.nrequests = 0; - malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); + if (must_flush) { + malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); + } + if (must_flush || + !malloc_mutex_trylock(tsd_tsdn(tsd), &bin->lock)) { + malloc_mutex_assert_owner(tsd_tsdn(tsd), &bin->lock); + bin->stats.nflushes++; + bin->stats.nrequests += tbin->tstats.nrequests; + tbin->tstats.nrequests = 0; + malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); + } } + assert(nflushed == tbin->ncached - rem - nskipped); + assert(nskipped == 0 || !must_flush); - memmove(tbin->avail - rem, tbin->avail - tbin->ncached, rem * - sizeof(void *)); - tbin->ncached = rem; + if (nflushed > 0) { + memmove(tbin->avail - (rem + nskipped), tbin->avail - + tbin->ncached, rem * sizeof(void *)); + } + tbin->ncached = rem + nskipped; if ((low_water_t)tbin->ncached < tbin->low_water) { tbin->low_water = tbin->ncached; } + + return nflushed; } void -tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, - unsigned rem, tcache_t *tcache) { - bool merged_stats = false; +tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, + szind_t binind, unsigned rem) { + tcache_bin_flush_small_impl(tsd, tcache, tbin, binind, rem, true); +} + +unsigned +tcache_bin_try_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, + szind_t binind, unsigned rem) { + return tcache_bin_flush_small_impl(tsd, tcache, tbin, binind, rem, + false); +} +static unsigned +tcache_bin_flush_large_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, + szind_t binind, unsigned rem, bool must_flush) { assert(binind < nhbins); assert(rem <= tbin->ncached); @@ -201,18 +243,31 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, item_extent[i] = iealloc(tsd_tsdn(tsd), *(tbin->avail - 1 - i)); } + bool merged_stats = false; + unsigned nflushed = 0; + unsigned nskipped = 0; while (nflush > 0) { /* Lock the arena associated with the first object. */ - extent_t *extent = item_extent[0]; + extent_t *extent = item_extent[nskipped]; arena_t *locked_arena = extent_arena_get(extent); UNUSED bool idump; if (config_prof) { idump = false; } + if (must_flush) { + malloc_mutex_lock(tsd_tsdn(tsd), &locked_arena->large_mtx); + } else { + /* Make best effort to flush w/o blocking. */ + if (malloc_mutex_trylock(tsd_tsdn(tsd), + &locked_arena->large_mtx)) { + nskipped++; + nflush--; + continue; + } + } - malloc_mutex_lock(tsd_tsdn(tsd), &locked_arena->large_mtx); - for (unsigned i = 0; i < nflush; i++) { + for (unsigned i = nskipped; i < nflush; i++) { void *ptr = *(tbin->avail - 1 - i); assert(ptr != NULL); extent = item_extent[i]; @@ -238,7 +293,7 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, malloc_mutex_unlock(tsd_tsdn(tsd), &locked_arena->large_mtx); unsigned ndeferred = 0; - for (unsigned i = 0; i < nflush; i++) { + for (unsigned i = nskipped; i < nflush; i++) { void *ptr = *(tbin->avail - 1 - i); extent = item_extent[i]; assert(ptr != NULL && extent != NULL); @@ -252,8 +307,8 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, * Stash the object, so that it can be handled * in a future pass. */ - *(tbin->avail - 1 - ndeferred) = ptr; - item_extent[ndeferred] = extent; + *(tbin->avail - 1 - ndeferred - nskipped) = ptr; + item_extent[ndeferred + nskipped] = extent; ndeferred++; } } @@ -262,6 +317,7 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, } arena_decay_ticks(tsd_tsdn(tsd), locked_arena, nflush - ndeferred); + nflushed += nflush - ndeferred; nflush = ndeferred; } if (config_stats && !merged_stats) { @@ -274,12 +330,31 @@ tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, tbin->tstats.nrequests = 0; } - memmove(tbin->avail - rem, tbin->avail - tbin->ncached, rem * - sizeof(void *)); - tbin->ncached = rem; + assert(nflushed == tbin->ncached - rem - nskipped); + assert(nskipped == 0 || !must_flush); + + if (nflushed > 0) { + memmove(tbin->avail - (rem + nskipped), tbin->avail - + tbin->ncached, rem * sizeof(void *)); + } + tbin->ncached = rem + nskipped; if ((low_water_t)tbin->ncached < tbin->low_water) { tbin->low_water = tbin->ncached; } + return nflushed; +} + +void +tcache_bin_flush_large(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, + szind_t binind, unsigned rem) { + tcache_bin_flush_large_impl(tsd, tcache, tbin, binind, rem, true); +} + +unsigned +tcache_bin_try_flush_large(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, + szind_t binind, unsigned rem) { + return tcache_bin_flush_large_impl(tsd, tcache, tbin, binind, rem, + false); } void @@ -461,7 +536,7 @@ tcache_flush_cache(tsd_t *tsd, tcache_t *tcache) { } for (unsigned i = NBINS; i < nhbins; i++) { tcache_bin_t *tbin = tcache_large_bin_get(tcache, i); - tcache_bin_flush_large(tsd, tbin, i, 0, tcache); + tcache_bin_flush_large(tsd, tcache, tbin, i, 0); if (config_stats) { assert(tbin->tstats.nrequests == 0); -- GitLab From b0c2a28280d363fc85aa8b4fdbe7814ef46cb17b Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 25 Apr 2017 14:10:31 -0700 Subject: [PATCH 458/544] Use try_flush first in tcache_dalloc. Only do must_flush if try_flush didn't manage to free anything. --- include/jemalloc/internal/tcache_inlines.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index 5e9a7a0f..511fceab 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -201,8 +201,11 @@ tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, tbin = tcache_small_bin_get(tcache, binind); tbin_info = &tcache_bin_info[binind]; if (unlikely(tbin->ncached == tbin_info->ncached_max)) { - tcache_bin_flush_small(tsd, tcache, tbin, binind, - (tbin_info->ncached_max >> 1)); + if (tcache_bin_try_flush_small(tsd, tcache, tbin, binind, + (tbin_info->ncached_max >> 1)) == 0) { + tcache_bin_flush_small(tsd, tcache, tbin, binind, + (tbin_info->ncached_max >> 1)); + } } assert(tbin->ncached < tbin_info->ncached_max); tbin->ncached++; @@ -227,8 +230,11 @@ tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, tbin = tcache_large_bin_get(tcache, binind); tbin_info = &tcache_bin_info[binind]; if (unlikely(tbin->ncached == tbin_info->ncached_max)) { - tcache_bin_flush_large(tsd, tcache, tbin, binind, - (tbin_info->ncached_max >> 1)); + if (tcache_bin_try_flush_large(tsd, tcache, tbin, binind, + (tbin_info->ncached_max >> 1)) == 0) { + tcache_bin_flush_large(tsd, tcache, tbin, binind, + (tbin_info->ncached_max >> 1)); + } } assert(tbin->ncached < tbin_info->ncached_max); tbin->ncached++; -- GitLab From 5c56603e91d8d0021280615f86b95efe0463b6a8 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Thu, 27 Apr 2017 14:55:07 -0700 Subject: [PATCH 459/544] Inline tcache_bin_flush_small_impl / _large_impl. --- src/tcache.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tcache.c b/src/tcache.c index 292c0176..a7e05b17 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -107,7 +107,7 @@ tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, return ret; } -static unsigned +static inline unsigned tcache_bin_flush_small_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, szind_t binind, unsigned rem, bool must_flush) { assert(binind < NBINS); @@ -228,7 +228,7 @@ tcache_bin_try_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, false); } -static unsigned +static inline unsigned tcache_bin_flush_large_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, szind_t binind, unsigned rem, bool must_flush) { assert(binind < nhbins); -- GitLab From d901a377753cf4c75d2f72f7a692c44f61eac4a4 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Thu, 27 Apr 2017 14:12:51 -0700 Subject: [PATCH 460/544] Revert "Use try_flush first in tcache_dalloc." This reverts commit b0c2a28280d363fc85aa8b4fdbe7814ef46cb17b. Production benchmark shows this caused significant regression in both CPU and memory consumption. Will investigate separately later on. --- include/jemalloc/internal/tcache_inlines.h | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index 511fceab..5e9a7a0f 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -201,11 +201,8 @@ tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, tbin = tcache_small_bin_get(tcache, binind); tbin_info = &tcache_bin_info[binind]; if (unlikely(tbin->ncached == tbin_info->ncached_max)) { - if (tcache_bin_try_flush_small(tsd, tcache, tbin, binind, - (tbin_info->ncached_max >> 1)) == 0) { - tcache_bin_flush_small(tsd, tcache, tbin, binind, - (tbin_info->ncached_max >> 1)); - } + tcache_bin_flush_small(tsd, tcache, tbin, binind, + (tbin_info->ncached_max >> 1)); } assert(tbin->ncached < tbin_info->ncached_max); tbin->ncached++; @@ -230,11 +227,8 @@ tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, tbin = tcache_large_bin_get(tcache, binind); tbin_info = &tcache_bin_info[binind]; if (unlikely(tbin->ncached == tbin_info->ncached_max)) { - if (tcache_bin_try_flush_large(tsd, tcache, tbin, binind, - (tbin_info->ncached_max >> 1)) == 0) { - tcache_bin_flush_large(tsd, tcache, tbin, binind, - (tbin_info->ncached_max >> 1)); - } + tcache_bin_flush_large(tsd, tcache, tbin, binind, + (tbin_info->ncached_max >> 1)); } assert(tbin->ncached < tbin_info->ncached_max); tbin->ncached++; -- GitLab From b9ab04a191dbcb9246d5180fc7ae822a85861939 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 26 Apr 2017 16:26:12 -0700 Subject: [PATCH 461/544] Refactor !opt.munmap to opt.retain. --- configure.ac | 12 ++++++------ doc/jemalloc.xml.in | 17 +++++++++-------- include/jemalloc/internal/arena_structs_b.h | 2 +- include/jemalloc/internal/extent_mmap_externs.h | 2 +- include/jemalloc/internal/extent_structs.h | 7 +++---- .../internal/jemalloc_internal_defs.h.in | 6 +++--- include/jemalloc/internal/stats.h | 7 +++---- src/arena.c | 6 +++--- src/ctl.c | 6 +++--- src/extent.c | 2 +- src/extent_mmap.c | 8 ++++---- src/jemalloc.c | 2 +- src/large.c | 2 +- src/stats.c | 2 +- test/unit/arena_reset.c | 2 +- test/unit/mallctl.c | 2 +- 16 files changed, 42 insertions(+), 43 deletions(-) diff --git a/configure.ac b/configure.ac index 6447c51a..9f8311cc 100644 --- a/configure.ac +++ b/configure.ac @@ -517,7 +517,7 @@ dnl dnl Define cpp macros in CPPFLAGS, rather than doing AC_DEFINE(macro), since the dnl definitions need to be seen before any headers are included, which is a pain dnl to make happen otherwise. -default_munmap="1" +default_retain="0" maps_coalesce="1" case "${host}" in *-*-darwin* | *-*-ios*) @@ -557,7 +557,7 @@ case "${host}" in AC_DEFINE([JEMALLOC_C11_ATOMICS]) force_tls="0" if test "${LG_SIZEOF_PTR}" = "3"; then - default_munmap="0" + default_retain="1" fi ;; *-*-linux* | *-*-kfreebsd*) @@ -570,7 +570,7 @@ case "${host}" in AC_DEFINE([JEMALLOC_THREADED_INIT], [ ]) AC_DEFINE([JEMALLOC_USE_CXX_THROW], [ ]) if test "${LG_SIZEOF_PTR}" = "3"; then - default_munmap="0" + default_retain="1" fi ;; *-*-netbsd*) @@ -1086,9 +1086,9 @@ if test "x${maps_coalesce}" = "x1" ; then AC_DEFINE([JEMALLOC_MAPS_COALESCE], [ ]) fi -dnl Indicate whether to use munmap() by default. -if test "x$default_munmap" = "x1" ; then - AC_DEFINE([JEMALLOC_MUNMAP], [ ]) +dnl Indicate whether to retain memory (rather than using) munmap()) by default. +if test "x$default_retain" = "x1" ; then + AC_DEFINE([JEMALLOC_RETAIN], [ ]) fi dnl Enable allocation from DSS if supported by the OS. diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 66d8e5df..fa65c39b 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -863,25 +863,26 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", - + - opt.munmap + opt.retain (bool) r- - If true, call + If true, retain unused virtual memory for later reuse + rather than discarding it by calling munmap - 2 or equivalent rather than - retaining unused virtual memory (see 2 or equivalent (see stats.retained for related details). - This option is enabled by default unless it is known to trigger + This option is disabled by default unless discarding virtual memory is + known to trigger platform-specific performance problems, e.g. for [64-bit] Linux, which has a quirk in its virtual memory allocation algorithm that causes semi-permanent VM map holes under normal jemalloc operation. Although munmap 2 causes issues on 32-bit Linux as - well, it is not disabled by default due to the practical possibility of - address space exhaustion. + well, retaining virtual memory for 32-bit Linux is disabled by default + due to the practical possibility of address space exhaustion. diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 6b83e526..d98b455e 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -230,7 +230,7 @@ struct arena_s { /* * Next extent size class in a growing series to use when satisfying a - * request via the extent hooks (only if !opt_munmap). This limits the + * request via the extent hooks (only if opt_retain). This limits the * number of disjoint virtual memory ranges so that extent merging can * be effective even if multiple arenas' extent allocation requests are * highly interleaved. diff --git a/include/jemalloc/internal/extent_mmap_externs.h b/include/jemalloc/internal/extent_mmap_externs.h index e5bc8110..fe9a79ac 100644 --- a/include/jemalloc/internal/extent_mmap_externs.h +++ b/include/jemalloc/internal/extent_mmap_externs.h @@ -1,7 +1,7 @@ #ifndef JEMALLOC_INTERNAL_EXTENT_MMAP_EXTERNS_H #define JEMALLOC_INTERNAL_EXTENT_MMAP_EXTERNS_H -extern bool opt_munmap; +extern bool opt_retain; void *extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit); diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 5d8c3a20..62bae39a 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -59,10 +59,9 @@ struct extent_s { * * sn: Serial number (potentially non-unique). * - * Serial numbers may wrap around if JEMALLOC_MUNMAP is defined, but - * as long as comparison functions fall back on address comparison - * for equal serial numbers, stable (if imperfect) ordering is - * maintained. + * Serial numbers may wrap around if !opt_retain, but as long as + * comparison functions fall back on address comparison for equal + * serial numbers, stable (if imperfect) ordering is maintained. * * Serial numbers may not be unique even in the absence of * wrap-around, e.g. when splitting an extent and assigning the same diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 8f7c42b8..bccee167 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -192,12 +192,12 @@ #undef JEMALLOC_MAPS_COALESCE /* - * If defined, use munmap() to unmap freed extents by default, rather than - * storing them for later reuse. This is disabled on 64-bit Linux because + * If defined, retain memory for later reuse by default rather than using e.g. + * munmap() to unmap freed extents. This is enabled on 64-bit Linux because * common sequences of mmap()/munmap() calls will cause virtual memory map * holes. */ -#undef JEMALLOC_MUNMAP +#undef JEMALLOC_RETAIN /* TLS is used to map arenas and magazine caches to threads. */ #undef JEMALLOC_TLS diff --git a/include/jemalloc/internal/stats.h b/include/jemalloc/internal/stats.h index 301a50ab..fd98422d 100644 --- a/include/jemalloc/internal/stats.h +++ b/include/jemalloc/internal/stats.h @@ -117,10 +117,9 @@ typedef struct arena_stats_s { atomic_zu_t mapped; /* Partially derived. */ /* - * Number of bytes currently retained as a side effect of munmap() being - * disabled/bypassed. Retained bytes are technically mapped (though - * always decommitted or purged), but they are excluded from the mapped - * statistic (above). + * Number of unused virtual memory bytes currently retained. Retained + * bytes are technically mapped (though always decommitted or purged), + * but they are excluded from the mapped statistic (above). */ atomic_zu_t retained; /* Derived. */ diff --git a/src/arena.c b/src/arena.c index 3b94a20d..2c7cea08 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1143,8 +1143,8 @@ arena_destroy_retained(tsdn_t *tsdn, arena_t *arena) { * opportunity to unmap all retained memory without having to keep its * own metadata structures, but if deallocation fails, that is the * application's decision/problem. In practice, retained extents are - * leaked here if !opt_munmap unless the application provided custom - * extent hooks, so best practice is to either enable munmap (and avoid + * leaked here if opt_retain unless the application provided custom + * extent hooks, so best practice is to either disable retain (and avoid * dss for arenas to be destroyed), or provide custom extent hooks that * either unmap retained extents or track them for later use. */ @@ -1947,7 +1947,7 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { goto label_error; } - if (!opt_munmap) { + if (opt_retain) { atomic_store_u(&arena->extent_grow_next, psz2ind(HUGEPAGE), ATOMIC_RELAXED); } diff --git a/src/ctl.c b/src/ctl.c index 3591f891..7d53a336 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -74,7 +74,7 @@ CTL_PROTO(config_stats) CTL_PROTO(config_utrace) CTL_PROTO(config_xmalloc) CTL_PROTO(opt_abort) -CTL_PROTO(opt_munmap) +CTL_PROTO(opt_retain) CTL_PROTO(opt_dss) CTL_PROTO(opt_narenas) CTL_PROTO(opt_percpu_arena) @@ -260,7 +260,7 @@ static const ctl_named_node_t config_node[] = { static const ctl_named_node_t opt_node[] = { {NAME("abort"), CTL(opt_abort)}, - {NAME("munmap"), CTL(opt_munmap)}, + {NAME("retain"), CTL(opt_retain)}, {NAME("dss"), CTL(opt_dss)}, {NAME("narenas"), CTL(opt_narenas)}, {NAME("percpu_arena"), CTL(opt_percpu_arena)}, @@ -1455,7 +1455,7 @@ CTL_RO_CONFIG_GEN(config_xmalloc, bool) /******************************************************************************/ CTL_RO_NL_GEN(opt_abort, opt_abort, bool) -CTL_RO_NL_GEN(opt_munmap, opt_munmap, bool) +CTL_RO_NL_GEN(opt_retain, opt_retain, bool) CTL_RO_NL_GEN(opt_dss, opt_dss, const char *) CTL_RO_NL_GEN(opt_narenas, opt_narenas, unsigned) CTL_RO_NL_GEN(opt_percpu_arena, opt_percpu_arena, const char *) diff --git a/src/extent.c b/src/extent.c index 1ddaf240..bc17711c 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1123,7 +1123,7 @@ extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, extent_gdump_add(tsdn, extent); } } - if (!opt_munmap && extent == NULL) { + if (opt_retain && extent == NULL) { extent = extent_grow_retained(tsdn, arena, r_extent_hooks, new_addr, size, pad, alignment, slab, szind, zero, commit); } diff --git a/src/extent_mmap.c b/src/extent_mmap.c index 5fe82ee5..3e4e1ef7 100644 --- a/src/extent_mmap.c +++ b/src/extent_mmap.c @@ -7,8 +7,8 @@ /******************************************************************************/ /* Data. */ -bool opt_munmap = -#ifdef JEMALLOC_MUNMAP +bool opt_retain = +#ifdef JEMALLOC_RETAIN true #else false @@ -34,8 +34,8 @@ extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, bool extent_dalloc_mmap(void *addr, size_t size) { - if (opt_munmap) { + if (!opt_retain) { pages_unmap(addr, size); } - return !opt_munmap; + return opt_retain; } diff --git a/src/jemalloc.c b/src/jemalloc.c index 42146004..97a64431 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1043,7 +1043,7 @@ malloc_conf_init(void) { } CONF_HANDLE_BOOL(opt_abort, "abort") - CONF_HANDLE_BOOL(opt_munmap, "munmap") + CONF_HANDLE_BOOL(opt_retain, "retain") if (strncmp("dss", k, klen) == 0) { int i; bool match = false; diff --git a/src/large.c b/src/large.c index 4d515fbb..f657ccbe 100644 --- a/src/large.c +++ b/src/large.c @@ -93,7 +93,7 @@ large_dalloc_maybe_junk(void *ptr, size_t size) { * Only bother junk filling if the extent isn't about to be * unmapped. */ - if (!opt_munmap || (have_dss && extent_in_dss(ptr))) { + if (opt_retain || (have_dss && extent_in_dss(ptr))) { large_dalloc_junk(ptr, size); } } diff --git a/src/stats.c b/src/stats.c index 5d515186..34fc37f2 100644 --- a/src/stats.c +++ b/src/stats.c @@ -802,7 +802,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, "Run-time option settings:\n"); } OPT_WRITE_BOOL(abort, ",") - OPT_WRITE_BOOL(munmap, ",") + OPT_WRITE_BOOL(retain, ",") OPT_WRITE_CHAR_P(dss, ",") OPT_WRITE_UNSIGNED(narenas, ",") OPT_WRITE_CHAR_P(percpu_arena, ",") diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 0fa240b7..5d6c1a77 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -251,7 +251,7 @@ TEST_BEGIN(test_arena_destroy_hooks_default) { TEST_END /* - * Actually unmap extents, regardless of opt_munmap, so that attempts to access + * Actually unmap extents, regardless of opt_retain, so that attempts to access * a destroyed arena's memory will segfault. */ static bool diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 51a5244e..b07a6d04 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -157,7 +157,7 @@ TEST_BEGIN(test_mallctl_opt) { } while (0) TEST_MALLCTL_OPT(bool, abort, always); - TEST_MALLCTL_OPT(bool, munmap, always); + TEST_MALLCTL_OPT(bool, retain, always); TEST_MALLCTL_OPT(const char *, dss, always); TEST_MALLCTL_OPT(unsigned, narenas, always); TEST_MALLCTL_OPT(const char *, percpu_arena, always); -- GitLab From c86c8f4ffbf8c118203f7327610a2ad80cf9622c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 27 Apr 2017 15:51:35 -0700 Subject: [PATCH 462/544] Add extent_destroy_t and use it during arena destruction. Add the extent_destroy_t extent destruction hook to extent_hooks_t, and use it during arena destruction. This hook explicitly communicates to the callee that the extent must be destroyed or tracked for later reuse, lest it be permanently leaked. Prior to this change, retained extents could unintentionally be leaked if extent retention was enabled. This resolves #560. --- configure.ac | 2 +- doc/jemalloc.xml.in | 20 ++++++++ include/jemalloc/internal/extent_externs.h | 4 +- include/jemalloc/internal/private_symbols.txt | 2 +- include/jemalloc/jemalloc_typedefs.h.in | 9 ++++ src/arena.c | 20 ++++---- src/extent.c | 47 ++++++++++++++++++- test/include/test/extent_hooks.h | 24 ++++++++++ test/unit/arena_reset.c | 1 + test/unit/base.c | 8 +++- 10 files changed, 120 insertions(+), 17 deletions(-) diff --git a/configure.ac b/configure.ac index 9f8311cc..462f509f 100644 --- a/configure.ac +++ b/configure.ac @@ -1086,7 +1086,7 @@ if test "x${maps_coalesce}" = "x1" ; then AC_DEFINE([JEMALLOC_MAPS_COALESCE], [ ]) fi -dnl Indicate whether to retain memory (rather than using) munmap()) by default. +dnl Indicate whether to retain memory (rather than using munmap()) by default. if test "x$default_retain" = "x1" ; then AC_DEFINE([JEMALLOC_RETAIN], [ ]) fi diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index fa65c39b..d1b2e334 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -1605,6 +1605,7 @@ typedef extent_hooks_s extent_hooks_t; struct extent_hooks_s { extent_alloc_t *alloc; extent_dalloc_t *dalloc; + extent_destroy_t *destroy; extent_commit_t *commit; extent_decommit_t *decommit; extent_purge_t *purge_lazy; @@ -1681,6 +1682,25 @@ struct extent_hooks_s { remains mapped, in the same commit state, and available for future use, in which case it will be automatically retained for later reuse. + + typedef void (extent_destroy_t) + extent_hooks_t *extent_hooks + void *addr + size_t size + bool committed + unsigned arena_ind + + + + An extent destruction function conforms to the + extent_destroy_t type and unconditionally destroys an + extent at given addr and + size with + committed/decommited memory as indicated, on + behalf of arena arena_ind. This function may be + called to destroy retained extents during arena destruction (see arena.<i>.destroy). + typedef bool (extent_commit_t) extent_hooks_t *extent_hooks diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index 58e57e70..c4fe8425 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -40,10 +40,10 @@ extent_t *extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, size_t pad, size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit); void extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent); -bool extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *extent); void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent); +void extent_destroy_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent); bool extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length); diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt index 50590957..eb9b3010 100644 --- a/include/jemalloc/internal/private_symbols.txt +++ b/include/jemalloc/internal/private_symbols.txt @@ -154,8 +154,8 @@ extent_dalloc extent_dalloc_gap extent_dalloc_mmap extent_dalloc_wrapper -extent_dalloc_wrapper_try extent_decommit_wrapper +extent_destroy_wrapper extent_dss_boot extent_dss_mergeable extent_dss_prec_get diff --git a/include/jemalloc/jemalloc_typedefs.h.in b/include/jemalloc/jemalloc_typedefs.h.in index 91b5a8dc..1a588743 100644 --- a/include/jemalloc/jemalloc_typedefs.h.in +++ b/include/jemalloc/jemalloc_typedefs.h.in @@ -16,6 +16,14 @@ typedef void *(extent_alloc_t)(extent_hooks_t *, void *, size_t, size_t, bool *, typedef bool (extent_dalloc_t)(extent_hooks_t *, void *, size_t, bool, unsigned); +/* + * void + * extent_destroy(extent_hooks_t *extent_hooks, void *addr, size_t size, + * bool committed, unsigned arena_ind); + */ +typedef void (extent_destroy_t)(extent_hooks_t *, void *, size_t, bool, + unsigned); + /* * bool * extent_commit(extent_hooks_t *extent_hooks, void *addr, size_t size, @@ -59,6 +67,7 @@ typedef bool (extent_merge_t)(extent_hooks_t *, void *, size_t, void *, size_t, struct extent_hooks_s { extent_alloc_t *alloc; extent_dalloc_t *dalloc; + extent_destroy_t *destroy; extent_commit_t *commit; extent_decommit_t *decommit; extent_purge_t *purge_lazy; diff --git a/src/arena.c b/src/arena.c index 2c7cea08..edbd875f 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1138,21 +1138,19 @@ arena_reset(tsd_t *tsd, arena_t *arena) { static void arena_destroy_retained(tsdn_t *tsdn, arena_t *arena) { /* - * Iterate over the retained extents and blindly attempt to deallocate - * them. This gives the extent allocator underlying the extent hooks an - * opportunity to unmap all retained memory without having to keep its - * own metadata structures, but if deallocation fails, that is the - * application's decision/problem. In practice, retained extents are - * leaked here if opt_retain unless the application provided custom - * extent hooks, so best practice is to either disable retain (and avoid - * dss for arenas to be destroyed), or provide custom extent hooks that - * either unmap retained extents or track them for later use. + * Iterate over the retained extents and destroy them. This gives the + * extent allocator underlying the extent hooks an opportunity to unmap + * all retained memory without having to keep its own metadata + * structures. In practice, virtual memory for dss-allocated extents is + * leaked here, so best practice is to avoid dss for arenas to be + * destroyed, or provide custom extent hooks that track retained + * dss-based extents for later reuse. */ extent_hooks_t *extent_hooks = extent_hooks_get(arena); extent_t *extent; while ((extent = extents_evict(tsdn, arena, &extent_hooks, &arena->extents_retained, 0)) != NULL) { - extent_dalloc_wrapper_try(tsdn, arena, &extent_hooks, extent); + extent_destroy_wrapper(tsdn, arena, &extent_hooks, extent); } } @@ -1169,7 +1167,7 @@ arena_destroy(tsd_t *tsd, arena_t *arena) { */ assert(extents_npages_get(&arena->extents_dirty) == 0); - /* Attempt to deallocate retained memory. */ + /* Deallocate retained memory. */ arena_destroy_retained(tsd_tsdn(tsd), arena); /* diff --git a/src/extent.c b/src/extent.c index bc17711c..1b284535 100644 --- a/src/extent.c +++ b/src/extent.c @@ -19,6 +19,8 @@ static void *extent_alloc_default(extent_hooks_t *extent_hooks, unsigned arena_ind); static bool extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, size_t size, bool committed, unsigned arena_ind); +static void extent_destroy_default(extent_hooks_t *extent_hooks, void *addr, + size_t size, bool committed, unsigned arena_ind); static bool extent_commit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); static bool extent_decommit_default(extent_hooks_t *extent_hooks, @@ -43,6 +45,7 @@ static bool extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, const extent_hooks_t extent_hooks_default = { extent_alloc_default, extent_dalloc_default, + extent_destroy_default, extent_commit_default, extent_decommit_default #ifdef PAGES_CAN_PURGE_LAZY @@ -1366,7 +1369,7 @@ extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, size_t size, return extent_dalloc_default_impl(addr, size); } -bool +static bool extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { bool err; @@ -1443,6 +1446,48 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent); } +static void +extent_destroy_default_impl(void *addr, size_t size) { + if (!have_dss || !extent_in_dss(addr)) { + pages_unmap(addr, size); + } +} + +static void +extent_destroy_default(extent_hooks_t *extent_hooks, void *addr, size_t size, + bool committed, unsigned arena_ind) { + assert(extent_hooks == &extent_hooks_default); + + extent_destroy_default_impl(addr, size); +} + +void +extent_destroy_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent) { + assert(extent_base_get(extent) != NULL); + assert(extent_size_get(extent) != 0); + witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + + /* Deregister first to avoid a race with other allocating threads. */ + extent_deregister(tsdn, extent); + + extent_addr_set(extent, extent_base_get(extent)); + + extent_hooks_assure_initialized(arena, r_extent_hooks); + /* Try to destroy; silently fail otherwise. */ + if (*r_extent_hooks == &extent_hooks_default) { + /* Call directly to propagate tsdn. */ + extent_destroy_default_impl(extent_base_get(extent), + extent_size_get(extent)); + } else if ((*r_extent_hooks)->destroy != NULL) { + (*r_extent_hooks)->destroy(*r_extent_hooks, + extent_base_get(extent), extent_size_get(extent), + extent_committed_get(extent), arena_ind_get(arena)); + } + + extent_dalloc(tsdn, arena, extent); +} + static bool extent_commit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { diff --git a/test/include/test/extent_hooks.h b/test/include/test/extent_hooks.h index 96fee103..ea012857 100644 --- a/test/include/test/extent_hooks.h +++ b/test/include/test/extent_hooks.h @@ -8,6 +8,8 @@ static void *extent_alloc_hook(extent_hooks_t *extent_hooks, void *new_addr, unsigned arena_ind); static bool extent_dalloc_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, bool committed, unsigned arena_ind); +static void extent_destroy_hook(extent_hooks_t *extent_hooks, void *addr, + size_t size, bool committed, unsigned arena_ind); static bool extent_commit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); static bool extent_decommit_hook(extent_hooks_t *extent_hooks, void *addr, @@ -27,6 +29,7 @@ static extent_hooks_t *default_hooks; static extent_hooks_t hooks = { extent_alloc_hook, extent_dalloc_hook, + extent_destroy_hook, extent_commit_hook, extent_decommit_hook, extent_purge_lazy_hook, @@ -38,6 +41,7 @@ static extent_hooks_t hooks = { /* Control whether hook functions pass calls through to default hooks. */ static bool try_alloc = true; static bool try_dalloc = true; +static bool try_destroy = true; static bool try_commit = true; static bool try_decommit = true; static bool try_purge_lazy = true; @@ -48,6 +52,7 @@ static bool try_merge = true; /* Set to false prior to operations, then introspect after operations. */ static bool called_alloc; static bool called_dalloc; +static bool called_destroy; static bool called_commit; static bool called_decommit; static bool called_purge_lazy; @@ -58,6 +63,7 @@ static bool called_merge; /* Set to false prior to operations, then introspect after operations. */ static bool did_alloc; static bool did_dalloc; +static bool did_destroy; static bool did_commit; static bool did_decommit; static bool did_purge_lazy; @@ -115,6 +121,24 @@ extent_dalloc_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, return err; } +static void +extent_destroy_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, + bool committed, unsigned arena_ind) { + TRACE_HOOK("%s(extent_hooks=%p, addr=%p, size=%zu, committed=%s, " + "arena_ind=%u)\n", __func__, extent_hooks, addr, size, committed ? + "true" : "false", arena_ind); + assert_ptr_eq(extent_hooks, &hooks, + "extent_hooks should be same as pointer used to set hooks"); + assert_ptr_eq(extent_hooks->destroy, extent_destroy_hook, + "Wrong hook function"); + called_destroy = true; + if (!try_destroy) { + return; + } + default_hooks->destroy(default_hooks, addr, size, committed, 0); + did_destroy = true; +} + static bool extent_commit_hook(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 5d6c1a77..d1698325 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -278,6 +278,7 @@ static extent_hooks_t hooks_orig; static extent_hooks_t hooks_unmap = { extent_alloc_hook, extent_dalloc_unmap, /* dalloc */ + extent_destroy_hook, extent_commit_hook, extent_decommit_hook, extent_purge_lazy_hook, diff --git a/test/unit/base.c b/test/unit/base.c index f498394e..5dc42f0a 100644 --- a/test/unit/base.c +++ b/test/unit/base.c @@ -5,6 +5,7 @@ static extent_hooks_t hooks_null = { extent_alloc_hook, NULL, /* dalloc */ + NULL, /* destroy */ NULL, /* commit */ NULL, /* decommit */ NULL, /* purge_lazy */ @@ -16,6 +17,7 @@ static extent_hooks_t hooks_null = { static extent_hooks_t hooks_not_null = { extent_alloc_hook, extent_dalloc_hook, + extent_destroy_hook, NULL, /* commit */ extent_decommit_hook, extent_purge_lazy_hook, @@ -59,6 +61,7 @@ TEST_BEGIN(test_base_hooks_null) { extent_hooks_prep(); try_dalloc = false; + try_destroy = true; try_decommit = false; try_purge_lazy = false; try_purge_forced = false; @@ -98,6 +101,7 @@ TEST_BEGIN(test_base_hooks_not_null) { extent_hooks_prep(); try_dalloc = false; + try_destroy = true; try_decommit = false; try_purge_lazy = false; try_purge_forced = false; @@ -194,15 +198,17 @@ TEST_BEGIN(test_base_hooks_not_null) { } } - called_dalloc = called_decommit = called_purge_lazy = + called_dalloc = called_destroy = called_decommit = called_purge_lazy = called_purge_forced = false; base_delete(base); assert_true(called_dalloc, "Expected dalloc call"); + assert_true(!called_destroy, "Unexpected destroy call"); assert_true(called_decommit, "Expected decommit call"); assert_true(called_purge_lazy, "Expected purge_lazy call"); assert_true(called_purge_forced, "Expected purge_forced call"); try_dalloc = true; + try_destroy = true; try_decommit = true; try_purge_lazy = true; try_purge_forced = true; -- GitLab From 209f2926b8e734317942231332f24b4bfd94587e Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 26 Apr 2017 18:37:44 -0700 Subject: [PATCH 463/544] Header refactoring: tsd - cleanup and dependency breaking. This removes the tsd macros (which are used only for tsd_t in real builds). We break up the circular dependencies involving tsd. We also move all tsd access through getters and setters. This allows us to assert that we only touch data when tsd is in a valid state. We simplify the usages of the x macro trick, removing all the customizability (get/set, init, cleanup), moving the lifetime logic to tsd_init and tsd_cleanup. This lets us make initialization order independent of order within tsd_t. --- include/jemalloc/internal/ckh.h | 2 +- .../internal/jemalloc_internal_externs.h | 2 + .../internal/jemalloc_internal_includes.h | 8 +- include/jemalloc/internal/mutex_externs.h | 2 + include/jemalloc/internal/mutex_inlines.h | 1 + include/jemalloc/internal/mutex_prof.h | 1 + include/jemalloc/internal/prof_inlines_b.h | 2 +- include/jemalloc/internal/rtree_ctx.h | 22 + include/jemalloc/internal/rtree_externs.h | 2 - include/jemalloc/internal/rtree_structs.h | 21 - include/jemalloc/internal/rtree_types.h | 4 - include/jemalloc/internal/rtree_witness.h | 19 + include/jemalloc/internal/stats.h | 3 + include/jemalloc/internal/ticker.h | 2 + include/jemalloc/internal/tsd.h | 298 ++++++++++ include/jemalloc/internal/tsd_externs.h | 20 - include/jemalloc/internal/tsd_generic.h | 160 ++++++ include/jemalloc/internal/tsd_inlines.h | 121 ---- .../internal/tsd_malloc_thread_cleanup.h | 60 ++ include/jemalloc/internal/tsd_structs.h | 114 ---- include/jemalloc/internal/tsd_tls.h | 59 ++ include/jemalloc/internal/tsd_types.h | 541 +----------------- include/jemalloc/internal/tsd_win.h | 139 +++++ src/jemalloc.c | 8 +- src/prof.c | 10 +- src/rtree.c | 7 - src/tcache.c | 5 +- src/tsd.c | 73 ++- test/unit/tsd.c | 77 ++- 29 files changed, 870 insertions(+), 913 deletions(-) create mode 100644 include/jemalloc/internal/rtree_ctx.h create mode 100644 include/jemalloc/internal/rtree_witness.h create mode 100644 include/jemalloc/internal/tsd.h delete mode 100644 include/jemalloc/internal/tsd_externs.h create mode 100644 include/jemalloc/internal/tsd_generic.h delete mode 100644 include/jemalloc/internal/tsd_inlines.h create mode 100644 include/jemalloc/internal/tsd_malloc_thread_cleanup.h delete mode 100644 include/jemalloc/internal/tsd_structs.h create mode 100644 include/jemalloc/internal/tsd_tls.h create mode 100644 include/jemalloc/internal/tsd_win.h diff --git a/include/jemalloc/internal/ckh.h b/include/jemalloc/internal/ckh.h index 96922e04..7b3850bc 100644 --- a/include/jemalloc/internal/ckh.h +++ b/include/jemalloc/internal/ckh.h @@ -1,7 +1,7 @@ #ifndef JEMALLOC_INTERNAL_CKH_H #define JEMALLOC_INTERNAL_CKH_H -#include "jemalloc/internal/tsd_types.h" +#include "jemalloc/internal/tsd.h" /* Cuckoo hashing implementation. Skip to the end for the interface. */ diff --git a/include/jemalloc/internal/jemalloc_internal_externs.h b/include/jemalloc/internal/jemalloc_internal_externs.h index 45c119f8..9a431fc1 100644 --- a/include/jemalloc/internal/jemalloc_internal_externs.h +++ b/include/jemalloc/internal/jemalloc_internal_externs.h @@ -2,6 +2,8 @@ #define JEMALLOC_INTERNAL_EXTERNS_H #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/size_classes.h" +#include "jemalloc/internal/tsd_types.h" /* TSD checks this to set thread local slow state accordingly. */ extern bool malloc_slow; diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 340cb1ce..84917a70 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -26,8 +26,8 @@ * dependency information into the header files (i.e. we still rely on the * ordering in this file to ensure all a header's dependencies are available in * its translation unit). Each component is now broken up into multiple header - * files, corresponding to the sections above (e.g. instead of "tsd.h", we now - * have "tsd_types.h", "tsd_structs.h", "tsd_externs.h", "tsd_inlines.h"). + * files, corresponding to the sections above (e.g. instead of "foo.h", we now + * have "foo_types.h", "foo_structs.h", "foo_externs.h", "foo_inlines.h"). * * Those files which have been converted to explicitly include their * inter-component dependencies are now in the initial HERMETIC HEADERS @@ -42,7 +42,6 @@ #include "jemalloc/internal/witness_types.h" #include "jemalloc/internal/mutex_types.h" -#include "jemalloc/internal/tsd_types.h" #include "jemalloc/internal/extent_types.h" #include "jemalloc/internal/extent_dss_types.h" #include "jemalloc/internal/base_types.h" @@ -65,7 +64,6 @@ #include "jemalloc/internal/arena_structs_b.h" #include "jemalloc/internal/rtree_structs.h" #include "jemalloc/internal/tcache_structs.h" -#include "jemalloc/internal/tsd_structs.h" /******************************************************************************/ /* EXTERNS */ @@ -83,13 +81,11 @@ #include "jemalloc/internal/large_externs.h" #include "jemalloc/internal/tcache_externs.h" #include "jemalloc/internal/prof_externs.h" -#include "jemalloc/internal/tsd_externs.h" /******************************************************************************/ /* INLINES */ /******************************************************************************/ -#include "jemalloc/internal/tsd_inlines.h" #include "jemalloc/internal/witness_inlines.h" #include "jemalloc/internal/mutex_inlines.h" #include "jemalloc/internal/jemalloc_internal_inlines_a.h" diff --git a/include/jemalloc/internal/mutex_externs.h b/include/jemalloc/internal/mutex_externs.h index 5199d3cf..8e40cb34 100644 --- a/include/jemalloc/internal/mutex_externs.h +++ b/include/jemalloc/internal/mutex_externs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_MUTEX_EXTERNS_H #define JEMALLOC_INTERNAL_MUTEX_EXTERNS_H +#include "jemalloc/internal/tsd_types.h" + #ifdef JEMALLOC_LAZY_LOCK extern bool isthreaded; #else diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index 6da21cf6..babe8d3a 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_MUTEX_INLINES_H #include "jemalloc/internal/nstime.h" +#include "jemalloc/internal/tsd_types.h" void malloc_mutex_lock_slow(malloc_mutex_t *mutex); diff --git a/include/jemalloc/internal/mutex_prof.h b/include/jemalloc/internal/mutex_prof.h index 50c0af0a..f7301c88 100644 --- a/include/jemalloc/internal/mutex_prof.h +++ b/include/jemalloc/internal/mutex_prof.h @@ -3,6 +3,7 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/nstime.h" +#include "jemalloc/internal/tsd_types.h" #define MUTEX_PROF_GLOBAL_MUTEXES \ OP(ctl) \ diff --git a/include/jemalloc/internal/prof_inlines_b.h b/include/jemalloc/internal/prof_inlines_b.h index 8cdea615..fba7b998 100644 --- a/include/jemalloc/internal/prof_inlines_b.h +++ b/include/jemalloc/internal/prof_inlines_b.h @@ -96,7 +96,7 @@ prof_sample_accum_update(tsd_t *tsd, size_t usize, bool update, } return true; } else { - if (tsd->reentrancy_level > 0) { + if (tsd_reentrancy_level_get(tsd) > 0) { return true; } /* Compute new sample threshold. */ diff --git a/include/jemalloc/internal/rtree_ctx.h b/include/jemalloc/internal/rtree_ctx.h new file mode 100644 index 00000000..fe2c8bde --- /dev/null +++ b/include/jemalloc/internal/rtree_ctx.h @@ -0,0 +1,22 @@ +#ifndef JEMALLOC_INTERNAL_RTREE_CTX_H +#define JEMALLOC_INTERNAL_RTREE_CTX_H + +#include "jemalloc/internal/rtree_types.h" + +typedef struct rtree_ctx_cache_elm_s rtree_ctx_cache_elm_t; +struct rtree_ctx_cache_elm_s { + uintptr_t leafkey; + rtree_leaf_elm_t *leaf; +}; + +typedef struct rtree_ctx_s rtree_ctx_t; +struct rtree_ctx_s { + /* Direct mapped cache. */ + rtree_ctx_cache_elm_t cache[RTREE_CTX_NCACHE]; + /* L2 LRU cache. */ + rtree_ctx_cache_elm_t l2_cache[RTREE_CTX_NCACHE_L2]; +}; + +void rtree_ctx_data_init(rtree_ctx_t *ctx); + +#endif /* JEMALLOC_INTERNAL_RTREE_CTX_H */ diff --git a/include/jemalloc/internal/rtree_externs.h b/include/jemalloc/internal/rtree_externs.h index c8d1c376..5145c12c 100644 --- a/include/jemalloc/internal/rtree_externs.h +++ b/include/jemalloc/internal/rtree_externs.h @@ -43,7 +43,5 @@ void rtree_leaf_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, const rtree_leaf_elm_t *elm); void rtree_leaf_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, const rtree_leaf_elm_t *elm); -void rtree_ctx_data_init(rtree_ctx_t *ctx); -bool tsd_rtree_ctx_data_init(tsd_t *tsd); #endif /* JEMALLOC_INTERNAL_RTREE_EXTERNS_H */ diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h index 7ff92e61..4418934f 100644 --- a/include/jemalloc/internal/rtree_structs.h +++ b/include/jemalloc/internal/rtree_structs.h @@ -30,15 +30,6 @@ struct rtree_leaf_elm_s { #endif }; -struct rtree_leaf_elm_witness_s { - const rtree_leaf_elm_t *elm; - witness_t witness; -}; - -struct rtree_leaf_elm_witness_tsd_s { - rtree_leaf_elm_witness_t witnesses[RTREE_ELM_ACQUIRE_MAX]; -}; - struct rtree_level_s { /* Number of key bits distinguished by this level. */ unsigned bits; @@ -49,18 +40,6 @@ struct rtree_level_s { unsigned cumbits; }; -struct rtree_ctx_cache_elm_s { - uintptr_t leafkey; - rtree_leaf_elm_t *leaf; -}; - -struct rtree_ctx_s { - /* Direct mapped cache. */ - rtree_ctx_cache_elm_t cache[RTREE_CTX_NCACHE]; - /* L2 LRU cache. */ - rtree_ctx_cache_elm_t l2_cache[RTREE_CTX_NCACHE_L2]; -}; - struct rtree_s { malloc_mutex_t init_lock; /* Number of elements based on rtree_levels[0].bits. */ diff --git a/include/jemalloc/internal/rtree_types.h b/include/jemalloc/internal/rtree_types.h index 402f741c..b465086d 100644 --- a/include/jemalloc/internal/rtree_types.h +++ b/include/jemalloc/internal/rtree_types.h @@ -12,11 +12,7 @@ typedef struct rtree_node_elm_s rtree_node_elm_t; typedef struct rtree_leaf_elm_s rtree_leaf_elm_t; -typedef struct rtree_leaf_elm_witness_s rtree_leaf_elm_witness_t; -typedef struct rtree_leaf_elm_witness_tsd_s rtree_leaf_elm_witness_tsd_t; typedef struct rtree_level_s rtree_level_t; -typedef struct rtree_ctx_cache_elm_s rtree_ctx_cache_elm_t; -typedef struct rtree_ctx_s rtree_ctx_t; typedef struct rtree_s rtree_t; /* Number of high insignificant bits. */ diff --git a/include/jemalloc/internal/rtree_witness.h b/include/jemalloc/internal/rtree_witness.h new file mode 100644 index 00000000..4a136203 --- /dev/null +++ b/include/jemalloc/internal/rtree_witness.h @@ -0,0 +1,19 @@ +#ifndef JEMALLOC_INTERNAL_RTREE_WITNESS_H +#define JEMALLOC_INTERNAL_RTREE_WITNESS_H + +#include "jemalloc/internal/rtree_types.h" +#include "jemalloc/internal/witness_types.h" +#include "jemalloc/internal/witness_structs.h" + +typedef struct rtree_leaf_elm_witness_s rtree_leaf_elm_witness_t; +struct rtree_leaf_elm_witness_s { + const rtree_leaf_elm_t *elm; + witness_t witness; +}; + +typedef struct rtree_leaf_elm_witness_tsd_s rtree_leaf_elm_witness_tsd_t; +struct rtree_leaf_elm_witness_tsd_s { + rtree_leaf_elm_witness_t witnesses[RTREE_ELM_ACQUIRE_MAX]; +}; + +#endif /* JEMALLOC_INTERNAL_RTREE_WITNESS_H */ diff --git a/include/jemalloc/internal/stats.h b/include/jemalloc/internal/stats.h index fd98422d..385a8514 100644 --- a/include/jemalloc/internal/stats.h +++ b/include/jemalloc/internal/stats.h @@ -2,6 +2,9 @@ #define JEMALLOC_INTERNAL_STATS_H #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/mutex_prof.h" +#include "jemalloc/internal/mutex_types.h" +#include "jemalloc/internal/mutex_structs.h" #include "jemalloc/internal/size_classes.h" /* The opt.stats_print storage. */ diff --git a/include/jemalloc/internal/ticker.h b/include/jemalloc/internal/ticker.h index faaac91d..572b9645 100644 --- a/include/jemalloc/internal/ticker.h +++ b/include/jemalloc/internal/ticker.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_TICKER_H #define JEMALLOC_INTERNAL_TICKER_H +#include "jemalloc/internal/util.h" + /** * A ticker makes it easy to count-down events until some limit. You * ticker_init the ticker to trigger every nticks events. You then notify it diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h new file mode 100644 index 00000000..3d6576b4 --- /dev/null +++ b/include/jemalloc/internal/tsd.h @@ -0,0 +1,298 @@ +#ifndef JEMALLOC_INTERNAL_TSD_H +#define JEMALLOC_INTERNAL_TSD_H + +#include "jemalloc/internal/arena_types.h" +#include "jemalloc/internal/assert.h" +#include "jemalloc/internal/jemalloc_internal_externs.h" +#include "jemalloc/internal/prof_types.h" +#include "jemalloc/internal/ql.h" +#include "jemalloc/internal/rtree_ctx.h" +#include "jemalloc/internal/rtree_witness.h" +#include "jemalloc/internal/tcache_types.h" +#include "jemalloc/internal/tcache_structs.h" +#include "jemalloc/internal/util.h" +#include "jemalloc/internal/witness_types.h" +#include "jemalloc/internal/witness_structs.h" + +/* + * Thread-Specific-Data layout + * --- data accessed on tcache fast path: state, rtree_ctx, stats, prof --- + * s: state + * e: tcache_enabled + * m: thread_allocated (config_stats) + * f: thread_deallocated (config_stats) + * p: prof_tdata (config_prof) + * c: rtree_ctx (rtree cache accessed on deallocation) + * t: tcache + * --- data not accessed on tcache fast path: arena-related fields --- + * d: arenas_tdata_bypass + * r: reentrancy_level + * x: narenas_tdata + * i: iarena + * a: arena + * o: arenas_tdata + * Loading TSD data is on the critical path of basically all malloc operations. + * In particular, tcache and rtree_ctx rely on hot CPU cache to be effective. + * Use a compact layout to reduce cache footprint. + * +--- 64-bit and 64B cacheline; 1B each letter; First byte on the left. ---+ + * |---------------------------- 1st cacheline ----------------------------| + * | sedrxxxx mmmmmmmm ffffffff pppppppp [c * 32 ........ ........ .......] | + * |---------------------------- 2nd cacheline ----------------------------| + * | [c * 64 ........ ........ ........ ........ ........ ........ .......] | + * |---------------------------- 3nd cacheline ----------------------------| + * | [c * 32 ........ ........ .......] iiiiiiii aaaaaaaa oooooooo [t...... | + * +-------------------------------------------------------------------------+ + * Note: the entire tcache is embedded into TSD and spans multiple cachelines. + * + * The last 3 members (i, a and o) before tcache isn't really needed on tcache + * fast path. However we have a number of unused tcache bins and witnesses + * (never touched unless config_debug) at the end of tcache, so we place them + * there to avoid breaking the cachelines and possibly paging in an extra page. + */ +#ifdef JEMALLOC_JET +typedef void (*test_callback_t)(int *); +# define MALLOC_TSD_TEST_DATA_INIT 0x72b65c10 +# define MALLOC_TEST_TSD \ + O(test_data, int) \ + O(test_callback, test_callback_t) +# define MALLOC_TEST_TSD_INITIALIZER , MALLOC_TSD_TEST_DATA_INIT, NULL +#else +# define MALLOC_TEST_TSD +# define MALLOC_TEST_TSD_INITIALIZER +#endif + +#define MALLOC_TSD \ +/* O(name, type) */ \ + O(tcache_enabled, bool) \ + O(arenas_tdata_bypass, bool) \ + O(reentrancy_level, int8_t) \ + O(narenas_tdata, uint32_t) \ + O(thread_allocated, uint64_t) \ + O(thread_deallocated, uint64_t) \ + O(prof_tdata, prof_tdata_t *) \ + O(rtree_ctx, rtree_ctx_t) \ + O(iarena, arena_t *) \ + O(arena, arena_t *) \ + O(arenas_tdata, arena_tdata_t *) \ + O(tcache, tcache_t) \ + O(witnesses, witness_list_t) \ + O(rtree_leaf_elm_witnesses, rtree_leaf_elm_witness_tsd_t) \ + O(witness_fork, bool) \ + MALLOC_TEST_TSD + +#define TSD_INITIALIZER { \ + tsd_state_uninitialized, \ + TCACHE_ENABLED_ZERO_INITIALIZER, \ + false, \ + 0, \ + 0, \ + 0, \ + 0, \ + NULL, \ + RTREE_CTX_ZERO_INITIALIZER, \ + NULL, \ + NULL, \ + NULL, \ + TCACHE_ZERO_INITIALIZER, \ + ql_head_initializer(witnesses), \ + RTREE_ELM_WITNESS_TSD_INITIALIZER, \ + false \ + MALLOC_TEST_TSD_INITIALIZER \ +} + +enum { + tsd_state_nominal = 0, /* Common case --> jnz. */ + tsd_state_nominal_slow = 1, /* Initialized but on slow path. */ + /* the above 2 nominal states should be lower values. */ + tsd_state_nominal_max = 1, /* used for comparison only. */ + tsd_state_purgatory = 2, + tsd_state_reincarnated = 3, + tsd_state_uninitialized = 4 +}; + +/* Manually limit tsd_state_t to a single byte. */ +typedef uint8_t tsd_state_t; + +/* The actual tsd. */ +typedef struct tsd_s tsd_t; +struct tsd_s { + /* + * The contents should be treated as totally opaque outside the tsd + * module. Access any thread-local state through the getters and + * setters below. + */ + tsd_state_t state; +#define O(n, t) \ + t use_a_getter_or_setter_instead_##n; +MALLOC_TSD +#undef O +}; + +/* + * Wrapper around tsd_t that makes it possible to avoid implicit conversion + * between tsd_t and tsdn_t, where tsdn_t is "nullable" and has to be + * explicitly converted to tsd_t, which is non-nullable. + */ +typedef struct tsdn_s tsdn_t; +struct tsdn_s { + tsd_t tsd; +}; +#define TSDN_NULL ((tsdn_t *)0) + +void *malloc_tsd_malloc(size_t size); +void malloc_tsd_dalloc(void *wrapper); +void malloc_tsd_cleanup_register(bool (*f)(void)); +tsd_t *malloc_tsd_boot0(void); +void malloc_tsd_boot1(void); +bool tsd_data_init(void *arg); +void tsd_cleanup(void *arg); +tsd_t *tsd_fetch_slow(tsd_t *tsd); +void tsd_slow_update(tsd_t *tsd); + +/* + * We put the platform-specific data declarations and inlines into their own + * header files to avoid cluttering this file. They define tsd_boot0, + * tsd_boot1, tsd_boot, tsd_booted_get, tsd_get_allocates, tsd_get, and tsd_set. + */ +#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP +#include "jemalloc/internal/tsd_malloc_thread_cleanup.h" +#elif (defined(JEMALLOC_TLS)) +#include "jemalloc/internal/tsd_tls.h" +#elif (defined(_WIN32)) +#include "jemalloc/internal/tsd_win.h" +#else +#include "jemalloc/internal/tsd_generic.h" +#endif + +/* + * tsd_foop_get_unsafe(tsd) returns a pointer to the thread-local instance of + * foo. This omits some safety checks, and so can be used during tsd + * initialization and cleanup. + */ +#define O(n, t) \ +JEMALLOC_ALWAYS_INLINE t * \ +tsd_##n##p_get_unsafe(tsd_t *tsd) { \ + return &tsd->use_a_getter_or_setter_instead_##n; \ +} +MALLOC_TSD +#undef O + +/* tsd_foop_get(tsd) returns a pointer to the thread-local instance of foo. */ +#define O(n, t) \ +JEMALLOC_ALWAYS_INLINE t * \ +tsd_##n##p_get(tsd_t *tsd) { \ + assert(tsd->state == tsd_state_nominal || \ + tsd->state == tsd_state_nominal_slow || \ + tsd->state == tsd_state_reincarnated); \ + return tsd_##n##p_get_unsafe(tsd); \ +} +MALLOC_TSD +#undef O + +/* tsd_foo_get(tsd) returns the value of the thread-local instance of foo. */ +#define O(n, t) \ +JEMALLOC_ALWAYS_INLINE t \ +tsd_##n##_get(tsd_t *tsd) { \ + return *tsd_##n##p_get(tsd); \ +} +MALLOC_TSD +#undef O + +/* tsd_foo_set(tsd, val) updates the thread-local instance of foo to be val. */ +#define O(n, t) \ +JEMALLOC_ALWAYS_INLINE void \ +tsd_##n##_set(tsd_t *tsd, t val) { \ + *tsd_##n##p_get(tsd) = val; \ +} +MALLOC_TSD +#undef O + +JEMALLOC_ALWAYS_INLINE void +tsd_assert_fast(tsd_t *tsd) { + assert(!malloc_slow && tsd_tcache_enabled_get(tsd) && + tsd_reentrancy_level_get(tsd) == 0); +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_fast(tsd_t *tsd) { + bool fast = (tsd->state == tsd_state_nominal); + if (fast) { + tsd_assert_fast(tsd); + } + + return fast; +} + +JEMALLOC_ALWAYS_INLINE tsd_t * +tsd_fetch_impl(bool init) { + tsd_t *tsd = tsd_get(init); + + if (!init && tsd_get_allocates() && tsd == NULL) { + return NULL; + } + assert(tsd != NULL); + + if (unlikely(tsd->state != tsd_state_nominal)) { + return tsd_fetch_slow(tsd); + } + assert(tsd_fast(tsd)); + tsd_assert_fast(tsd); + + return tsd; +} + +JEMALLOC_ALWAYS_INLINE tsd_t * +tsd_fetch(void) { + return tsd_fetch_impl(true); +} + +JEMALLOC_ALWAYS_INLINE tsdn_t * +tsd_tsdn(tsd_t *tsd) { + return (tsdn_t *)tsd; +} + +static inline bool +tsd_nominal(tsd_t *tsd) { + return (tsd->state <= tsd_state_nominal_max); +} + +JEMALLOC_ALWAYS_INLINE tsdn_t * +tsdn_fetch(void) { + if (!tsd_booted_get()) { + return NULL; + } + + return tsd_tsdn(tsd_fetch_impl(false)); +} + +JEMALLOC_ALWAYS_INLINE bool +tsdn_null(const tsdn_t *tsdn) { + return tsdn == NULL; +} + +JEMALLOC_ALWAYS_INLINE tsd_t * +tsdn_tsd(tsdn_t *tsdn) { + assert(!tsdn_null(tsdn)); + + return &tsdn->tsd; +} + +JEMALLOC_ALWAYS_INLINE rtree_ctx_t * +tsd_rtree_ctx(tsd_t *tsd) { + return tsd_rtree_ctxp_get(tsd); +} + +JEMALLOC_ALWAYS_INLINE rtree_ctx_t * +tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback) { + /* + * If tsd cannot be accessed, initialize the fallback rtree_ctx and + * return a pointer to it. + */ + if (unlikely(tsdn_null(tsdn))) { + rtree_ctx_data_init(fallback); + return fallback; + } + return tsd_rtree_ctx(tsdn_tsd(tsdn)); +} + +#endif /* JEMALLOC_INTERNAL_TSD_H */ diff --git a/include/jemalloc/internal/tsd_externs.h b/include/jemalloc/internal/tsd_externs.h deleted file mode 100644 index 6b9dfdc6..00000000 --- a/include/jemalloc/internal/tsd_externs.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_TSD_EXTERNS_H -#define JEMALLOC_INTERNAL_TSD_EXTERNS_H - -void *malloc_tsd_malloc(size_t size); -void malloc_tsd_dalloc(void *wrapper); -void malloc_tsd_cleanup_register(bool (*f)(void)); -tsd_t *malloc_tsd_boot0(void); -void malloc_tsd_boot1(void); -#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ - !defined(_WIN32)) -void *tsd_init_check_recursion(tsd_init_head_t *head, - tsd_init_block_t *block); -void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block); -#endif -bool tsd_data_init(void *arg); -void tsd_cleanup(void *arg); -tsd_t *tsd_fetch_slow(tsd_t *tsd); -void tsd_slow_update(tsd_t *tsd); - -#endif /* JEMALLOC_INTERNAL_TSD_EXTERNS_H */ diff --git a/include/jemalloc/internal/tsd_generic.h b/include/jemalloc/internal/tsd_generic.h new file mode 100644 index 00000000..d59cb743 --- /dev/null +++ b/include/jemalloc/internal/tsd_generic.h @@ -0,0 +1,160 @@ +#ifdef JEMALLOC_INTERNAL_TSD_GENERIC_H +#error This file should be included only once, by tsd.h. +#endif +#define JEMALLOC_INTERNAL_TSD_GENERIC_H + +typedef struct tsd_init_block_s tsd_init_block_t; +struct tsd_init_block_s { + ql_elm(tsd_init_block_t) link; + pthread_t thread; + void *data; +}; + +typedef struct tsd_init_head_s tsd_init_head_t; +struct tsd_init_head_s { + ql_head(tsd_init_block_t) blocks; + malloc_mutex_t lock; +}; + +typedef struct { + bool initialized; + tsd_t val; +} tsd_wrapper_t; + +void *tsd_init_check_recursion(tsd_init_head_t *head, + tsd_init_block_t *block); +void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block); + +extern pthread_key_t tsd_tsd; +extern tsd_init_head_t tsd_init_head; +extern tsd_wrapper_t tsd_boot_wrapper; +extern bool tsd_booted; + +/* Initialization/cleanup. */ +JEMALLOC_ALWAYS_INLINE void +tsd_cleanup_wrapper(void *arg) { + tsd_wrapper_t *wrapper = (tsd_wrapper_t *)arg; + + if (wrapper->initialized) { + wrapper->initialized = false; + tsd_cleanup(&wrapper->val); + if (wrapper->initialized) { + /* Trigger another cleanup round. */ + if (pthread_setspecific(tsd_tsd, (void *)wrapper) != 0) + { + malloc_write(": Error setting TSD\n"); + if (opt_abort) { + abort(); + } + } + return; + } + } + malloc_tsd_dalloc(wrapper); +} + +JEMALLOC_ALWAYS_INLINE void +tsd_wrapper_set(tsd_wrapper_t *wrapper) { + if (pthread_setspecific(tsd_tsd, (void *)wrapper) != 0) { + malloc_write(": Error setting TSD\n"); + abort(); + } +} + +JEMALLOC_ALWAYS_INLINE tsd_wrapper_t * +tsd_wrapper_get(bool init) { + tsd_wrapper_t *wrapper = (tsd_wrapper_t *)pthread_getspecific(tsd_tsd); + + if (init && unlikely(wrapper == NULL)) { + tsd_init_block_t block; + wrapper = (tsd_wrapper_t *) + tsd_init_check_recursion(&tsd_init_head, &block); + if (wrapper) { + return wrapper; + } + wrapper = (tsd_wrapper_t *) + malloc_tsd_malloc(sizeof(tsd_wrapper_t)); + block.data = (void *)wrapper; + if (wrapper == NULL) { + malloc_write(": Error allocating TSD\n"); + abort(); + } else { + wrapper->initialized = false; + tsd_t initializer = TSD_INITIALIZER; + wrapper->val = initializer; + } + tsd_wrapper_set(wrapper); + tsd_init_finish(&tsd_init_head, &block); + } + return wrapper; +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_boot0(void) { + if (pthread_key_create(&tsd_tsd, tsd_cleanup_wrapper) != 0) { + return true; + } + tsd_wrapper_set(&tsd_boot_wrapper); + tsd_booted = true; + return false; +} + +JEMALLOC_ALWAYS_INLINE void +tsd_boot1(void) { + tsd_wrapper_t *wrapper; + wrapper = (tsd_wrapper_t *)malloc_tsd_malloc(sizeof(tsd_wrapper_t)); + if (wrapper == NULL) { + malloc_write(": Error allocating TSD\n"); + abort(); + } + tsd_boot_wrapper.initialized = false; + tsd_cleanup(&tsd_boot_wrapper.val); + wrapper->initialized = false; + tsd_t initializer = TSD_INITIALIZER; + wrapper->val = initializer; + tsd_wrapper_set(wrapper); +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_boot(void) { + if (tsd_boot0()) { + return true; + } + tsd_boot1(); + return false; +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_booted_get(void) { + return tsd_booted; +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_get_allocates(void) { + return true; +} + +/* Get/set. */ +JEMALLOC_ALWAYS_INLINE tsd_t * +tsd_get(bool init) { + tsd_wrapper_t *wrapper; + + assert(tsd_booted); + wrapper = tsd_wrapper_get(init); + if (tsd_get_allocates() && !init && wrapper == NULL) { + return NULL; + } + return &wrapper->val; +} + +JEMALLOC_ALWAYS_INLINE void +tsd_set(tsd_t *val) { + tsd_wrapper_t *wrapper; + + assert(tsd_booted); + wrapper = tsd_wrapper_get(true); + if (likely(&wrapper->val != val)) { + wrapper->val = *(val); + } + wrapper->initialized = true; +} diff --git a/include/jemalloc/internal/tsd_inlines.h b/include/jemalloc/internal/tsd_inlines.h deleted file mode 100644 index f0f77e48..00000000 --- a/include/jemalloc/internal/tsd_inlines.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_TSD_INLINES_H -#define JEMALLOC_INTERNAL_TSD_INLINES_H - -malloc_tsd_externs(, tsd_t) -malloc_tsd_funcs(JEMALLOC_ALWAYS_INLINE, , tsd_t, tsd_initializer, tsd_cleanup) - -#define MALLOC_TSD_getset_yes(n, t) \ -JEMALLOC_ALWAYS_INLINE t \ -tsd_##n##_get(tsd_t *tsd) { \ - return *tsd_##n##p_get(tsd); \ -} \ -JEMALLOC_ALWAYS_INLINE void \ -tsd_##n##_set(tsd_t *tsd, t n) { \ - assert(tsd->state == tsd_state_nominal || \ - tsd->state == tsd_state_nominal_slow || \ - tsd->state == tsd_state_reincarnated); \ - tsd->n = n; \ -} -#define MALLOC_TSD_getset_no(n, t) -#define O(n, t, gs, i, c) \ -JEMALLOC_ALWAYS_INLINE t * \ -tsd_##n##p_get(tsd_t *tsd) { \ - return &tsd->n; \ -} \ - \ -MALLOC_TSD_getset_##gs(n, t) -MALLOC_TSD -#undef MALLOC_TSD_getset_yes -#undef MALLOC_TSD_getset_no -#undef O - -JEMALLOC_ALWAYS_INLINE bool -tsd_assert_fast(tsd_t *tsd) { - assert(!malloc_slow && tsd_tcache_enabled_get(tsd) && - tsd_reentrancy_level_get(tsd) == 0); - return true; -} - -JEMALLOC_ALWAYS_INLINE bool -tsd_fast(tsd_t *tsd) { - bool fast = (tsd->state == tsd_state_nominal); - if (fast) { - tsd_assert_fast(tsd); - } - - return fast; -} - -JEMALLOC_ALWAYS_INLINE tsd_t * -tsd_fetch_impl(bool init) { - tsd_t *tsd = tsd_get(init); - - if (!init && tsd_get_allocates() && tsd == NULL) { - return NULL; - } - assert(tsd != NULL); - - if (unlikely(tsd->state != tsd_state_nominal)) { - return tsd_fetch_slow(tsd); - } - assert(tsd_fast(tsd)); - tsd_assert_fast(tsd); - - return tsd; -} - -JEMALLOC_ALWAYS_INLINE tsd_t * -tsd_fetch(void) { - return tsd_fetch_impl(true); -} - -JEMALLOC_ALWAYS_INLINE tsdn_t * -tsd_tsdn(tsd_t *tsd) { - return (tsdn_t *)tsd; -} - -static inline bool -tsd_nominal(tsd_t *tsd) { - return (tsd->state <= tsd_state_nominal_max); -} - -JEMALLOC_ALWAYS_INLINE tsdn_t * -tsdn_fetch(void) { - if (!tsd_booted_get()) { - return NULL; - } - - return tsd_tsdn(tsd_fetch_impl(false)); -} - -JEMALLOC_ALWAYS_INLINE bool -tsdn_null(const tsdn_t *tsdn) { - return tsdn == NULL; -} - -JEMALLOC_ALWAYS_INLINE tsd_t * -tsdn_tsd(tsdn_t *tsdn) { - assert(!tsdn_null(tsdn)); - - return &tsdn->tsd; -} - -JEMALLOC_ALWAYS_INLINE rtree_ctx_t * -tsd_rtree_ctx(tsd_t *tsd) { - return tsd_rtree_ctxp_get(tsd); -} - -JEMALLOC_ALWAYS_INLINE rtree_ctx_t * -tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback) { - /* - * If tsd cannot be accessed, initialize the fallback rtree_ctx and - * return a pointer to it. - */ - if (unlikely(tsdn_null(tsdn))) { - rtree_ctx_data_init(fallback); - return fallback; - } - return tsd_rtree_ctx(tsdn_tsd(tsdn)); -} - -#endif /* JEMALLOC_INTERNAL_TSD_INLINES_H */ diff --git a/include/jemalloc/internal/tsd_malloc_thread_cleanup.h b/include/jemalloc/internal/tsd_malloc_thread_cleanup.h new file mode 100644 index 00000000..beb467a6 --- /dev/null +++ b/include/jemalloc/internal/tsd_malloc_thread_cleanup.h @@ -0,0 +1,60 @@ +#ifdef JEMALLOC_INTERNAL_TSD_MALLOC_THREAD_CLEANUP_H +#error This file should be included only once, by tsd.h. +#endif +#define JEMALLOC_INTERNAL_TSD_MALLOC_THREAD_CLEANUP_H + +extern __thread tsd_t tsd_tls; +extern __thread bool tsd_initialized; +extern bool tsd_booted; + +/* Initialization/cleanup. */ +JEMALLOC_ALWAYS_INLINE bool +tsd_cleanup_wrapper(void) { + if (tsd_initialized) { + tsd_initialized = false; + tsd_cleanup(&tsd_tls); + } + return tsd_initialized; +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_boot0(void) { + malloc_tsd_cleanup_register(&tsd_cleanup_wrapper); + tsd_booted = true; + return false; +} + +JEMALLOC_ALWAYS_INLINE void +tsd_boot1(void) { + /* Do nothing. */ +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_boot(void) { + return tsd_boot0(); +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_booted_get(void) { + return tsd_booted; +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_get_allocates(void) { + return false; +} + +/* Get/set. */ +JEMALLOC_ALWAYS_INLINE tsd_t * +tsd_get(bool init) { + assert(tsd_booted); + return &tsd_tls; +} +JEMALLOC_ALWAYS_INLINE void +tsd_set(tsd_t *val) { + assert(tsd_booted); + if (likely(&tsd_tls != val)) { + tsd_tls = (*val); + } + tsd_initialized = true; +} diff --git a/include/jemalloc/internal/tsd_structs.h b/include/jemalloc/internal/tsd_structs.h deleted file mode 100644 index 40fea97b..00000000 --- a/include/jemalloc/internal/tsd_structs.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_TSD_STRUCTS_H -#define JEMALLOC_INTERNAL_TSD_STRUCTS_H - -#include "jemalloc/internal/ql.h" - -#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ - !defined(_WIN32)) -struct tsd_init_block_s { - ql_elm(tsd_init_block_t) link; - pthread_t thread; - void *data; -}; -struct tsd_init_head_s { - ql_head(tsd_init_block_t) blocks; - malloc_mutex_t lock; -}; -#endif - -/* - * Thread-Specific-Data layout - * --- data accessed on tcache fast path: state, rtree_ctx, stats, prof --- - * s: state - * e: tcache_enabled - * m: thread_allocated (config_stats) - * f: thread_deallocated (config_stats) - * p: prof_tdata (config_prof) - * c: rtree_ctx (rtree cache accessed on deallocation) - * t: tcache - * --- data not accessed on tcache fast path: arena related fields --- - * d: arenas_tdata_bypass - * r: reentrancy_level - * x: narenas_tdata - * i: iarena - * a: arena - * o: arenas_tdata - * Loading TSD data is on the critical path of basically all malloc operations. - * In particular, tcache and rtree_ctx rely on hot CPU cache to be effective. - * Use a compact layout to reduce cache footprint. - * +--- 64-bit and 64B cacheline; 1B each letter; First byte on the left. ---+ - * |---------------------------- 1st cacheline ----------------------------| - * | sedrxxxx mmmmmmmm ffffffff pppppppp [c * 32 ........ ........ .......] | - * |---------------------------- 2nd cacheline ----------------------------| - * | [c * 64 ........ ........ ........ ........ ........ ........ .......] | - * |---------------------------- 3nd cacheline ----------------------------| - * | [c * 32 ........ ........ .......] iiiiiiii aaaaaaaa oooooooo [t...... | - * +-------------------------------------------------------------------------+ - * Note: the entire tcache is embedded into TSD and spans multiple cachelines. - * - * The last 3 members (i, a and o) before tcache isn't really needed on tcache - * fast path. However we have a number of unused tcache bins and witnesses - * (never touched unless config_debug) at the end of tcache, so we place them - * there to avoid breaking the cachelines and possibly paging in an extra page. - */ -#define MALLOC_TSD \ -/* O(name, type, [gs]et, init, cleanup) */ \ - O(tcache_enabled, bool, yes, yes, no) \ - O(arenas_tdata_bypass, bool, no, no, no) \ - O(reentrancy_level, int8_t, yes, no, no) \ - O(narenas_tdata, uint32_t, yes, no, no) \ - O(thread_allocated, uint64_t, yes, no, no) \ - O(thread_deallocated, uint64_t, yes, no, no) \ - O(prof_tdata, prof_tdata_t *, yes, no, yes) \ - O(rtree_ctx, rtree_ctx_t, no, yes, no) \ - O(iarena, arena_t *, yes, no, yes) \ - O(arena, arena_t *, yes, no, yes) \ - O(arenas_tdata, arena_tdata_t *,yes, no, yes) \ - O(tcache, tcache_t, no, no, yes) \ - O(witnesses, witness_list_t, no, no, yes) \ - O(rtree_leaf_elm_witnesses, rtree_leaf_elm_witness_tsd_t, \ - no, no, no) \ - O(witness_fork, bool, yes, no, no) - -#define TSD_INITIALIZER { \ - tsd_state_uninitialized, \ - TCACHE_ENABLED_ZERO_INITIALIZER, \ - false, \ - 0, \ - 0, \ - 0, \ - 0, \ - NULL, \ - RTREE_CTX_ZERO_INITIALIZER, \ - NULL, \ - NULL, \ - NULL, \ - TCACHE_ZERO_INITIALIZER, \ - ql_head_initializer(witnesses), \ - RTREE_ELM_WITNESS_TSD_INITIALIZER, \ - false \ -} - -struct tsd_s { - tsd_state_t state; -#define O(n, t, gs, i, c) \ - t n; -MALLOC_TSD -#undef O -}; - -/* - * Wrapper around tsd_t that makes it possible to avoid implicit conversion - * between tsd_t and tsdn_t, where tsdn_t is "nullable" and has to be - * explicitly converted to tsd_t, which is non-nullable. - */ -struct tsdn_s { - tsd_t tsd; -}; - -static const tsd_t tsd_initializer = TSD_INITIALIZER; -UNUSED static const void *malloc_tsd_no_cleanup = (void *)0; - -malloc_tsd_types(, tsd_t) - -#endif /* JEMALLOC_INTERNAL_TSD_STRUCTS_H */ diff --git a/include/jemalloc/internal/tsd_tls.h b/include/jemalloc/internal/tsd_tls.h new file mode 100644 index 00000000..757aaa0e --- /dev/null +++ b/include/jemalloc/internal/tsd_tls.h @@ -0,0 +1,59 @@ +#ifdef JEMALLOC_INTERNAL_TSD_TLS_H +#error This file should be included only once, by tsd.h. +#endif +#define JEMALLOC_INTERNAL_TSD_TLS_H + +extern __thread tsd_t tsd_tls; +extern pthread_key_t tsd_tsd; +extern bool tsd_booted; + +/* Initialization/cleanup. */ +JEMALLOC_ALWAYS_INLINE bool +tsd_boot0(void) { + if (pthread_key_create(&tsd_tsd, &tsd_cleanup) != 0) { + return true; + } + tsd_booted = true; + return false; +} + +JEMALLOC_ALWAYS_INLINE void +tsd_boot1(void) { + /* Do nothing. */ +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_boot(void) { + return tsd_boot0(); +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_booted_get(void) { + return tsd_booted; +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_get_allocates(void) { + return false; +} + +/* Get/set. */ +JEMALLOC_ALWAYS_INLINE tsd_t * +tsd_get(bool init) { + assert(tsd_booted); + return &tsd_tls; +} + +JEMALLOC_ALWAYS_INLINE void +tsd_set(tsd_t *val) { + assert(tsd_booted); + if (likely(&tsd_tls != val)) { + tsd_tls = (*val); + } + if (pthread_setspecific(tsd_tsd, (void *)(&tsd_tls)) != 0) { + malloc_write(": Error setting tsd.\n"); + if (opt_abort) { + abort(); + } + } +} diff --git a/include/jemalloc/internal/tsd_types.h b/include/jemalloc/internal/tsd_types.h index dc9efbb6..6200af61 100644 --- a/include/jemalloc/internal/tsd_types.h +++ b/include/jemalloc/internal/tsd_types.h @@ -1,549 +1,10 @@ #ifndef JEMALLOC_INTERNAL_TSD_TYPES_H #define JEMALLOC_INTERNAL_TSD_TYPES_H -#include "jemalloc/internal/ql.h" - -/* Maximum number of malloc_tsd users with cleanup functions. */ #define MALLOC_TSD_CLEANUPS_MAX 2 -typedef bool (*malloc_tsd_cleanup_t)(void); - -#if (!defined(JEMALLOC_MALLOC_THREAD_CLEANUP) && !defined(JEMALLOC_TLS) && \ - !defined(_WIN32)) -typedef struct tsd_init_block_s tsd_init_block_t; -typedef struct tsd_init_head_s tsd_init_head_t; -#endif - typedef struct tsd_s tsd_t; typedef struct tsdn_s tsdn_t; - -#define TSDN_NULL ((tsdn_t *)0) - -enum { - tsd_state_nominal = 0, /* Common case --> jnz. */ - tsd_state_nominal_slow = 1, /* Initialized but on slow path. */ - /* the above 2 nominal states should be lower values. */ - tsd_state_nominal_max = 1, /* used for comparison only. */ - tsd_state_purgatory = 2, - tsd_state_reincarnated = 3, - tsd_state_uninitialized = 4 -}; - -/* Manually limit tsd_state_t to a single byte. */ -typedef uint8_t tsd_state_t; - -/* - * TLS/TSD-agnostic macro-based implementation of thread-specific data. There - * are five macros that support (at least) three use cases: file-private, - * library-private, and library-private inlined. Following is an example - * library-private tsd variable: - * - * In example.h: - * typedef struct { - * int x; - * int y; - * } example_t; - * #define EX_INITIALIZER JEMALLOC_CONCAT({0, 0}) - * malloc_tsd_types(example_, example_t) - * malloc_tsd_protos(, example_, example_t) - * malloc_tsd_externs(example_, example_t) - * In example.c: - * malloc_tsd_data(, example_, example_t, EX_INITIALIZER) - * malloc_tsd_funcs(, example_, example_t, EX_INITIALIZER, - * example_tsd_cleanup) - * - * The result is a set of generated functions, e.g.: - * - * bool example_tsd_boot(void) {...} - * bool example_tsd_booted_get(void) {...} - * example_t *example_tsd_get(bool init) {...} - * void example_tsd_set(example_t *val) {...} - * - * Note that all of the functions deal in terms of (a_type *) rather than - * (a_type) so that it is possible to support non-pointer types (unlike - * pthreads TSD). example_tsd_cleanup() is passed an (a_type *) pointer that is - * cast to (void *). This means that the cleanup function needs to cast the - * function argument to (a_type *), then dereference the resulting pointer to - * access fields, e.g. - * - * void - * example_tsd_cleanup(void *arg) - * { - * example_t *example = (example_t *)arg; - * - * example->x = 42; - * [...] - * if ([want the cleanup function to be called again]) - * example_tsd_set(example); - * } - * - * If example_tsd_set() is called within example_tsd_cleanup(), it will be - * called again. This is similar to how pthreads TSD destruction works, except - * that pthreads only calls the cleanup function again if the value was set to - * non-NULL. - */ - -/* malloc_tsd_types(). */ -#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP -#define malloc_tsd_types(a_name, a_type) -#elif (defined(JEMALLOC_TLS)) -#define malloc_tsd_types(a_name, a_type) -#elif (defined(_WIN32)) -#define malloc_tsd_types(a_name, a_type) \ -typedef struct { \ - bool initialized; \ - a_type val; \ -} a_name##tsd_wrapper_t; -#else -#define malloc_tsd_types(a_name, a_type) \ -typedef struct { \ - bool initialized; \ - a_type val; \ -} a_name##tsd_wrapper_t; -#endif - -/* malloc_tsd_protos(). */ -#define malloc_tsd_protos(a_attr, a_name, a_type) \ -a_attr bool \ -a_name##tsd_boot0(void); \ -a_attr void \ -a_name##tsd_boot1(void); \ -a_attr bool \ -a_name##tsd_boot(void); \ -a_attr bool \ -a_name##tsd_booted_get(void); \ -a_attr a_type * \ -a_name##tsd_get(bool init); \ -a_attr void \ -a_name##tsd_set(a_type *val); - -/* malloc_tsd_externs(). */ -#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP -#define malloc_tsd_externs(a_name, a_type) \ -extern __thread a_type a_name##tsd_tls; \ -extern __thread bool a_name##tsd_initialized; \ -extern bool a_name##tsd_booted; -#elif (defined(JEMALLOC_TLS)) -#define malloc_tsd_externs(a_name, a_type) \ -extern __thread a_type a_name##tsd_tls; \ -extern pthread_key_t a_name##tsd_tsd; \ -extern bool a_name##tsd_booted; -#elif (defined(_WIN32)) -#define malloc_tsd_externs(a_name, a_type) \ -extern DWORD a_name##tsd_tsd; \ -extern a_name##tsd_wrapper_t a_name##tsd_boot_wrapper; \ -extern bool a_name##tsd_booted; -#else -#define malloc_tsd_externs(a_name, a_type) \ -extern pthread_key_t a_name##tsd_tsd; \ -extern tsd_init_head_t a_name##tsd_init_head; \ -extern a_name##tsd_wrapper_t a_name##tsd_boot_wrapper; \ -extern bool a_name##tsd_booted; -#endif - -/* malloc_tsd_data(). */ -#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP -#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ -a_attr __thread a_type JEMALLOC_TLS_MODEL \ - a_name##tsd_tls = a_initializer; \ -a_attr __thread bool JEMALLOC_TLS_MODEL \ - a_name##tsd_initialized = false; \ -a_attr bool a_name##tsd_booted = false; -#elif (defined(JEMALLOC_TLS)) -#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ -a_attr __thread a_type JEMALLOC_TLS_MODEL \ - a_name##tsd_tls = a_initializer; \ -a_attr pthread_key_t a_name##tsd_tsd; \ -a_attr bool a_name##tsd_booted = false; -#elif (defined(_WIN32)) -#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ -a_attr DWORD a_name##tsd_tsd; \ -a_attr a_name##tsd_wrapper_t a_name##tsd_boot_wrapper = { \ - false, \ - a_initializer \ -}; \ -a_attr bool a_name##tsd_booted = false; -#else -#define malloc_tsd_data(a_attr, a_name, a_type, a_initializer) \ -a_attr pthread_key_t a_name##tsd_tsd; \ -a_attr tsd_init_head_t a_name##tsd_init_head = { \ - ql_head_initializer(blocks), \ - MALLOC_MUTEX_INITIALIZER \ -}; \ -a_attr a_name##tsd_wrapper_t a_name##tsd_boot_wrapper = { \ - false, \ - a_initializer \ -}; \ -a_attr bool a_name##tsd_booted = false; -#endif - -/* malloc_tsd_funcs(). */ -#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP -#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ - a_cleanup) \ -/* Initialization/cleanup. */ \ -a_attr bool \ -a_name##tsd_cleanup_wrapper(void) { \ - if (a_name##tsd_initialized) { \ - a_name##tsd_initialized = false; \ - a_cleanup(&a_name##tsd_tls); \ - } \ - return a_name##tsd_initialized; \ -} \ -a_attr bool \ -a_name##tsd_boot0(void) { \ - if (a_cleanup != malloc_tsd_no_cleanup) { \ - malloc_tsd_cleanup_register( \ - &a_name##tsd_cleanup_wrapper); \ - } \ - a_name##tsd_booted = true; \ - return false; \ -} \ -a_attr void \ -a_name##tsd_boot1(void) { \ - /* Do nothing. */ \ -} \ -a_attr bool \ -a_name##tsd_boot(void) { \ - return a_name##tsd_boot0(); \ -} \ -a_attr bool \ -a_name##tsd_booted_get(void) { \ - return a_name##tsd_booted; \ -} \ -a_attr bool \ -a_name##tsd_get_allocates(void) { \ - return false; \ -} \ -/* Get/set. */ \ -a_attr a_type * \ -a_name##tsd_get(bool init) { \ - assert(a_name##tsd_booted); \ - return &a_name##tsd_tls; \ -} \ -a_attr void \ -a_name##tsd_set(a_type *val) { \ - assert(a_name##tsd_booted); \ - if (likely(&a_name##tsd_tls != val)) { \ - a_name##tsd_tls = (*val); \ - } \ - if (a_cleanup != malloc_tsd_no_cleanup) { \ - a_name##tsd_initialized = true; \ - } \ -} -#elif (defined(JEMALLOC_TLS)) -#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ - a_cleanup) \ -/* Initialization/cleanup. */ \ -a_attr bool \ -a_name##tsd_boot0(void) { \ - if (a_cleanup != malloc_tsd_no_cleanup) { \ - if (pthread_key_create(&a_name##tsd_tsd, a_cleanup) != \ - 0) { \ - return true; \ - } \ - } \ - a_name##tsd_booted = true; \ - return false; \ -} \ -a_attr void \ -a_name##tsd_boot1(void) { \ - /* Do nothing. */ \ -} \ -a_attr bool \ -a_name##tsd_boot(void) { \ - return a_name##tsd_boot0(); \ -} \ -a_attr bool \ -a_name##tsd_booted_get(void) { \ - return a_name##tsd_booted; \ -} \ -a_attr bool \ -a_name##tsd_get_allocates(void) { \ - return false; \ -} \ -/* Get/set. */ \ -a_attr a_type * \ -a_name##tsd_get(bool init) { \ - assert(a_name##tsd_booted); \ - return &a_name##tsd_tls; \ -} \ -a_attr void \ -a_name##tsd_set(a_type *val) { \ - assert(a_name##tsd_booted); \ - if (likely(&a_name##tsd_tls != val)) { \ - a_name##tsd_tls = (*val); \ - } \ - if (a_cleanup != malloc_tsd_no_cleanup) { \ - if (pthread_setspecific(a_name##tsd_tsd, \ - (void *)(&a_name##tsd_tls))) { \ - malloc_write(": Error" \ - " setting TSD for "#a_name"\n"); \ - if (opt_abort) { \ - abort(); \ - } \ - } \ - } \ -} -#elif (defined(_WIN32)) -#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ - a_cleanup) \ -/* Initialization/cleanup. */ \ -a_attr bool \ -a_name##tsd_cleanup_wrapper(void) { \ - DWORD error = GetLastError(); \ - a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ - TlsGetValue(a_name##tsd_tsd); \ - SetLastError(error); \ - \ - if (wrapper == NULL) { \ - return false; \ - } \ - if (a_cleanup != malloc_tsd_no_cleanup && \ - wrapper->initialized) { \ - wrapper->initialized = false; \ - a_cleanup(&wrapper->val); \ - if (wrapper->initialized) { \ - /* Trigger another cleanup round. */ \ - return true; \ - } \ - } \ - malloc_tsd_dalloc(wrapper); \ - return false; \ -} \ -a_attr void \ -a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) { \ - if (!TlsSetValue(a_name##tsd_tsd, (void *)wrapper)) { \ - malloc_write(": Error setting" \ - " TSD for "#a_name"\n"); \ - abort(); \ - } \ -} \ -a_attr a_name##tsd_wrapper_t * \ -a_name##tsd_wrapper_get(bool init) { \ - DWORD error = GetLastError(); \ - a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ - TlsGetValue(a_name##tsd_tsd); \ - SetLastError(error); \ - \ - if (init && unlikely(wrapper == NULL)) { \ - wrapper = (a_name##tsd_wrapper_t *) \ - malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ - if (wrapper == NULL) { \ - malloc_write(": Error allocating" \ - " TSD for "#a_name"\n"); \ - abort(); \ - } else { \ - wrapper->initialized = false; \ - wrapper->val = a_initializer; \ - } \ - a_name##tsd_wrapper_set(wrapper); \ - } \ - return wrapper; \ -} \ -a_attr bool \ -a_name##tsd_boot0(void) { \ - a_name##tsd_tsd = TlsAlloc(); \ - if (a_name##tsd_tsd == TLS_OUT_OF_INDEXES) { \ - return true; \ - } \ - if (a_cleanup != malloc_tsd_no_cleanup) { \ - malloc_tsd_cleanup_register( \ - &a_name##tsd_cleanup_wrapper); \ - } \ - a_name##tsd_wrapper_set(&a_name##tsd_boot_wrapper); \ - a_name##tsd_booted = true; \ - return false; \ -} \ -a_attr void \ -a_name##tsd_boot1(void) { \ - a_name##tsd_wrapper_t *wrapper; \ - wrapper = (a_name##tsd_wrapper_t *) \ - malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ - if (wrapper == NULL) { \ - malloc_write(": Error allocating" \ - " TSD for "#a_name"\n"); \ - abort(); \ - } \ - a_name##tsd_boot_wrapper.initialized = false; \ - a_cleanup(&a_name##tsd_boot_wrapper.val); \ - wrapper->initialized = false; \ - wrapper->val = a_initializer; \ - a_name##tsd_wrapper_set(wrapper); \ -} \ -a_attr bool \ -a_name##tsd_boot(void) { \ - if (a_name##tsd_boot0()) { \ - return true; \ - } \ - a_name##tsd_boot1(); \ - return false; \ -} \ -a_attr bool \ -a_name##tsd_booted_get(void) { \ - return a_name##tsd_booted; \ -} \ -a_attr bool \ -a_name##tsd_get_allocates(void) { \ - return true; \ -} \ -/* Get/set. */ \ -a_attr a_type * \ -a_name##tsd_get(bool init) { \ - a_name##tsd_wrapper_t *wrapper; \ - \ - assert(a_name##tsd_booted); \ - wrapper = a_name##tsd_wrapper_get(init); \ - if (a_name##tsd_get_allocates() && !init && wrapper == NULL) { \ - return NULL; \ - } \ - return &wrapper->val; \ -} \ -a_attr void \ -a_name##tsd_set(a_type *val) { \ - a_name##tsd_wrapper_t *wrapper; \ - \ - assert(a_name##tsd_booted); \ - wrapper = a_name##tsd_wrapper_get(true); \ - if (likely(&wrapper->val != val)) { \ - wrapper->val = *(val); \ - } \ - if (a_cleanup != malloc_tsd_no_cleanup) { \ - wrapper->initialized = true; \ - } \ -} -#else -#define malloc_tsd_funcs(a_attr, a_name, a_type, a_initializer, \ - a_cleanup) \ -/* Initialization/cleanup. */ \ -a_attr void \ -a_name##tsd_cleanup_wrapper(void *arg) { \ - a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *)arg; \ - \ - if (a_cleanup != malloc_tsd_no_cleanup && \ - wrapper->initialized) { \ - wrapper->initialized = false; \ - a_cleanup(&wrapper->val); \ - if (wrapper->initialized) { \ - /* Trigger another cleanup round. */ \ - if (pthread_setspecific(a_name##tsd_tsd, \ - (void *)wrapper)) { \ - malloc_write(": Error" \ - " setting TSD for "#a_name"\n"); \ - if (opt_abort) { \ - abort(); \ - } \ - } \ - return; \ - } \ - } \ - malloc_tsd_dalloc(wrapper); \ -} \ -a_attr void \ -a_name##tsd_wrapper_set(a_name##tsd_wrapper_t *wrapper) { \ - if (pthread_setspecific(a_name##tsd_tsd, \ - (void *)wrapper)) { \ - malloc_write(": Error setting" \ - " TSD for "#a_name"\n"); \ - abort(); \ - } \ -} \ -a_attr a_name##tsd_wrapper_t * \ -a_name##tsd_wrapper_get(bool init) { \ - a_name##tsd_wrapper_t *wrapper = (a_name##tsd_wrapper_t *) \ - pthread_getspecific(a_name##tsd_tsd); \ - \ - if (init && unlikely(wrapper == NULL)) { \ - tsd_init_block_t block; \ - wrapper = (a_name##tsd_wrapper_t *) \ - tsd_init_check_recursion(&a_name##tsd_init_head, \ - &block); \ - if (wrapper) { \ - return wrapper; \ - } \ - wrapper = (a_name##tsd_wrapper_t *) \ - malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ - block.data = (void *)wrapper; \ - if (wrapper == NULL) { \ - malloc_write(": Error allocating" \ - " TSD for "#a_name"\n"); \ - abort(); \ - } else { \ - wrapper->initialized = false; \ - wrapper->val = a_initializer; \ - } \ - a_name##tsd_wrapper_set(wrapper); \ - tsd_init_finish(&a_name##tsd_init_head, &block); \ - } \ - return wrapper; \ -} \ -a_attr bool \ -a_name##tsd_boot0(void) { \ - if (pthread_key_create(&a_name##tsd_tsd, \ - a_name##tsd_cleanup_wrapper) != 0) { \ - return true; \ - } \ - a_name##tsd_wrapper_set(&a_name##tsd_boot_wrapper); \ - a_name##tsd_booted = true; \ - return false; \ -} \ -a_attr void \ -a_name##tsd_boot1(void) { \ - a_name##tsd_wrapper_t *wrapper; \ - wrapper = (a_name##tsd_wrapper_t *) \ - malloc_tsd_malloc(sizeof(a_name##tsd_wrapper_t)); \ - if (wrapper == NULL) { \ - malloc_write(": Error allocating" \ - " TSD for "#a_name"\n"); \ - abort(); \ - } \ - a_name##tsd_boot_wrapper.initialized = false; \ - a_cleanup(&a_name##tsd_boot_wrapper.val); \ - wrapper->initialized = false; \ - wrapper->val = a_initializer; \ - a_name##tsd_wrapper_set(wrapper); \ -} \ -a_attr bool \ -a_name##tsd_boot(void) { \ - if (a_name##tsd_boot0()) { \ - return true; \ - } \ - a_name##tsd_boot1(); \ - return false; \ -} \ -a_attr bool \ -a_name##tsd_booted_get(void) { \ - return a_name##tsd_booted; \ -} \ -a_attr bool \ -a_name##tsd_get_allocates(void) { \ - return true; \ -} \ -/* Get/set. */ \ -a_attr a_type * \ -a_name##tsd_get(bool init) { \ - a_name##tsd_wrapper_t *wrapper; \ - \ - assert(a_name##tsd_booted); \ - wrapper = a_name##tsd_wrapper_get(init); \ - if (a_name##tsd_get_allocates() && !init && wrapper == NULL) { \ - return NULL; \ - } \ - return &wrapper->val; \ -} \ -a_attr void \ -a_name##tsd_set(a_type *val) { \ - a_name##tsd_wrapper_t *wrapper; \ - \ - assert(a_name##tsd_booted); \ - wrapper = a_name##tsd_wrapper_get(true); \ - if (likely(&wrapper->val != val)) { \ - wrapper->val = *(val); \ - } \ - if (a_cleanup != malloc_tsd_no_cleanup) { \ - wrapper->initialized = true; \ - } \ -} -#endif +typedef bool (*malloc_tsd_cleanup_t)(void); #endif /* JEMALLOC_INTERNAL_TSD_TYPES_H */ diff --git a/include/jemalloc/internal/tsd_win.h b/include/jemalloc/internal/tsd_win.h new file mode 100644 index 00000000..cf30d18e --- /dev/null +++ b/include/jemalloc/internal/tsd_win.h @@ -0,0 +1,139 @@ +#ifdef JEMALLOC_INTERNAL_TSD_WIN_H +#error This file should be included only once, by tsd.h. +#endif +#define JEMALLOC_INTERNAL_TSD_WIN_H + +typedef struct { + bool initialized; + tsd_t val; +} tsd_wrapper_t; + +extern DWORD tsd_tsd; +extern tsd_wrapper_t tsd_boot_wrapper; +extern bool tsd_booted; + +/* Initialization/cleanup. */ +JEMALLOC_ALWAYS_INLINE bool +tsd_cleanup_wrapper(void) { + DWORD error = GetLastError(); + tsd_wrapper_t *wrapper = (tsd_wrapper_t *)TlsGetValue(tsd_tsd); + SetLastError(error); + + if (wrapper == NULL) { + return false; + } + + if (wrapper->initialized) { + wrapper->initialized = false; + tsd_cleanup(&wrapper->val); + if (wrapper->initialized) { + /* Trigger another cleanup round. */ + return true; + } + } + malloc_tsd_dalloc(wrapper); + return false; +} + +JEMALLOC_ALWAYS_INLINE void +tsd_wrapper_set(tsd_wrapper_t *wrapper) { + if (!TlsSetValue(tsd_tsd, (void *)wrapper)) { + malloc_write(": Error setting TSD\n"); + abort(); + } +} + +JEMALLOC_ALWAYS_INLINE tsd_wrapper_t * +tsd_wrapper_get(bool init) { + DWORD error = GetLastError(); + tsd_wrapper_t *wrapper = (tsd_wrapper_t *) TlsGetValue(tsd_tsd); + SetLastError(error); + + if (init && unlikely(wrapper == NULL)) { + wrapper = (tsd_wrapper_t *) + malloc_tsd_malloc(sizeof(tsd_wrapper_t)); + if (wrapper == NULL) { + malloc_write(": Error allocating TSD\n"); + abort(); + } else { + wrapper->initialized = false; + /* MSVC is finicky about aggregate initialization. */ + tsd_t tsd_initializer = TSD_INITIALIZER; + wrapper->val = tsd_initializer; + } + tsd_wrapper_set(wrapper); + } + return wrapper; +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_boot0(void) { + tsd_tsd = TlsAlloc(); + if (tsd_tsd == TLS_OUT_OF_INDEXES) { + return true; + } + malloc_tsd_cleanup_register(&tsd_cleanup_wrapper); + tsd_wrapper_set(&tsd_boot_wrapper); + tsd_booted = true; + return false; +} + +JEMALLOC_ALWAYS_INLINE void +tsd_boot1(void) { + tsd_wrapper_t *wrapper; + wrapper = (tsd_wrapper_t *) + malloc_tsd_malloc(sizeof(tsd_wrapper_t)); + if (wrapper == NULL) { + malloc_write(": Error allocating TSD\n"); + abort(); + } + tsd_boot_wrapper.initialized = false; + tsd_cleanup(&tsd_boot_wrapper.val); + wrapper->initialized = false; + tsd_t initializer = TSD_INITIALIZER; + wrapper->val = initializer; + tsd_wrapper_set(wrapper); +} +JEMALLOC_ALWAYS_INLINE bool +tsd_boot(void) { + if (tsd_boot0()) { + return true; + } + tsd_boot1(); + return false; +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_booted_get(void) { + return tsd_booted; +} + +JEMALLOC_ALWAYS_INLINE bool +tsd_get_allocates(void) { + return true; +} + +/* Get/set. */ +JEMALLOC_ALWAYS_INLINE tsd_t * +tsd_get(bool init) { + tsd_wrapper_t *wrapper; + + assert(tsd_booted); + wrapper = tsd_wrapper_get(init); + if (tsd_get_allocates() && !init && wrapper == NULL) { + return NULL; + } + return &wrapper->val; +} + +JEMALLOC_ALWAYS_INLINE void +tsd_set(tsd_t *val) { + tsd_wrapper_t *wrapper; + + assert(tsd_booted); + wrapper = tsd_wrapper_get(true); + if (likely(&wrapper->val != val)) { + wrapper->val = *(val); + } + wrapper->initialized = true; +} diff --git a/src/jemalloc.c b/src/jemalloc.c index 97a64431..b8c94133 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -2035,7 +2035,9 @@ irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize, JEMALLOC_ALWAYS_INLINE void ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { - assert(slow_path || tsd_assert_fast(tsd)); + if (!slow_path) { + tsd_assert_fast(tsd); + } if (tsd_reentrancy_level_get(tsd) == 0) { witness_assert_lockless(tsd_tsdn(tsd)); } else { @@ -2073,7 +2075,9 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { JEMALLOC_ALWAYS_INLINE void isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) { - assert(slow_path || tsd_assert_fast(tsd)); + if (!slow_path) { + tsd_assert_fast(tsd); + } if (tsd_reentrancy_level_get(tsd) == 0) { witness_assert_lockless(tsd_tsdn(tsd)); } else { diff --git a/src/prof.c b/src/prof.c index 1e818ab4..d60680c1 100644 --- a/src/prof.c +++ b/src/prof.c @@ -1642,7 +1642,7 @@ static bool prof_dump(tsd_t *tsd, bool propagate_err, const char *filename, bool leakcheck) { cassert(config_prof); - assert(tsd->reentrancy_level == 0); + assert(tsd_reentrancy_level_get(tsd) == 0); prof_tdata_t * tdata = prof_tdata_get(tsd, true); if (tdata == NULL) { @@ -1757,7 +1757,7 @@ prof_fdump(void) { return; } tsd = tsd_fetch(); - assert(tsd->reentrancy_level == 0); + assert(tsd_reentrancy_level_get(tsd) == 0); malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_seq_mtx); prof_dump_filename(filename, 'f', VSEQ_INVALID); @@ -1792,7 +1792,7 @@ prof_idump(tsdn_t *tsdn) { return; } tsd = tsdn_tsd(tsdn); - if (tsd->reentrancy_level > 0) { + if (tsd_reentrancy_level_get(tsd) > 0) { return; } @@ -1818,7 +1818,7 @@ prof_idump(tsdn_t *tsdn) { bool prof_mdump(tsd_t *tsd, const char *filename) { cassert(config_prof); - assert(tsd->reentrancy_level == 0); + assert(tsd_reentrancy_level_get(tsd) == 0); if (!opt_prof || !prof_booted) { return true; @@ -1849,7 +1849,7 @@ prof_gdump(tsdn_t *tsdn) { return; } tsd = tsdn_tsd(tsdn); - if (tsd->reentrancy_level > 0) { + if (tsd_reentrancy_level_get(tsd) > 0) { return; } diff --git a/src/rtree.c b/src/rtree.c index ada6e9d5..72786ff5 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -461,10 +461,3 @@ rtree_ctx_data_init(rtree_ctx_t *ctx) { cache->leaf = NULL; } } - -bool -tsd_rtree_ctx_data_init(tsd_t *tsd) { - rtree_ctx_data_init(&tsd->rtree_ctx); - - return false; -} diff --git a/src/tcache.c b/src/tcache.c index a7e05b17..afb1faa6 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -453,15 +453,12 @@ tcache_init(tsd_t *tsd, tcache_t *tcache, void *avail_stack) { /* Initialize auto tcache (embedded in TSD). */ bool tsd_tcache_data_init(tsd_t *tsd) { - tcache_t *tcache = &tsd->tcache; + tcache_t *tcache = tsd_tcachep_get_unsafe(tsd); assert(tcache_small_bin_get(tcache, 0)->avail == NULL); size_t size = stack_nelms * sizeof(void *); /* Avoid false cacheline sharing. */ size = sa2u(size, CACHELINE); - /* Manually initialize rcache as we may need it for allocation. */ - tsd_rtree_ctx_data_init(tsd); - void *avail_array = ipallocztm(tsd_tsdn(tsd), size, CACHELINE, true, NULL, true, arena_get(TSDN_NULL, 0, true)); if (avail_array == NULL) { diff --git a/src/tsd.c b/src/tsd.c index 686b4ef4..612f7523 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -10,14 +10,38 @@ static unsigned ncleanups; static malloc_tsd_cleanup_t cleanups[MALLOC_TSD_CLEANUPS_MAX]; -malloc_tsd_data(, , tsd_t, TSD_INITIALIZER) +#ifdef JEMALLOC_MALLOC_THREAD_CLEANUP +__thread tsd_t JEMALLOC_TLS_MODEL tsd_tls = TSD_INITIALIZER; +__thread bool JEMALLOC_TLS_MODEL tsd_initialized = false; +bool tsd_booted = false; +#elif (defined(JEMALLOC_TLS)) +__thread tsd_t JEMALLOC_TLS_MODEL tsd_tls = TSD_INITIALIZER; +pthread_key_t tsd_tsd; +bool tsd_booted = false; +#elif (defined(_WIN32)) +DWORD tsd_tsd; +tsd_wrapper_t tsd_boot_wrapper = {false, TSD_INITIALIZER}; +bool tsd_booted = false; +#else +pthread_key_t tsd_tsd; +tsd_init_head_t tsd_init_head = { + ql_head_initializer(blocks), + MALLOC_MUTEX_INITIALIZER +}; +tsd_wrapper_t tsd_boot_wrapper = { + false, + TSD_INITIALIZER +}; +bool tsd_booted = false; +#endif + /******************************************************************************/ void tsd_slow_update(tsd_t *tsd) { if (tsd_nominal(tsd)) { - if (malloc_slow || !tsd->tcache_enabled || + if (malloc_slow || !tsd_tcache_enabled_get(tsd) || tsd_reentrancy_level_get(tsd) > 0) { tsd->state = tsd_state_nominal_slow; } else { @@ -97,20 +121,28 @@ malloc_tsd_cleanup_register(bool (*f)(void)) { bool tsd_data_init(void *arg) { tsd_t *tsd = (tsd_t *)arg; -#define MALLOC_TSD_init_yes(n, t) \ - if (tsd_##n##_data_init(tsd)) { \ - return true; \ + /* + * We initialize the rtree context first (before the tcache), since the + * tcache initialization depends on it. + */ + rtree_ctx_data_init(tsd_rtree_ctxp_get_unsafe(tsd)); + + if (tsd_tcache_enabled_data_init(tsd)) { + return true; } -#define MALLOC_TSD_init_no(n, t) -#define O(n, t, gs, i, c) \ - MALLOC_TSD_init_##i(n, t) -MALLOC_TSD -#undef MALLOC_TSD_init_yes -#undef MALLOC_TSD_init_no -#undef O return false; } +static void +tsd_do_data_cleanup(tsd_t *tsd) { + prof_tdata_cleanup(tsd); + iarena_cleanup(tsd); + arena_cleanup(tsd); + arenas_tdata_cleanup(tsd); + tcache_cleanup(tsd); + witnesses_cleanup(tsd); +} + void tsd_cleanup(void *arg) { tsd_t *tsd = (tsd_t *)arg; @@ -127,15 +159,7 @@ tsd_cleanup(void *arg) { * after this destructor was called. Reset state to * tsd_state_purgatory and request another callback. */ -#define MALLOC_TSD_cleanup_yes(n, t) \ - n##_cleanup(tsd); -#define MALLOC_TSD_cleanup_no(n, t) -#define O(n, t, gs, i, c) \ - MALLOC_TSD_cleanup_##c(n, t) -MALLOC_TSD -#undef MALLOC_TSD_cleanup_yes -#undef MALLOC_TSD_cleanup_no -#undef O + tsd_do_data_cleanup(tsd); tsd->state = tsd_state_purgatory; tsd_set(tsd); break; @@ -150,6 +174,13 @@ MALLOC_TSD default: not_reached(); } +#ifdef JEMALLOC_JET + test_callback_t test_callback = *tsd_test_callbackp_get_unsafe(tsd); + int *data = tsd_test_datap_get_unsafe(tsd); + if (test_callback != NULL) { + test_callback(data); + } +#endif } tsd_t * diff --git a/test/unit/tsd.c b/test/unit/tsd.c index 38114674..c9a7d809 100644 --- a/test/unit/tsd.c +++ b/test/unit/tsd.c @@ -1,41 +1,29 @@ #include "test/jemalloc_test.h" -#define THREAD_DATA 0x72b65c10 - -typedef unsigned int data_t; - -static bool data_cleanup_executed; -static bool data_test_started; - -malloc_tsd_types(data_, data_t) -malloc_tsd_protos(, data_, data_t) +static int data_cleanup_count; void -data_cleanup(void *arg) { - data_t *data = (data_t *)arg; - - if (!data_test_started) { - return; - } - if (!data_cleanup_executed) { - assert_x_eq(*data, THREAD_DATA, +data_cleanup(int *data) { + if (data_cleanup_count == 0) { + assert_x_eq(*data, MALLOC_TSD_TEST_DATA_INIT, "Argument passed into cleanup function should match tsd " "value"); } - data_cleanup_executed = true; + ++data_cleanup_count; /* * Allocate during cleanup for two rounds, in order to assure that * jemalloc's internal tsd reinitialization happens. */ + bool reincarnate = false; switch (*data) { - case THREAD_DATA: + case MALLOC_TSD_TEST_DATA_INIT: *data = 1; - data_tsd_set(data); + reincarnate = true; break; case 1: *data = 2; - data_tsd_set(data); + reincarnate = true; break; case 2: return; @@ -43,37 +31,35 @@ data_cleanup(void *arg) { not_reached(); } - { + if (reincarnate) { void *p = mallocx(1, 0); assert_ptr_not_null(p, "Unexpeced mallocx() failure"); dallocx(p, 0); } } -malloc_tsd_externs(data_, data_t) -#define DATA_INIT 0x12345678 -malloc_tsd_data(, data_, data_t, DATA_INIT) -malloc_tsd_funcs(, data_, data_t, DATA_INIT, data_cleanup) - static void * thd_start(void *arg) { - data_t d = (data_t)(uintptr_t)arg; + int d = (int)(uintptr_t)arg; void *p; - assert_x_eq(*data_tsd_get(true), DATA_INIT, + tsd_t *tsd = tsd_fetch(); + assert_x_eq(tsd_test_data_get(tsd), MALLOC_TSD_TEST_DATA_INIT, "Initial tsd get should return initialization value"); p = malloc(1); assert_ptr_not_null(p, "Unexpected malloc() failure"); - data_tsd_set(&d); - assert_x_eq(*data_tsd_get(true), d, + tsd_test_data_set(tsd, d); + assert_x_eq(tsd_test_data_get(tsd), d, "After tsd set, tsd get should return value that was set"); d = 0; - assert_x_eq(*data_tsd_get(true), (data_t)(uintptr_t)arg, + assert_x_eq(tsd_test_data_get(tsd), (int)(uintptr_t)arg, "Resetting local data should have no effect on tsd"); + tsd_test_callback_set(tsd, &data_cleanup); + free(p); return NULL; } @@ -86,11 +72,15 @@ TEST_END TEST_BEGIN(test_tsd_sub_thread) { thd_t thd; - data_cleanup_executed = false; - thd_create(&thd, thd_start, (void *)THREAD_DATA); + data_cleanup_count = 0; + thd_create(&thd, thd_start, (void *)MALLOC_TSD_TEST_DATA_INIT); thd_join(thd, NULL); - assert_true(data_cleanup_executed, - "Cleanup function should have executed"); + /* + * We reincarnate twice in the data cleanup, so it should execute at + * least 3 times. + */ + assert_x_ge(data_cleanup_count, 3, + "Cleanup function should have executed multiple times."); } TEST_END @@ -103,9 +93,11 @@ thd_start_reincarnated(void *arg) { assert_ptr_not_null(p, "Unexpected malloc() failure"); /* Manually trigger reincarnation. */ - assert_ptr_not_null(tsd->arena, "Should have tsd arena set."); + assert_ptr_not_null(tsd_arena_get(tsd), + "Should have tsd arena set."); tsd_cleanup((void *)tsd); - assert_ptr_null(tsd->arena, "TSD arena should have been cleared."); + assert_ptr_null(*tsd_arenap_get_unsafe(tsd), + "TSD arena should have been cleared."); assert_u_eq(tsd->state, tsd_state_purgatory, "TSD state should be purgatory\n"); @@ -114,12 +106,12 @@ thd_start_reincarnated(void *arg) { "TSD state should be reincarnated\n"); p = mallocx(1, MALLOCX_TCACHE_NONE); assert_ptr_not_null(p, "Unexpected malloc() failure"); - assert_ptr_not_null(tsd->arena, + assert_ptr_not_null(*tsd_arenap_get_unsafe(tsd), "Should have tsd arena set after reincarnation."); free(p); tsd_cleanup((void *)tsd); - assert_ptr_null(tsd->arena, + assert_ptr_null(*tsd_arenap_get_unsafe(tsd), "TSD arena should have been cleared after 2nd cleanup."); return NULL; @@ -134,14 +126,11 @@ TEST_END int main(void) { - /* Core tsd bootstrapping must happen prior to data_tsd_boot(). */ + /* Ensure tsd bootstrapped. */ if (nallocx(1, 0) == 0) { malloc_printf("Initialization error"); return test_status_fail; } - data_test_started = false; - data_tsd_boot(); - data_test_started = true; return test_no_reentrancy( test_tsd_main_thread, -- GitLab From fc1aaf13fed6f9344c0681440e5a5782c889d0dc Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 28 Apr 2017 13:31:09 -0700 Subject: [PATCH 464/544] Revert "Use trylock in tcache_bin_flush when possible." This reverts commit 8584adc451f31adfc4ab8693d9189cf3a7e5d858. Production results not favorable. Will investigate separately. --- include/jemalloc/internal/tcache_externs.h | 30 ++-- include/jemalloc/internal/tcache_inlines.h | 4 +- src/tcache.c | 171 ++++++--------------- 3 files changed, 63 insertions(+), 142 deletions(-) diff --git a/include/jemalloc/internal/tcache_externs.h b/include/jemalloc/internal/tcache_externs.h index 95dfe446..abe133fa 100644 --- a/include/jemalloc/internal/tcache_externs.h +++ b/include/jemalloc/internal/tcache_externs.h @@ -27,27 +27,23 @@ extern size_t tcache_maxclass; */ extern tcaches_t *tcaches; -size_t tcache_salloc(tsdn_t *tsdn, const void *ptr); -void tcache_event_hard(tsd_t *tsd, tcache_t *tcache); -void *tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, +size_t tcache_salloc(tsdn_t *tsdn, const void *ptr); +void tcache_event_hard(tsd_t *tsd, tcache_t *tcache); +void *tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, tcache_bin_t *tbin, szind_t binind, bool *tcache_success); -void tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, +void tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, szind_t binind, unsigned rem); -unsigned tcache_bin_try_flush_small(tsd_t *tsd, tcache_t *tcache, - tcache_bin_t *tbin, szind_t binind, unsigned rem); -void tcache_bin_flush_large(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, - szind_t binind, unsigned rem); -unsigned tcache_bin_try_flush_large(tsd_t *tsd, tcache_t *tcache, - tcache_bin_t *tbin, szind_t binind, unsigned rem); -void tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, +void tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, + unsigned rem, tcache_t *tcache); +void tcache_arena_reassociate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); tcache_t *tcache_create_explicit(tsd_t *tsd); -void tcache_cleanup(tsd_t *tsd); -void tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); -bool tcaches_create(tsd_t *tsd, unsigned *r_ind); -void tcaches_flush(tsd_t *tsd, unsigned ind); -void tcaches_destroy(tsd_t *tsd, unsigned ind); -bool tcache_boot(tsdn_t *tsdn); +void tcache_cleanup(tsd_t *tsd); +void tcache_stats_merge(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); +bool tcaches_create(tsd_t *tsd, unsigned *r_ind); +void tcaches_flush(tsd_t *tsd, unsigned ind); +void tcaches_destroy(tsd_t *tsd, unsigned ind); +bool tcache_boot(tsdn_t *tsdn); void tcache_arena_associate(tsdn_t *tsdn, tcache_t *tcache, arena_t *arena); void tcache_prefork(tsdn_t *tsdn); void tcache_postfork_parent(tsdn_t *tsdn); diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index 5e9a7a0f..8a65ba2b 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -227,8 +227,8 @@ tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, tbin = tcache_large_bin_get(tcache, binind); tbin_info = &tcache_bin_info[binind]; if (unlikely(tbin->ncached == tbin_info->ncached_max)) { - tcache_bin_flush_large(tsd, tcache, tbin, binind, - (tbin_info->ncached_max >> 1)); + tcache_bin_flush_large(tsd, tbin, binind, + (tbin_info->ncached_max >> 1), tcache); } assert(tbin->ncached < tbin_info->ncached_max); tbin->ncached++; diff --git a/src/tcache.c b/src/tcache.c index afb1faa6..ee5e816f 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -45,16 +45,14 @@ tcache_event_hard(tsd_t *tsd, tcache_t *tcache) { } else { tbin = tcache_large_bin_get(tcache, binind); } - bool repeat_bin; if (tbin->low_water > 0) { /* * Flush (ceiling) 3/4 of the objects below the low water mark. */ - unsigned nflushed; if (binind < NBINS) { - nflushed = tcache_bin_try_flush_small(tsd, tcache, tbin, - binind, tbin->ncached - tbin->low_water + - (tbin->low_water >> 2)); + tcache_bin_flush_small(tsd, tcache, tbin, binind, + tbin->ncached - tbin->low_water + (tbin->low_water + >> 2)); /* * Reduce fill count by 2X. Limit lg_fill_div such that * the fill count is always at least 1. @@ -65,29 +63,23 @@ tcache_event_hard(tsd_t *tsd, tcache_t *tcache) { tcache->lg_fill_div[binind]++; } } else { - nflushed = tcache_bin_try_flush_large(tsd, tcache, tbin, - binind, tbin->ncached - tbin->low_water + - (tbin->low_water >> 2)); + tcache_bin_flush_large(tsd, tbin, binind, tbin->ncached + - tbin->low_water + (tbin->low_water >> 2), tcache); } - repeat_bin = (nflushed == 0); - } else { - if (tbin->low_water < 0) { - /* - * Increase fill count by 2X for small bins. Make sure - * lg_fill_div stays greater than 0. - */ - if (binind < NBINS && tcache->lg_fill_div[binind] > 1) { - tcache->lg_fill_div[binind]--; - } + } else if (tbin->low_water < 0) { + /* + * Increase fill count by 2X for small bins. Make sure + * lg_fill_div stays greater than 0. + */ + if (binind < NBINS && tcache->lg_fill_div[binind] > 1) { + tcache->lg_fill_div[binind]--; } - repeat_bin = false; } - if (!repeat_bin) { - tcache->next_gc_bin++; - if (tcache->next_gc_bin == nhbins) { - tcache->next_gc_bin = 0; - } - tbin->low_water = tbin->ncached; + tbin->low_water = tbin->ncached; + + tcache->next_gc_bin++; + if (tcache->next_gc_bin == nhbins) { + tcache->next_gc_bin = 0; } } @@ -107,9 +99,11 @@ tcache_alloc_small_hard(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, return ret; } -static inline unsigned -tcache_bin_flush_small_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, - szind_t binind, unsigned rem, bool must_flush) { +void +tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, + szind_t binind, unsigned rem) { + bool merged_stats = false; + assert(binind < NBINS); assert(rem <= tbin->ncached); @@ -122,12 +116,9 @@ tcache_bin_flush_small_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, item_extent[i] = iealloc(tsd_tsdn(tsd), *(tbin->avail - 1 - i)); } - bool merged_stats = false; - unsigned nflushed = 0; - unsigned nskipped = 0; while (nflush > 0) { /* Lock the arena bin associated with the first object. */ - extent_t *extent = item_extent[nskipped]; + extent_t *extent = item_extent[0]; arena_t *bin_arena = extent_arena_get(extent); arena_bin_t *bin = &bin_arena->bins[binind]; @@ -139,16 +130,7 @@ tcache_bin_flush_small_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, tcache->prof_accumbytes = 0; } - if (must_flush) { - malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); - } else { - /* Make best effort to flush w/o blocking. */ - if (malloc_mutex_trylock(tsd_tsdn(tsd), &bin->lock)) { - nskipped++; - nflush--; - continue; - } - } + malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); if (config_stats && bin_arena == arena) { assert(!merged_stats); merged_stats = true; @@ -157,7 +139,7 @@ tcache_bin_flush_small_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, tbin->tstats.nrequests = 0; } unsigned ndeferred = 0; - for (unsigned i = nskipped; i < nflush; i++) { + for (unsigned i = 0; i < nflush; i++) { void *ptr = *(tbin->avail - 1 - i); extent = item_extent[i]; assert(ptr != NULL && extent != NULL); @@ -172,14 +154,13 @@ tcache_bin_flush_small_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, * locked. Stash the object, so that it can be * handled in a future pass. */ - *(tbin->avail - 1 - ndeferred - nskipped) = ptr; - item_extent[ndeferred + nskipped] = extent; + *(tbin->avail - 1 - ndeferred) = ptr; + item_extent[ndeferred] = extent; ndeferred++; } } malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); arena_decay_ticks(tsd_tsdn(tsd), bin_arena, nflush - ndeferred); - nflushed += nflush - ndeferred; nflush = ndeferred; } if (config_stats && !merged_stats) { @@ -188,49 +169,26 @@ tcache_bin_flush_small_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, * arena, so the stats didn't get merged. Manually do so now. */ arena_bin_t *bin = &arena->bins[binind]; - if (must_flush) { - malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); - } - if (must_flush || - !malloc_mutex_trylock(tsd_tsdn(tsd), &bin->lock)) { - malloc_mutex_assert_owner(tsd_tsdn(tsd), &bin->lock); - bin->stats.nflushes++; - bin->stats.nrequests += tbin->tstats.nrequests; - tbin->tstats.nrequests = 0; - malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); - } + malloc_mutex_lock(tsd_tsdn(tsd), &bin->lock); + bin->stats.nflushes++; + bin->stats.nrequests += tbin->tstats.nrequests; + tbin->tstats.nrequests = 0; + malloc_mutex_unlock(tsd_tsdn(tsd), &bin->lock); } - assert(nflushed == tbin->ncached - rem - nskipped); - assert(nskipped == 0 || !must_flush); - if (nflushed > 0) { - memmove(tbin->avail - (rem + nskipped), tbin->avail - - tbin->ncached, rem * sizeof(void *)); - } - tbin->ncached = rem + nskipped; + memmove(tbin->avail - rem, tbin->avail - tbin->ncached, rem * + sizeof(void *)); + tbin->ncached = rem; if ((low_water_t)tbin->ncached < tbin->low_water) { tbin->low_water = tbin->ncached; } - - return nflushed; } void -tcache_bin_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, - szind_t binind, unsigned rem) { - tcache_bin_flush_small_impl(tsd, tcache, tbin, binind, rem, true); -} - -unsigned -tcache_bin_try_flush_small(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, - szind_t binind, unsigned rem) { - return tcache_bin_flush_small_impl(tsd, tcache, tbin, binind, rem, - false); -} +tcache_bin_flush_large(tsd_t *tsd, tcache_bin_t *tbin, szind_t binind, + unsigned rem, tcache_t *tcache) { + bool merged_stats = false; -static inline unsigned -tcache_bin_flush_large_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, - szind_t binind, unsigned rem, bool must_flush) { assert(binind < nhbins); assert(rem <= tbin->ncached); @@ -243,31 +201,18 @@ tcache_bin_flush_large_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, item_extent[i] = iealloc(tsd_tsdn(tsd), *(tbin->avail - 1 - i)); } - bool merged_stats = false; - unsigned nflushed = 0; - unsigned nskipped = 0; while (nflush > 0) { /* Lock the arena associated with the first object. */ - extent_t *extent = item_extent[nskipped]; + extent_t *extent = item_extent[0]; arena_t *locked_arena = extent_arena_get(extent); UNUSED bool idump; if (config_prof) { idump = false; } - if (must_flush) { - malloc_mutex_lock(tsd_tsdn(tsd), &locked_arena->large_mtx); - } else { - /* Make best effort to flush w/o blocking. */ - if (malloc_mutex_trylock(tsd_tsdn(tsd), - &locked_arena->large_mtx)) { - nskipped++; - nflush--; - continue; - } - } - for (unsigned i = nskipped; i < nflush; i++) { + malloc_mutex_lock(tsd_tsdn(tsd), &locked_arena->large_mtx); + for (unsigned i = 0; i < nflush; i++) { void *ptr = *(tbin->avail - 1 - i); assert(ptr != NULL); extent = item_extent[i]; @@ -293,7 +238,7 @@ tcache_bin_flush_large_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, malloc_mutex_unlock(tsd_tsdn(tsd), &locked_arena->large_mtx); unsigned ndeferred = 0; - for (unsigned i = nskipped; i < nflush; i++) { + for (unsigned i = 0; i < nflush; i++) { void *ptr = *(tbin->avail - 1 - i); extent = item_extent[i]; assert(ptr != NULL && extent != NULL); @@ -307,8 +252,8 @@ tcache_bin_flush_large_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, * Stash the object, so that it can be handled * in a future pass. */ - *(tbin->avail - 1 - ndeferred - nskipped) = ptr; - item_extent[ndeferred + nskipped] = extent; + *(tbin->avail - 1 - ndeferred) = ptr; + item_extent[ndeferred] = extent; ndeferred++; } } @@ -317,7 +262,6 @@ tcache_bin_flush_large_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, } arena_decay_ticks(tsd_tsdn(tsd), locked_arena, nflush - ndeferred); - nflushed += nflush - ndeferred; nflush = ndeferred; } if (config_stats && !merged_stats) { @@ -330,31 +274,12 @@ tcache_bin_flush_large_impl(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, tbin->tstats.nrequests = 0; } - assert(nflushed == tbin->ncached - rem - nskipped); - assert(nskipped == 0 || !must_flush); - - if (nflushed > 0) { - memmove(tbin->avail - (rem + nskipped), tbin->avail - - tbin->ncached, rem * sizeof(void *)); - } - tbin->ncached = rem + nskipped; + memmove(tbin->avail - rem, tbin->avail - tbin->ncached, rem * + sizeof(void *)); + tbin->ncached = rem; if ((low_water_t)tbin->ncached < tbin->low_water) { tbin->low_water = tbin->ncached; } - return nflushed; -} - -void -tcache_bin_flush_large(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, - szind_t binind, unsigned rem) { - tcache_bin_flush_large_impl(tsd, tcache, tbin, binind, rem, true); -} - -unsigned -tcache_bin_try_flush_large(tsd_t *tsd, tcache_t *tcache, tcache_bin_t *tbin, - szind_t binind, unsigned rem) { - return tcache_bin_flush_large_impl(tsd, tcache, tbin, binind, rem, - false); } void @@ -533,7 +458,7 @@ tcache_flush_cache(tsd_t *tsd, tcache_t *tcache) { } for (unsigned i = NBINS; i < nhbins; i++) { tcache_bin_t *tbin = tcache_large_bin_get(tcache, i); - tcache_bin_flush_large(tsd, tcache, tbin, i, 0); + tcache_bin_flush_large(tsd, tbin, i, 0, tcache); if (config_stats) { assert(tbin->tstats.nrequests == 0); -- GitLab From 1c982c37d94fae5211206b3e41a8722b326ad5d4 Mon Sep 17 00:00:00 2001 From: rustyx Date: Tue, 2 May 2017 16:29:35 +0200 Subject: [PATCH 465/544] Make VS2015 project work again --- .../projects/vc2015/jemalloc/jemalloc.vcxproj | 61 +----- .../vc2015/jemalloc/jemalloc.vcxproj.filters | 186 +----------------- 2 files changed, 9 insertions(+), 238 deletions(-) diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj index 75ea8fba..832ff69d 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj @@ -34,63 +34,8 @@ x64 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -99,9 +44,10 @@ + - + @@ -113,7 +59,6 @@ - @@ -395,4 +340,4 @@ - + \ No newline at end of file diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters index a328a6f9..9d4a7c7d 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters @@ -5,185 +5,11 @@ {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {5697dfa3-16cf-4932-b428-6e0ec6e9f98e} - - - {0cbd2ca6-42a7-4f82-8517-d7e7a14fd986} - - - {0abe6f30-49b5-46dd-8aca-6e33363fa52c} - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\internal - - - Header Files\msvc_compat - - - Header Files\msvc_compat - - - Header Files\msvc_compat\C99 - - - Header Files\msvc_compat\C99 - Source Files - - Source Files - Source Files @@ -214,9 +40,6 @@ Source Files - - Source Files - Source Files @@ -250,11 +73,14 @@ Source Files - + Source Files - + + Source Files + + Source Files - + \ No newline at end of file -- GitLab From 344dd342dddf341f2db47c0a37f8b2aadccfdce7 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 2 May 2017 21:42:33 -0700 Subject: [PATCH 466/544] rtree_leaf_elm_extent_write() --> rtree_leaf_elm_extent_lock_write() Refactor rtree_leaf_elm_extent_write() as rtree_leaf_elm_extent_lock_write(), so that whether the leaf element is currently acquired is separate from what lock state to write. This allows for a relaxed atomic read when releasing the lock. --- include/jemalloc/internal/rtree_inlines.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index 7bc52383..b66e8ae2 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -54,7 +54,7 @@ rtree_leaf_elm_bits_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, } return (uintptr_t)atomic_load_p(&elm->le_bits, dependent - ? ATOMIC_RELAXED : ATOMIC_ACQUIRE); + ? ATOMIC_RELAXED : ATOMIC_ACQUIRE); } JEMALLOC_ALWAYS_INLINE extent_t * @@ -143,8 +143,8 @@ rtree_leaf_elm_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, } static inline void -rtree_leaf_elm_extent_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, - bool acquired, extent_t *extent) { +rtree_leaf_elm_extent_lock_write(tsdn_t *tsdn, rtree_t *rtree, + rtree_leaf_elm_t *elm, bool acquired, extent_t *extent, bool lock) { if (config_debug && acquired) { rtree_leaf_elm_witness_access(tsdn, rtree, elm); } @@ -156,10 +156,10 @@ rtree_leaf_elm_extent_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, uintptr_t bits = ((uintptr_t)rtree_leaf_elm_bits_szind_get(old_bits) << LG_VADDR) | ((uintptr_t)extent & (((uintptr_t)0x1 << LG_VADDR) - 1)) | ((uintptr_t)rtree_leaf_elm_bits_slab_get(old_bits) << 1) | - (uintptr_t)acquired; + (uintptr_t)lock; atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE); #else - if (acquired) { + if (lock) { /* Overlay lock bit. */ extent = (extent_t *)((uintptr_t)extent | (uintptr_t)0x1); } @@ -222,7 +222,6 @@ rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, ((uintptr_t)extent & (((uintptr_t)0x1 << LG_VADDR) - 1)) | ((uintptr_t)slab << 1) | (uintptr_t)acquired; - atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE); #else rtree_leaf_elm_slab_write(tsdn, rtree, elm, acquired, slab); @@ -231,7 +230,8 @@ rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, * Write extent last, since the element is atomically considered valid * as soon as the extent field is non-NULL. */ - rtree_leaf_elm_extent_write(tsdn, rtree, elm, acquired, extent); + rtree_leaf_elm_extent_lock_write(tsdn, rtree, elm, acquired, extent, + acquired); #endif } @@ -463,7 +463,8 @@ static inline void rtree_leaf_elm_release(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm) { extent_t *extent = rtree_leaf_elm_extent_read(tsdn, rtree, elm, true, true); - rtree_leaf_elm_extent_write(tsdn, rtree, elm, false, extent); + rtree_leaf_elm_extent_lock_write(tsdn, rtree, elm, true, extent, false); + if (config_debug) { rtree_leaf_elm_witness_release(tsdn, rtree, elm); } -- GitLab From 0798fe6e7056a2eb571dde06927e87635dd2e74c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 2 May 2017 21:45:46 -0700 Subject: [PATCH 467/544] Fix rtree_leaf_elm_szind_slab_update(). Re-read the leaf element when atomic CAS fails due to a race with another thread that has locked the leaf element, since atomic_compare_exchange_strong_p() overwrites the expected value with the actual value on failure. This regression was introduced by 0ee0e0c155a05d0d028a9972ad86b9eaac4ccabd (Implement compact rtree leaf element representation.). This resolves #798. --- include/jemalloc/internal/rtree_inlines.h | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index b66e8ae2..bcc2041a 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -251,17 +251,16 @@ rtree_leaf_elm_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, * modified by another thread, the fact that the lock is embedded in the * same word requires that a CAS operation be used here. */ - uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, false, - true) & ~((uintptr_t)0x1); /* Mask lock bit. */ - uintptr_t bits = ((uintptr_t)szind << LG_VADDR) | - ((uintptr_t)rtree_leaf_elm_bits_extent_get(old_bits) & - (((uintptr_t)0x1 << LG_VADDR) - 1)) | - ((uintptr_t)slab << 1); spin_t spinner = SPIN_INITIALIZER; while (true) { + void *old_bits = (void *)(rtree_leaf_elm_bits_read(tsdn, rtree, + elm, false, true) & ~((uintptr_t)0x1)); /* Mask lock bit. */ + void *bits = (void *)(((uintptr_t)szind << LG_VADDR) | + ((uintptr_t)rtree_leaf_elm_bits_extent_get( + (uintptr_t)old_bits) & (((uintptr_t)0x1 << LG_VADDR) - 1)) | + ((uintptr_t)slab << 1)); if (likely(atomic_compare_exchange_strong_p(&elm->le_bits, - (void **)&old_bits, (void *)bits, ATOMIC_ACQUIRE, - ATOMIC_RELAXED))) { + &old_bits, bits, ATOMIC_ACQUIRE, ATOMIC_RELAXED))) { break; } spin_adaptive(&spinner); -- GitLab From 31baedbbb9d1701b13312415b59d2b6240bb18e4 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 3 May 2017 10:07:39 -0700 Subject: [PATCH 468/544] Add --with-version=VERSION . This simplifies configuration when embedding a jemalloc release into another project's git repository. This resolves #811. --- INSTALL | 17 ++++++++++++++--- configure.ac | 10 +++++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/INSTALL b/INSTALL index abf3290b..125cad2b 100644 --- a/INSTALL +++ b/INSTALL @@ -35,9 +35,20 @@ any of the following arguments (not a definitive list) to 'configure': will cause files to be installed into /usr/local/include, /usr/local/lib, and /usr/local/man. ---with-version=..--g - Use the specified version string rather than trying to generate one (if in - a git repository) or use existing the VERSION file (if present). +--with-version=(..--g|VERSION) + The VERSION file is mandatory for successful configuration, and the + following steps are taken to assure its presence: + 1) If --with-version=..--g is specified, + generate VERSION using the specified value. + 2) If --with-version is not specified in either form and the source + directory is inside a git repository, try to generate VERSION via 'git + describe' invocations that pattern-match release tags. + 3) If VERSION is missing, generate it with a bogus version: + 0.0.0-0-g0000000000000000000000000000000000000000 + + Note that --with-version=VERSION bypasses (1) and (2), which simplifies + VERSION configuration when embedding a jemalloc release into another + project's git repository. --with-rpath= Embed one or more library paths, so that libjemalloc can find the libraries diff --git a/configure.ac b/configure.ac index 462f509f..7ffdbea8 100644 --- a/configure.ac +++ b/configure.ac @@ -1349,10 +1349,14 @@ AC_ARG_WITH([version], [Version string])], [ echo "${with_version}" | grep ['^[0-9]\+\.[0-9]\+\.[0-9]\+-[0-9]\+-g[0-9a-f]\+$'] 2>&1 1>/dev/null - if test $? -ne 0 ; then - AC_MSG_ERROR([${with_version} does not match ..--g]) + if test $? -eq 0 ; then + echo "$with_version" > "${objroot}VERSION" + else + echo "${with_version}" | grep ['^VERSION$'] 2>&1 1>/dev/null + if test $? -ne 0 ; then + AC_MSG_ERROR([${with_version} does not match ..--g or VERSION]) + fi fi - echo "$with_version" > "${objroot}VERSION" ], [ dnl Set VERSION if source directory is inside a git repository. if test "x`test ! \"${srcroot}\" && cd \"${srcroot}\"; git rev-parse --is-inside-work-tree 2>/dev/null`" = "xtrue" ; then -- GitLab From 11d2f39d96d1a1e4d35a438e184fa0785a2baf08 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 11 May 2017 09:06:41 -0700 Subject: [PATCH 469/544] Remove mutex_prof_data_t redeclaration. Redeclaration causes compilations failures with e.g. gcc 4.2.1 on FreeBSD. This regression was introduced by 89e2d3c12b573310e60b97beaf178007a71d83a3 (Header refactoring: ctl - unify and remove from catchall.). --- include/jemalloc/internal/mutex_prof.h | 2 +- include/jemalloc/internal/mutex_types.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/jemalloc/internal/mutex_prof.h b/include/jemalloc/internal/mutex_prof.h index f7301c88..1cc198d6 100644 --- a/include/jemalloc/internal/mutex_prof.h +++ b/include/jemalloc/internal/mutex_prof.h @@ -50,7 +50,7 @@ typedef enum { mutex_prof_num_counters } mutex_prof_counter_ind_t; -typedef struct mutex_prof_data_s { +typedef struct { /* * Counters touched on the slow path, i.e. when there is lock * contention. We update them once we have the lock. diff --git a/include/jemalloc/internal/mutex_types.h b/include/jemalloc/internal/mutex_types.h index e6589374..5af8d099 100644 --- a/include/jemalloc/internal/mutex_types.h +++ b/include/jemalloc/internal/mutex_types.h @@ -1,7 +1,6 @@ #ifndef JEMALLOC_INTERNAL_MUTEX_TYPES_H #define JEMALLOC_INTERNAL_MUTEX_TYPES_H -typedef struct mutex_prof_data_s mutex_prof_data_t; typedef struct malloc_mutex_s malloc_mutex_t; /* -- GitLab From 81ef365622c52d9252f546061652b0b31513c0b7 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 11 May 2017 16:50:49 -0700 Subject: [PATCH 470/544] Avoid compiler warnings on Windows. --- include/jemalloc/internal/bitmap.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/jemalloc/internal/bitmap.h b/include/jemalloc/internal/bitmap.h index f6374e14..ac990290 100644 --- a/include/jemalloc/internal/bitmap.h +++ b/include/jemalloc/internal/bitmap.h @@ -249,8 +249,8 @@ bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) { 1)); bitmap_t group = bitmap[binfo->levels[level].group_offset + (bit >> lg_bits_per_group)]; - unsigned group_nmask = ((min_bit > bit) ? (min_bit - bit) : 0) - >> (lg_bits_per_group - LG_BITMAP_GROUP_NBITS); + unsigned group_nmask = (unsigned)(((min_bit > bit) ? (min_bit - + bit) : 0) >> (lg_bits_per_group - LG_BITMAP_GROUP_NBITS)); assert(group_nmask <= BITMAP_GROUP_NBITS); bitmap_t group_mask = ~((1LU << group_nmask) - 1); bitmap_t group_masked = group & group_mask; @@ -265,7 +265,7 @@ bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) { * next sibling. This will recurse at most once per * non-root level. */ - size_t sib_base = bit + (1U << lg_bits_per_group); + size_t sib_base = bit + (ZU(1) << lg_bits_per_group); assert(sib_base > min_bit); assert(sib_base > bit); if (sib_base >= binfo->nbits) { @@ -273,8 +273,8 @@ bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) { } return bitmap_ffu(bitmap, binfo, sib_base); } - bit += (ffs_lu(group_masked) - 1) << (lg_bits_per_group - - LG_BITMAP_GROUP_NBITS); + bit += ((size_t)(ffs_lu(group_masked) - 1)) << + (lg_bits_per_group - LG_BITMAP_GROUP_NBITS); } assert(bit >= min_bit); assert(bit < binfo->nbits); -- GitLab From 17ddddee10c85dec0765a8329fc466c48c8c0592 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 11 May 2017 13:56:41 -0700 Subject: [PATCH 471/544] Specify -Werror for run_tests builds. --- scripts/gen_run_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gen_run_tests.py b/scripts/gen_run_tests.py index 9e46ba90..0446c65c 100755 --- a/scripts/gen_run_tests.py +++ b/scripts/gen_run_tests.py @@ -33,7 +33,7 @@ for cc, cxx in possible_compilers: and '--enable-prof' in config_opts: continue config_line = ( - './configure ' + 'EXTRA_CFLAGS=-Werror EXTRA_CXXFLAGS=-Werror ./configure ' + 'CC="{} {}" '.format(cc, " ".join(compiler_opts)) + 'CXX="{} {}" '.format(cxx, " ".join(compiler_opts)) + " ".join(config_opts) -- GitLab From 6f58e630b6257c1e64efae952cc0b9c280b92622 Mon Sep 17 00:00:00 2001 From: Arkady Shapkin Date: Thu, 11 May 2017 21:57:05 +0300 Subject: [PATCH 472/544] Update and rename INSTALL to INSTALL.md --- INSTALL => INSTALL.md | 164 +++++++++++++++++++++++++++--------------- 1 file changed, 107 insertions(+), 57 deletions(-) rename INSTALL => INSTALL.md (87%) diff --git a/INSTALL b/INSTALL.md similarity index 87% rename from INSTALL rename to INSTALL.md index 125cad2b..e0cfc0be 100644 --- a/INSTALL +++ b/INSTALL.md @@ -18,16 +18,19 @@ would create a dependency on xsltproc in packaged releases, hence the requirement to either run 'make dist' or avoid installing docs via the various install_* targets documented below. -=== Advanced configuration ===================================================== + +## Advanced configuration The 'configure' script supports numerous options that allow control of which functionality is enabled, where jemalloc is installed, etc. Optionally, pass any of the following arguments (not a definitive list) to 'configure': ---help +* `--help` + Print a definitive list of options. ---prefix= +* `--prefix=` + Set the base directory in which to install. For example: ./configure --prefix=/usr/local @@ -35,7 +38,8 @@ any of the following arguments (not a definitive list) to 'configure': will cause files to be installed into /usr/local/include, /usr/local/lib, and /usr/local/man. ---with-version=(..--g|VERSION) +* `--with-version=(..--g|VERSION)` + The VERSION file is mandatory for successful configuration, and the following steps are taken to assure its presence: 1) If --with-version=..--g is specified, @@ -50,11 +54,13 @@ any of the following arguments (not a definitive list) to 'configure': VERSION configuration when embedding a jemalloc release into another project's git repository. ---with-rpath= +* `--with-rpath=` + Embed one or more library paths, so that libjemalloc can find the libraries it is linked to. This works only on ELF-based systems. ---with-mangling= +* `--with-mangling=` + Mangle public symbols specified in which is a comma-separated list of name:mangled pairs. @@ -67,7 +73,8 @@ any of the following arguments (not a definitive list) to 'configure': --with-jemalloc-prefix, and mangled symbols are then ignored when applying the prefix. ---with-jemalloc-prefix= +* `--with-jemalloc-prefix=` + Prefix all public APIs with . For example, if is "prefix_", API changes like the following occur: @@ -83,39 +90,46 @@ any of the following arguments (not a definitive list) to 'configure': jemalloc overlays the default malloc zone, but makes no attempt to actually replace the "malloc", "calloc", etc. symbols. ---without-export +* `--without-export` + Don't export public APIs. This can be useful when building jemalloc as a static library, or to avoid exporting public APIs when using the zone allocator on OSX. ---with-private-namespace= +* `--with-private-namespace=` + Prefix all library-private APIs with je_. For shared libraries, symbol visibility mechanisms prevent these symbols from being exported, but for static libraries, naming collisions are a real possibility. By default, is empty, which results in a symbol prefix of je_ . ---with-install-suffix= +* `--with-install-suffix=` + Append to the base name of all installed files, such that multiple versions of jemalloc can coexist in the same installation directory. For example, libjemalloc.so.0 becomes libjemalloc.so.0. ---with-malloc-conf= - Embed as a run-time options string that is processed prior to +* `--with-malloc-conf=` + + Embed `` as a run-time options string that is processed prior to the malloc_conf global variable, the /etc/malloc.conf symlink, and the MALLOC_CONF environment variable. For example, to change the default decay time to 30 seconds: --with-malloc-conf=decay_time:30 ---enable-debug +* `--enable-debug` + Enable assertions and validation code. This incurs a substantial performance hit, but is very useful during application development. ---disable-stats +* `--disable-stats` + Disable statistics gathering functionality. See the "opt.stats_print" option documentation for usage details. ---enable-prof +* `--enable-prof` + Enable heap profiling and leak detection functionality. See the "opt.prof" option documentation for usage details. When enabled, there are several approaches to backtracing, and the configure script chooses the first one @@ -125,45 +139,55 @@ any of the following arguments (not a definitive list) to 'configure': + libgcc (unless --disable-prof-libgcc) + gcc intrinsics (unless --disable-prof-gcc) ---enable-prof-libunwind +* `--enable-prof-libunwind` + Use the libunwind library (http://www.nongnu.org/libunwind/) for stack backtracing. ---disable-prof-libgcc +* `--disable-prof-libgcc` + Disable the use of libgcc's backtracing functionality. ---disable-prof-gcc +* `--disable-prof-gcc` + Disable the use of gcc intrinsics for backtracing. ---with-static-libunwind= +* `--with-static-libunwind=` + Statically link against the specified libunwind.a rather than dynamically linking with -lunwind. ---disable-fill +* `--disable-fill` + Disable support for junk/zero filling of memory. See the "opt.junk" and "opt.zero" option documentation for usage details. ---disable-zone-allocator +* `--disable-zone-allocator` + Disable zone allocator for Darwin. This means jemalloc won't be hooked as the default allocator on OSX/iOS. ---enable-utrace +* `--enable-utrace` + Enable utrace(2)-based allocation tracing. This feature is not broadly portable (FreeBSD has it, but Linux and OS X do not). ---enable-xmalloc +* `--enable-xmalloc` + Enable support for optional immediate termination due to out-of-memory errors, as is commonly implemented by "xmalloc" wrapper function for malloc. See the "opt.xmalloc" option documentation for usage details. ---enable-lazy-lock +* `--enable-lazy-lock` + Enable code that wraps pthread_create() to detect when an application switches from single-threaded to multi-threaded mode, so that it can avoid mutex locking/unlocking operations while in single-threaded mode. In practice, this feature usually has little impact on performance unless thread-specific caching is disabled. ---disable-cache-oblivious +* `--disable-cache-oblivious` + Disable cache-oblivious large allocation alignment for large allocation requests with no alignment constraints. If this feature is disabled, all large allocations are page-aligned as an implementation artifact, which can @@ -172,20 +196,24 @@ any of the following arguments (not a definitive list) to 'configure': most extreme case increases physical memory usage for the 16 KiB size class to 20 KiB. ---disable-syscall +* `--disable-syscall` + Disable use of syscall(2) rather than {open,read,write,close}(2). This is intended as a workaround for systems that place security limitations on syscall(2). ---disable-cxx +* `--disable-cxx` + Disable C++ integration. This will cause new and delete operator implementations to be omitted. ---with-xslroot= +* `--with-xslroot=` + Specify where to find DocBook XSL stylesheets when building the documentation. ---with-lg-page= +* `--with-lg-page=` + Specify the base 2 log of the allocator page size, which must in turn be at least as large as the system page size. By default the configure script determines the host's page size and sets the allocator page size equal to @@ -193,23 +221,26 @@ any of the following arguments (not a definitive list) to 'configure': system page size may change between configuration and execution, e.g. when cross compiling. ---with-lg-page-sizes= +* `--with-lg-page-sizes=` + Specify the comma-separated base 2 logs of the page sizes to support. This option may be useful when cross-compiling in combination with - --with-lg-page, but its primary use case is for integration with FreeBSD's + `--with-lg-page`, but its primary use case is for integration with FreeBSD's libc, wherein jemalloc is embedded. ---with-lg-hugepage= +* `--with-lg-hugepage=` + Specify the base 2 log of the system huge page size. This option is useful when cross compiling, or when overriding the default for systems that do not explicitly support huge pages. ---with-lg-quantum= +* `--with-lg-quantum=` + Specify the base 2 log of the minimum allocation alignment. jemalloc needs to know the minimum alignment that meets the following C standard requirement (quoted from the April 12, 2011 draft of the C11 standard): - The pointer returned if the allocation succeeds is suitably aligned so + > The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated [...] @@ -220,44 +251,50 @@ any of the following arguments (not a definitive list) to 'configure': . On most modern architectures, this mandates 16-byte alignment (=4), but the glibc developers chose not to meet this requirement for performance reasons. An old discussion can be found at - https://sourceware.org/bugzilla/show_bug.cgi?id=206 . Unlike glibc, + . Unlike glibc, jemalloc does follow the C standard by default (caveat: jemalloc technically cheats for size classes smaller than the quantum), but the fact that Linux systems already work around this allocator noncompliance means that it is generally safe in practice to let jemalloc's minimum alignment - follow glibc's lead. If you specify --with-lg-quantum=3 during + follow glibc's lead. If you specify `--with-lg-quantum=3` during configuration, jemalloc will provide additional size classes that are not 16-byte-aligned (24, 40, and 56). The following environment variables (not a definitive list) impact configure's behavior: -CFLAGS="?" -CXXFLAGS="?" +* `CFLAGS="?"` +* `CXXFLAGS="?"` + Pass these flags to the C/C++ compiler. Any flags set by the configure script are prepended, which means explicitly set flags generally take precedence. Take care when specifying flags such as -Werror, because configure tests may be affected in undesirable ways. -EXTRA_CFLAGS="?" -EXTRA_CXXFLAGS="?" +* `EXTRA_CFLAGS="?"` +* `EXTRA_CXXFLAGS="?"` + Append these flags to CFLAGS/CXXFLAGS, without passing them to the compiler(s) during configuration. This makes it possible to add flags such as -Werror, while allowing the configure script to determine what other flags are appropriate for the specified configuration. -CPPFLAGS="?" +* `CPPFLAGS="?"` + Pass these flags to the C preprocessor. Note that CFLAGS is not passed to 'cpp' when 'configure' is looking for include files, so you must use CPPFLAGS instead if you need to help 'configure' find header files. -LD_LIBRARY_PATH="?" +* `LD_LIBRARY_PATH="?"` + 'ld' uses this colon-separated list to find libraries. -LDFLAGS="?" +* `LDFLAGS="?"` + Pass these flags when linking. -PATH="?" +* `PATH="?"` + 'configure' uses this to find programs. In some cases it may be necessary to work around configuration results that do @@ -269,7 +306,8 @@ e.g.: echo "je_cv_madv_free=no" > config.cache && ./configure -C -=== Advanced compilation ======================================================= + +## Advanced compilation To build only parts of jemalloc, use the following targets: @@ -297,40 +335,51 @@ To clean up build results to varying degrees, use the following make targets: distclean relclean -=== Advanced installation ====================================================== + +## Advanced installation Optionally, define make variables when invoking make, including (not exclusively): -INCLUDEDIR="?" +* `INCLUDEDIR="?"` + Use this as the installation prefix for header files. -LIBDIR="?" +* `LIBDIR="?"` + Use this as the installation prefix for libraries. -MANDIR="?" +* `MANDIR="?"` + Use this as the installation prefix for man pages. -DESTDIR="?" +* `DESTDIR="?"` + Prepend DESTDIR to INCLUDEDIR, LIBDIR, DATADIR, and MANDIR. This is useful when installing to a different path than was specified via --prefix. -CC="?" +* `CC="?"` + Use this to invoke the C compiler. -CFLAGS="?" +* `CFLAGS="?"` + Pass these flags to the compiler. -CPPFLAGS="?" +* `CPPFLAGS="?"` + Pass these flags to the C preprocessor. -LDFLAGS="?" +* `LDFLAGS="?"` + Pass these flags when linking. -PATH="?" +* `PATH="?"` + Use this to search for programs used during configuration and building. -=== Development ================================================================ + +## Development If you intend to make non-trivial changes to jemalloc, use the 'autogen.sh' script rather than 'configure'. This re-generates 'configure', enables @@ -347,7 +396,8 @@ directory, issue configuration and build commands: ../configure --enable-autogen make -=== Documentation ============================================================== + +## Documentation The manual page is generated in both html and roff formats. Any web browser can be used to view the html manual. The roff manual page can be formatted -- GitLab From b3b033eefd7892f0bed7fc30f431016660b44918 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 11 May 2017 20:22:48 -0700 Subject: [PATCH 473/544] Do not build in parallel on AppVeyor. The compiler database used by MSVC is increasingly becoming corrupt, presumably due to concurrency-related corruption, despite the -FS compiler flag being specified as recommended. --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 510815dc..9a7d00a9 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -36,7 +36,7 @@ install: build_script: - bash -c "autoconf" - bash -c "./configure $CONFIG_FLAGS" - - mingw32-make -j3 + - mingw32-make - file lib/jemalloc.dll - - mingw32-make -j3 tests + - mingw32-make tests - mingw32-make -k check -- GitLab From a268af50857f0a4d139f26c66d22debbfae7a674 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 1 May 2017 23:10:42 -0700 Subject: [PATCH 474/544] Stop depending on JEMALLOC_N() for function interception during testing. Instead, always define function pointers for interceptable functions, but mark them const unless testing, so that the compiler can optimize out the pointer dereferences. --- include/jemalloc/internal/arena_externs.h | 8 +- .../internal/jemalloc_internal_macros.h | 7 ++ include/jemalloc/internal/large_externs.h | 38 +++++---- include/jemalloc/internal/nstime.h | 36 ++++----- include/jemalloc/internal/prof_externs.h | 77 ++++++++++--------- include/jemalloc/internal/rtree_externs.h | 14 ++-- include/jemalloc/internal/witness_externs.h | 40 ++++------ src/arena.c | 16 +--- src/large.c | 32 ++------ src/nstime.c | 28 ++----- src/prof.c | 27 ++----- src/rtree.c | 54 +++---------- src/witness.c | 61 ++++----------- 13 files changed, 157 insertions(+), 281 deletions(-) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 7d56e44b..410709c6 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -59,12 +59,10 @@ void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, tcache_bin_t *tbin, szind_t binind, uint64_t prof_accumbytes); void arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, bool zero); -#ifdef JEMALLOC_JET + typedef void (arena_dalloc_junk_small_t)(void *, const arena_bin_info_t *); -extern arena_dalloc_junk_small_t *arena_dalloc_junk_small; -#else -void arena_dalloc_junk_small(void *ptr, const arena_bin_info_t *bin_info); -#endif +extern arena_dalloc_junk_small_t *JET_MUTABLE arena_dalloc_junk_small; + void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero); void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, diff --git a/include/jemalloc/internal/jemalloc_internal_macros.h b/include/jemalloc/internal/jemalloc_internal_macros.h index a1712cf5..4571895e 100644 --- a/include/jemalloc/internal/jemalloc_internal_macros.h +++ b/include/jemalloc/internal/jemalloc_internal_macros.h @@ -30,4 +30,11 @@ # define restrict #endif +/* Various function pointers are statick and immutable except during testing. */ +#ifdef JEMALLOC_JET +# define JET_MUTABLE +#else +# define JET_MUTABLE const +#endif + #endif /* JEMALLOC_INTERNAL_MACROS_H */ diff --git a/include/jemalloc/internal/large_externs.h b/include/jemalloc/internal/large_externs.h index 2a208c83..3f36282c 100644 --- a/include/jemalloc/internal/large_externs.h +++ b/include/jemalloc/internal/large_externs.h @@ -1,28 +1,26 @@ #ifndef JEMALLOC_INTERNAL_LARGE_EXTERNS_H #define JEMALLOC_INTERNAL_LARGE_EXTERNS_H -void *large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero); -void *large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, - size_t alignment, bool zero); -bool large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, +void *large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero); +void *large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, + bool zero); +bool large_ralloc_no_move(tsdn_t *tsdn, extent_t *extent, size_t usize_min, size_t usize_max, bool zero); -void *large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, - size_t usize, size_t alignment, bool zero, tcache_t *tcache); -#ifdef JEMALLOC_JET +void *large_ralloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t usize, + size_t alignment, bool zero, tcache_t *tcache); + typedef void (large_dalloc_junk_t)(void *, size_t); -extern large_dalloc_junk_t *large_dalloc_junk; +extern large_dalloc_junk_t *JET_MUTABLE large_dalloc_junk; + typedef void (large_dalloc_maybe_junk_t)(void *, size_t); -extern large_dalloc_maybe_junk_t *large_dalloc_maybe_junk; -#else -void large_dalloc_junk(void *ptr, size_t size); -void large_dalloc_maybe_junk(void *ptr, size_t size); -#endif -void large_dalloc_prep_junked_locked(tsdn_t *tsdn, extent_t *extent); -void large_dalloc_finish(tsdn_t *tsdn, extent_t *extent); -void large_dalloc(tsdn_t *tsdn, extent_t *extent); -size_t large_salloc(tsdn_t *tsdn, const extent_t *extent); -prof_tctx_t *large_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent); -void large_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx); -void large_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent); +extern large_dalloc_maybe_junk_t *JET_MUTABLE large_dalloc_maybe_junk; + +void large_dalloc_prep_junked_locked(tsdn_t *tsdn, extent_t *extent); +void large_dalloc_finish(tsdn_t *tsdn, extent_t *extent); +void large_dalloc(tsdn_t *tsdn, extent_t *extent); +size_t large_salloc(tsdn_t *tsdn, const extent_t *extent); +prof_tctx_t *large_prof_tctx_get(tsdn_t *tsdn, const extent_t *extent); +void large_prof_tctx_set(tsdn_t *tsdn, extent_t *extent, prof_tctx_t *tctx); +void large_prof_tctx_reset(tsdn_t *tsdn, extent_t *extent); #endif /* JEMALLOC_INTERNAL_LARGE_EXTERNS_H */ diff --git a/include/jemalloc/internal/nstime.h b/include/jemalloc/internal/nstime.h index cfccca09..ad7efb89 100644 --- a/include/jemalloc/internal/nstime.h +++ b/include/jemalloc/internal/nstime.h @@ -10,27 +10,23 @@ typedef struct { } nstime_t; void nstime_init(nstime_t *time, uint64_t ns); -void nstime_init2(nstime_t *time, uint64_t sec, uint64_t nsec); -uint64_t nstime_ns(const nstime_t *time); -uint64_t nstime_sec(const nstime_t *time); -uint64_t nstime_msec(const nstime_t *time); -uint64_t nstime_nsec(const nstime_t *time); -void nstime_copy(nstime_t *time, const nstime_t *source); -int nstime_compare(const nstime_t *a, const nstime_t *b); -void nstime_add(nstime_t *time, const nstime_t *addend); -void nstime_subtract(nstime_t *time, const nstime_t *subtrahend); -void nstime_imultiply(nstime_t *time, uint64_t multiplier); -void nstime_idivide(nstime_t *time, uint64_t divisor); -uint64_t nstime_divide(const nstime_t *time, const nstime_t *divisor); -#ifdef JEMALLOC_JET +void nstime_init2(nstime_t *time, uint64_t sec, uint64_t nsec); +uint64_t nstime_ns(const nstime_t *time); +uint64_t nstime_sec(const nstime_t *time); +uint64_t nstime_msec(const nstime_t *time); +uint64_t nstime_nsec(const nstime_t *time); +void nstime_copy(nstime_t *time, const nstime_t *source); +int nstime_compare(const nstime_t *a, const nstime_t *b); +void nstime_add(nstime_t *time, const nstime_t *addend); +void nstime_subtract(nstime_t *time, const nstime_t *subtrahend); +void nstime_imultiply(nstime_t *time, uint64_t multiplier); +void nstime_idivide(nstime_t *time, uint64_t divisor); +uint64_t nstime_divide(const nstime_t *time, const nstime_t *divisor); + typedef bool (nstime_monotonic_t)(void); -extern nstime_monotonic_t *nstime_monotonic; -typedef bool (nstime_update_t)(nstime_t *); -extern nstime_update_t *nstime_update; -#else -bool nstime_monotonic(void); -bool nstime_update(nstime_t *time); -#endif +extern nstime_monotonic_t *JET_MUTABLE nstime_monotonic; +typedef bool (nstime_update_t)(nstime_t *); +extern nstime_update_t *JET_MUTABLE nstime_update; #endif /* JEMALLOC_INTERNAL_NSTIME_H */ diff --git a/include/jemalloc/internal/prof_externs.h b/include/jemalloc/internal/prof_externs.h index cbd9795b..2891b8bd 100644 --- a/include/jemalloc/internal/prof_externs.h +++ b/include/jemalloc/internal/prof_externs.h @@ -40,48 +40,51 @@ extern uint64_t prof_interval; */ extern size_t lg_prof_sample; -void prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated); -void prof_malloc_sample_object(tsdn_t *tsdn, const void *ptr, size_t usize, +void prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated); +void prof_malloc_sample_object(tsdn_t *tsdn, const void *ptr, size_t usize, prof_tctx_t *tctx); -void prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_tctx_t *tctx); -void bt_init(prof_bt_t *bt, void **vec); -void prof_backtrace(prof_bt_t *bt); -prof_tctx_t *prof_lookup(tsd_t *tsd, prof_bt_t *bt); +void prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_tctx_t *tctx); +void bt_init(prof_bt_t *bt, void **vec); +void prof_backtrace(prof_bt_t *bt); +prof_tctx_t *prof_lookup(tsd_t *tsd, prof_bt_t *bt); #ifdef JEMALLOC_JET -size_t prof_tdata_count(void); -size_t prof_bt_count(void); +size_t prof_tdata_count(void); +size_t prof_bt_count(void); +#endif typedef int (prof_dump_open_t)(bool, const char *); -extern prof_dump_open_t *prof_dump_open; +extern prof_dump_open_t *JET_MUTABLE prof_dump_open; + typedef bool (prof_dump_header_t)(tsdn_t *, bool, const prof_cnt_t *); -extern prof_dump_header_t *prof_dump_header; -void prof_cnt_all(uint64_t *curobjs, uint64_t *curbytes, - uint64_t *accumobjs, uint64_t *accumbytes); +extern prof_dump_header_t *JET_MUTABLE prof_dump_header; +#ifdef JEMALLOC_JET +void prof_cnt_all(uint64_t *curobjs, uint64_t *curbytes, uint64_t *accumobjs, + uint64_t *accumbytes); #endif bool prof_accum_init(tsdn_t *tsdn, prof_accum_t *prof_accum); -void prof_idump(tsdn_t *tsdn); -bool prof_mdump(tsd_t *tsd, const char *filename); -void prof_gdump(tsdn_t *tsdn); -prof_tdata_t *prof_tdata_init(tsd_t *tsd); -prof_tdata_t *prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata); -void prof_reset(tsd_t *tsd, size_t lg_sample); -void prof_tdata_cleanup(tsd_t *tsd); -bool prof_active_get(tsdn_t *tsdn); -bool prof_active_set(tsdn_t *tsdn, bool active); -const char *prof_thread_name_get(tsd_t *tsd); -int prof_thread_name_set(tsd_t *tsd, const char *thread_name); -bool prof_thread_active_get(tsd_t *tsd); -bool prof_thread_active_set(tsd_t *tsd, bool active); -bool prof_thread_active_init_get(tsdn_t *tsdn); -bool prof_thread_active_init_set(tsdn_t *tsdn, bool active_init); -bool prof_gdump_get(tsdn_t *tsdn); -bool prof_gdump_set(tsdn_t *tsdn, bool active); -void prof_boot0(void); -void prof_boot1(void); -bool prof_boot2(tsd_t *tsd); -void prof_prefork0(tsdn_t *tsdn); -void prof_prefork1(tsdn_t *tsdn); -void prof_postfork_parent(tsdn_t *tsdn); -void prof_postfork_child(tsdn_t *tsdn); -void prof_sample_threshold_update(prof_tdata_t *tdata); +void prof_idump(tsdn_t *tsdn); +bool prof_mdump(tsd_t *tsd, const char *filename); +void prof_gdump(tsdn_t *tsdn); +prof_tdata_t *prof_tdata_init(tsd_t *tsd); +prof_tdata_t *prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata); +void prof_reset(tsd_t *tsd, size_t lg_sample); +void prof_tdata_cleanup(tsd_t *tsd); +bool prof_active_get(tsdn_t *tsdn); +bool prof_active_set(tsdn_t *tsdn, bool active); +const char *prof_thread_name_get(tsd_t *tsd); +int prof_thread_name_set(tsd_t *tsd, const char *thread_name); +bool prof_thread_active_get(tsd_t *tsd); +bool prof_thread_active_set(tsd_t *tsd, bool active); +bool prof_thread_active_init_get(tsdn_t *tsdn); +bool prof_thread_active_init_set(tsdn_t *tsdn, bool active_init); +bool prof_gdump_get(tsdn_t *tsdn); +bool prof_gdump_set(tsdn_t *tsdn, bool active); +void prof_boot0(void); +void prof_boot1(void); +bool prof_boot2(tsd_t *tsd); +void prof_prefork0(tsdn_t *tsdn); +void prof_prefork1(tsdn_t *tsdn); +void prof_postfork_parent(tsdn_t *tsdn); +void prof_postfork_child(tsdn_t *tsdn); +void prof_sample_threshold_update(prof_tdata_t *tdata); #endif /* JEMALLOC_INTERNAL_PROF_EXTERNS_H */ diff --git a/include/jemalloc/internal/rtree_externs.h b/include/jemalloc/internal/rtree_externs.h index 5145c12c..5742f589 100644 --- a/include/jemalloc/internal/rtree_externs.h +++ b/include/jemalloc/internal/rtree_externs.h @@ -24,15 +24,19 @@ static const rtree_level_t rtree_levels[] = { }; bool rtree_new(rtree_t *rtree, bool zeroed); -#ifdef JEMALLOC_JET + typedef rtree_node_elm_t *(rtree_node_alloc_t)(tsdn_t *, rtree_t *, size_t); -extern rtree_node_alloc_t *rtree_node_alloc; +extern rtree_node_alloc_t *JET_MUTABLE rtree_node_alloc; + typedef rtree_leaf_elm_t *(rtree_leaf_alloc_t)(tsdn_t *, rtree_t *, size_t); -extern rtree_leaf_alloc_t *rtree_leaf_alloc; +extern rtree_leaf_alloc_t *JET_MUTABLE rtree_leaf_alloc; + typedef void (rtree_node_dalloc_t)(tsdn_t *, rtree_t *, rtree_node_elm_t *); -extern rtree_node_dalloc_t *rtree_node_dalloc; +extern rtree_node_dalloc_t *JET_MUTABLE rtree_node_dalloc; + typedef void (rtree_leaf_dalloc_t)(tsdn_t *, rtree_t *, rtree_leaf_elm_t *); -extern rtree_leaf_dalloc_t *rtree_leaf_dalloc; +extern rtree_leaf_dalloc_t *JET_MUTABLE rtree_leaf_dalloc; +#ifdef JEMALLOC_JET void rtree_delete(tsdn_t *tsdn, rtree_t *rtree); #endif rtree_leaf_elm_t *rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, diff --git a/include/jemalloc/internal/witness_externs.h b/include/jemalloc/internal/witness_externs.h index 5d91fde2..99df4c50 100644 --- a/include/jemalloc/internal/witness_externs.h +++ b/include/jemalloc/internal/witness_externs.h @@ -1,39 +1,25 @@ #ifndef JEMALLOC_INTERNAL_WITNESS_EXTERNS_H #define JEMALLOC_INTERNAL_WITNESS_EXTERNS_H -void witness_init(witness_t *witness, const char *name, witness_rank_t rank, +void witness_init(witness_t *witness, const char *name, witness_rank_t rank, witness_comp_t *comp, void *opaque); -#ifdef JEMALLOC_JET + typedef void (witness_lock_error_t)(const witness_list_t *, const witness_t *); -extern witness_lock_error_t *witness_lock_error; -#else -void witness_lock_error(const witness_list_t *witnesses, - const witness_t *witness); -#endif -#ifdef JEMALLOC_JET +extern witness_lock_error_t *JET_MUTABLE witness_lock_error; + typedef void (witness_owner_error_t)(const witness_t *); -extern witness_owner_error_t *witness_owner_error; -#else -void witness_owner_error(const witness_t *witness); -#endif -#ifdef JEMALLOC_JET +extern witness_owner_error_t *JET_MUTABLE witness_owner_error; + typedef void (witness_not_owner_error_t)(const witness_t *); -extern witness_not_owner_error_t *witness_not_owner_error; -#else -void witness_not_owner_error(const witness_t *witness); -#endif -#ifdef JEMALLOC_JET +extern witness_not_owner_error_t *JET_MUTABLE witness_not_owner_error; + typedef void (witness_depth_error_t)(const witness_list_t *, witness_rank_t rank_inclusive, unsigned depth); -extern witness_depth_error_t *witness_depth_error; -#else -void witness_depth_error(const witness_list_t *witnesses, - witness_rank_t rank_inclusive, unsigned depth); -#endif +extern witness_depth_error_t *JET_MUTABLE witness_depth_error; -void witnesses_cleanup(tsd_t *tsd); -void witness_prefork(tsd_t *tsd); -void witness_postfork_parent(tsd_t *tsd); -void witness_postfork_child(tsd_t *tsd); +void witnesses_cleanup(tsd_t *tsd); +void witness_prefork(tsd_t *tsd); +void witness_postfork_parent(tsd_t *tsd); +void witness_postfork_child(tsd_t *tsd); #endif /* JEMALLOC_INTERNAL_WITNESS_EXTERNS_H */ diff --git a/src/arena.c b/src/arena.c index edbd875f..045e6127 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1407,20 +1407,12 @@ arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, bool zero) { } } -#ifdef JEMALLOC_JET -#undef arena_dalloc_junk_small -#define arena_dalloc_junk_small JEMALLOC_N(n_arena_dalloc_junk_small) -#endif -void -arena_dalloc_junk_small(void *ptr, const arena_bin_info_t *bin_info) { +static void +arena_dalloc_junk_small_impl(void *ptr, const arena_bin_info_t *bin_info) { memset(ptr, JEMALLOC_FREE_JUNK, bin_info->reg_size); } -#ifdef JEMALLOC_JET -#undef arena_dalloc_junk_small -#define arena_dalloc_junk_small JEMALLOC_N(arena_dalloc_junk_small) -arena_dalloc_junk_small_t *arena_dalloc_junk_small = - JEMALLOC_N(n_arena_dalloc_junk_small); -#endif +arena_dalloc_junk_small_t *JET_MUTABLE arena_dalloc_junk_small = + arena_dalloc_junk_small_impl; static void * arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) { diff --git a/src/large.c b/src/large.c index f657ccbe..ed73dc22 100644 --- a/src/large.c +++ b/src/large.c @@ -68,26 +68,14 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, return extent_addr_get(extent); } -#ifdef JEMALLOC_JET -#undef large_dalloc_junk -#define large_dalloc_junk JEMALLOC_N(n_large_dalloc_junk) -#endif -void -large_dalloc_junk(void *ptr, size_t size) { +static void +large_dalloc_junk_impl(void *ptr, size_t size) { memset(ptr, JEMALLOC_FREE_JUNK, size); } -#ifdef JEMALLOC_JET -#undef large_dalloc_junk -#define large_dalloc_junk JEMALLOC_N(large_dalloc_junk) -large_dalloc_junk_t *large_dalloc_junk = JEMALLOC_N(n_large_dalloc_junk); -#endif - -#ifdef JEMALLOC_JET -#undef large_dalloc_maybe_junk -#define large_dalloc_maybe_junk JEMALLOC_N(n_large_dalloc_maybe_junk) -#endif -void -large_dalloc_maybe_junk(void *ptr, size_t size) { +large_dalloc_junk_t *JET_MUTABLE large_dalloc_junk = large_dalloc_junk_impl; + +static void +large_dalloc_maybe_junk_impl(void *ptr, size_t size) { if (config_fill && have_dss && unlikely(opt_junk_free)) { /* * Only bother junk filling if the extent isn't about to be @@ -98,12 +86,8 @@ large_dalloc_maybe_junk(void *ptr, size_t size) { } } } -#ifdef JEMALLOC_JET -#undef large_dalloc_maybe_junk -#define large_dalloc_maybe_junk JEMALLOC_N(large_dalloc_maybe_junk) -large_dalloc_maybe_junk_t *large_dalloc_maybe_junk = - JEMALLOC_N(n_large_dalloc_maybe_junk); -#endif +large_dalloc_maybe_junk_t *JET_MUTABLE large_dalloc_maybe_junk = + large_dalloc_maybe_junk_impl; static bool large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { diff --git a/src/nstime.c b/src/nstime.c index 20c00422..e5412274 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -131,27 +131,15 @@ nstime_get(nstime_t *time) { } #endif -#ifdef JEMALLOC_JET -#undef nstime_monotonic -#define nstime_monotonic JEMALLOC_N(n_nstime_monotonic) -#endif -bool -nstime_monotonic(void) { +static bool +nstime_monotonic_impl(void) { return NSTIME_MONOTONIC; #undef NSTIME_MONOTONIC } -#ifdef JEMALLOC_JET -#undef nstime_monotonic -#define nstime_monotonic JEMALLOC_N(nstime_monotonic) -nstime_monotonic_t *nstime_monotonic = JEMALLOC_N(n_nstime_monotonic); -#endif +nstime_monotonic_t *JET_MUTABLE nstime_monotonic = nstime_monotonic_impl; -#ifdef JEMALLOC_JET -#undef nstime_update -#define nstime_update JEMALLOC_N(n_nstime_update) -#endif -bool -nstime_update(nstime_t *time) { +static bool +nstime_update_impl(nstime_t *time) { nstime_t old_time; nstime_copy(&old_time, time); @@ -165,8 +153,4 @@ nstime_update(nstime_t *time) { return false; } -#ifdef JEMALLOC_JET -#undef nstime_update -#define nstime_update JEMALLOC_N(nstime_update) -nstime_update_t *nstime_update = JEMALLOC_N(n_nstime_update); -#endif +nstime_update_t *JET_MUTABLE nstime_update = nstime_update_impl; diff --git a/src/prof.c b/src/prof.c index d60680c1..470d926f 100644 --- a/src/prof.c +++ b/src/prof.c @@ -932,9 +932,7 @@ prof_tdata_count(void) { return tdata_count; } -#endif -#ifdef JEMALLOC_JET size_t prof_bt_count(void) { size_t bt_count; @@ -955,12 +953,8 @@ prof_bt_count(void) { } #endif -#ifdef JEMALLOC_JET -#undef prof_dump_open -#define prof_dump_open JEMALLOC_N(prof_dump_open_impl) -#endif static int -prof_dump_open(bool propagate_err, const char *filename) { +prof_dump_open_impl(bool propagate_err, const char *filename) { int fd; fd = creat(filename, 0644); @@ -974,11 +968,7 @@ prof_dump_open(bool propagate_err, const char *filename) { return fd; } -#ifdef JEMALLOC_JET -#undef prof_dump_open -#define prof_dump_open JEMALLOC_N(prof_dump_open) -prof_dump_open_t *prof_dump_open = JEMALLOC_N(prof_dump_open_impl); -#endif +prof_dump_open_t *JET_MUTABLE prof_dump_open = prof_dump_open_impl; static bool prof_dump_flush(bool propagate_err) { @@ -1331,12 +1321,9 @@ prof_tdata_dump_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, return NULL; } -#ifdef JEMALLOC_JET -#undef prof_dump_header -#define prof_dump_header JEMALLOC_N(prof_dump_header_impl) -#endif static bool -prof_dump_header(tsdn_t *tsdn, bool propagate_err, const prof_cnt_t *cnt_all) { +prof_dump_header_impl(tsdn_t *tsdn, bool propagate_err, + const prof_cnt_t *cnt_all) { bool ret; if (prof_dump_printf(propagate_err, @@ -1353,11 +1340,7 @@ prof_dump_header(tsdn_t *tsdn, bool propagate_err, const prof_cnt_t *cnt_all) { malloc_mutex_unlock(tsdn, &tdatas_mtx); return ret; } -#ifdef JEMALLOC_JET -#undef prof_dump_header -#define prof_dump_header JEMALLOC_N(prof_dump_header) -prof_dump_header_t *prof_dump_header = JEMALLOC_N(prof_dump_header_impl); -#endif +prof_dump_header_t *JET_MUTABLE prof_dump_header = prof_dump_header_impl; static bool prof_dump_gctx(tsdn_t *tsdn, bool propagate_err, prof_gctx_t *gctx, diff --git a/src/rtree.c b/src/rtree.c index 72786ff5..62df0143 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -25,65 +25,35 @@ rtree_new(rtree_t *rtree, bool zeroed) { return false; } -#ifdef JEMALLOC_JET -#undef rtree_node_alloc -#define rtree_node_alloc JEMALLOC_N(rtree_node_alloc_impl) -#endif static rtree_node_elm_t * -rtree_node_alloc(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { +rtree_node_alloc_impl(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { return (rtree_node_elm_t *)base_alloc(tsdn, b0get(), nelms * sizeof(rtree_node_elm_t), CACHELINE); } -#ifdef JEMALLOC_JET -#undef rtree_node_alloc -#define rtree_node_alloc JEMALLOC_N(rtree_node_alloc) -rtree_node_alloc_t *rtree_node_alloc = JEMALLOC_N(rtree_node_alloc_impl); -#endif +rtree_node_alloc_t *JET_MUTABLE rtree_node_alloc = rtree_node_alloc_impl; -#ifdef JEMALLOC_JET -#undef rtree_node_dalloc -#define rtree_node_dalloc JEMALLOC_N(rtree_node_dalloc_impl) -#endif -UNUSED static void -rtree_node_dalloc(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *node) { +static void +rtree_node_dalloc_impl(tsdn_t *tsdn, rtree_t *rtree, rtree_node_elm_t *node) { /* Nodes are never deleted during normal operation. */ not_reached(); } -#ifdef JEMALLOC_JET -#undef rtree_node_dalloc -#define rtree_node_dalloc JEMALLOC_N(rtree_node_dalloc) -rtree_node_dalloc_t *rtree_node_dalloc = JEMALLOC_N(rtree_node_dalloc_impl); -#endif +UNUSED rtree_node_dalloc_t *JET_MUTABLE rtree_node_dalloc = + rtree_node_dalloc_impl; -#ifdef JEMALLOC_JET -#undef rtree_leaf_alloc -#define rtree_leaf_alloc JEMALLOC_N(rtree_leaf_alloc_impl) -#endif static rtree_leaf_elm_t * -rtree_leaf_alloc(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { +rtree_leaf_alloc_impl(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { return (rtree_leaf_elm_t *)base_alloc(tsdn, b0get(), nelms * sizeof(rtree_leaf_elm_t), CACHELINE); } -#ifdef JEMALLOC_JET -#undef rtree_leaf_alloc -#define rtree_leaf_alloc JEMALLOC_N(rtree_leaf_alloc) -rtree_leaf_alloc_t *rtree_leaf_alloc = JEMALLOC_N(rtree_leaf_alloc_impl); -#endif +rtree_leaf_alloc_t *JET_MUTABLE rtree_leaf_alloc = rtree_leaf_alloc_impl; -#ifdef JEMALLOC_JET -#undef rtree_leaf_dalloc -#define rtree_leaf_dalloc JEMALLOC_N(rtree_leaf_dalloc_impl) -#endif -UNUSED static void -rtree_leaf_dalloc(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *leaf) { +static void +rtree_leaf_dalloc_impl(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *leaf) { /* Leaves are never deleted during normal operation. */ not_reached(); } -#ifdef JEMALLOC_JET -#undef rtree_leaf_dalloc -#define rtree_leaf_dalloc JEMALLOC_N(rtree_leaf_dalloc) -rtree_leaf_dalloc_t *rtree_leaf_dalloc = JEMALLOC_N(rtree_leaf_dalloc_impl); -#endif +UNUSED rtree_leaf_dalloc_t *JET_MUTABLE rtree_leaf_dalloc = + rtree_leaf_dalloc_impl; #ifdef JEMALLOC_JET # if RTREE_HEIGHT > 1 diff --git a/src/witness.c b/src/witness.c index edb736bf..0e910dca 100644 --- a/src/witness.c +++ b/src/witness.c @@ -14,12 +14,9 @@ witness_init(witness_t *witness, const char *name, witness_rank_t rank, witness->opaque = opaque; } -#ifdef JEMALLOC_JET -#undef witness_lock_error -#define witness_lock_error JEMALLOC_N(n_witness_lock_error) -#endif -void -witness_lock_error(const witness_list_t *witnesses, const witness_t *witness) { +static void +witness_lock_error_impl(const witness_list_t *witnesses, + const witness_t *witness) { witness_t *w; malloc_printf(": Lock rank order reversal:"); @@ -29,51 +26,28 @@ witness_lock_error(const witness_list_t *witnesses, const witness_t *witness) { malloc_printf(" %s(%u)\n", witness->name, witness->rank); abort(); } -#ifdef JEMALLOC_JET -#undef witness_lock_error -#define witness_lock_error JEMALLOC_N(witness_lock_error) -witness_lock_error_t *witness_lock_error = JEMALLOC_N(n_witness_lock_error); -#endif +witness_lock_error_t *JET_MUTABLE witness_lock_error = witness_lock_error_impl; -#ifdef JEMALLOC_JET -#undef witness_owner_error -#define witness_owner_error JEMALLOC_N(n_witness_owner_error) -#endif -void -witness_owner_error(const witness_t *witness) { +static void +witness_owner_error_impl(const witness_t *witness) { malloc_printf(": Should own %s(%u)\n", witness->name, witness->rank); abort(); } -#ifdef JEMALLOC_JET -#undef witness_owner_error -#define witness_owner_error JEMALLOC_N(witness_owner_error) -witness_owner_error_t *witness_owner_error = JEMALLOC_N(n_witness_owner_error); -#endif +witness_owner_error_t *JET_MUTABLE witness_owner_error = + witness_owner_error_impl; -#ifdef JEMALLOC_JET -#undef witness_not_owner_error -#define witness_not_owner_error JEMALLOC_N(n_witness_not_owner_error) -#endif -void -witness_not_owner_error(const witness_t *witness) { +static void +witness_not_owner_error_impl(const witness_t *witness) { malloc_printf(": Should not own %s(%u)\n", witness->name, witness->rank); abort(); } -#ifdef JEMALLOC_JET -#undef witness_not_owner_error -#define witness_not_owner_error JEMALLOC_N(witness_not_owner_error) -witness_not_owner_error_t *witness_not_owner_error = - JEMALLOC_N(n_witness_not_owner_error); -#endif +witness_not_owner_error_t *JET_MUTABLE witness_not_owner_error = + witness_not_owner_error_impl; -#ifdef JEMALLOC_JET -#undef witness_depth_error -#define witness_depth_error JEMALLOC_N(n_witness_depth_error) -#endif -void -witness_depth_error(const witness_list_t *witnesses, +static void +witness_depth_error_impl(const witness_list_t *witnesses, witness_rank_t rank_inclusive, unsigned depth) { witness_t *w; @@ -85,11 +59,8 @@ witness_depth_error(const witness_list_t *witnesses, malloc_printf("\n"); abort(); } -#ifdef JEMALLOC_JET -#undef witness_depth_error -#define witness_depth_error JEMALLOC_N(witness_depth_error) -witness_depth_error_t *witness_depth_error = JEMALLOC_N(n_witness_depth_error); -#endif +witness_depth_error_t *JET_MUTABLE witness_depth_error = + witness_depth_error_impl; void witnesses_cleanup(tsd_t *tsd) { -- GitLab From a4ae9707daee680a6fa0575646849fa8ef0bfad1 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 3 May 2017 11:07:00 -0700 Subject: [PATCH 475/544] Remove unused private_unnamespace infrastructure. --- .gitignore | 1 - configure.ac | 9 --------- include/jemalloc/internal/private_unnamespace.sh | 5 ----- 3 files changed, 15 deletions(-) delete mode 100755 include/jemalloc/internal/private_unnamespace.sh diff --git a/.gitignore b/.gitignore index 9bbc5d66..df2fb21a 100644 --- a/.gitignore +++ b/.gitignore @@ -24,7 +24,6 @@ /include/jemalloc/internal/jemalloc_preamble.h /include/jemalloc/internal/jemalloc_internal_defs.h /include/jemalloc/internal/private_namespace.h -/include/jemalloc/internal/private_unnamespace.h /include/jemalloc/internal/public_namespace.h /include/jemalloc/internal/public_symbols.txt /include/jemalloc/internal/public_unnamespace.h diff --git a/configure.ac b/configure.ac index 7ffdbea8..ffbe11a4 100644 --- a/configure.ac +++ b/configure.ac @@ -886,7 +886,6 @@ cfgoutputs_tup="${cfgoutputs_tup} test/include/test/jemalloc_test.h:test/include cfghdrs_in="include/jemalloc/jemalloc_defs.h.in" cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/jemalloc_internal_defs.h.in" cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_namespace.sh" -cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_unnamespace.sh" cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_symbols.txt" cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_namespace.sh" cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_unnamespace.sh" @@ -899,7 +898,6 @@ cfghdrs_in="${cfghdrs_in} test/include/test/jemalloc_test_defs.h.in" cfghdrs_out="include/jemalloc/jemalloc_defs.h" cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc${install_suffix}.h" cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_namespace.h" -cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_unnamespace.h" cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_symbols.txt" cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_namespace.h" cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_unnamespace.h" @@ -1913,13 +1911,6 @@ AC_CONFIG_COMMANDS([include/jemalloc/internal/private_namespace.h], [ srcdir="${srcdir}" objroot="${objroot}" ]) -AC_CONFIG_COMMANDS([include/jemalloc/internal/private_unnamespace.h], [ - mkdir -p "${objroot}include/jemalloc/internal" - "${srcdir}/include/jemalloc/internal/private_unnamespace.sh" "${srcdir}/include/jemalloc/internal/private_symbols.txt" > "${objroot}include/jemalloc/internal/private_unnamespace.h" -], [ - srcdir="${srcdir}" - objroot="${objroot}" -]) AC_CONFIG_COMMANDS([include/jemalloc/internal/public_symbols.txt], [ f="${objroot}include/jemalloc/internal/public_symbols.txt" mkdir -p "${objroot}include/jemalloc/internal" diff --git a/include/jemalloc/internal/private_unnamespace.sh b/include/jemalloc/internal/private_unnamespace.sh deleted file mode 100755 index 23fed8e8..00000000 --- a/include/jemalloc/internal/private_unnamespace.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -for symbol in `cat $1` ; do - echo "#undef ${symbol}" -done -- GitLab From 909f0482e479c1914a1bd528bf7ade702ed6415c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 4 May 2017 11:20:43 -0700 Subject: [PATCH 476/544] Automatically generate private symbol name mangling macros. Rather than using a manually maintained list of internal symbols to drive name mangling, add a compilation phase to automatically extract the list of internal symbols. This resolves #677. --- .gitignore | 18 +- Makefile.in | 53 +- configure.ac | 110 +++- .../internal/jemalloc_internal_defs.h.in | 12 + .../jemalloc/internal/jemalloc_preamble.h.in | 8 +- .../jemalloc/internal/private_namespace.sh | 2 +- include/jemalloc/internal/private_symbols.sh | 51 ++ include/jemalloc/internal/private_symbols.txt | 609 ------------------ src/jemalloc.c | 47 +- 9 files changed, 239 insertions(+), 671 deletions(-) create mode 100755 include/jemalloc/internal/private_symbols.sh delete mode 100644 include/jemalloc/internal/private_symbols.txt diff --git a/.gitignore b/.gitignore index df2fb21a..216d3c9d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ -/*.gcov.* - /bin/jemalloc-config /bin/jemalloc.sh /bin/jeprof @@ -24,6 +22,9 @@ /include/jemalloc/internal/jemalloc_preamble.h /include/jemalloc/internal/jemalloc_internal_defs.h /include/jemalloc/internal/private_namespace.h +/include/jemalloc/internal/private_namespace_jet.h +/include/jemalloc/internal/private_symbols.awk +/include/jemalloc/internal/private_symbols_jet.awk /include/jemalloc/internal/public_namespace.h /include/jemalloc/internal/public_symbols.txt /include/jemalloc/internal/public_unnamespace.h @@ -39,8 +40,7 @@ /include/jemalloc/jemalloc_typedefs.h /src/*.[od] -/src/*.gcda -/src/*.gcno +/src/*.sym /test/test.sh test/include/test/jemalloc_test.h @@ -49,33 +49,23 @@ test/include/test/jemalloc_test_defs.h /test/integration/[A-Za-z]* !/test/integration/[A-Za-z]*.* /test/integration/*.[od] -/test/integration/*.gcda -/test/integration/*.gcno /test/integration/*.out /test/integration/cpp/[A-Za-z]* !/test/integration/cpp/[A-Za-z]*.* /test/integration/cpp/*.[od] -/test/integration/cpp/*.gcda -/test/integration/cpp/*.gcno /test/integration/cpp/*.out /test/src/*.[od] -/test/src/*.gcda -/test/src/*.gcno /test/stress/[A-Za-z]* !/test/stress/[A-Za-z]*.* /test/stress/*.[od] -/test/stress/*.gcda -/test/stress/*.gcno /test/stress/*.out /test/unit/[A-Za-z]* !/test/unit/[A-Za-z]*.* /test/unit/*.[od] -/test/unit/*.gcda -/test/unit/*.gcno /test/unit/*.out /VERSION diff --git a/Makefile.in b/Makefile.in index 418e92b4..94d8021f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -68,6 +68,8 @@ TEST_LD_MODE = @TEST_LD_MODE@ MKLIB = @MKLIB@ AR = @AR@ ARFLAGS = @ARFLAGS@ +DUMP_SYMS = @DUMP_SYMS@ +AWK := @AWK@ CC_MM = @CC_MM@ LM := @LM@ INSTALL = @INSTALL@ @@ -224,10 +226,15 @@ TESTS_STRESS := $(srcroot)test/stress/microbench.c TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_INTEGRATION_CPP) $(TESTS_STRESS) +PRIVATE_NAMESPACE_HDRS := $(objroot)include/jemalloc/internal/private_namespace.h $(objroot)include/jemalloc/internal/private_namespace_jet.h +C_SYM_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.sym.$(O)) +C_SYMS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.sym) C_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.$(O)) CPP_OBJS := $(CPP_SRCS:$(srcroot)%.cpp=$(objroot)%.$(O)) C_PIC_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.pic.$(O)) CPP_PIC_OBJS := $(CPP_SRCS:$(srcroot)%.cpp=$(objroot)%.pic.$(O)) +C_JET_SYM_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.sym.$(O)) +C_JET_SYMS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.sym) C_JET_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.$(O)) C_TESTLIB_UNIT_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.unit.$(O)) C_TESTLIB_INTEGRATION_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.integration.$(O)) @@ -268,24 +275,32 @@ build_doc: $(DOCS) # Include generated dependency files. # ifdef CC_MM +-include $(C_SYM_OBJS:%.$(O)=%.d) -include $(C_OBJS:%.$(O)=%.d) -include $(CPP_OBJS:%.$(O)=%.d) -include $(C_PIC_OBJS:%.$(O)=%.d) -include $(CPP_PIC_OBJS:%.$(O)=%.d) +-include $(C_JET_SYM_OBJS:%.$(O)=%.d) -include $(C_JET_OBJS:%.$(O)=%.d) -include $(C_TESTLIB_OBJS:%.$(O)=%.d) -include $(TESTS_OBJS:%.$(O)=%.d) -include $(TESTS_CPP_OBJS:%.$(O)=%.d) endif +$(C_SYM_OBJS): $(objroot)src/%.sym.$(O): $(srcroot)src/%.c +$(C_SYM_OBJS): CPPFLAGS += -DJEMALLOC_NO_PRIVATE_NAMESPACE +$(C_SYMS): $(objroot)src/%.sym: $(objroot)src/%.sym.$(O) $(C_OBJS): $(objroot)src/%.$(O): $(srcroot)src/%.c $(CPP_OBJS): $(objroot)src/%.$(O): $(srcroot)src/%.cpp $(C_PIC_OBJS): $(objroot)src/%.pic.$(O): $(srcroot)src/%.c $(C_PIC_OBJS): CFLAGS += $(PIC_CFLAGS) $(CPP_PIC_OBJS): $(objroot)src/%.pic.$(O): $(srcroot)src/%.cpp $(CPP_PIC_OBJS): CXXFLAGS += $(PIC_CFLAGS) +$(C_JET_SYM_OBJS): $(objroot)src/%.jet.sym.$(O): $(srcroot)src/%.c +$(C_JET_SYM_OBJS): CPPFLAGS += -DJEMALLOC_JET -DJEMALLOC_NO_PRIVATE_NAMESPACE +$(C_JET_SYMS): $(objroot)src/%.jet.sym: $(objroot)src/%.jet.sym.$(O) $(C_JET_OBJS): $(objroot)src/%.jet.$(O): $(srcroot)src/%.c -$(C_JET_OBJS): CFLAGS += -DJEMALLOC_JET +$(C_JET_OBJS): CPPFLAGS += -DJEMALLOC_JET $(C_TESTLIB_UNIT_OBJS): $(objroot)test/src/%.unit.$(O): $(srcroot)test/src/%.c $(C_TESTLIB_UNIT_OBJS): CPPFLAGS += -DJEMALLOC_UNIT_TEST $(C_TESTLIB_INTEGRATION_OBJS): $(objroot)test/src/%.integration.$(O): $(srcroot)test/src/%.c @@ -303,25 +318,42 @@ $(TESTS_CPP_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.cpp $(TESTS_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include $(TESTS_CPP_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include ifneq ($(IMPORTLIB),$(SO)) -$(CPP_OBJS) $(C_OBJS) $(C_JET_OBJS): CPPFLAGS += -DDLLEXPORT +$(CPP_OBJS) $(C_SYM_OBJS) $(C_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS): CPPFLAGS += -DDLLEXPORT endif -ifndef CC_MM # Dependencies. +ifndef CC_MM HEADER_DIRS = $(srcroot)include/jemalloc/internal \ $(objroot)include/jemalloc $(objroot)include/jemalloc/internal -HEADERS = $(wildcard $(foreach dir,$(HEADER_DIRS),$(dir)/*.h)) -$(C_OBJS) $(CPP_OBJS) $(C_PIC_OBJS) $(CPP_PIC_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): $(HEADERS) +HEADERS = $(filter-out $(PRIVATE_NAMESPACE_HDRS),$(wildcard $(foreach dir,$(HEADER_DIRS),$(dir)/*.h))) +$(C_SYM_OBJS) $(C_OBJS) $(CPP_OBJS) $(C_PIC_OBJS) $(CPP_PIC_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS) $(TESTS_CPP_OBJS): $(HEADERS) $(TESTS_OBJS) $(TESTS_CPP_OBJS): $(objroot)test/include/test/jemalloc_test.h endif -$(C_OBJS) $(C_PIC_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): %.$(O): +$(C_OBJS) $(CPP_OBJS) $(C_PIC_OBJS) $(CPP_PIC_OBJS) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(TESTS_INTEGRATION_OBJS) $(TESTS_INTEGRATION_CPP_OBJS): $(objroot)include/jemalloc/internal/private_namespace.h +$(C_JET_OBJS) $(C_TESTLIB_UNIT_OBJS) $(C_TESTLIB_STRESS_OBJS) $(TESTS_UNIT_OBJS) $(TESTS_STRESS_OBJS): $(objroot)include/jemalloc/internal/private_namespace_jet.h + +$(C_SYM_OBJS) $(C_OBJS) $(C_PIC_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): %.$(O): @mkdir -p $(@D) $(CC) $(CFLAGS) -c $(CPPFLAGS) $(CTARGET) $< ifdef CC_MM @$(CC) -MM $(CPPFLAGS) -MT $@ -o $(@:%.$(O)=%.d) $< endif +$(C_SYMS): %.sym: + @mkdir -p $(@D) + $(DUMP_SYMS) $< | $(AWK) -f $(objroot)include/jemalloc/internal/private_symbols.awk > $@ + +$(C_JET_SYMS): %.sym: + @mkdir -p $(@D) + $(DUMP_SYMS) $< | $(AWK) -f $(objroot)include/jemalloc/internal/private_symbols_jet.awk > $@ + +$(objroot)include/jemalloc/internal/private_namespace.h: $(C_SYMS) + $(SHELL) $(objdir)include/jemalloc/internal/private_namespace.sh $^ > $@ + +$(objroot)include/jemalloc/internal/private_namespace_jet.h: $(C_JET_SYMS) + $(SHELL) $(objdir)include/jemalloc/internal/private_namespace.sh $^ > $@ + $(CPP_OBJS) $(CPP_PIC_OBJS) $(TESTS_CPP_OBJS): %.$(O): @mkdir -p $(@D) $(CXX) $(CXXFLAGS) -c $(CPPFLAGS) $(CTARGET) $< @@ -347,7 +379,7 @@ $(STATIC_LIBS): @mkdir -p $(@D) $(AR) $(ARFLAGS)@AROUT@ $+ -$(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(TESTS_UNIT_LINK_OBJS) $(C_JET_OBJS) $(C_TESTLIB_UNIT_OBJS) +$(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(C_JET_OBJS) $(C_TESTLIB_UNIT_OBJS) @mkdir -p $(@D) $(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LDFLAGS) $(filter-out -lm,$(LIBS)) $(LM) $(EXTRA_LDFLAGS) @@ -452,16 +484,23 @@ stress: tests_stress stress_dir check: check_unit check_integration check_integration_decay check_integration_prof clean: + rm -f $(PRIVATE_NAMESPACE_HDRS) + rm -f $(C_SYM_OBJS) + rm -f $(C_SYMS) rm -f $(C_OBJS) rm -f $(CPP_OBJS) rm -f $(C_PIC_OBJS) rm -f $(CPP_PIC_OBJS) + rm -f $(C_JET_SYM_OBJS) + rm -f $(C_JET_SYMS) rm -f $(C_JET_OBJS) rm -f $(C_TESTLIB_OBJS) + rm -f $(C_SYM_OBJS:%.$(O)=%.d) rm -f $(C_OBJS:%.$(O)=%.d) rm -f $(CPP_OBJS:%.$(O)=%.d) rm -f $(C_PIC_OBJS:%.$(O)=%.d) rm -f $(CPP_PIC_OBJS:%.$(O)=%.d) + rm -f $(C_JET_SYM_OBJS:%.$(O)=%.d) rm -f $(C_JET_OBJS:%.$(O)=%.d) rm -f $(C_TESTLIB_OBJS:%.$(O)=%.d) rm -f $(TESTS_OBJS:%.$(O)=%$(EXE)) diff --git a/configure.ac b/configure.ac index ffbe11a4..6c1d4ffc 100644 --- a/configure.ac +++ b/configure.ac @@ -510,6 +510,8 @@ AN_PROGRAM([ar], [AC_PROG_AR]) AC_DEFUN([AC_PROG_AR], [AC_CHECK_TOOL(AR, ar, :)]) AC_PROG_AR +AC_PROG_AWK + dnl Platform-specific settings. abi and RPATH can probably be determined dnl programmatically, but doing so is error-prone, which makes it generally dnl not worth the trouble. @@ -519,6 +521,8 @@ dnl definitions need to be seen before any headers are included, which is a pain dnl to make happen otherwise. default_retain="0" maps_coalesce="1" +DUMP_SYMS="nm -a" +SYM_PREFIX="" case "${host}" in *-*-darwin* | *-*-ios*) abi="macho" @@ -530,6 +534,7 @@ case "${host}" in DSO_LDFLAGS='-shared -Wl,-install_name,$(LIBDIR)/$(@F)' SOREV="${rev}.${so}" sbrk_deprecated="1" + SYM_PREFIX="_" ;; *-*-freebsd*) abi="elf" @@ -624,6 +629,7 @@ case "${host}" in DSO_LDFLAGS="-shared" link_whole_archive="1" fi + DUMP_SYMS="dumpbin /SYMBOLS" a="lib" libprefix="" SOREV="${so}" @@ -671,6 +677,7 @@ AC_SUBST([TEST_LD_MODE]) AC_SUBST([MKLIB]) AC_SUBST([ARFLAGS]) AC_SUBST([AROUT]) +AC_SUBST([DUMP_SYMS]) AC_SUBST([CC_MM]) dnl Determine whether libm must be linked to use e.g. log(3). @@ -773,16 +780,6 @@ AC_PROG_RANLIB AC_PATH_PROG([LD], [ld], [false], [$PATH]) AC_PATH_PROG([AUTOCONF], [autoconf], [false], [$PATH]) -public_syms="malloc_conf malloc_message malloc calloc posix_memalign aligned_alloc realloc free mallocx rallocx xallocx sallocx dallocx sdallocx nallocx mallctl mallctlnametomib mallctlbymib malloc_stats_print malloc_usable_size" - -dnl Check for allocator-related functions that should be wrapped. -AC_CHECK_FUNC([memalign], - [AC_DEFINE([JEMALLOC_OVERRIDE_MEMALIGN], [ ]) - public_syms="${public_syms} memalign"]) -AC_CHECK_FUNC([valloc], - [AC_DEFINE([JEMALLOC_OVERRIDE_VALLOC], [ ]) - public_syms="${public_syms} valloc"]) - dnl Perform no name mangling by default. AC_ARG_WITH([mangling], [AS_HELP_STRING([--with-mangling=], [Mangle symbols in ])], @@ -814,6 +811,49 @@ AC_ARG_WITH([export], fi] ) +public_syms="aligned_alloc calloc dallocx free mallctl mallctlbymib mallctlnametomib malloc malloc_conf malloc_message malloc_stats_print malloc_usable_size mallocx nallocx posix_memalign rallocx realloc sallocx sdallocx xallocx" +dnl Check for additional platform-specific public API functions. +AC_CHECK_FUNC([memalign], + [AC_DEFINE([JEMALLOC_OVERRIDE_MEMALIGN], [ ]) + public_syms="${public_syms} memalign"]) +AC_CHECK_FUNC([valloc], + [AC_DEFINE([JEMALLOC_OVERRIDE_VALLOC], [ ]) + public_syms="${public_syms} valloc"]) + +dnl Check for allocator-related functions that should be wrapped. +wrap_syms= +if test "x${JEMALLOC_PREFIX}" = "x" ; then + AC_CHECK_FUNC([__libc_calloc], + [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_CALLOC], [ ]) + wrap_syms="${wrap_syms} __libc_calloc"]) + AC_CHECK_FUNC([__libc_free], + [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_FREE], [ ]) + wrap_syms="${wrap_syms} __libc_free"]) + AC_CHECK_FUNC([__libc_malloc], + [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_MALLOC], [ ]) + wrap_syms="${wrap_syms} __libc_malloc"]) + AC_CHECK_FUNC([__libc_memalign], + [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_MEMALIGN], [ ]) + wrap_syms="${wrap_syms} __libc_memalign"]) + AC_CHECK_FUNC([__libc_realloc], + [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_REALLOC], [ ]) + wrap_syms="${wrap_syms} __libc_realloc"]) + AC_CHECK_FUNC([__libc_valloc], + [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_VALLOC], [ ]) + wrap_syms="${wrap_syms} __libc_valloc"]) + AC_CHECK_FUNC([__posix_memalign], + [AC_DEFINE([JEMALLOC_OVERRIDE___POSIX_MEMALIGN], [ ]) + wrap_syms="${wrap_syms} __posix_memalign"]) +fi + +case "${host}" in + *-*-mingw* | *-*-cygwin*) + wrap_syms="${wrap_syms} tls_callback" + ;; + *) + ;; +esac + dnl Mangle library-private APIs. AC_ARG_WITH([private_namespace], [AS_HELP_STRING([--with-private-namespace=], [Prefix to prepend to all library-private APIs])], @@ -885,8 +925,8 @@ cfgoutputs_tup="${cfgoutputs_tup} test/include/test/jemalloc_test.h:test/include cfghdrs_in="include/jemalloc/jemalloc_defs.h.in" cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/jemalloc_internal_defs.h.in" +cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_symbols.sh" cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_namespace.sh" -cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_symbols.txt" cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_namespace.sh" cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_unnamespace.sh" cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/size_classes.sh" @@ -897,7 +937,8 @@ cfghdrs_in="${cfghdrs_in} test/include/test/jemalloc_test_defs.h.in" cfghdrs_out="include/jemalloc/jemalloc_defs.h" cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc${install_suffix}.h" -cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_namespace.h" +cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_symbols.awk" +cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_symbols_jet.awk" cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_symbols.txt" cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_namespace.h" cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_unnamespace.h" @@ -1541,6 +1582,7 @@ AC_CHECK_FUNC([_malloc_thread_cleanup], ) if test "x$have__malloc_thread_cleanup" = "x1" ; then AC_DEFINE([JEMALLOC_MALLOC_THREAD_CLEANUP], [ ]) + wrap_syms="${wrap_syms} _malloc_thread_cleanup" force_tls="1" fi @@ -1553,6 +1595,7 @@ AC_CHECK_FUNC([_pthread_mutex_init_calloc_cb], ) if test "x$have__pthread_mutex_init_calloc_cb" = "x1" ; then AC_DEFINE([JEMALLOC_MUTEX_INIT_CB]) + wrap_syms="${wrap_syms} _malloc_prefork _malloc_postfork" fi dnl Disable lazy locking by default. @@ -1588,6 +1631,7 @@ if test "x$enable_lazy_lock" = "x1" ; then ]) fi AC_DEFINE([JEMALLOC_LAZY_LOCK], [ ]) + wrap_syms="${wrap_syms} pthread_create" fi AC_SUBST([enable_lazy_lock]) @@ -1870,7 +1914,10 @@ extern void *(* __realloc_hook)(void *ptr, size_t size); if (__free_hook && ptr) __free_hook(ptr); ], [je_cv_glibc_malloc_hook]) if test "x${je_cv_glibc_malloc_hook}" = "xyes" ; then - AC_DEFINE([JEMALLOC_GLIBC_MALLOC_HOOK], [ ]) + if test "x${JEMALLOC_PREFIX}" = "x" ; then + AC_DEFINE([JEMALLOC_GLIBC_MALLOC_HOOK], [ ]) + wrap_syms="${wrap_syms} __free_hook __malloc_hook __realloc_hook" + fi fi JE_COMPILABLE([glibc memalign hook], [ @@ -1882,7 +1929,10 @@ extern void *(* __memalign_hook)(size_t alignment, size_t size); if (__memalign_hook) ptr = __memalign_hook(16, 7); ], [je_cv_glibc_memalign_hook]) if test "x${je_cv_glibc_memalign_hook}" = "xyes" ; then - AC_DEFINE([JEMALLOC_GLIBC_MEMALIGN_HOOK], [ ]) + if test "x${JEMALLOC_PREFIX}" = "x" ; then + AC_DEFINE([JEMALLOC_GLIBC_MEMALIGN_HOOK], [ ]) + wrap_syms="${wrap_syms} __memalign_hook" + fi fi JE_COMPILABLE([pthreads adaptive mutexes], [ @@ -1904,13 +1954,6 @@ AC_HEADER_STDBOOL dnl ============================================================================ dnl Define commands that generate output files. -AC_CONFIG_COMMANDS([include/jemalloc/internal/private_namespace.h], [ - mkdir -p "${objroot}include/jemalloc/internal" - "${srcdir}/include/jemalloc/internal/private_namespace.sh" "${srcdir}/include/jemalloc/internal/private_symbols.txt" > "${objroot}include/jemalloc/internal/private_namespace.h" -], [ - srcdir="${srcdir}" - objroot="${objroot}" -]) AC_CONFIG_COMMANDS([include/jemalloc/internal/public_symbols.txt], [ f="${objroot}include/jemalloc/internal/public_symbols.txt" mkdir -p "${objroot}include/jemalloc/internal" @@ -1934,6 +1977,31 @@ AC_CONFIG_COMMANDS([include/jemalloc/internal/public_symbols.txt], [ public_syms="${public_syms}" JEMALLOC_PREFIX="${JEMALLOC_PREFIX}" ]) +AC_CONFIG_COMMANDS([include/jemalloc/internal/private_symbols.awk], [ + f="${objroot}include/jemalloc/internal/private_symbols.awk" + mkdir -p "${objroot}include/jemalloc/internal" + export_syms=`for sym in ${public_syms}; do echo "${JEMALLOC_PREFIX}${sym}"; done; for sym in ${wrap_syms}; do echo "${sym}"; done;` + "${srcdir}/include/jemalloc/internal/private_symbols.sh" "${SYM_PREFIX}" ${export_syms} > "${objroot}include/jemalloc/internal/private_symbols.awk" +], [ + srcdir="${srcdir}" + objroot="${objroot}" + public_syms="${public_syms}" + wrap_syms="${wrap_syms}" + SYM_PREFIX="${SYM_PREFIX}" + JEMALLOC_PREFIX="${JEMALLOC_PREFIX}" +]) +AC_CONFIG_COMMANDS([include/jemalloc/internal/private_symbols_jet.awk], [ + f="${objroot}include/jemalloc/internal/private_symbols_jet.awk" + mkdir -p "${objroot}include/jemalloc/internal" + export_syms=`for sym in ${public_syms}; do echo "jet_${sym}"; done; for sym in ${wrap_syms}; do echo "${sym}"; done;` + "${srcdir}/include/jemalloc/internal/private_symbols.sh" "${SYM_PREFIX}" ${export_syms} > "${objroot}include/jemalloc/internal/private_symbols_jet.awk" +], [ + srcdir="${srcdir}" + objroot="${objroot}" + public_syms="${public_syms}" + wrap_syms="${wrap_syms}" + SYM_PREFIX="${SYM_PREFIX}" +]) AC_CONFIG_COMMANDS([include/jemalloc/internal/public_namespace.h], [ mkdir -p "${objroot}include/jemalloc/internal" "${srcdir}/include/jemalloc/internal/public_namespace.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" > "${objroot}include/jemalloc/internal/public_namespace.h" diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index bccee167..78ddd376 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -8,6 +8,18 @@ #undef JEMALLOC_PREFIX #undef JEMALLOC_CPREFIX +/* + * Define overrides for non-standard allocator-related functions if they are + * present on the system. + */ +#undef JEMALLOC_OVERRIDE___LIBC_CALLOC +#undef JEMALLOC_OVERRIDE___LIBC_FREE +#undef JEMALLOC_OVERRIDE___LIBC_MALLOC +#undef JEMALLOC_OVERRIDE___LIBC_MEMALIGN +#undef JEMALLOC_OVERRIDE___LIBC_REALLOC +#undef JEMALLOC_OVERRIDE___LIBC_VALLOC +#undef JEMALLOC_OVERRIDE___POSIX_MEMALIGN + /* * JEMALLOC_PRIVATE_NAMESPACE is used as a prefix for all library-private APIs. * For shared libraries, symbol visibility mechanisms prevent these symbols diff --git a/include/jemalloc/internal/jemalloc_preamble.h.in b/include/jemalloc/internal/jemalloc_preamble.h.in index bc0ca641..9e9225ef 100644 --- a/include/jemalloc/internal/jemalloc_preamble.h.in +++ b/include/jemalloc/internal/jemalloc_preamble.h.in @@ -38,7 +38,13 @@ * want the inclusion of hooks to happen early, so that we hook as much as * possible. */ -#include "jemalloc/internal/private_namespace.h" +#ifndef JEMALLOC_NO_PRIVATE_NAMESPACE +# ifndef JEMALLOC_JET +# include "jemalloc/internal/private_namespace.h" +# else +# include "jemalloc/internal/private_namespace_jet.h" +# endif +#endif #include "jemalloc/internal/hooks.h" static const bool config_debug = diff --git a/include/jemalloc/internal/private_namespace.sh b/include/jemalloc/internal/private_namespace.sh index 820862fe..6ef1346a 100755 --- a/include/jemalloc/internal/private_namespace.sh +++ b/include/jemalloc/internal/private_namespace.sh @@ -1,5 +1,5 @@ #!/bin/sh -for symbol in `cat $1` ; do +for symbol in `cat "$@"` ; do echo "#define ${symbol} JEMALLOC_N(${symbol})" done diff --git a/include/jemalloc/internal/private_symbols.sh b/include/jemalloc/internal/private_symbols.sh new file mode 100755 index 00000000..442a259f --- /dev/null +++ b/include/jemalloc/internal/private_symbols.sh @@ -0,0 +1,51 @@ +#!/bin/sh +# +# Generate private_symbols[_jet].awk. +# +# Usage: private_symbols.sh * +# +# is typically "" or "_". + +sym_prefix=$1 +shift + +cat <' output. +# +# Handle lines like: +# 0000000000000008 D opt_junk +# 0000000000007574 T malloc_initialized +(NF == 3 && $2 ~ /^[ABCDGRSTVW]$/ && !($3 in exported_symbols) && $3 ~ /^[A-Za-z0-9_]+$/) { + print substr($3, 1+length(sym_prefix), length($3)-length(sym_prefix)) +} + +# Process 'dumpbin /SYMBOLS ' output. +# +# Handle lines like: +# 353 00008098 SECT4 notype External | opt_junk +# 3F1 00000000 SECT7 notype () External | malloc_initialized +($3 ~ /^SECT[0-9]+/ && $(NF-2) == "External" && !($NF in exported_symbols)) { + print $NF +} +EOF diff --git a/include/jemalloc/internal/private_symbols.txt b/include/jemalloc/internal/private_symbols.txt deleted file mode 100644 index eb9b3010..00000000 --- a/include/jemalloc/internal/private_symbols.txt +++ /dev/null @@ -1,609 +0,0 @@ -a0dalloc -a0malloc -arena_aalloc -arena_alloc_junk_small -arena_basic_stats_merge -arena_bin_index -arena_bin_info -arena_boot -arena_choose -arena_choose_hard -arena_choose_impl -arena_cleanup -arena_dalloc -arena_dalloc_bin_junked_locked -arena_dalloc_junk_small -arena_dalloc_no_tcache -arena_dalloc_promoted -arena_dalloc_small -arena_decay -arena_decay_tick -arena_decay_ticks -arena_dirty_decay_time_default_get -arena_dirty_decay_time_default_set -arena_dirty_decay_time_get -arena_dirty_decay_time_set -arena_muzzy_decay_time_default_get -arena_muzzy_decay_time_default_set -arena_muzzy_decay_time_get -arena_muzzy_decay_time_set -arena_destroy -arena_dss_prec_get -arena_dss_prec_set -arena_extent_alloc_large -arena_extent_dalloc_large_prep -arena_extent_ralloc_large_expand -arena_extent_ralloc_large_shrink -arena_extent_sn_next -arena_extents_dirty_dalloc -arena_get -arena_ichoose -arena_ind_get -arena_init -arena_internal_add -arena_internal_get -arena_internal_sub -arena_malloc -arena_malloc_hard -arena_migrate -arena_new -arena_nthreads_dec -arena_nthreads_get -arena_nthreads_inc -arena_palloc -arena_postfork_child -arena_postfork_parent -arena_prefork0 -arena_prefork1 -arena_prefork2 -arena_prefork3 -arena_prefork4 -arena_prefork5 -arena_prefork6 -arena_prof_accum -arena_prof_promote -arena_prof_tctx_get -arena_prof_tctx_reset -arena_prof_tctx_set -arena_ralloc -arena_ralloc_no_move -arena_reset -arena_salloc -arena_sdalloc -arena_sdalloc_no_tcache -arena_set -arena_slab_regind -arena_stats_init -arena_stats_mapped_add -arena_stats_merge -arena_tcache_fill_small -arena_tdata_get -arena_tdata_get_hard -arena_vsalloc -arenas -arenas_tdata_cleanup -b0get -base_alloc -base_boot -base_delete -base_extent_alloc -base_extent_hooks_get -base_extent_hooks_set -base_ind_get -base_new -base_postfork_child -base_postfork_parent -base_prefork -base_stats_get -bitmap_ffu -bitmap_full -bitmap_get -bitmap_info_init -bitmap_init -bitmap_set -bitmap_sfu -bitmap_size -bitmap_unset -bootstrap_calloc -bootstrap_free -bootstrap_malloc -bt_init -bt2gctx_mtx -buferror -ckh_count -ckh_delete -ckh_insert -ckh_iter -ckh_new -ckh_pointer_hash -ckh_pointer_keycomp -ckh_remove -ckh_search -ckh_string_hash -ckh_string_keycomp -ctl_boot -ctl_bymib -ctl_byname -ctl_nametomib -ctl_postfork_child -ctl_postfork_parent -ctl_prefork -decay_ticker_get -dss_prec_names -extent_ad_comp -extent_addr_get -extent_addr_randomize -extent_addr_set -extent_alloc -extent_alloc_cache -extent_alloc_dss -extent_alloc_mmap -extent_alloc_wrapper -extent_arena_get -extent_arena_set -extent_base_get -extent_before_get -extent_boot -extent_binit -extent_bsize_get -extent_bsize_set -extent_commit_wrapper -extent_committed_get -extent_committed_set -extent_dalloc -extent_dalloc_gap -extent_dalloc_mmap -extent_dalloc_wrapper -extent_decommit_wrapper -extent_destroy_wrapper -extent_dss_boot -extent_dss_mergeable -extent_dss_prec_get -extent_dss_prec_set -extent_ead_comp -extent_esn_comp -extent_esn_get -extent_esn_set -extent_esnead_comp -extent_heap_empty -extent_heap_first -extent_heap_insert -extent_heap_new -extent_heap_remove -extent_heap_remove_first -extent_hooks_default -extent_hooks_get -extent_hooks_set -extent_in_dss -extent_init -extent_last_get -extent_list_append -extent_list_first -extent_list_init -extent_list_last -extent_list_remove -extent_list_replace -extent_merge_wrapper -extent_nfree_dec -extent_nfree_get -extent_nfree_inc -extent_nfree_set -extent_past_get -extent_prof_tctx_get -extent_prof_tctx_set -extent_purge_forced_wrapper -extent_purge_lazy_wrapper -extent_size_get -extent_size_quantize_ceil -extent_size_quantize_floor -extent_size_set -extent_slab_data_get -extent_slab_data_get_const -extent_slab_get -extent_slab_set -extent_sn_comp -extent_sn_get -extent_sn_set -extent_snad_comp -extent_split_wrapper -extent_state_get -extent_state_set -extent_szind_get -extent_szind_get_maybe_invalid -extent_szind_set -extent_usize_get -extent_zeroed_get -extent_zeroed_set -extents_alloc -extents_dalloc -extents_evict -extents_init -extents_npages_get -extents_prefork -extents_postfork_child -extents_postfork_parent -extents_rtree -extents_state_get -ffs_llu -ffs_lu -ffs_u -ffs_u32 -ffs_u64 -ffs_zu -get_errno -hash -hash_fmix_32 -hash_fmix_64 -hash_get_block_32 -hash_get_block_64 -hash_rotl_32 -hash_rotl_64 -hash_x64_128 -hash_x86_128 -hash_x86_32 -hooks_arena_new_hook -hooks_libc_hook -iaalloc -ialloc -iallocztm -iarena_cleanup -idalloc -idalloctm -iealloc -index2size -index2size_compute -index2size_lookup -index2size_tab -ipalloc -ipalloct -ipallocztm -iralloc -iralloct -iralloct_realign -isalloc -isdalloct -isthreaded -ivsalloc -ixalloc -jemalloc_postfork_child -jemalloc_postfork_parent -jemalloc_prefork -large_dalloc -large_dalloc_finish -large_dalloc_junk -large_dalloc_maybe_junk -large_dalloc_prep_junked_locked -large_malloc -large_palloc -large_prof_tctx_get -large_prof_tctx_reset -large_prof_tctx_set -large_ralloc -large_ralloc_no_move -large_salloc -lg_floor -lg_prof_sample -malloc_cprintf -malloc_getcpu -malloc_initialized -malloc_mutex_prof_data_reset -malloc_mutex_assert_not_owner -malloc_mutex_assert_owner -malloc_mutex_boot -malloc_mutex_init -malloc_mutex_lock -malloc_mutex_lock_final -malloc_mutex_lock_slow -malloc_mutex_postfork_child -malloc_mutex_postfork_parent -malloc_mutex_prefork -malloc_mutex_trylock -malloc_mutex_trylock_final -malloc_mutex_unlock -malloc_printf -malloc_slow -malloc_snprintf -malloc_strtoumax -malloc_tsd_boot0 -malloc_tsd_boot1 -malloc_tsd_cleanup_register -malloc_tsd_dalloc -malloc_tsd_malloc -malloc_vcprintf -malloc_vsnprintf -malloc_write -mutex_owner_stats_update -narenas_auto -narenas_total_get -ncpus -nhbins -nstime_add -nstime_compare -nstime_copy -nstime_divide -nstime_idivide -nstime_imultiply -nstime_init -nstime_init2 -nstime_monotonic -nstime_msec -nstime_ns -nstime_nsec -nstime_sec -nstime_subtract -nstime_update -opt_abort -opt_dirty_decay_time -opt_muzzy_decay_time -opt_dss -opt_junk -opt_junk_alloc -opt_junk_free -opt_lg_prof_interval -opt_lg_prof_sample -opt_lg_tcache_max -opt_narenas -opt_prof -opt_prof_accum -opt_prof_active -opt_prof_final -opt_prof_gdump -opt_prof_leak -opt_prof_prefix -opt_prof_thread_active_init -opt_stats_print -opt_tcache -opt_utrace -opt_xmalloc -opt_zero -pages_boot -pages_commit -pages_decommit -pages_huge -pages_map -pages_nohuge -pages_purge_forced -pages_purge_lazy -pages_unmap -percpu_arena_choose -percpu_arena_ind_limit -percpu_arena_update -pind2sz -pind2sz_compute -pind2sz_lookup -pind2sz_tab -pow2_ceil_u32 -pow2_ceil_u64 -pow2_ceil_zu -prng_lg_range_u32 -prng_lg_range_u64 -prng_lg_range_zu -prng_range_u32 -prng_range_u64 -prng_range_zu -prng_state_next_u32 -prng_state_next_u64 -prng_state_next_zu -prof_accum_add -prof_accum_cancel -prof_accum_init -prof_active -prof_active_get -prof_active_get_unlocked -prof_active_set -prof_alloc_prep -prof_alloc_rollback -prof_backtrace -prof_boot0 -prof_boot1 -prof_boot2 -prof_bt_count -prof_cnt_all -prof_dump_header -prof_dump_open -prof_free -prof_free_sampled_object -prof_gdump -prof_gdump_get -prof_gdump_get_unlocked -prof_gdump_set -prof_gdump_val -prof_idump -prof_interval -prof_lookup -prof_malloc -prof_malloc_sample_object -prof_mdump -prof_postfork_child -prof_postfork_parent -prof_prefork0 -prof_prefork1 -prof_realloc -prof_reset -prof_sample_accum_update -prof_sample_threshold_update -prof_tctx_get -prof_tctx_reset -prof_tctx_set -prof_tdata_cleanup -prof_tdata_count -prof_tdata_get -prof_tdata_init -prof_tdata_reinit -prof_thread_active_get -prof_thread_active_init_get -prof_thread_active_init_set -prof_thread_active_set -prof_thread_name_get -prof_thread_name_set -psz2ind -psz2u -rtree_clear -rtree_ctx_data_init -rtree_delete -rtree_extent_read -rtree_extent_szind_read -rtree_leaf_alloc -rtree_leaf_dalloc -rtree_leaf_elm_acquire -rtree_leaf_elm_bits_extent_get -rtree_leaf_elm_bits_locked_get -rtree_leaf_elm_bits_read -rtree_leaf_elm_bits_slab_get -rtree_leaf_elm_bits_szind_get -rtree_leaf_elm_extent_read -rtree_leaf_elm_extent_write -rtree_leaf_elm_lookup -rtree_leaf_elm_lookup_hard -rtree_leaf_elm_release -rtree_leaf_elm_slab_read -rtree_leaf_elm_slab_write -rtree_leaf_elm_szind_read -rtree_leaf_elm_szind_slab_update -rtree_leaf_elm_szind_write -rtree_leaf_elm_witness_access -rtree_leaf_elm_witness_acquire -rtree_leaf_elm_witness_release -rtree_leaf_elm_write -rtree_leafkey -rtree_new -rtree_node_alloc -rtree_node_dalloc -rtree_read -rtree_subkey -rtree_szind_read -rtree_szind_slab_read -rtree_szind_slab_update -rtree_write -s2u -s2u_compute -s2u_lookup -sa2u -set_errno -size2index -size2index_compute -size2index_lookup -size2index_tab -spin_adaptive -stats_print -tcache_alloc_easy -tcache_alloc_large -tcache_alloc_small -tcache_alloc_small_hard -tcache_arena_associate -tcache_arena_reassociate -tcache_bin_flush_large -tcache_bin_flush_small -tcache_bin_info -tcache_boot -tcache_cleanup -tcache_create_explicit -tcache_dalloc_large -tcache_dalloc_small -tcache_data_init -tcache_enabled_get -tcache_enabled_set -tcache_event -tcache_event_hard -tcache_flush -tcache_get -tcache_maxclass -tcache_prefork -tcache_postfork_child -tcache_postfork_parent -tcache_salloc -tcache_stats_merge -tcaches -tcaches_create -tcaches_destroy -tcaches_flush -tcaches_get -ticker_copy -ticker_init -ticker_read -ticker_tick -ticker_ticks -tsd_arena_get -tsd_arena_set -tsd_arenap_get -tsd_arenas_tdata_bypassp_get -tsd_arenas_tdata_get -tsd_arenas_tdata_set -tsd_arenas_tdatap_get -tsd_boot -tsd_boot0 -tsd_boot1 -tsd_booted -tsd_booted_get -tsd_cleanup -tsd_cleanup_wrapper -tsd_fetch -tsd_fetch_impl -tsd_fetch_slow -tsd_get -tsd_get_allocates -tsd_iarena_get -tsd_iarena_set -tsd_iarenap_get -tsd_initialized -tsd_init_check_recursion -tsd_init_finish -tsd_init_head -tsd_narenas_tdata_get -tsd_narenas_tdata_set -tsd_narenas_tdatap_get -tsd_reentrancy_level_get -tsd_reentrancy_level_set -tsd_reentrancy_levelp_get -tsd_slow_update -tsd_wrapper_get -tsd_wrapper_set -tsd_nominal -tsd_prof_tdata_get -tsd_prof_tdata_set -tsd_prof_tdatap_get -tsd_rtree_ctx -tsd_rtree_ctxp_get -tsd_rtree_leaf_elm_witnessesp_get -tsd_set -tsd_tcache_enabled_get -tsd_tcache_enabled_set -tsd_tcache_enabledp_get -tsd_tcache_get -tsd_tcache_set -tsd_tcachep_get -tsd_thread_allocated_get -tsd_thread_allocated_set -tsd_thread_allocatedp_get -tsd_thread_deallocated_get -tsd_thread_deallocated_set -tsd_thread_deallocatedp_get -tsd_tls -tsd_tsd -tsd_tsdn -tsd_witness_fork_get -tsd_witness_fork_set -tsd_witness_forkp_get -tsd_witnessesp_get -tsdn_fetch -tsdn_null -tsdn_rtree_ctx -tsdn_tsd -witness_assert_depth -witness_assert_depth_to_rank -witness_assert_lockless -witness_assert_not_owner -witness_assert_owner -witness_depth_error -witness_init -witness_lock -witness_lock_error -witness_not_owner_error -witness_owner -witness_owner_error -witness_postfork_child -witness_postfork_parent -witness_prefork -witness_unlock -witnesses_cleanup -zone_register diff --git a/src/jemalloc.c b/src/jemalloc.c index b8c94133..b5ef3ace 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -2299,33 +2299,44 @@ je_valloc(size_t size) { JEMALLOC_EXPORT void (*__free_hook)(void *ptr) = je_free; JEMALLOC_EXPORT void *(*__malloc_hook)(size_t size) = je_malloc; JEMALLOC_EXPORT void *(*__realloc_hook)(void *ptr, size_t size) = je_realloc; -# ifdef JEMALLOC_GLIBC_MEMALIGN_HOOK +# ifdef JEMALLOC_GLIBC_MEMALIGN_HOOK JEMALLOC_EXPORT void *(*__memalign_hook)(size_t alignment, size_t size) = je_memalign; -# endif +# endif -#ifdef CPU_COUNT +# ifdef CPU_COUNT /* * To enable static linking with glibc, the libc specific malloc interface must * be implemented also, so none of glibc's malloc.o functions are added to the * link. */ -#define ALIAS(je_fn) __attribute__((alias (#je_fn), used)) +# define ALIAS(je_fn) __attribute__((alias (#je_fn), used)) /* To force macro expansion of je_ prefix before stringification. */ -#define PREALIAS(je_fn) ALIAS(je_fn) -void *__libc_malloc(size_t size) PREALIAS(je_malloc); -void __libc_free(void* ptr) PREALIAS(je_free); -void *__libc_realloc(void* ptr, size_t size) PREALIAS(je_realloc); -void *__libc_calloc(size_t n, size_t size) PREALIAS(je_calloc); -void *__libc_memalign(size_t align, size_t s) PREALIAS(je_memalign); -void *__libc_valloc(size_t size) PREALIAS(je_valloc); -int __posix_memalign(void** r, size_t a, size_t s) - PREALIAS(je_posix_memalign); -#undef PREALIAS -#undef ALIAS - -#endif - +# define PREALIAS(je_fn) ALIAS(je_fn) +# ifdef JEMALLOC_OVERRIDE___LIBC_CALLOC +void *__libc_calloc(size_t n, size_t size) PREALIAS(je_calloc); +# endif +# ifdef JEMALLOC_OVERRIDE___LIBC_FREE +void __libc_free(void* ptr) PREALIAS(je_free); +# endif +# ifdef JEMALLOC_OVERRIDE___LIBC_MALLOC +void *__libc_malloc(size_t size) PREALIAS(je_malloc); +# endif +# ifdef JEMALLOC_OVERRIDE___LIBC_MEMALIGN +void *__libc_memalign(size_t align, size_t s) PREALIAS(je_memalign); +# endif +# ifdef JEMALLOC_OVERRIDE___LIBC_REALLOC +void *__libc_realloc(void* ptr, size_t size) PREALIAS(je_realloc); +# endif +# ifdef JEMALLOC_OVERRIDE___LIBC_VALLOC +void *__libc_valloc(size_t size) PREALIAS(je_valloc); +# endif +# ifdef JEMALLOC_OVERRIDE___POSIX_MEMALIGN +int __posix_memalign(void** r, size_t a, size_t s) PREALIAS(je_posix_memalign); +# endif +# undef PREALIAS +# undef ALIAS +# endif #endif /* -- GitLab From 18a83681cf6fa0ab79cd0a89f8755d53931a39fb Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Sat, 13 May 2017 15:20:48 -0700 Subject: [PATCH 477/544] Refactor (MALLOCX_ARENA_MAX + 1) to be MALLOCX_ARENA_LIMIT. This resolves #673. --- include/jemalloc/internal/ctl.h | 4 ++-- include/jemalloc/internal/extent_inlines.h | 4 ++-- .../jemalloc/internal/jemalloc_internal_inlines_a.h | 2 +- include/jemalloc/internal/jemalloc_internal_types.h | 2 +- src/jemalloc.c | 10 +++++----- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/jemalloc/internal/ctl.h b/include/jemalloc/internal/ctl.h index de74a75d..23c95510 100644 --- a/include/jemalloc/internal/ctl.h +++ b/include/jemalloc/internal/ctl.h @@ -83,9 +83,9 @@ typedef struct ctl_arenas_s { * Element 0 corresponds to merged stats for extant arenas (accessed via * MALLCTL_ARENAS_ALL), element 1 corresponds to merged stats for * destroyed arenas (accessed via MALLCTL_ARENAS_DESTROYED), and the - * remaining MALLOCX_ARENA_MAX+1 elements correspond to arenas. + * remaining MALLOCX_ARENA_LIMIT elements correspond to arenas. */ - ctl_arena_t *arenas[MALLOCX_ARENA_MAX + 3]; + ctl_arena_t *arenas[2 + MALLOCX_ARENA_LIMIT]; } ctl_arenas_t; int ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp, diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index e1f8bd9e..0e6311d9 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -13,10 +13,10 @@ extent_arena_get(const extent_t *extent) { * The following check is omitted because we should never actually read * a NULL arena pointer. */ - if (false && arena_ind > MALLOCX_ARENA_MAX) { + if (false && arena_ind >= MALLOCX_ARENA_LIMIT) { return NULL; } - assert(arena_ind <= MALLOCX_ARENA_MAX); + assert(arena_ind < MALLOCX_ARENA_LIMIT); return (arena_t *)atomic_load_p(&arenas[arena_ind], ATOMIC_ACQUIRE); } diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_a.h b/include/jemalloc/internal/jemalloc_internal_inlines_a.h index 1755c3ac..c8e26298 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_a.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_a.h @@ -350,7 +350,7 @@ static inline arena_t * arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing) { arena_t *ret; - assert(ind <= MALLOCX_ARENA_MAX); + assert(ind < MALLOCX_ARENA_LIMIT); ret = (arena_t *)atomic_load_p(&arenas[ind], ATOMIC_ACQUIRE); if (unlikely(ret == NULL)) { diff --git a/include/jemalloc/internal/jemalloc_internal_types.h b/include/jemalloc/internal/jemalloc_internal_types.h index 663ed8b5..50f9d001 100644 --- a/include/jemalloc/internal/jemalloc_internal_types.h +++ b/include/jemalloc/internal/jemalloc_internal_types.h @@ -29,7 +29,7 @@ typedef int malloc_cpuid_t; #define MALLOCX_ARENA_MASK \ (((1 << MALLOCX_ARENA_BITS) - 1) << MALLOCX_ARENA_SHIFT) /* NB: Arena index bias decreases the maximum number of arenas by 1. */ -#define MALLOCX_ARENA_MAX ((1 << MALLOCX_ARENA_BITS) - 2) +#define MALLOCX_ARENA_LIMIT ((1 << MALLOCX_ARENA_BITS) - 1) #define MALLOCX_TCACHE_MASK \ (((1 << MALLOCX_TCACHE_BITS) - 1) << MALLOCX_TCACHE_SHIFT) #define MALLOCX_TCACHE_MAX ((1 << MALLOCX_TCACHE_BITS) - 3) diff --git a/src/jemalloc.c b/src/jemalloc.c index b5ef3ace..13218449 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -70,7 +70,7 @@ static malloc_mutex_t arenas_lock; * Points to an arena_t. */ JEMALLOC_ALIGNED(CACHELINE) -atomic_p_t arenas[MALLOCX_ARENA_MAX + 1]; +atomic_p_t arenas[MALLOCX_ARENA_LIMIT]; static atomic_u_t narenas_total; /* Use narenas_total_*(). */ static arena_t *a0; /* arenas[0]; read-only after initialization. */ unsigned narenas_auto; /* Read-only after initialization. */ @@ -400,7 +400,7 @@ arena_init_locked(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena_t *arena; assert(ind <= narenas_total_get()); - if (ind > MALLOCX_ARENA_MAX) { + if (ind >= MALLOCX_ARENA_LIMIT) { return NULL; } if (ind == narenas_total_get()) { @@ -1318,7 +1318,7 @@ malloc_init_narenas(void) { abort(); } } else { - if (ncpus > MALLOCX_ARENA_MAX) { + if (ncpus >= MALLOCX_ARENA_LIMIT) { malloc_printf(": narenas w/ percpu" "arena beyond limit (%d)\n", ncpus); if (opt_abort) { @@ -1364,8 +1364,8 @@ malloc_init_narenas(void) { /* * Limit the number of arenas to the indexing range of MALLOCX_ARENA(). */ - if (narenas_auto > MALLOCX_ARENA_MAX) { - narenas_auto = MALLOCX_ARENA_MAX; + if (narenas_auto >= MALLOCX_ARENA_LIMIT) { + narenas_auto = MALLOCX_ARENA_LIMIT - 1; malloc_printf(": Reducing narenas to limit (%d)\n", narenas_auto); } -- GitLab From b8ba3c313205fd8269b9f0f9f8460b172d2fa32d Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 15 May 2017 11:03:14 -0700 Subject: [PATCH 478/544] Use srcroot path for private_namespace.sh. --- Makefile.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.in b/Makefile.in index 94d8021f..5476617f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -349,10 +349,10 @@ $(C_JET_SYMS): %.sym: $(DUMP_SYMS) $< | $(AWK) -f $(objroot)include/jemalloc/internal/private_symbols_jet.awk > $@ $(objroot)include/jemalloc/internal/private_namespace.h: $(C_SYMS) - $(SHELL) $(objdir)include/jemalloc/internal/private_namespace.sh $^ > $@ + $(SHELL) $(srcroot)include/jemalloc/internal/private_namespace.sh $^ > $@ $(objroot)include/jemalloc/internal/private_namespace_jet.h: $(C_JET_SYMS) - $(SHELL) $(objdir)include/jemalloc/internal/private_namespace.sh $^ > $@ + $(SHELL) $(srcroot)include/jemalloc/internal/private_namespace.sh $^ > $@ $(CPP_OBJS) $(CPP_PIC_OBJS) $(TESTS_CPP_OBJS): %.$(O): @mkdir -p $(@D) -- GitLab From 04fec5e0844bd0cc10dcd290e82f5f6aa486e494 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 16 May 2017 23:12:59 -0700 Subject: [PATCH 479/544] Avoid over-rebuilding due to namespace mangling. Take care not to touch generated namespace mangling headers unless their contents would change. This resolves #838. --- .gitignore | 2 ++ Makefile.in | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 216d3c9d..9acf374b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,9 @@ /include/jemalloc/internal/jemalloc_preamble.h /include/jemalloc/internal/jemalloc_internal_defs.h +/include/jemalloc/internal/private_namespace.gen.h /include/jemalloc/internal/private_namespace.h +/include/jemalloc/internal/private_namespace_jet.gen.h /include/jemalloc/internal/private_namespace_jet.h /include/jemalloc/internal/private_symbols.awk /include/jemalloc/internal/private_symbols_jet.awk diff --git a/Makefile.in b/Makefile.in index 5476617f..370ead58 100644 --- a/Makefile.in +++ b/Makefile.in @@ -227,6 +227,7 @@ TESTS_STRESS := $(srcroot)test/stress/microbench.c TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_INTEGRATION_CPP) $(TESTS_STRESS) PRIVATE_NAMESPACE_HDRS := $(objroot)include/jemalloc/internal/private_namespace.h $(objroot)include/jemalloc/internal/private_namespace_jet.h +PRIVATE_NAMESPACE_GEN_HDRS := $(PRIVATE_NAMESPACE_HDRS:%.h=%.gen.h) C_SYM_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.sym.$(O)) C_SYMS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.sym) C_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.$(O)) @@ -254,7 +255,7 @@ TESTS_CPP_OBJS := $(TESTS_INTEGRATION_CPP_OBJS) .PHONY: install_doc_html install_doc_man install_doc install .PHONY: tests check clean distclean relclean -.SECONDARY : $(TESTS_OBJS) $(TESTS_CPP_OBJS) +.SECONDARY : $(PRIVATE_NAMESPACE_GEN_HDRS) $(TESTS_OBJS) $(TESTS_CPP_OBJS) # Default target. all: build_lib @@ -348,12 +349,15 @@ $(C_JET_SYMS): %.sym: @mkdir -p $(@D) $(DUMP_SYMS) $< | $(AWK) -f $(objroot)include/jemalloc/internal/private_symbols_jet.awk > $@ -$(objroot)include/jemalloc/internal/private_namespace.h: $(C_SYMS) +$(objroot)include/jemalloc/internal/private_namespace.gen.h: $(C_SYMS) $(SHELL) $(srcroot)include/jemalloc/internal/private_namespace.sh $^ > $@ -$(objroot)include/jemalloc/internal/private_namespace_jet.h: $(C_JET_SYMS) +$(objroot)include/jemalloc/internal/private_namespace_jet.gen.h: $(C_JET_SYMS) $(SHELL) $(srcroot)include/jemalloc/internal/private_namespace.sh $^ > $@ +%.h: %.gen.h + @if ! `cmp -s $< $@` ; then echo "cp $< $<"; cp $< $@ ; fi + $(CPP_OBJS) $(CPP_PIC_OBJS) $(TESTS_CPP_OBJS): %.$(O): @mkdir -p $(@D) $(CXX) $(CXXFLAGS) -c $(CPPFLAGS) $(CTARGET) $< @@ -485,6 +489,7 @@ check: check_unit check_integration check_integration_decay check_integration_pr clean: rm -f $(PRIVATE_NAMESPACE_HDRS) + rm -f $(PRIVATE_NAMESPACE_GEN_HDRS) rm -f $(C_SYM_OBJS) rm -f $(C_SYMS) rm -f $(C_OBJS) -- GitLab From baf3e294e05ab62b0f80b825a76687c8a1ea001e Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 16 May 2017 13:56:00 -0700 Subject: [PATCH 480/544] Add stats: arena uptime. --- doc/jemalloc.xml.in | 12 ++++++++++++ include/jemalloc/internal/arena_structs_b.h | 2 ++ include/jemalloc/internal/stats.h | 3 +++ src/arena.c | 7 +++++++ src/ctl.c | 8 ++++++++ src/stats.c | 10 ++++++++++ 6 files changed, 42 insertions(+) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index d1b2e334..1efc9163 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -2280,6 +2280,18 @@ struct extent_hooks_s { arena. + + + stats.arenas.<i>.uptime + (uint64_t) + r- + + Time elapsed (in nanoseconds) since the arena was + created. If <i> equals 0 or + MALLCTL_ARENAS_ALL, this is the uptime since malloc + initialization. + + stats.arenas.<i>.pactive diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index d98b455e..99e5f6a0 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -261,6 +261,8 @@ struct arena_s { * Synchronization: internal. */ base_t *base; + /* Used to determine uptime. Read-only after initialization. */ + nstime_t create_time; }; /* Used in conjunction with tsd for fast arena-related context lookup. */ diff --git a/include/jemalloc/internal/stats.h b/include/jemalloc/internal/stats.h index 385a8514..3f5c20c7 100644 --- a/include/jemalloc/internal/stats.h +++ b/include/jemalloc/internal/stats.h @@ -145,6 +145,9 @@ typedef struct arena_stats_s { /* One element for each large size class. */ malloc_large_stats_t lstats[NSIZES - NBINS]; + + /* Arena uptime. */ + nstime_t uptime; } arena_stats_t; #endif /* JEMALLOC_INTERNAL_STATS_H */ diff --git a/src/arena.c b/src/arena.c index 045e6127..03680e00 100644 --- a/src/arena.c +++ b/src/arena.c @@ -330,6 +330,10 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, arena_prof_mutex_base) #undef READ_ARENA_MUTEX_PROF_DATA + nstime_copy(&astats->uptime, &arena->create_time); + nstime_update(&astats->uptime); + nstime_subtract(&astats->uptime, &arena->create_time); + for (szind_t i = 0; i < NBINS; i++) { arena_bin_t *bin = &arena->bins[i]; @@ -1965,6 +1969,9 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena->base = base; + nstime_init(&arena->create_time, 0); + nstime_update(&arena->create_time); + /* We don't support reetrancy for arena 0 bootstrapping. */ if (ind != 0 && hooks_arena_new_hook) { /* diff --git a/src/ctl.c b/src/ctl.c index 7d53a336..79f2447f 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -157,6 +157,7 @@ CTL_PROTO(stats_arenas_i_lextents_j_nrequests) CTL_PROTO(stats_arenas_i_lextents_j_curlextents) INDEX_PROTO(stats_arenas_i_lextents_j) CTL_PROTO(stats_arenas_i_nthreads) +CTL_PROTO(stats_arenas_i_uptime) CTL_PROTO(stats_arenas_i_dss) CTL_PROTO(stats_arenas_i_dirty_decay_time) CTL_PROTO(stats_arenas_i_muzzy_decay_time) @@ -441,6 +442,7 @@ MUTEX_PROF_ARENA_MUTEXES static const ctl_named_node_t stats_arenas_i_node[] = { {NAME("nthreads"), CTL(stats_arenas_i_nthreads)}, + {NAME("uptime"), CTL(stats_arenas_i_uptime)}, {NAME("dss"), CTL(stats_arenas_i_dss)}, {NAME("dirty_decay_time"), CTL(stats_arenas_i_dirty_decay_time)}, {NAME("muzzy_decay_time"), CTL(stats_arenas_i_muzzy_decay_time)}, @@ -778,6 +780,10 @@ MUTEX_PROF_ARENA_MUTEXES accum_atomic_zu(&sdstats->astats.tcache_bytes, &astats->astats.tcache_bytes); + if (ctl_arena->arena_ind == 0) { + sdstats->astats.uptime = astats->astats.uptime; + } + for (i = 0; i < NBINS; i++) { sdstats->bstats[i].nmalloc += astats->bstats[i].nmalloc; sdstats->bstats[i].ndalloc += astats->bstats[i].ndalloc; @@ -2317,6 +2323,8 @@ CTL_RO_GEN(stats_arenas_i_dirty_decay_time, arenas_i(mib[2])->dirty_decay_time, CTL_RO_GEN(stats_arenas_i_muzzy_decay_time, arenas_i(mib[2])->muzzy_decay_time, ssize_t) CTL_RO_GEN(stats_arenas_i_nthreads, arenas_i(mib[2])->nthreads, unsigned) +CTL_RO_GEN(stats_arenas_i_uptime, + nstime_ns(&arenas_i(mib[2])->astats->astats.uptime), uint64_t) CTL_RO_GEN(stats_arenas_i_pactive, arenas_i(mib[2])->pactive, size_t) CTL_RO_GEN(stats_arenas_i_pdirty, arenas_i(mib[2])->pdirty, size_t) CTL_RO_GEN(stats_arenas_i_pmuzzy, arenas_i(mib[2])->pmuzzy, size_t) diff --git a/src/stats.c b/src/stats.c index 34fc37f2..883c7d14 100644 --- a/src/stats.c +++ b/src/stats.c @@ -421,6 +421,7 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, size_t large_allocated; uint64_t large_nmalloc, large_ndalloc, large_nrequests; size_t tcache_bytes; + uint64_t uptime; CTL_GET("arenas.page", &page, size_t); @@ -433,6 +434,15 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, "assigned threads: %u\n", nthreads); } + CTL_M2_GET("stats.arenas.0.uptime", i, &uptime, uint64_t); + if (json) { + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"uptime_ns\": %"FMTu64",\n", uptime); + } else { + malloc_cprintf(write_cb, cbopaque, + "uptime: %"FMTu64"\n", uptime); + } + CTL_M2_GET("stats.arenas.0.dss", i, &dss, const char *); if (json) { malloc_cprintf(write_cb, cbopaque, -- GitLab From 6e62c6286258e340308b4a989b4bd80232fed8e1 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 17 May 2017 10:47:00 -0700 Subject: [PATCH 481/544] Refactor *decay_time into *decay_ms. Support millisecond resolution for decay times. Among other use cases this makes it possible to specify a short initial dirty-->muzzy decay phase, followed by a longer muzzy-->clean decay phase. This resolves #812. --- INSTALL.md | 2 +- Makefile.in | 4 +- doc/jemalloc.xml.in | 118 ++++++------ include/jemalloc/internal/arena_externs.h | 28 ++- include/jemalloc/internal/arena_structs_b.h | 4 +- include/jemalloc/internal/arena_types.h | 6 +- include/jemalloc/internal/ctl.h | 4 +- .../internal/jemalloc_internal_decls.h | 3 + src/arena.c | 130 ++++++------- src/ctl.c | 95 +++++----- src/jemalloc.c | 12 +- src/stats.c | 42 ++--- test/unit/decay.c | 24 +-- test/unit/decay.sh | 2 +- test/unit/mallctl.c | 172 +++++++++--------- test/unit/pack.sh | 2 +- 16 files changed, 320 insertions(+), 328 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index e0cfc0be..25f625af 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -116,7 +116,7 @@ any of the following arguments (not a definitive list) to 'configure': MALLOC_CONF environment variable. For example, to change the default decay time to 30 seconds: - --with-malloc-conf=decay_time:30 + --with-malloc-conf=decay_ms:30000 * `--enable-debug` diff --git a/Makefile.in b/Makefile.in index 370ead58..2f16fbf3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -479,8 +479,8 @@ ifeq ($(enable_prof), 1) $(MALLOC_CONF)="prof:true,prof_active:false" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) endif check_integration_decay: tests_integration check_integration_dir - $(MALLOC_CONF)="dirty_decay_time:-1,muzzy_decay_time:-1" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) - $(MALLOC_CONF)="dirty_decay_time:0,muzzy_decay_time:0" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) + $(MALLOC_CONF)="dirty_decay_ms:-1,muzzy_decay_ms:-1" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) + $(MALLOC_CONF)="dirty_decay_ms:0,muzzy_decay_ms:0" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) check_integration: tests_integration check_integration_dir $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%) stress: tests_stress stress_dir diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 1efc9163..be018bfb 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -937,15 +937,15 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", percpu. - + - opt.dirty_decay_time + opt.dirty_decay_ms (ssize_t) r- - Approximate time in seconds from the creation of a set - of unused dirty pages until an equivalent set of unused dirty pages is - purged (i.e. converted to muzzy via e.g. + Approximate time in milliseconds from the creation of a + set of unused dirty pages until an equivalent set of unused dirty pages + is purged (i.e. converted to muzzy via e.g. madvise(...MADV_FREE) if supported by the operating system, or converted to clean otherwise) and/or reused. Dirty pages are defined as previously having been @@ -955,35 +955,35 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", zero purge rate. A decay time of 0 causes all unused dirty pages to be purged immediately upon creation. A decay time of -1 disables purging. The default decay time is 10 seconds. See arenas.dirty_decay_time + linkend="arenas.dirty_decay_ms">arenas.dirty_decay_ms and arena.<i>.muzzy_decay_time + linkend="arena.i.muzzy_decay_ms">arena.<i>.muzzy_decay_ms for related dynamic control options. See opt.muzzy_decay_time + linkend="opt.muzzy_decay_ms">opt.muzzy_decay_ms for a description of muzzy pages. - + - opt.muzzy_decay_time + opt.muzzy_decay_ms (ssize_t) r- - Approximate time in seconds from the creation of a set - of unused muzzy pages until an equivalent set of unused muzzy pages is - purged (i.e. converted to clean) and/or reused. Muzzy pages are defined - as previously having been unused dirty pages that were subsequently - purged in a manner that left them subject to the reclamation whims of - the operating system (e.g. + Approximate time in milliseconds from the creation of a + set of unused muzzy pages until an equivalent set of unused muzzy pages + is purged (i.e. converted to clean) and/or reused. Muzzy pages are + defined as previously having been unused dirty pages that were + subsequently purged in a manner that left them subject to the + reclamation whims of the operating system (e.g. madvise(...MADV_FREE)), and therefore in an indeterminate state. The pages are incrementally purged according to a sigmoidal decay curve that starts and ends with zero purge rate. A decay time of 0 causes all unused muzzy pages to be purged immediately upon creation. A decay time of -1 disables purging. The default decay time is 10 seconds. See arenas.muzzy_decay_time + linkend="arenas.muzzy_decay_ms">arenas.muzzy_decay_ms and arena.<i>.muzzy_decay_time + linkend="arena.i.muzzy_decay_ms">arena.<i>.muzzy_decay_ms for related dynamic control options. @@ -1486,9 +1486,9 @@ malloc_conf = "xmalloc:true";]]> for arena <i>, or for all arenas if <i> equals MALLCTL_ARENAS_ALL. The proportion of unused dirty/muzzy pages to be purged depends on the current time; see opt.dirty_decay_time + linkend="opt.dirty_decay_ms">opt.dirty_decay_ms and opt.muzy_decay_time + linkend="opt.muzzy_decay_ms">opt.muzy_decay_ms for details. @@ -1550,35 +1550,35 @@ malloc_conf = "xmalloc:true";]]> settings. - + - arena.<i>.dirty_decay_time + arena.<i>.dirty_decay_ms (ssize_t) rw - Current per-arena approximate time in seconds from the - creation of a set of unused dirty pages until an equivalent set of + Current per-arena approximate time in milliseconds from + the creation of a set of unused dirty pages until an equivalent set of unused dirty pages is purged and/or reused. Each time this interface is set, all currently unused dirty pages are considered to have fully decayed, which causes immediate purging of all unused dirty pages unless the decay time is set to -1 (i.e. purging disabled). See opt.dirty_decay_time + linkend="opt.dirty_decay_ms">opt.dirty_decay_ms for additional information. - + - arena.<i>.muzzy_decay_time + arena.<i>.muzzy_decay_ms (ssize_t) rw - Current per-arena approximate time in seconds from the - creation of a set of unused muzzy pages until an equivalent set of + Current per-arena approximate time in milliseconds from + the creation of a set of unused muzzy pages until an equivalent set of unused muzzy pages is purged and/or reused. Each time this interface is set, all currently unused muzzy pages are considered to have fully decayed, which causes immediate purging of all unused muzzy pages unless the decay time is set to -1 (i.e. purging disabled). See opt.muzzy_decay_time + linkend="opt.muzzy_decay_ms">opt.muzzy_decay_ms for additional information. @@ -1825,33 +1825,35 @@ struct extent_hooks_s { Current limit on number of arenas. - + - arenas.dirty_decay_time + arenas.dirty_decay_ms (ssize_t) rw - Current default per-arena approximate time in seconds - from the creation of a set of unused dirty pages until an equivalent set - of unused dirty pages is purged and/or reused, used to initialize arena.<i>.dirty_decay_time + Current default per-arena approximate time in + milliseconds from the creation of a set of unused dirty pages until an + equivalent set of unused dirty pages is purged and/or reused, used to + initialize arena.<i>.dirty_decay_ms during arena creation. See opt.dirty_decay_time + linkend="opt.dirty_decay_ms">opt.dirty_decay_ms for additional information. - + - arenas.muzzy_decay_time + arenas.muzzy_decay_ms (ssize_t) rw - Current default per-arena approximate time in seconds - from the creation of a set of unused muzzy pages until an equivalent set - of unused muzzy pages is purged and/or reused, used to initialize arena.<i>.muzzy_decay_time + Current default per-arena approximate time in + milliseconds from the creation of a set of unused muzzy pages until an + equivalent set of unused muzzy pages is purged and/or reused, used to + initialize arena.<i>.muzzy_decay_ms during arena creation. See opt.muzzy_decay_time + linkend="opt.muzzy_decay_ms">opt.muzzy_decay_ms for additional information. @@ -2244,29 +2246,29 @@ struct extent_hooks_s { - + - stats.arenas.<i>.dirty_decay_time + stats.arenas.<i>.dirty_decay_ms (ssize_t) r- - Approximate time in seconds from the creation of a set - of unused dirty pages until an equivalent set of unused dirty pages is - purged and/or reused. See opt.dirty_decay_time + Approximate time in milliseconds from the creation of a + set of unused dirty pages until an equivalent set of unused dirty pages + is purged and/or reused. See opt.dirty_decay_ms for details. - + - stats.arenas.<i>.muzzy_decay_time + stats.arenas.<i>.muzzy_decay_ms (ssize_t) r- - Approximate time in seconds from the creation of a set - of unused muzzy pages until an equivalent set of unused muzzy pages is - purged and/or reused. See opt.muzzy_decay_time + Approximate time in milliseconds from the creation of a + set of unused muzzy pages until an equivalent set of unused muzzy pages + is purged and/or reused. See opt.muzzy_decay_ms for details. @@ -2310,7 +2312,7 @@ struct extent_hooks_s { Number of pages within unused extents that are potentially dirty, and for which madvise() or similar has not been called. See opt.dirty_decay_time + linkend="opt.dirty_decay_ms">opt.dirty_decay_ms for a description of dirty pages. @@ -2322,7 +2324,7 @@ struct extent_hooks_s { Number of pages within unused extents that are muzzy. See opt.muzzy_decay_time + linkend="opt.muzzy_decay_ms">opt.muzzy_decay_ms for a description of muzzy pages. diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 410709c6..292b8d6d 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -13,8 +13,8 @@ static const size_t large_pad = #endif ; -extern ssize_t opt_dirty_decay_time; -extern ssize_t opt_muzzy_decay_time; +extern ssize_t opt_dirty_decay_ms; +extern ssize_t opt_muzzy_decay_ms; extern const arena_bin_info_t arena_bin_info[NBINS]; @@ -27,10 +27,10 @@ void arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats, void arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t size); void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, - unsigned *nthreads, const char **dss, ssize_t *dirty_decay_time, - ssize_t *muzzy_decay_time, size_t *nactive, size_t *ndirty, size_t *nmuzzy); + unsigned *nthreads, const char **dss, ssize_t *dirty_decay_ms, + ssize_t *muzzy_decay_ms, size_t *nactive, size_t *ndirty, size_t *nmuzzy); void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *dirty_decay_time, ssize_t *muzzy_decay_time, + const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms, size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats, malloc_bin_stats_t *bstats, malloc_large_stats_t *lstats); void arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena, @@ -46,12 +46,10 @@ void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); -ssize_t arena_dirty_decay_time_get(arena_t *arena); -bool arena_dirty_decay_time_set(tsdn_t *tsdn, arena_t *arena, - ssize_t decay_time); -ssize_t arena_muzzy_decay_time_get(arena_t *arena); -bool arena_muzzy_decay_time_set(tsdn_t *tsdn, arena_t *arena, - ssize_t decay_time); +ssize_t arena_dirty_decay_ms_get(arena_t *arena); +bool arena_dirty_decay_ms_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_ms); +ssize_t arena_muzzy_decay_ms_get(arena_t *arena); +bool arena_muzzy_decay_ms_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_ms); void arena_decay(tsdn_t *tsdn, arena_t *arena, bool all); void arena_reset(tsd_t *tsd, arena_t *arena); void arena_destroy(tsd_t *tsd, arena_t *arena); @@ -79,10 +77,10 @@ void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache); dss_prec_t arena_dss_prec_get(arena_t *arena); bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec); -ssize_t arena_dirty_decay_time_default_get(void); -bool arena_dirty_decay_time_default_set(ssize_t decay_time); -ssize_t arena_muzzy_decay_time_default_get(void); -bool arena_muzzy_decay_time_default_set(ssize_t decay_time); +ssize_t arena_dirty_decay_ms_default_get(void); +bool arena_dirty_decay_ms_default_set(ssize_t decay_ms); +ssize_t arena_muzzy_decay_ms_default_get(void); +bool arena_muzzy_decay_ms_default_set(ssize_t decay_ms); unsigned arena_nthreads_get(arena_t *arena, bool internal); void arena_nthreads_inc(arena_t *arena, bool internal); void arena_nthreads_dec(arena_t *arena, bool internal); diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 99e5f6a0..459dd89d 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -56,11 +56,11 @@ struct arena_decay_s { */ bool purging; /* - * Approximate time in seconds from the creation of a set of unused + * Approximate time in milliseconds from the creation of a set of unused * dirty pages until an equivalent set of unused dirty pages is purged * and/or reused. */ - atomic_zd_t time; + atomic_zd_t time_ms; /* time / SMOOTHSTEP_NSTEPS. */ nstime_t interval; /* diff --git a/include/jemalloc/internal/arena_types.h b/include/jemalloc/internal/arena_types.h index e243aabf..34d4f6f2 100644 --- a/include/jemalloc/internal/arena_types.h +++ b/include/jemalloc/internal/arena_types.h @@ -7,9 +7,9 @@ #define LG_SLAB_MAXREGS (LG_PAGE - LG_TINY_MIN) #define SLAB_MAXREGS (1U << LG_SLAB_MAXREGS) -/* Default decay times in seconds. */ -#define DIRTY_DECAY_TIME_DEFAULT 10 -#define MUZZY_DECAY_TIME_DEFAULT 10 +/* Default decay times in milliseconds. */ +#define DIRTY_DECAY_MS_DEFAULT ZD(10 * 1000) +#define MUZZY_DECAY_MS_DEFAULT ZD(10 * 1000) /* Number of event ticks between time checks. */ #define DECAY_NTICKS_PER_UPDATE 1000 diff --git a/include/jemalloc/internal/ctl.h b/include/jemalloc/internal/ctl.h index 23c95510..60b3979f 100644 --- a/include/jemalloc/internal/ctl.h +++ b/include/jemalloc/internal/ctl.h @@ -64,8 +64,8 @@ struct ctl_arena_s { /* Basic stats, supported even if !config_stats. */ unsigned nthreads; const char *dss; - ssize_t dirty_decay_time; - ssize_t muzzy_decay_time; + ssize_t dirty_decay_ms; + ssize_t muzzy_decay_ms; size_t pactive; size_t pdirty; size_t pmuzzy; diff --git a/include/jemalloc/internal/jemalloc_internal_decls.h b/include/jemalloc/internal/jemalloc_internal_decls.h index d75de0b9..1efdb56b 100644 --- a/include/jemalloc/internal/jemalloc_internal_decls.h +++ b/include/jemalloc/internal/jemalloc_internal_decls.h @@ -41,6 +41,9 @@ #ifndef SIZE_T_MAX # define SIZE_T_MAX SIZE_MAX #endif +#ifndef SSIZE_MAX +# define SSIZE_MAX ((ssize_t)(SIZE_T_MAX >> 1)) +#endif #include #include #include diff --git a/src/arena.c b/src/arena.c index 03680e00..42bfc6b1 100644 --- a/src/arena.c +++ b/src/arena.c @@ -18,11 +18,11 @@ const char *percpu_arena_mode_names[] = { const char *opt_percpu_arena = OPT_PERCPU_ARENA_DEFAULT; percpu_arena_mode_t percpu_arena_mode = PERCPU_ARENA_MODE_DEFAULT; -ssize_t opt_dirty_decay_time = DIRTY_DECAY_TIME_DEFAULT; -ssize_t opt_muzzy_decay_time = MUZZY_DECAY_TIME_DEFAULT; +ssize_t opt_dirty_decay_ms = DIRTY_DECAY_MS_DEFAULT; +ssize_t opt_muzzy_decay_ms = MUZZY_DECAY_MS_DEFAULT; -static atomic_zd_t dirty_decay_time_default; -static atomic_zd_t muzzy_decay_time_default; +static atomic_zd_t dirty_decay_ms_default; +static atomic_zd_t muzzy_decay_ms_default; const arena_bin_info_t arena_bin_info[NBINS] = { #define BIN_INFO_bin_yes(reg_size, slab_size, nregs) \ @@ -196,13 +196,12 @@ arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t size) { void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *dirty_decay_time, ssize_t *muzzy_decay_time, - size_t *nactive, size_t *ndirty, - size_t *nmuzzy) { + const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms, + size_t *nactive, size_t *ndirty, size_t *nmuzzy) { *nthreads += arena_nthreads_get(arena, false); *dss = dss_prec_names[arena_dss_prec_get(arena)]; - *dirty_decay_time = arena_dirty_decay_time_get(arena); - *muzzy_decay_time = arena_muzzy_decay_time_get(arena); + *dirty_decay_ms = arena_dirty_decay_ms_get(arena); + *muzzy_decay_ms = arena_muzzy_decay_ms_get(arena); *nactive += atomic_load_zu(&arena->nactive, ATOMIC_RELAXED); *ndirty += extents_npages_get(&arena->extents_dirty); *nmuzzy += extents_npages_get(&arena->extents_muzzy); @@ -210,13 +209,13 @@ arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, - const char **dss, ssize_t *dirty_decay_time, ssize_t *muzzy_decay_time, + const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms, size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats, malloc_bin_stats_t *bstats, malloc_large_stats_t *lstats) { cassert(config_stats); - arena_basic_stats_merge(tsdn, arena, nthreads, dss, dirty_decay_time, - muzzy_decay_time, nactive, ndirty, nmuzzy); + arena_basic_stats_merge(tsdn, arena, nthreads, dss, dirty_decay_ms, + muzzy_decay_ms, nactive, ndirty, nmuzzy); size_t base_allocated, base_resident, base_mapped; base_stats_get(tsdn, arena->base, &base_allocated, &base_resident, @@ -359,7 +358,7 @@ arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena, extents_dalloc(tsdn, arena, r_extent_hooks, &arena->extents_dirty, extent); - if (arena_dirty_decay_time_get(arena) == 0) { + if (arena_dirty_decay_ms_get(arena) == 0) { arena_decay_dirty(tsdn, arena, true); } } @@ -574,13 +573,13 @@ arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, } static ssize_t -arena_decay_time_read(arena_decay_t *decay) { - return atomic_load_zd(&decay->time, ATOMIC_RELAXED); +arena_decay_ms_read(arena_decay_t *decay) { + return atomic_load_zd(&decay->time_ms, ATOMIC_RELAXED); } static void -arena_decay_time_write(arena_decay_t *decay, ssize_t decay_time) { - atomic_store_zd(&decay->time, decay_time, ATOMIC_RELAXED); +arena_decay_ms_write(arena_decay_t *decay, ssize_t decay_ms) { + atomic_store_zd(&decay->time_ms, decay_ms, ATOMIC_RELAXED); } static void @@ -591,7 +590,7 @@ arena_decay_deadline_init(arena_decay_t *decay) { */ nstime_copy(&decay->deadline, &decay->epoch); nstime_add(&decay->deadline, &decay->interval); - if (arena_decay_time_read(decay) > 0) { + if (arena_decay_ms_read(decay) > 0) { nstime_t jitter; nstime_init(&jitter, prng_range_u64(&decay->jitter_state, @@ -711,11 +710,11 @@ arena_decay_epoch_advance(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, } static void -arena_decay_reinit(arena_decay_t *decay, extents_t *extents, - ssize_t decay_time) { - arena_decay_time_write(decay, decay_time); - if (decay_time > 0) { - nstime_init2(&decay->interval, decay_time, 0); +arena_decay_reinit(arena_decay_t *decay, extents_t *extents, ssize_t decay_ms) { + arena_decay_ms_write(decay, decay_ms); + if (decay_ms > 0) { + nstime_init(&decay->interval, (uint64_t)decay_ms * + KQU(1000000)); nstime_idivide(&decay->interval, SMOOTHSTEP_NSTEPS); } @@ -728,7 +727,7 @@ arena_decay_reinit(arena_decay_t *decay, extents_t *extents, } static bool -arena_decay_init(arena_decay_t *decay, extents_t *extents, ssize_t decay_time, +arena_decay_init(arena_decay_t *decay, extents_t *extents, ssize_t decay_ms, decay_stats_t *stats) { if (config_debug) { for (size_t i = 0; i < sizeof(arena_decay_t); i++) { @@ -739,7 +738,7 @@ arena_decay_init(arena_decay_t *decay, extents_t *extents, ssize_t decay_time, return true; } decay->purging = false; - arena_decay_reinit(decay, extents, decay_time); + arena_decay_reinit(decay, extents, decay_ms); /* Memory is zeroed, so there is no need to clear stats. */ if (config_stats) { decay->stats = stats; @@ -748,11 +747,12 @@ arena_decay_init(arena_decay_t *decay, extents_t *extents, ssize_t decay_time, } static bool -arena_decay_time_valid(ssize_t decay_time) { - if (decay_time < -1) { +arena_decay_ms_valid(ssize_t decay_ms) { + if (decay_ms < -1) { return false; } - if (decay_time == -1 || (uint64_t)decay_time <= NSTIME_SEC_MAX) { + if (decay_ms == -1 || (uint64_t)decay_ms <= NSTIME_SEC_MAX * + KQU(1000)) { return true; } return false; @@ -764,9 +764,9 @@ arena_maybe_decay(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, malloc_mutex_assert_owner(tsdn, &decay->mtx); /* Purge all or nothing if the option is disabled. */ - ssize_t decay_time = arena_decay_time_read(decay); - if (decay_time <= 0) { - if (decay_time == 0) { + ssize_t decay_ms = arena_decay_ms_read(decay); + if (decay_ms <= 0) { + if (decay_ms == 0) { arena_decay_to_limit(tsdn, arena, decay, extents, false, 0); } @@ -806,24 +806,24 @@ arena_maybe_decay(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, } static ssize_t -arena_decay_time_get(arena_decay_t *decay) { - return arena_decay_time_read(decay); +arena_decay_ms_get(arena_decay_t *decay) { + return arena_decay_ms_read(decay); } ssize_t -arena_dirty_decay_time_get(arena_t *arena) { - return arena_decay_time_get(&arena->decay_dirty); +arena_dirty_decay_ms_get(arena_t *arena) { + return arena_decay_ms_get(&arena->decay_dirty); } ssize_t -arena_muzzy_decay_time_get(arena_t *arena) { - return arena_decay_time_get(&arena->decay_muzzy); +arena_muzzy_decay_ms_get(arena_t *arena) { + return arena_decay_ms_get(&arena->decay_muzzy); } static bool -arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, - extents_t *extents, ssize_t decay_time) { - if (!arena_decay_time_valid(decay_time)) { +arena_decay_ms_set(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, + extents_t *extents, ssize_t decay_ms) { + if (!arena_decay_ms_valid(decay_ms)) { return true; } @@ -832,11 +832,11 @@ arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, * Restart decay backlog from scratch, which may cause many dirty pages * to be immediately purged. It would conceptually be possible to map * the old backlog onto the new backlog, but there is no justification - * for such complexity since decay_time changes are intended to be + * for such complexity since decay_ms changes are intended to be * infrequent, either between the {-1, 0, >0} states, or a one-time * arbitrary change during initial arena configuration. */ - arena_decay_reinit(decay, extents, decay_time); + arena_decay_reinit(decay, extents, decay_ms); arena_maybe_decay(tsdn, arena, decay, extents); malloc_mutex_unlock(tsdn, &decay->mtx); @@ -844,15 +844,17 @@ arena_decay_time_set(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, } bool -arena_dirty_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { - return arena_decay_time_set(tsdn, arena, &arena->decay_dirty, - &arena->extents_dirty, decay_time); +arena_dirty_decay_ms_set(tsdn_t *tsdn, arena_t *arena, + ssize_t decay_ms) { + return arena_decay_ms_set(tsdn, arena, &arena->decay_dirty, + &arena->extents_dirty, decay_ms); } bool -arena_muzzy_decay_time_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_time) { - return arena_decay_time_set(tsdn, arena, &arena->decay_muzzy, - &arena->extents_muzzy, decay_time); +arena_muzzy_decay_ms_set(tsdn_t *tsdn, arena_t *arena, + ssize_t decay_ms) { + return arena_decay_ms_set(tsdn, arena, &arena->decay_muzzy, + &arena->extents_muzzy, decay_ms); } static size_t @@ -885,7 +887,7 @@ arena_decay_stashed(tsdn_t *tsdn, arena_t *arena, } npurged = 0; - ssize_t muzzy_decay_time = arena_muzzy_decay_time_get(arena); + ssize_t muzzy_decay_ms = arena_muzzy_decay_ms_get(arena); for (extent_t *extent = extent_list_first(decay_extents); extent != NULL; extent = extent_list_first(decay_extents)) { if (config_stats) { @@ -898,7 +900,7 @@ arena_decay_stashed(tsdn_t *tsdn, arena_t *arena, case extent_state_active: not_reached(); case extent_state_dirty: - if (!all && muzzy_decay_time != 0 && + if (!all && muzzy_decay_ms != 0 && !extent_purge_lazy_wrapper(tsdn, arena, r_extent_hooks, extent, 0, extent_size_get(extent))) { @@ -1789,30 +1791,30 @@ arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec) { } ssize_t -arena_dirty_decay_time_default_get(void) { - return atomic_load_zd(&dirty_decay_time_default, ATOMIC_RELAXED); +arena_dirty_decay_ms_default_get(void) { + return atomic_load_zd(&dirty_decay_ms_default, ATOMIC_RELAXED); } bool -arena_dirty_decay_time_default_set(ssize_t decay_time) { - if (!arena_decay_time_valid(decay_time)) { +arena_dirty_decay_ms_default_set(ssize_t decay_ms) { + if (!arena_decay_ms_valid(decay_ms)) { return true; } - atomic_store_zd(&dirty_decay_time_default, decay_time, ATOMIC_RELAXED); + atomic_store_zd(&dirty_decay_ms_default, decay_ms, ATOMIC_RELAXED); return false; } ssize_t -arena_muzzy_decay_time_default_get(void) { - return atomic_load_zd(&muzzy_decay_time_default, ATOMIC_RELAXED); +arena_muzzy_decay_ms_default_get(void) { + return atomic_load_zd(&muzzy_decay_ms_default, ATOMIC_RELAXED); } bool -arena_muzzy_decay_time_default_set(ssize_t decay_time) { - if (!arena_decay_time_valid(decay_time)) { +arena_muzzy_decay_ms_default_set(ssize_t decay_ms) { + if (!arena_decay_ms_valid(decay_ms)) { return true; } - atomic_store_zd(&muzzy_decay_time_default, decay_time, ATOMIC_RELAXED); + atomic_store_zd(&muzzy_decay_ms_default, decay_ms, ATOMIC_RELAXED); return false; } @@ -1933,11 +1935,11 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { } if (arena_decay_init(&arena->decay_dirty, &arena->extents_dirty, - arena_dirty_decay_time_default_get(), &arena->stats.decay_dirty)) { + arena_dirty_decay_ms_default_get(), &arena->stats.decay_dirty)) { goto label_error; } if (arena_decay_init(&arena->decay_muzzy, &arena->extents_muzzy, - arena_muzzy_decay_time_default_get(), &arena->stats.decay_muzzy)) { + arena_muzzy_decay_ms_default_get(), &arena->stats.decay_muzzy)) { goto label_error; } @@ -1993,8 +1995,8 @@ label_error: void arena_boot(void) { - arena_dirty_decay_time_default_set(opt_dirty_decay_time); - arena_muzzy_decay_time_default_set(opt_muzzy_decay_time); + arena_dirty_decay_ms_default_set(opt_dirty_decay_ms); + arena_muzzy_decay_ms_default_set(opt_muzzy_decay_ms); } void diff --git a/src/ctl.c b/src/ctl.c index 79f2447f..296e74f2 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -78,8 +78,8 @@ CTL_PROTO(opt_retain) CTL_PROTO(opt_dss) CTL_PROTO(opt_narenas) CTL_PROTO(opt_percpu_arena) -CTL_PROTO(opt_dirty_decay_time) -CTL_PROTO(opt_muzzy_decay_time) +CTL_PROTO(opt_dirty_decay_ms) +CTL_PROTO(opt_muzzy_decay_ms) CTL_PROTO(opt_stats_print) CTL_PROTO(opt_junk) CTL_PROTO(opt_zero) @@ -106,8 +106,8 @@ CTL_PROTO(arena_i_purge) CTL_PROTO(arena_i_reset) CTL_PROTO(arena_i_destroy) CTL_PROTO(arena_i_dss) -CTL_PROTO(arena_i_dirty_decay_time) -CTL_PROTO(arena_i_muzzy_decay_time) +CTL_PROTO(arena_i_dirty_decay_ms) +CTL_PROTO(arena_i_muzzy_decay_ms) CTL_PROTO(arena_i_extent_hooks) INDEX_PROTO(arena_i) CTL_PROTO(arenas_bin_i_size) @@ -117,8 +117,8 @@ INDEX_PROTO(arenas_bin_i) CTL_PROTO(arenas_lextent_i_size) INDEX_PROTO(arenas_lextent_i) CTL_PROTO(arenas_narenas) -CTL_PROTO(arenas_dirty_decay_time) -CTL_PROTO(arenas_muzzy_decay_time) +CTL_PROTO(arenas_dirty_decay_ms) +CTL_PROTO(arenas_muzzy_decay_ms) CTL_PROTO(arenas_quantum) CTL_PROTO(arenas_page) CTL_PROTO(arenas_tcache_max) @@ -159,8 +159,8 @@ INDEX_PROTO(stats_arenas_i_lextents_j) CTL_PROTO(stats_arenas_i_nthreads) CTL_PROTO(stats_arenas_i_uptime) CTL_PROTO(stats_arenas_i_dss) -CTL_PROTO(stats_arenas_i_dirty_decay_time) -CTL_PROTO(stats_arenas_i_muzzy_decay_time) +CTL_PROTO(stats_arenas_i_dirty_decay_ms) +CTL_PROTO(stats_arenas_i_muzzy_decay_ms) CTL_PROTO(stats_arenas_i_pactive) CTL_PROTO(stats_arenas_i_pdirty) CTL_PROTO(stats_arenas_i_pmuzzy) @@ -265,8 +265,8 @@ static const ctl_named_node_t opt_node[] = { {NAME("dss"), CTL(opt_dss)}, {NAME("narenas"), CTL(opt_narenas)}, {NAME("percpu_arena"), CTL(opt_percpu_arena)}, - {NAME("dirty_decay_time"), CTL(opt_dirty_decay_time)}, - {NAME("muzzy_decay_time"), CTL(opt_muzzy_decay_time)}, + {NAME("dirty_decay_ms"), CTL(opt_dirty_decay_ms)}, + {NAME("muzzy_decay_ms"), CTL(opt_muzzy_decay_ms)}, {NAME("stats_print"), CTL(opt_stats_print)}, {NAME("junk"), CTL(opt_junk)}, {NAME("zero"), CTL(opt_zero)}, @@ -299,8 +299,8 @@ static const ctl_named_node_t arena_i_node[] = { {NAME("reset"), CTL(arena_i_reset)}, {NAME("destroy"), CTL(arena_i_destroy)}, {NAME("dss"), CTL(arena_i_dss)}, - {NAME("dirty_decay_time"), CTL(arena_i_dirty_decay_time)}, - {NAME("muzzy_decay_time"), CTL(arena_i_muzzy_decay_time)}, + {NAME("dirty_decay_ms"), CTL(arena_i_dirty_decay_ms)}, + {NAME("muzzy_decay_ms"), CTL(arena_i_muzzy_decay_ms)}, {NAME("extent_hooks"), CTL(arena_i_extent_hooks)} }; static const ctl_named_node_t super_arena_i_node[] = { @@ -337,8 +337,8 @@ static const ctl_indexed_node_t arenas_lextent_node[] = { static const ctl_named_node_t arenas_node[] = { {NAME("narenas"), CTL(arenas_narenas)}, - {NAME("dirty_decay_time"), CTL(arenas_dirty_decay_time)}, - {NAME("muzzy_decay_time"), CTL(arenas_muzzy_decay_time)}, + {NAME("dirty_decay_ms"), CTL(arenas_dirty_decay_ms)}, + {NAME("muzzy_decay_ms"), CTL(arenas_muzzy_decay_ms)}, {NAME("quantum"), CTL(arenas_quantum)}, {NAME("page"), CTL(arenas_page)}, {NAME("tcache_max"), CTL(arenas_tcache_max)}, @@ -444,8 +444,8 @@ static const ctl_named_node_t stats_arenas_i_node[] = { {NAME("nthreads"), CTL(stats_arenas_i_nthreads)}, {NAME("uptime"), CTL(stats_arenas_i_uptime)}, {NAME("dss"), CTL(stats_arenas_i_dss)}, - {NAME("dirty_decay_time"), CTL(stats_arenas_i_dirty_decay_time)}, - {NAME("muzzy_decay_time"), CTL(stats_arenas_i_muzzy_decay_time)}, + {NAME("dirty_decay_ms"), CTL(stats_arenas_i_dirty_decay_ms)}, + {NAME("muzzy_decay_ms"), CTL(stats_arenas_i_muzzy_decay_ms)}, {NAME("pactive"), CTL(stats_arenas_i_pactive)}, {NAME("pdirty"), CTL(stats_arenas_i_pdirty)}, {NAME("pmuzzy"), CTL(stats_arenas_i_pmuzzy)}, @@ -644,8 +644,8 @@ static void ctl_arena_clear(ctl_arena_t *ctl_arena) { ctl_arena->nthreads = 0; ctl_arena->dss = dss_prec_names[dss_prec_limit]; - ctl_arena->dirty_decay_time = -1; - ctl_arena->muzzy_decay_time = -1; + ctl_arena->dirty_decay_ms = -1; + ctl_arena->muzzy_decay_ms = -1; ctl_arena->pactive = 0; ctl_arena->pdirty = 0; ctl_arena->pmuzzy = 0; @@ -668,8 +668,8 @@ ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_t *ctl_arena, arena_t *arena) { if (config_stats) { arena_stats_merge(tsdn, arena, &ctl_arena->nthreads, - &ctl_arena->dss, &ctl_arena->dirty_decay_time, - &ctl_arena->muzzy_decay_time, &ctl_arena->pactive, + &ctl_arena->dss, &ctl_arena->dirty_decay_ms, + &ctl_arena->muzzy_decay_ms, &ctl_arena->pactive, &ctl_arena->pdirty, &ctl_arena->pmuzzy, &ctl_arena->astats->astats, ctl_arena->astats->bstats, ctl_arena->astats->lstats); @@ -687,8 +687,8 @@ ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_t *ctl_arena, arena_t *arena) { } } else { arena_basic_stats_merge(tsdn, arena, &ctl_arena->nthreads, - &ctl_arena->dss, &ctl_arena->dirty_decay_time, - &ctl_arena->muzzy_decay_time, &ctl_arena->pactive, + &ctl_arena->dss, &ctl_arena->dirty_decay_ms, + &ctl_arena->muzzy_decay_ms, &ctl_arena->pactive, &ctl_arena->pdirty, &ctl_arena->pmuzzy); } } @@ -1465,8 +1465,8 @@ CTL_RO_NL_GEN(opt_retain, opt_retain, bool) CTL_RO_NL_GEN(opt_dss, opt_dss, const char *) CTL_RO_NL_GEN(opt_narenas, opt_narenas, unsigned) CTL_RO_NL_GEN(opt_percpu_arena, opt_percpu_arena, const char *) -CTL_RO_NL_GEN(opt_dirty_decay_time, opt_dirty_decay_time, ssize_t) -CTL_RO_NL_GEN(opt_muzzy_decay_time, opt_muzzy_decay_time, ssize_t) +CTL_RO_NL_GEN(opt_dirty_decay_ms, opt_dirty_decay_ms, ssize_t) +CTL_RO_NL_GEN(opt_muzzy_decay_ms, opt_muzzy_decay_ms, ssize_t) CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool) CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *) CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool) @@ -1955,7 +1955,7 @@ label_return: } static int -arena_i_decay_time_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen, +arena_i_decay_ms_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen, bool dirty) { int ret; unsigned arena_ind; @@ -1969,8 +1969,8 @@ arena_i_decay_time_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen, } if (oldp != NULL && oldlenp != NULL) { - size_t oldval = dirty ? arena_dirty_decay_time_get(arena) : - arena_muzzy_decay_time_get(arena); + size_t oldval = dirty ? arena_dirty_decay_ms_get(arena) : + arena_muzzy_decay_ms_get(arena); READ(oldval, ssize_t); } if (newp != NULL) { @@ -1978,10 +1978,9 @@ arena_i_decay_time_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen, ret = EINVAL; goto label_return; } - if (dirty ? arena_dirty_decay_time_set(tsd_tsdn(tsd), arena, - *(ssize_t *)newp) : - arena_muzzy_decay_time_set(tsd_tsdn(tsd), arena, - *(ssize_t *)newp)) { + if (dirty ? arena_dirty_decay_ms_set(tsd_tsdn(tsd), arena, + *(ssize_t *)newp) : arena_muzzy_decay_ms_set(tsd_tsdn(tsd), + arena, *(ssize_t *)newp)) { ret = EFAULT; goto label_return; } @@ -1993,17 +1992,17 @@ label_return: } static int -arena_i_dirty_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, +arena_i_dirty_decay_ms_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { - return arena_i_decay_time_ctl_impl(tsd, mib, miblen, oldp, oldlenp, - newp, newlen, true); + return arena_i_decay_ms_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp, + newlen, true); } static int -arena_i_muzzy_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, +arena_i_muzzy_decay_ms_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { - return arena_i_decay_time_ctl_impl(tsd, mib, miblen, oldp, oldlenp, - newp, newlen, false); + return arena_i_decay_ms_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp, + newlen, false); } static int @@ -2087,13 +2086,13 @@ label_return: } static int -arenas_decay_time_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen, +arenas_decay_ms_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen, bool dirty) { int ret; if (oldp != NULL && oldlenp != NULL) { - size_t oldval = (dirty ? arena_dirty_decay_time_default_get() : - arena_muzzy_decay_time_default_get()); + size_t oldval = (dirty ? arena_dirty_decay_ms_default_get() : + arena_muzzy_decay_ms_default_get()); READ(oldval, ssize_t); } if (newp != NULL) { @@ -2101,8 +2100,8 @@ arenas_decay_time_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen, ret = EINVAL; goto label_return; } - if (dirty ? arena_dirty_decay_time_default_set(*(ssize_t *)newp) - : arena_muzzy_decay_time_default_set(*(ssize_t *)newp)) { + if (dirty ? arena_dirty_decay_ms_default_set(*(ssize_t *)newp) + : arena_muzzy_decay_ms_default_set(*(ssize_t *)newp)) { ret = EFAULT; goto label_return; } @@ -2114,16 +2113,16 @@ label_return: } static int -arenas_dirty_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, +arenas_dirty_decay_ms_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { - return arenas_decay_time_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp, + return arenas_decay_ms_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp, newlen, true); } static int -arenas_muzzy_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, +arenas_muzzy_decay_ms_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { - return arenas_decay_time_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp, + return arenas_decay_ms_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp, newlen, false); } @@ -2318,9 +2317,9 @@ CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats->mapped, size_t) CTL_RO_CGEN(config_stats, stats_retained, ctl_stats->retained, size_t) CTL_RO_GEN(stats_arenas_i_dss, arenas_i(mib[2])->dss, const char *) -CTL_RO_GEN(stats_arenas_i_dirty_decay_time, arenas_i(mib[2])->dirty_decay_time, +CTL_RO_GEN(stats_arenas_i_dirty_decay_ms, arenas_i(mib[2])->dirty_decay_ms, ssize_t) -CTL_RO_GEN(stats_arenas_i_muzzy_decay_time, arenas_i(mib[2])->muzzy_decay_time, +CTL_RO_GEN(stats_arenas_i_muzzy_decay_ms, arenas_i(mib[2])->muzzy_decay_ms, ssize_t) CTL_RO_GEN(stats_arenas_i_nthreads, arenas_i(mib[2])->nthreads, unsigned) CTL_RO_GEN(stats_arenas_i_uptime, diff --git a/src/jemalloc.c b/src/jemalloc.c index 13218449..47133edf 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1070,10 +1070,14 @@ malloc_conf_init(void) { } CONF_HANDLE_UNSIGNED(opt_narenas, "narenas", 1, UINT_MAX, yes, no, false) - CONF_HANDLE_SSIZE_T(opt_dirty_decay_time, - "dirty_decay_time", -1, NSTIME_SEC_MAX); - CONF_HANDLE_SSIZE_T(opt_muzzy_decay_time, - "muzzy_decay_time", -1, NSTIME_SEC_MAX); + CONF_HANDLE_SSIZE_T(opt_dirty_decay_ms, + "dirty_decay_ms", -1, NSTIME_SEC_MAX * KQU(1000) < + QU(SSIZE_MAX) ? NSTIME_SEC_MAX * KQU(1000) : + SSIZE_MAX); + CONF_HANDLE_SSIZE_T(opt_muzzy_decay_ms, + "muzzy_decay_ms", -1, NSTIME_SEC_MAX * KQU(1000) < + QU(SSIZE_MAX) ? NSTIME_SEC_MAX * KQU(1000) : + SSIZE_MAX); CONF_HANDLE_BOOL(opt_stats_print, "stats_print") if (config_fill) { if (CONF_MATCH("junk")) { diff --git a/src/stats.c b/src/stats.c index 883c7d14..3c9eb35a 100644 --- a/src/stats.c +++ b/src/stats.c @@ -411,7 +411,7 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, bool json, unsigned i, bool bins, bool large, bool mutex) { unsigned nthreads; const char *dss; - ssize_t dirty_decay_time, muzzy_decay_time; + ssize_t dirty_decay_ms, muzzy_decay_ms; size_t page, pactive, pdirty, pmuzzy, mapped, retained; size_t base, internal, resident; uint64_t dirty_npurge, dirty_nmadvise, dirty_purged; @@ -452,9 +452,9 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, "dss allocation precedence: %s\n", dss); } - CTL_M2_GET("stats.arenas.0.dirty_decay_time", i, &dirty_decay_time, + CTL_M2_GET("stats.arenas.0.dirty_decay_ms", i, &dirty_decay_ms, ssize_t); - CTL_M2_GET("stats.arenas.0.muzzy_decay_time", i, &muzzy_decay_time, + CTL_M2_GET("stats.arenas.0.muzzy_decay_ms", i, &muzzy_decay_ms, ssize_t); CTL_M2_GET("stats.arenas.0.pactive", i, &pactive, size_t); CTL_M2_GET("stats.arenas.0.pdirty", i, &pdirty, size_t); @@ -469,9 +469,9 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, CTL_M2_GET("stats.arenas.0.muzzy_purged", i, &muzzy_purged, uint64_t); if (json) { malloc_cprintf(write_cb, cbopaque, - "\t\t\t\t\"dirty_decay_time\": %zd,\n", dirty_decay_time); + "\t\t\t\t\"dirty_decay_ms\": %zd,\n", dirty_decay_ms); malloc_cprintf(write_cb, cbopaque, - "\t\t\t\t\"muzzy_decay_time\": %zd,\n", muzzy_decay_time); + "\t\t\t\t\"muzzy_decay_ms\": %zd,\n", muzzy_decay_ms); malloc_cprintf(write_cb, cbopaque, "\t\t\t\t\"pactive\": %zu,\n", pactive); malloc_cprintf(write_cb, cbopaque, @@ -494,10 +494,10 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "decaying: time npages sweeps madvises" " purged\n"); - if (dirty_decay_time >= 0) { + if (dirty_decay_ms >= 0) { malloc_cprintf(write_cb, cbopaque, " dirty: %5zd %12zu %12"FMTu64" %12"FMTu64" %12" - FMTu64"\n", dirty_decay_time, pdirty, dirty_npurge, + FMTu64"\n", dirty_decay_ms, pdirty, dirty_npurge, dirty_nmadvise, dirty_purged); } else { malloc_cprintf(write_cb, cbopaque, @@ -505,10 +505,10 @@ stats_arena_print(void (*write_cb)(void *, const char *), void *cbopaque, FMTu64"\n", pdirty, dirty_npurge, dirty_nmadvise, dirty_purged); } - if (muzzy_decay_time >= 0) { + if (muzzy_decay_ms >= 0) { malloc_cprintf(write_cb, cbopaque, " muzzy: %5zd %12zu %12"FMTu64" %12"FMTu64" %12" - FMTu64"\n", muzzy_decay_time, pmuzzy, muzzy_npurge, + FMTu64"\n", muzzy_decay_ms, pmuzzy, muzzy_npurge, muzzy_nmadvise, muzzy_purged); } else { malloc_cprintf(write_cb, cbopaque, @@ -816,10 +816,8 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, OPT_WRITE_CHAR_P(dss, ",") OPT_WRITE_UNSIGNED(narenas, ",") OPT_WRITE_CHAR_P(percpu_arena, ",") - OPT_WRITE_SSIZE_T_MUTABLE(dirty_decay_time, arenas.dirty_decay_time, - ",") - OPT_WRITE_SSIZE_T_MUTABLE(muzzy_decay_time, arenas.muzzy_decay_time, - ",") + OPT_WRITE_SSIZE_T_MUTABLE(dirty_decay_ms, arenas.dirty_decay_ms, ",") + OPT_WRITE_SSIZE_T_MUTABLE(muzzy_decay_ms, arenas.muzzy_decay_ms, ",") OPT_WRITE_CHAR_P(junk, ",") OPT_WRITE_BOOL(zero, ",") OPT_WRITE_BOOL(utrace, ",") @@ -867,24 +865,14 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "Arenas: %u\n", uv); } - CTL_GET("arenas.dirty_decay_time", &ssv, ssize_t); if (json) { + CTL_GET("arenas.dirty_decay_ms", &ssv, ssize_t); malloc_cprintf(write_cb, cbopaque, - "\t\t\t\"dirty_decay_time\": %zd,\n", ssv); - } else { - malloc_cprintf(write_cb, cbopaque, - "Unused dirty page decay time: %zd%s\n", ssv, (ssv < 0) ? - " (no decay)" : ""); - } + "\t\t\t\"dirty_decay_ms\": %zd,\n", ssv); - CTL_GET("arenas.muzzy_decay_time", &ssv, ssize_t); - if (json) { - malloc_cprintf(write_cb, cbopaque, - "\t\t\t\"muzzy_decay_time\": %zd,\n", ssv); - } else { + CTL_GET("arenas.muzzy_decay_ms", &ssv, ssize_t); malloc_cprintf(write_cb, cbopaque, - "Unused muzzy page decay time: %zd%s\n", ssv, (ssv < 0) ? - " (no decay)" : ""); + "\t\t\t\"muzzy_decay_ms\": %zd,\n", ssv); } CTL_GET("arenas.quantum", &sv, size_t); diff --git a/test/unit/decay.c b/test/unit/decay.c index 389f6e06..19f76fa5 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -24,7 +24,7 @@ nstime_update_mock(nstime_t *time) { } static unsigned -do_arena_create(ssize_t dirty_decay_time, ssize_t muzzy_decay_time) { +do_arena_create(ssize_t dirty_decay_ms, ssize_t muzzy_decay_ms) { unsigned arena_ind; size_t sz = sizeof(unsigned); assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), @@ -32,19 +32,19 @@ do_arena_create(ssize_t dirty_decay_time, ssize_t muzzy_decay_time) { size_t mib[3]; size_t miblen = sizeof(mib)/sizeof(size_t); - assert_d_eq(mallctlnametomib("arena.0.dirty_decay_time", mib, &miblen), + assert_d_eq(mallctlnametomib("arena.0.dirty_decay_ms", mib, &miblen), 0, "Unexpected mallctlnametomib() failure"); mib[1] = (size_t)arena_ind; assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, - (void *)&dirty_decay_time, - sizeof(dirty_decay_time)), 0, "Unexpected mallctlbymib() failure"); + (void *)&dirty_decay_ms, sizeof(dirty_decay_ms)), 0, + "Unexpected mallctlbymib() failure"); - assert_d_eq(mallctlnametomib("arena.0.muzzy_decay_time", mib, &miblen), + assert_d_eq(mallctlnametomib("arena.0.muzzy_decay_ms", mib, &miblen), 0, "Unexpected mallctlnametomib() failure"); mib[1] = (size_t)arena_ind; assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, - (void *)&muzzy_decay_time, - sizeof(muzzy_decay_time)), 0, "Unexpected mallctlbymib() failure"); + (void *)&muzzy_decay_ms, sizeof(muzzy_decay_ms)), 0, + "Unexpected mallctlbymib() failure"); return arena_ind; } @@ -362,14 +362,14 @@ static void decay_ticker_helper(unsigned arena_ind, int flags, bool dirty, ssize_t dt, uint64_t dirty_npurge0, uint64_t muzzy_npurge0, bool terminate_asap) { #define NINTERVALS 101 - nstime_t time, update_interval, decay_time, deadline; + nstime_t time, update_interval, decay_ms, deadline; nstime_init(&time, 0); nstime_update(&time); - nstime_init2(&decay_time, dt, 0); + nstime_init2(&decay_ms, dt, 0); nstime_copy(&deadline, &time); - nstime_add(&deadline, &decay_time); + nstime_add(&deadline, &decay_ms); nstime_init2(&update_interval, dt, 0); nstime_idivide(&update_interval, NINTERVALS); @@ -406,8 +406,8 @@ decay_ticker_helper(unsigned arena_ind, int flags, bool dirty, ssize_t dt, TEST_BEGIN(test_decay_ticker) { #define NPS 2048 - ssize_t ddt = opt_dirty_decay_time; - ssize_t mdt = opt_muzzy_decay_time; + ssize_t ddt = opt_dirty_decay_ms; + ssize_t mdt = opt_muzzy_decay_ms; unsigned arena_ind = do_arena_create(ddt, mdt); int flags = (MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE); void *ps[NPS]; diff --git a/test/unit/decay.sh b/test/unit/decay.sh index a41489b0..45aeccf4 100644 --- a/test/unit/decay.sh +++ b/test/unit/decay.sh @@ -1,3 +1,3 @@ #!/bin/sh -export MALLOC_CONF="dirty_decay_time:1,muzzy_decay_time:1,lg_tcache_max:0" +export MALLOC_CONF="dirty_decay_ms:1000,muzzy_decay_ms:1000,lg_tcache_max:0" diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index b07a6d04..f721c21d 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -161,8 +161,8 @@ TEST_BEGIN(test_mallctl_opt) { TEST_MALLCTL_OPT(const char *, dss, always); TEST_MALLCTL_OPT(unsigned, narenas, always); TEST_MALLCTL_OPT(const char *, percpu_arena, always); - TEST_MALLCTL_OPT(ssize_t, dirty_decay_time, always); - TEST_MALLCTL_OPT(ssize_t, muzzy_decay_time, always); + TEST_MALLCTL_OPT(ssize_t, dirty_decay_ms, always); + TEST_MALLCTL_OPT(ssize_t, muzzy_decay_ms, always); TEST_MALLCTL_OPT(bool, stats_print, always); TEST_MALLCTL_OPT(const char *, junk, fill); TEST_MALLCTL_OPT(bool, zero, fill); @@ -398,68 +398,66 @@ TEST_BEGIN(test_arena_i_initialized) { } TEST_END -TEST_BEGIN(test_arena_i_dirty_decay_time) { - ssize_t dirty_decay_time, orig_dirty_decay_time, prev_dirty_decay_time; +TEST_BEGIN(test_arena_i_dirty_decay_ms) { + ssize_t dirty_decay_ms, orig_dirty_decay_ms, prev_dirty_decay_ms; size_t sz = sizeof(ssize_t); - assert_d_eq(mallctl("arena.0.dirty_decay_time", - (void *)&orig_dirty_decay_time, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arena.0.dirty_decay_ms", + (void *)&orig_dirty_decay_ms, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); - dirty_decay_time = -2; - assert_d_eq(mallctl("arena.0.dirty_decay_time", NULL, NULL, - (void *)&dirty_decay_time, sizeof(ssize_t)), EFAULT, + dirty_decay_ms = -2; + assert_d_eq(mallctl("arena.0.dirty_decay_ms", NULL, NULL, + (void *)&dirty_decay_ms, sizeof(ssize_t)), EFAULT, "Unexpected mallctl() success"); - dirty_decay_time = 0x7fffffff; - assert_d_eq(mallctl("arena.0.dirty_decay_time", NULL, NULL, - (void *)&dirty_decay_time, sizeof(ssize_t)), 0, + dirty_decay_ms = 0x7fffffff; + assert_d_eq(mallctl("arena.0.dirty_decay_ms", NULL, NULL, + (void *)&dirty_decay_ms, sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); - for (prev_dirty_decay_time = dirty_decay_time, dirty_decay_time = -1; - dirty_decay_time < 20; prev_dirty_decay_time = dirty_decay_time, - dirty_decay_time++) { - ssize_t old_dirty_decay_time; + for (prev_dirty_decay_ms = dirty_decay_ms, dirty_decay_ms = -1; + dirty_decay_ms < 20; prev_dirty_decay_ms = dirty_decay_ms, + dirty_decay_ms++) { + ssize_t old_dirty_decay_ms; - assert_d_eq(mallctl("arena.0.dirty_decay_time", - (void *)&old_dirty_decay_time, &sz, - (void *)&dirty_decay_time, sizeof(ssize_t)), 0, - "Unexpected mallctl() failure"); - assert_zd_eq(old_dirty_decay_time, prev_dirty_decay_time, - "Unexpected old arena.0.dirty_decay_time"); + assert_d_eq(mallctl("arena.0.dirty_decay_ms", + (void *)&old_dirty_decay_ms, &sz, (void *)&dirty_decay_ms, + sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); + assert_zd_eq(old_dirty_decay_ms, prev_dirty_decay_ms, + "Unexpected old arena.0.dirty_decay_ms"); } } TEST_END -TEST_BEGIN(test_arena_i_muzzy_decay_time) { - ssize_t muzzy_decay_time, orig_muzzy_decay_time, prev_muzzy_decay_time; +TEST_BEGIN(test_arena_i_muzzy_decay_ms) { + ssize_t muzzy_decay_ms, orig_muzzy_decay_ms, prev_muzzy_decay_ms; size_t sz = sizeof(ssize_t); - assert_d_eq(mallctl("arena.0.muzzy_decay_time", - (void *)&orig_muzzy_decay_time, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arena.0.muzzy_decay_ms", + (void *)&orig_muzzy_decay_ms, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); - muzzy_decay_time = -2; - assert_d_eq(mallctl("arena.0.muzzy_decay_time", NULL, NULL, - (void *)&muzzy_decay_time, sizeof(ssize_t)), EFAULT, + muzzy_decay_ms = -2; + assert_d_eq(mallctl("arena.0.muzzy_decay_ms", NULL, NULL, + (void *)&muzzy_decay_ms, sizeof(ssize_t)), EFAULT, "Unexpected mallctl() success"); - muzzy_decay_time = 0x7fffffff; - assert_d_eq(mallctl("arena.0.muzzy_decay_time", NULL, NULL, - (void *)&muzzy_decay_time, sizeof(ssize_t)), 0, + muzzy_decay_ms = 0x7fffffff; + assert_d_eq(mallctl("arena.0.muzzy_decay_ms", NULL, NULL, + (void *)&muzzy_decay_ms, sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); - for (prev_muzzy_decay_time = muzzy_decay_time, muzzy_decay_time = -1; - muzzy_decay_time < 20; prev_muzzy_decay_time = muzzy_decay_time, - muzzy_decay_time++) { - ssize_t old_muzzy_decay_time; + for (prev_muzzy_decay_ms = muzzy_decay_ms, muzzy_decay_ms = -1; + muzzy_decay_ms < 20; prev_muzzy_decay_ms = muzzy_decay_ms, + muzzy_decay_ms++) { + ssize_t old_muzzy_decay_ms; - assert_d_eq(mallctl("arena.0.muzzy_decay_time", - (void *)&old_muzzy_decay_time, &sz, - (void *)&muzzy_decay_time, sizeof(ssize_t)), 0, - "Unexpected mallctl() failure"); - assert_zd_eq(old_muzzy_decay_time, prev_muzzy_decay_time, - "Unexpected old arena.0.muzzy_decay_time"); + assert_d_eq(mallctl("arena.0.muzzy_decay_ms", + (void *)&old_muzzy_decay_ms, &sz, (void *)&muzzy_decay_ms, + sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); + assert_zd_eq(old_muzzy_decay_ms, prev_muzzy_decay_ms, + "Unexpected old arena.0.muzzy_decay_ms"); } } TEST_END @@ -555,68 +553,66 @@ TEST_BEGIN(test_arena_i_dss) { } TEST_END -TEST_BEGIN(test_arenas_dirty_decay_time) { - ssize_t dirty_decay_time, orig_dirty_decay_time, prev_dirty_decay_time; +TEST_BEGIN(test_arenas_dirty_decay_ms) { + ssize_t dirty_decay_ms, orig_dirty_decay_ms, prev_dirty_decay_ms; size_t sz = sizeof(ssize_t); - assert_d_eq(mallctl("arenas.dirty_decay_time", - (void *)&orig_dirty_decay_time, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arenas.dirty_decay_ms", + (void *)&orig_dirty_decay_ms, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); - dirty_decay_time = -2; - assert_d_eq(mallctl("arenas.dirty_decay_time", NULL, NULL, - (void *)&dirty_decay_time, sizeof(ssize_t)), EFAULT, + dirty_decay_ms = -2; + assert_d_eq(mallctl("arenas.dirty_decay_ms", NULL, NULL, + (void *)&dirty_decay_ms, sizeof(ssize_t)), EFAULT, "Unexpected mallctl() success"); - dirty_decay_time = 0x7fffffff; - assert_d_eq(mallctl("arenas.dirty_decay_time", NULL, NULL, - (void *)&dirty_decay_time, sizeof(ssize_t)), 0, + dirty_decay_ms = 0x7fffffff; + assert_d_eq(mallctl("arenas.dirty_decay_ms", NULL, NULL, + (void *)&dirty_decay_ms, sizeof(ssize_t)), 0, "Expected mallctl() failure"); - for (prev_dirty_decay_time = dirty_decay_time, dirty_decay_time = -1; - dirty_decay_time < 20; prev_dirty_decay_time = dirty_decay_time, - dirty_decay_time++) { - ssize_t old_dirty_decay_time; + for (prev_dirty_decay_ms = dirty_decay_ms, dirty_decay_ms = -1; + dirty_decay_ms < 20; prev_dirty_decay_ms = dirty_decay_ms, + dirty_decay_ms++) { + ssize_t old_dirty_decay_ms; - assert_d_eq(mallctl("arenas.dirty_decay_time", - (void *)&old_dirty_decay_time, &sz, - (void *)&dirty_decay_time, sizeof(ssize_t)), 0, - "Unexpected mallctl() failure"); - assert_zd_eq(old_dirty_decay_time, prev_dirty_decay_time, - "Unexpected old arenas.dirty_decay_time"); + assert_d_eq(mallctl("arenas.dirty_decay_ms", + (void *)&old_dirty_decay_ms, &sz, (void *)&dirty_decay_ms, + sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); + assert_zd_eq(old_dirty_decay_ms, prev_dirty_decay_ms, + "Unexpected old arenas.dirty_decay_ms"); } } TEST_END -TEST_BEGIN(test_arenas_muzzy_decay_time) { - ssize_t muzzy_decay_time, orig_muzzy_decay_time, prev_muzzy_decay_time; +TEST_BEGIN(test_arenas_muzzy_decay_ms) { + ssize_t muzzy_decay_ms, orig_muzzy_decay_ms, prev_muzzy_decay_ms; size_t sz = sizeof(ssize_t); - assert_d_eq(mallctl("arenas.muzzy_decay_time", - (void *)&orig_muzzy_decay_time, &sz, NULL, 0), 0, + assert_d_eq(mallctl("arenas.muzzy_decay_ms", + (void *)&orig_muzzy_decay_ms, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); - muzzy_decay_time = -2; - assert_d_eq(mallctl("arenas.muzzy_decay_time", NULL, NULL, - (void *)&muzzy_decay_time, sizeof(ssize_t)), EFAULT, + muzzy_decay_ms = -2; + assert_d_eq(mallctl("arenas.muzzy_decay_ms", NULL, NULL, + (void *)&muzzy_decay_ms, sizeof(ssize_t)), EFAULT, "Unexpected mallctl() success"); - muzzy_decay_time = 0x7fffffff; - assert_d_eq(mallctl("arenas.muzzy_decay_time", NULL, NULL, - (void *)&muzzy_decay_time, sizeof(ssize_t)), 0, + muzzy_decay_ms = 0x7fffffff; + assert_d_eq(mallctl("arenas.muzzy_decay_ms", NULL, NULL, + (void *)&muzzy_decay_ms, sizeof(ssize_t)), 0, "Expected mallctl() failure"); - for (prev_muzzy_decay_time = muzzy_decay_time, muzzy_decay_time = -1; - muzzy_decay_time < 20; prev_muzzy_decay_time = muzzy_decay_time, - muzzy_decay_time++) { - ssize_t old_muzzy_decay_time; + for (prev_muzzy_decay_ms = muzzy_decay_ms, muzzy_decay_ms = -1; + muzzy_decay_ms < 20; prev_muzzy_decay_ms = muzzy_decay_ms, + muzzy_decay_ms++) { + ssize_t old_muzzy_decay_ms; - assert_d_eq(mallctl("arenas.muzzy_decay_time", - (void *)&old_muzzy_decay_time, &sz, - (void *)&muzzy_decay_time, sizeof(ssize_t)), 0, - "Unexpected mallctl() failure"); - assert_zd_eq(old_muzzy_decay_time, prev_muzzy_decay_time, - "Unexpected old arenas.muzzy_decay_time"); + assert_d_eq(mallctl("arenas.muzzy_decay_ms", + (void *)&old_muzzy_decay_ms, &sz, (void *)&muzzy_decay_ms, + sizeof(ssize_t)), 0, "Unexpected mallctl() failure"); + assert_zd_eq(old_muzzy_decay_ms, prev_muzzy_decay_ms, + "Unexpected old arenas.muzzy_decay_ms"); } } TEST_END @@ -699,8 +695,8 @@ TEST_BEGIN(test_stats_arenas) { TEST_STATS_ARENAS(unsigned, nthreads); TEST_STATS_ARENAS(const char *, dss); - TEST_STATS_ARENAS(ssize_t, dirty_decay_time); - TEST_STATS_ARENAS(ssize_t, muzzy_decay_time); + TEST_STATS_ARENAS(ssize_t, dirty_decay_ms); + TEST_STATS_ARENAS(ssize_t, muzzy_decay_ms); TEST_STATS_ARENAS(size_t, pactive); TEST_STATS_ARENAS(size_t, pdirty); @@ -723,13 +719,13 @@ main(void) { test_tcache, test_thread_arena, test_arena_i_initialized, - test_arena_i_dirty_decay_time, - test_arena_i_muzzy_decay_time, + test_arena_i_dirty_decay_ms, + test_arena_i_muzzy_decay_ms, test_arena_i_purge, test_arena_i_decay, test_arena_i_dss, - test_arenas_dirty_decay_time, - test_arenas_muzzy_decay_time, + test_arenas_dirty_decay_ms, + test_arenas_muzzy_decay_ms, test_arenas_constants, test_arenas_bin_constants, test_arenas_lextent_constants, diff --git a/test/unit/pack.sh b/test/unit/pack.sh index 76757ac3..6f451480 100644 --- a/test/unit/pack.sh +++ b/test/unit/pack.sh @@ -1,4 +1,4 @@ #!/bin/sh # Immediately purge to minimize fragmentation. -export MALLOC_CONF="dirty_decay_time:0,muzzy_decay_time:0" +export MALLOC_CONF="dirty_decay_ms:0,muzzy_decay_ms:0" -- GitLab From 26c792e61a163b38b373023bca2947283dcd1fc8 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 15 May 2017 15:38:15 -0700 Subject: [PATCH 482/544] Allow mutexes to take a lock ordering enum at construction. This lets us specify whether and how mutexes of the same rank are allowed to be acquired. Currently, we only allow two polices (only a single mutex at a given rank at a time, and mutexes acquired in ascending order), but we can plausibly allow more (e.g. the "release uncontended mutexes before blocking"). --- include/jemalloc/internal/mutex_externs.h | 2 +- include/jemalloc/internal/mutex_structs.h | 6 +++-- include/jemalloc/internal/mutex_types.h | 10 ++++++++ src/arena.c | 13 ++++++----- src/base.c | 3 ++- src/ctl.c | 3 ++- src/extent.c | 3 ++- src/jemalloc.c | 6 +++-- src/mutex.c | 28 ++++++++++++++++++++--- src/prof.c | 25 +++++++++++--------- src/rtree.c | 3 ++- src/tcache.c | 3 ++- 12 files changed, 75 insertions(+), 30 deletions(-) diff --git a/include/jemalloc/internal/mutex_externs.h b/include/jemalloc/internal/mutex_externs.h index 8e40cb34..c9a817fb 100644 --- a/include/jemalloc/internal/mutex_externs.h +++ b/include/jemalloc/internal/mutex_externs.h @@ -11,7 +11,7 @@ extern bool isthreaded; #endif bool malloc_mutex_init(malloc_mutex_t *mutex, const char *name, - witness_rank_t rank); + witness_rank_t rank, malloc_mutex_lock_order_t lock_order); void malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex); void malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex); void malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex); diff --git a/include/jemalloc/internal/mutex_structs.h b/include/jemalloc/internal/mutex_structs.h index 2691852d..a8b16a16 100644 --- a/include/jemalloc/internal/mutex_structs.h +++ b/include/jemalloc/internal/mutex_structs.h @@ -40,12 +40,14 @@ struct malloc_mutex_s { * memory cost. */ #if !defined(JEMALLOC_DEBUG) - witness_t witness; + witness_t witness; + malloc_mutex_lock_order_t lock_order; #endif }; #if defined(JEMALLOC_DEBUG) - witness_t witness; + witness_t witness; + malloc_mutex_lock_order_t lock_order; #endif }; diff --git a/include/jemalloc/internal/mutex_types.h b/include/jemalloc/internal/mutex_types.h index 5af8d099..65a9938d 100644 --- a/include/jemalloc/internal/mutex_types.h +++ b/include/jemalloc/internal/mutex_types.h @@ -3,6 +3,16 @@ typedef struct malloc_mutex_s malloc_mutex_t; +typedef enum { + /* Can only acquire one mutex of a given witness rank at a time. */ + malloc_mutex_rank_exclusive, + /* + * Can acquire multiple mutexes of the same witness rank, but in + * address-ascending order only. + */ + malloc_mutex_address_ordered +} malloc_mutex_lock_order_t; + /* * Based on benchmark results, a fixed spin with this amount of retries works * well for our critical sections. diff --git a/src/arena.c b/src/arena.c index 42bfc6b1..67e1b2f5 100644 --- a/src/arena.c +++ b/src/arena.c @@ -64,7 +64,7 @@ arena_stats_init(tsdn_t *tsdn, arena_stats_t *arena_stats) { } #ifndef JEMALLOC_ATOMIC_U64 if (malloc_mutex_init(&arena_stats->mtx, "arena_stats", - WITNESS_RANK_ARENA_STATS)) { + WITNESS_RANK_ARENA_STATS, malloc_mutex_rank_exclusive)) { return true; } #endif @@ -734,7 +734,8 @@ arena_decay_init(arena_decay_t *decay, extents_t *extents, ssize_t decay_ms, assert(((char *)decay)[i] == 0); } } - if (malloc_mutex_init(&decay->mtx, "decay", WITNESS_RANK_DECAY)) { + if (malloc_mutex_init(&decay->mtx, "decay", WITNESS_RANK_DECAY, + malloc_mutex_rank_exclusive)) { return true; } decay->purging = false; @@ -1869,7 +1870,7 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { ql_new(&arena->tcache_ql); if (malloc_mutex_init(&arena->tcache_ql_mtx, "tcache_ql", - WITNESS_RANK_TCACHE_QL)) { + WITNESS_RANK_TCACHE_QL, malloc_mutex_rank_exclusive)) { goto label_error; } } @@ -1901,7 +1902,7 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { extent_list_init(&arena->large); if (malloc_mutex_init(&arena->large_mtx, "arena_large", - WITNESS_RANK_ARENA_LARGE)) { + WITNESS_RANK_ARENA_LARGE, malloc_mutex_rank_exclusive)) { goto label_error; } @@ -1950,7 +1951,7 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { extent_avail_new(&arena->extent_avail); if (malloc_mutex_init(&arena->extent_avail_mtx, "extent_avail", - WITNESS_RANK_EXTENT_FREELIST)) { + WITNESS_RANK_EXTENT_FREELIST, malloc_mutex_rank_exclusive)) { goto label_error; } @@ -1958,7 +1959,7 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { for (i = 0; i < NBINS; i++) { arena_bin_t *bin = &arena->bins[i]; if (malloc_mutex_init(&bin->lock, "arena_bin", - WITNESS_RANK_ARENA_BIN)) { + WITNESS_RANK_ARENA_BIN, malloc_mutex_rank_exclusive)) { goto label_error; } bin->slabcur = NULL; diff --git a/src/base.c b/src/base.c index 3de6e3b0..7502a657 100644 --- a/src/base.c +++ b/src/base.c @@ -238,7 +238,8 @@ base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { &gap_size, base_size, base_alignment); base->ind = ind; atomic_store_p(&base->extent_hooks, extent_hooks, ATOMIC_RELAXED); - if (malloc_mutex_init(&base->mtx, "base", WITNESS_RANK_BASE)) { + if (malloc_mutex_init(&base->mtx, "base", WITNESS_RANK_BASE, + malloc_mutex_rank_exclusive)) { base_unmap(extent_hooks, ind, block, block->size); return NULL; } diff --git a/src/ctl.c b/src/ctl.c index 296e74f2..7f69f151 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1199,7 +1199,8 @@ label_return: bool ctl_boot(void) { - if (malloc_mutex_init(&ctl_mtx, "ctl", WITNESS_RANK_CTL)) { + if (malloc_mutex_init(&ctl_mtx, "ctl", WITNESS_RANK_CTL, + malloc_mutex_rank_exclusive)) { return true; } diff --git a/src/extent.c b/src/extent.c index 1b284535..513d16d5 100644 --- a/src/extent.c +++ b/src/extent.c @@ -195,7 +195,8 @@ ph_gen(, extent_heap_, extent_heap_t, extent_t, ph_link, extent_snad_comp) bool extents_init(tsdn_t *tsdn, extents_t *extents, extent_state_t state, bool delay_coalesce) { - if (malloc_mutex_init(&extents->mtx, "extents", WITNESS_RANK_EXTENTS)) { + if (malloc_mutex_init(&extents->mtx, "extents", WITNESS_RANK_EXTENTS, + malloc_mutex_rank_exclusive)) { return true; } for (unsigned i = 0; i < NPSIZES+1; i++) { diff --git a/src/jemalloc.c b/src/jemalloc.c index 47133edf..56aef5b0 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -235,7 +235,8 @@ _init_init_lock(void) { * doing anything. */ if (!init_lock_initialized) { - malloc_mutex_init(&init_lock, "init", WITNESS_RANK_INIT); + malloc_mutex_init(&init_lock, "init", WITNESS_RANK_INIT, + malloc_mutex_rank_exclusive); } init_lock_initialized = true; } @@ -1237,7 +1238,8 @@ malloc_init_hard_a0_locked() { if (tcache_boot(TSDN_NULL)) { return true; } - if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS)) { + if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS, + malloc_mutex_rank_exclusive)) { return true; } /* diff --git a/src/mutex.c b/src/mutex.c index 3eec970f..b15bbf6e 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -138,9 +138,25 @@ malloc_mutex_prof_data_reset(tsdn_t *tsdn, malloc_mutex_t *mutex) { mutex_prof_data_init(&mutex->prof_data); } +static int +mutex_addr_comp(const witness_t *witness1, void *mutex1, + const witness_t *witness2, void *mutex2) { + assert(mutex1 != NULL); + assert(mutex2 != NULL); + uintptr_t mu1int = (uintptr_t)mutex1; + uintptr_t mu2int = (uintptr_t)mutex2; + if (mu1int < mu2int) { + return -1; + } else if (mu1int == mu2int) { + return 0; + } else { + return 1; + } +} + bool malloc_mutex_init(malloc_mutex_t *mutex, const char *name, - witness_rank_t rank) { + witness_rank_t rank, malloc_mutex_lock_order_t lock_order) { mutex_prof_data_init(&mutex->prof_data); #ifdef _WIN32 # if _WIN32_WINNT >= 0x0600 @@ -179,7 +195,13 @@ malloc_mutex_init(malloc_mutex_t *mutex, const char *name, pthread_mutexattr_destroy(&attr); #endif if (config_debug) { - witness_init(&mutex->witness, name, rank, NULL, NULL); + mutex->lock_order = lock_order; + if (lock_order == malloc_mutex_address_ordered) { + witness_init(&mutex->witness, name, rank, + mutex_addr_comp, &mutex); + } else { + witness_init(&mutex->witness, name, rank, NULL, NULL); + } } return false; } @@ -200,7 +222,7 @@ malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex) { malloc_mutex_unlock(tsdn, mutex); #else if (malloc_mutex_init(mutex, mutex->witness.name, - mutex->witness.rank)) { + mutex->witness.rank, mutex->lock_order)) { malloc_printf(": Error re-initializing mutex in " "child\n"); if (opt_abort) { diff --git a/src/prof.c b/src/prof.c index 470d926f..18978810 100644 --- a/src/prof.c +++ b/src/prof.c @@ -1754,7 +1754,7 @@ prof_accum_init(tsdn_t *tsdn, prof_accum_t *prof_accum) { #ifndef JEMALLOC_ATOMIC_U64 if (malloc_mutex_init(&prof_accum->mtx, "prof_accum", - WITNESS_RANK_PROF_ACCUM)) { + WITNESS_RANK_PROF_ACCUM, malloc_mutex_rank_exclusive)) { return true; } prof_accum->accumbytes = 0; @@ -2289,20 +2289,21 @@ prof_boot2(tsd_t *tsd) { prof_active = opt_prof_active; if (malloc_mutex_init(&prof_active_mtx, "prof_active", - WITNESS_RANK_PROF_ACTIVE)) { + WITNESS_RANK_PROF_ACTIVE, malloc_mutex_rank_exclusive)) { return true; } prof_gdump_val = opt_prof_gdump; if (malloc_mutex_init(&prof_gdump_mtx, "prof_gdump", - WITNESS_RANK_PROF_GDUMP)) { + WITNESS_RANK_PROF_GDUMP, malloc_mutex_rank_exclusive)) { return true; } prof_thread_active_init = opt_prof_thread_active_init; if (malloc_mutex_init(&prof_thread_active_init_mtx, "prof_thread_active_init", - WITNESS_RANK_PROF_THREAD_ACTIVE_INIT)) { + WITNESS_RANK_PROF_THREAD_ACTIVE_INIT, + malloc_mutex_rank_exclusive)) { return true; } @@ -2311,28 +2312,28 @@ prof_boot2(tsd_t *tsd) { return true; } if (malloc_mutex_init(&bt2gctx_mtx, "prof_bt2gctx", - WITNESS_RANK_PROF_BT2GCTX)) { + WITNESS_RANK_PROF_BT2GCTX, malloc_mutex_rank_exclusive)) { return true; } tdata_tree_new(&tdatas); if (malloc_mutex_init(&tdatas_mtx, "prof_tdatas", - WITNESS_RANK_PROF_TDATAS)) { + WITNESS_RANK_PROF_TDATAS, malloc_mutex_rank_exclusive)) { return true; } next_thr_uid = 0; if (malloc_mutex_init(&next_thr_uid_mtx, "prof_next_thr_uid", - WITNESS_RANK_PROF_NEXT_THR_UID)) { + WITNESS_RANK_PROF_NEXT_THR_UID, malloc_mutex_rank_exclusive)) { return true; } if (malloc_mutex_init(&prof_dump_seq_mtx, "prof_dump_seq", - WITNESS_RANK_PROF_DUMP_SEQ)) { + WITNESS_RANK_PROF_DUMP_SEQ, malloc_mutex_rank_exclusive)) { return true; } if (malloc_mutex_init(&prof_dump_mtx, "prof_dump", - WITNESS_RANK_PROF_DUMP)) { + WITNESS_RANK_PROF_DUMP, malloc_mutex_rank_exclusive)) { return true; } @@ -2352,7 +2353,8 @@ prof_boot2(tsd_t *tsd) { } for (i = 0; i < PROF_NCTX_LOCKS; i++) { if (malloc_mutex_init(&gctx_locks[i], "prof_gctx", - WITNESS_RANK_PROF_GCTX)) { + WITNESS_RANK_PROF_GCTX, + malloc_mutex_rank_exclusive)) { return true; } } @@ -2365,7 +2367,8 @@ prof_boot2(tsd_t *tsd) { } for (i = 0; i < PROF_NTDATA_LOCKS; i++) { if (malloc_mutex_init(&tdata_locks[i], "prof_tdata", - WITNESS_RANK_PROF_TDATA)) { + WITNESS_RANK_PROF_TDATA, + malloc_mutex_rank_exclusive)) { return true; } } diff --git a/src/rtree.c b/src/rtree.c index 62df0143..6d4a71a2 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -18,7 +18,8 @@ rtree_new(rtree_t *rtree, bool zeroed) { assert(zeroed); #endif - if (malloc_mutex_init(&rtree->init_lock, "rtree", WITNESS_RANK_RTREE)) { + if (malloc_mutex_init(&rtree->init_lock, "rtree", WITNESS_RANK_RTREE, + malloc_mutex_rank_exclusive)) { return true; } diff --git a/src/tcache.c b/src/tcache.c index ee5e816f..d9f5e7cb 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -649,7 +649,8 @@ tcache_boot(tsdn_t *tsdn) { tcache_maxclass = (ZU(1) << opt_lg_tcache_max); } - if (malloc_mutex_init(&tcaches_mtx, "tcaches", WITNESS_RANK_TCACHES)) { + if (malloc_mutex_init(&tcaches_mtx, "tcaches", WITNESS_RANK_TCACHES, + malloc_mutex_rank_exclusive)) { return true; } -- GitLab From 3f685e88245c9807d7bdcaffce47b0fe14b974be Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 15 May 2017 14:23:51 -0700 Subject: [PATCH 483/544] Protect the rtree/extent interactions with a mutex pool. Instead of embedding a lock bit in rtree leaf elements, we associate extents with a small set of mutexes. This gets us two things: - We can use the system mutexes. This (hypothetically) protects us from priority inversion, and lets us stop doing a backoff/sleep loop, instead opting for precise wakeups from the mutex. - Cuts down on the number of mutex acquisitions we have to do (from 4 in the worst case to two). We end up simplifying most of the rtree code (which no longer has to deal with locking or concurrency at all), at the cost of additional complexity in the extent code: since the mutex protecting the rtree leaf elements is determined by reading the extent out of those elements, the initial read is racy, so that we may acquire an out of date mutex. We re-check the extent in the leaf after acquiring the mutex to protect us from this race. --- Makefile.in | 1 + include/jemalloc/internal/extent_externs.h | 1 + include/jemalloc/internal/extent_inlines.h | 27 ++ .../internal/jemalloc_internal_includes.h | 2 + .../jemalloc/internal/mutex_pool_inlines.h | 89 +++++++ .../jemalloc/internal/mutex_pool_structs.h | 14 + include/jemalloc/internal/mutex_structs.h | 2 + include/jemalloc/internal/rtree_externs.h | 6 - include/jemalloc/internal/rtree_inlines.h | 214 +++------------ include/jemalloc/internal/rtree_structs.h | 6 +- include/jemalloc/internal/rtree_types.h | 23 -- include/jemalloc/internal/rtree_witness.h | 19 -- include/jemalloc/internal/tsd.h | 3 - include/jemalloc/internal/witness_types.h | 2 +- src/extent.c | 244 +++++++++++------- src/mutex_pool.c | 15 ++ src/rtree.c | 115 --------- test/unit/rtree.c | 93 +------ 18 files changed, 340 insertions(+), 536 deletions(-) create mode 100644 include/jemalloc/internal/mutex_pool_inlines.h create mode 100644 include/jemalloc/internal/mutex_pool_structs.h delete mode 100644 include/jemalloc/internal/rtree_witness.h create mode 100644 src/mutex_pool.c diff --git a/Makefile.in b/Makefile.in index 2f16fbf3..264b077c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -103,6 +103,7 @@ C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/large.c \ $(srcroot)src/malloc_io.c \ $(srcroot)src/mutex.c \ + $(srcroot)src/mutex_pool.c \ $(srcroot)src/nstime.c \ $(srcroot)src/pages.c \ $(srcroot)src/prng.c \ diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index c4fe8425..7a5b38c6 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -6,6 +6,7 @@ extern rtree_t extents_rtree; extern const extent_hooks_t extent_hooks_default; +extern mutex_pool_t extent_mutex_pool; extent_t *extent_alloc(tsdn_t *tsdn, arena_t *arena); void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent); diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index 0e6311d9..2ebd9452 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -1,10 +1,37 @@ #ifndef JEMALLOC_INTERNAL_EXTENT_INLINES_H #define JEMALLOC_INTERNAL_EXTENT_INLINES_H +#include "jemalloc/internal/mutex_pool_inlines.h" #include "jemalloc/internal/pages.h" #include "jemalloc/internal/prng.h" #include "jemalloc/internal/ql.h" +static inline void +extent_lock(tsdn_t *tsdn, extent_t *extent) { + assert(extent != NULL); + mutex_pool_lock(tsdn, &extent_mutex_pool, (uintptr_t)extent); +} + +static inline void +extent_unlock(tsdn_t *tsdn, extent_t *extent) { + assert(extent != NULL); + mutex_pool_unlock(tsdn, &extent_mutex_pool, (uintptr_t)extent); +} + +static inline void +extent_lock2(tsdn_t *tsdn, extent_t *extent1, extent_t *extent2) { + assert(extent1 != NULL && extent2 != NULL); + mutex_pool_lock2(tsdn, &extent_mutex_pool, (uintptr_t)extent1, + (uintptr_t)extent2); +} + +static inline void +extent_unlock2(tsdn_t *tsdn, extent_t *extent1, extent_t *extent2) { + assert(extent1 != NULL && extent2 != NULL); + mutex_pool_unlock2(tsdn, &extent_mutex_pool, (uintptr_t)extent1, + (uintptr_t)extent2); +} + static inline arena_t * extent_arena_get(const extent_t *extent) { unsigned arena_ind = (unsigned)((extent->e_bits & diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 84917a70..cf321c12 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -56,6 +56,7 @@ #include "jemalloc/internal/witness_structs.h" #include "jemalloc/internal/mutex_structs.h" +#include "jemalloc/internal/mutex_pool_structs.h" #include "jemalloc/internal/arena_structs_a.h" #include "jemalloc/internal/extent_structs.h" #include "jemalloc/internal/extent_dss_structs.h" @@ -88,6 +89,7 @@ #include "jemalloc/internal/witness_inlines.h" #include "jemalloc/internal/mutex_inlines.h" +#include "jemalloc/internal/mutex_pool_inlines.h" #include "jemalloc/internal/jemalloc_internal_inlines_a.h" #include "jemalloc/internal/rtree_inlines.h" #include "jemalloc/internal/base_inlines.h" diff --git a/include/jemalloc/internal/mutex_pool_inlines.h b/include/jemalloc/internal/mutex_pool_inlines.h new file mode 100644 index 00000000..0b667aaa --- /dev/null +++ b/include/jemalloc/internal/mutex_pool_inlines.h @@ -0,0 +1,89 @@ +#ifndef JEMALLOC_INTERNAL_MUTEX_POOL_INLINES_H +#define JEMALLOC_INTERNAL_MUTEX_POOL_INLINES_H + +#include "jemalloc/internal/hash.h" +#include "jemalloc/internal/mutex_inlines.h" +#include "jemalloc/internal/mutex_pool_structs.h" + +/* + * This file really combines "inlines" and "externs", but only transitionally. + */ + +bool mutex_pool_init(mutex_pool_t *pool, const char *name, witness_rank_t rank); + +static inline malloc_mutex_t * +mutex_pool_mutex(mutex_pool_t *pool, uintptr_t key) { + size_t hash_result[2]; + hash(&key, sizeof(key), 0xd50dcc1b, hash_result); + return &pool->mutexes[hash_result[0] % MUTEX_POOL_SIZE]; +} + +static inline void +mutex_pool_assert_not_held(tsdn_t *tsdn, mutex_pool_t *pool) { + for (int i = 0; i < MUTEX_POOL_SIZE; i++) { + malloc_mutex_assert_not_owner(tsdn, &pool->mutexes[i]); + } +} + +/* + * Note that a mutex pool doesn't work exactly the way an embdedded mutex would. + * You're not allowed to acquire mutexes in the pool one at a time. You have to + * acquire all the mutexes you'll need in a single function call, and then + * release them all in a single function call. + */ + +static inline void +mutex_pool_lock(tsdn_t *tsdn, mutex_pool_t *pool, uintptr_t key) { + mutex_pool_assert_not_held(tsdn, pool); + + malloc_mutex_t *mutex = mutex_pool_mutex(pool, key); + malloc_mutex_lock(tsdn, mutex); +} + +static inline void +mutex_pool_unlock(tsdn_t *tsdn, mutex_pool_t *pool, uintptr_t key) { + malloc_mutex_t *mutex = mutex_pool_mutex(pool, key); + malloc_mutex_unlock(tsdn, mutex); + + mutex_pool_assert_not_held(tsdn, pool); +} + +static inline void +mutex_pool_lock2(tsdn_t *tsdn, mutex_pool_t *pool, uintptr_t key1, + uintptr_t key2) { + mutex_pool_assert_not_held(tsdn, pool); + + malloc_mutex_t *mutex1 = mutex_pool_mutex(pool, key1); + malloc_mutex_t *mutex2 = mutex_pool_mutex(pool, key2); + if ((uintptr_t)mutex1 < (uintptr_t)mutex2) { + malloc_mutex_lock(tsdn, mutex1); + malloc_mutex_lock(tsdn, mutex2); + } else if ((uintptr_t)mutex1 == (uintptr_t)mutex2) { + malloc_mutex_lock(tsdn, mutex1); + } else { + malloc_mutex_lock(tsdn, mutex2); + malloc_mutex_lock(tsdn, mutex1); + } +} + +static inline void +mutex_pool_unlock2(tsdn_t *tsdn, mutex_pool_t *pool, uintptr_t key1, + uintptr_t key2) { + malloc_mutex_t *mutex1 = mutex_pool_mutex(pool, key1); + malloc_mutex_t *mutex2 = mutex_pool_mutex(pool, key2); + if (mutex1 == mutex2) { + malloc_mutex_unlock(tsdn, mutex1); + } else { + malloc_mutex_unlock(tsdn, mutex1); + malloc_mutex_unlock(tsdn, mutex2); + } + + mutex_pool_assert_not_held(tsdn, pool); +} + +static inline void +mutex_pool_assert_owner(tsdn_t *tsdn, mutex_pool_t *pool, uintptr_t key) { + malloc_mutex_assert_owner(tsdn, mutex_pool_mutex(pool, key)); +} + +#endif /* JEMALLOC_INTERNAL_MUTEX_POOL_INLINES_H */ diff --git a/include/jemalloc/internal/mutex_pool_structs.h b/include/jemalloc/internal/mutex_pool_structs.h new file mode 100644 index 00000000..a662166c --- /dev/null +++ b/include/jemalloc/internal/mutex_pool_structs.h @@ -0,0 +1,14 @@ +#ifndef JEMALLOC_INTERNAL_MUTEX_POOL_STRUCTS_H +#define JEMALLOC_INTERNAL_MUTEX_POOL_STRUCTS_H + +/* This file really combines "structs" and "types", but only transitionally. */ + +/* We do mod reductions by this value, so it should be kept a power of 2. */ +#define MUTEX_POOL_SIZE 256 + +typedef struct mutex_pool_s mutex_pool_t; +struct mutex_pool_s { + malloc_mutex_t mutexes[MUTEX_POOL_SIZE]; +}; + +#endif /* JEMALLOC_INTERNAL_MUTEX_POOL_STRUCTS_H */ diff --git a/include/jemalloc/internal/mutex_structs.h b/include/jemalloc/internal/mutex_structs.h index a8b16a16..92f41676 100644 --- a/include/jemalloc/internal/mutex_structs.h +++ b/include/jemalloc/internal/mutex_structs.h @@ -3,6 +3,8 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/mutex_prof.h" +#include "jemalloc/internal/witness_types.h" +#include "jemalloc/internal/witness_structs.h" struct malloc_mutex_s { union { diff --git a/include/jemalloc/internal/rtree_externs.h b/include/jemalloc/internal/rtree_externs.h index 5742f589..d7d81654 100644 --- a/include/jemalloc/internal/rtree_externs.h +++ b/include/jemalloc/internal/rtree_externs.h @@ -41,11 +41,5 @@ void rtree_delete(tsdn_t *tsdn, rtree_t *rtree); #endif rtree_leaf_elm_t *rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); -void rtree_leaf_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, - uintptr_t key, const rtree_leaf_elm_t *elm); -void rtree_leaf_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, - const rtree_leaf_elm_t *elm); -void rtree_leaf_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, - const rtree_leaf_elm_t *elm); #endif /* JEMALLOC_INTERNAL_RTREE_EXTERNS_H */ diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree_inlines.h index bcc2041a..335a89cf 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree_inlines.h @@ -47,21 +47,16 @@ rtree_subkey(uintptr_t key, unsigned level) { # ifdef RTREE_LEAF_COMPACT JEMALLOC_ALWAYS_INLINE uintptr_t rtree_leaf_elm_bits_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, - bool acquired, bool dependent) { - if (config_debug && acquired) { - assert(dependent); - rtree_leaf_elm_witness_access(tsdn, rtree, elm); - } - + bool dependent) { return (uintptr_t)atomic_load_p(&elm->le_bits, dependent ? ATOMIC_RELAXED : ATOMIC_ACQUIRE); } JEMALLOC_ALWAYS_INLINE extent_t * rtree_leaf_elm_bits_extent_get(uintptr_t bits) { - /* Restore sign-extended high bits, mask slab and lock bits. */ + /* Restore sign-extended high bits, mask slab bit. */ return (extent_t *)((uintptr_t)((intptr_t)(bits << RTREE_NHIB) >> - RTREE_NHIB) & ~((uintptr_t)0x3)); + RTREE_NHIB) & ~((uintptr_t)0x1)); } JEMALLOC_ALWAYS_INLINE szind_t @@ -71,51 +66,29 @@ rtree_leaf_elm_bits_szind_get(uintptr_t bits) { JEMALLOC_ALWAYS_INLINE bool rtree_leaf_elm_bits_slab_get(uintptr_t bits) { - return (bool)((bits >> 1) & (uintptr_t)0x1); -} - -JEMALLOC_ALWAYS_INLINE bool -rtree_leaf_elm_bits_locked_get(uintptr_t bits) { return (bool)(bits & (uintptr_t)0x1); } + # endif JEMALLOC_ALWAYS_INLINE extent_t * rtree_leaf_elm_extent_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, - bool acquired, bool dependent) { - if (config_debug && acquired) { - assert(dependent); - rtree_leaf_elm_witness_access(tsdn, rtree, elm); - } - + bool dependent) { #ifdef RTREE_LEAF_COMPACT - uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, acquired, - dependent); - assert(!acquired || rtree_leaf_elm_bits_locked_get(bits)); + uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent); return rtree_leaf_elm_bits_extent_get(bits); #else extent_t *extent = (extent_t *)atomic_load_p(&elm->le_extent, dependent ? ATOMIC_RELAXED : ATOMIC_ACQUIRE); - assert(!acquired || ((uintptr_t)extent & (uintptr_t)0x1) == - (uintptr_t)0x1); - /* Mask lock bit. */ - extent = (extent_t *)((uintptr_t)extent & ~((uintptr_t)0x1)); return extent; #endif } JEMALLOC_ALWAYS_INLINE szind_t rtree_leaf_elm_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, - bool acquired, bool dependent) { - if (config_debug && acquired) { - assert(dependent); - rtree_leaf_elm_witness_access(tsdn, rtree, elm); - } - + bool dependent) { #ifdef RTREE_LEAF_COMPACT - uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, acquired, - dependent); - assert(!acquired || rtree_leaf_elm_bits_locked_get(bits)); + uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent); return rtree_leaf_elm_bits_szind_get(bits); #else return (szind_t)atomic_load_u(&elm->le_szind, dependent ? ATOMIC_RELAXED @@ -125,16 +98,9 @@ rtree_leaf_elm_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, JEMALLOC_ALWAYS_INLINE bool rtree_leaf_elm_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, - bool acquired, bool dependent) { - if (config_debug && acquired) { - assert(dependent); - rtree_leaf_elm_witness_access(tsdn, rtree, elm); - } - + bool dependent) { #ifdef RTREE_LEAF_COMPACT - uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, acquired, - dependent); - assert(!acquired || rtree_leaf_elm_bits_locked_get(bits)); + uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent); return rtree_leaf_elm_bits_slab_get(bits); #else return atomic_load_b(&elm->le_slab, dependent ? ATOMIC_RELAXED : @@ -143,46 +109,31 @@ rtree_leaf_elm_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, } static inline void -rtree_leaf_elm_extent_lock_write(tsdn_t *tsdn, rtree_t *rtree, - rtree_leaf_elm_t *elm, bool acquired, extent_t *extent, bool lock) { - if (config_debug && acquired) { - rtree_leaf_elm_witness_access(tsdn, rtree, elm); - } - assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0); - +rtree_leaf_elm_extent_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, + extent_t *extent) { #ifdef RTREE_LEAF_COMPACT - uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, - acquired, acquired); + uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, true); uintptr_t bits = ((uintptr_t)rtree_leaf_elm_bits_szind_get(old_bits) << LG_VADDR) | ((uintptr_t)extent & (((uintptr_t)0x1 << LG_VADDR) - 1)) - | ((uintptr_t)rtree_leaf_elm_bits_slab_get(old_bits) << 1) | - (uintptr_t)lock; + | ((uintptr_t)rtree_leaf_elm_bits_slab_get(old_bits)); atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE); #else - if (lock) { - /* Overlay lock bit. */ - extent = (extent_t *)((uintptr_t)extent | (uintptr_t)0x1); - } atomic_store_p(&elm->le_extent, extent, ATOMIC_RELEASE); #endif } static inline void rtree_leaf_elm_szind_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, - bool acquired, szind_t szind) { - if (config_debug && acquired) { - rtree_leaf_elm_witness_access(tsdn, rtree, elm); - } + szind_t szind) { assert(szind <= NSIZES); #ifdef RTREE_LEAF_COMPACT uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, - acquired, acquired); + true); uintptr_t bits = ((uintptr_t)szind << LG_VADDR) | ((uintptr_t)rtree_leaf_elm_bits_extent_get(old_bits) & (((uintptr_t)0x1 << LG_VADDR) - 1)) | - ((uintptr_t)rtree_leaf_elm_bits_slab_get(old_bits) << 1) | - (uintptr_t)acquired; + ((uintptr_t)rtree_leaf_elm_bits_slab_get(old_bits)); atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE); #else atomic_store_u(&elm->le_szind, szind, ATOMIC_RELEASE); @@ -191,18 +142,13 @@ rtree_leaf_elm_szind_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, static inline void rtree_leaf_elm_slab_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, - bool acquired, bool slab) { - if (config_debug && acquired) { - rtree_leaf_elm_witness_access(tsdn, rtree, elm); - } - + bool slab) { #ifdef RTREE_LEAF_COMPACT uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, - acquired, acquired); + true); uintptr_t bits = ((uintptr_t)rtree_leaf_elm_bits_szind_get(old_bits) << LG_VADDR) | ((uintptr_t)rtree_leaf_elm_bits_extent_get(old_bits) & - (((uintptr_t)0x1 << LG_VADDR) - 1)) | ((uintptr_t)slab << 1) | - (uintptr_t)acquired; + (((uintptr_t)0x1 << LG_VADDR) - 1)) | ((uintptr_t)slab); atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE); #else atomic_store_b(&elm->le_slab, slab, ATOMIC_RELEASE); @@ -211,27 +157,20 @@ rtree_leaf_elm_slab_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, static inline void rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, - bool acquired, extent_t *extent, szind_t szind, bool slab) { - if (config_debug && acquired) { - rtree_leaf_elm_witness_access(tsdn, rtree, elm); - } - assert(!slab || szind < NBINS); - + extent_t *extent, szind_t szind, bool slab) { #ifdef RTREE_LEAF_COMPACT uintptr_t bits = ((uintptr_t)szind << LG_VADDR) | ((uintptr_t)extent & (((uintptr_t)0x1 << LG_VADDR) - 1)) | - ((uintptr_t)slab << 1) | - (uintptr_t)acquired; + ((uintptr_t)slab); atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE); #else - rtree_leaf_elm_slab_write(tsdn, rtree, elm, acquired, slab); - rtree_leaf_elm_szind_write(tsdn, rtree, elm, acquired, szind); + rtree_leaf_elm_slab_write(tsdn, rtree, elm, slab); + rtree_leaf_elm_szind_write(tsdn, rtree, elm, szind); /* * Write extent last, since the element is atomically considered valid * as soon as the extent field is non-NULL. */ - rtree_leaf_elm_extent_lock_write(tsdn, rtree, elm, acquired, extent, - acquired); + rtree_leaf_elm_extent_write(tsdn, rtree, elm, extent); #endif } @@ -244,32 +183,8 @@ rtree_leaf_elm_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, * The caller implicitly assures that it is the only writer to the szind * and slab fields, and that the extent field cannot currently change. */ -#ifdef RTREE_LEAF_COMPACT - /* - * Another thread may concurrently acquire the elm, which means that - * even though the szind and slab fields will not be concurrently - * modified by another thread, the fact that the lock is embedded in the - * same word requires that a CAS operation be used here. - */ - spin_t spinner = SPIN_INITIALIZER; - while (true) { - void *old_bits = (void *)(rtree_leaf_elm_bits_read(tsdn, rtree, - elm, false, true) & ~((uintptr_t)0x1)); /* Mask lock bit. */ - void *bits = (void *)(((uintptr_t)szind << LG_VADDR) | - ((uintptr_t)rtree_leaf_elm_bits_extent_get( - (uintptr_t)old_bits) & (((uintptr_t)0x1 << LG_VADDR) - 1)) | - ((uintptr_t)slab << 1)); - if (likely(atomic_compare_exchange_strong_p(&elm->le_bits, - &old_bits, bits, ATOMIC_ACQUIRE, ATOMIC_RELAXED))) { - break; - } - spin_adaptive(&spinner); - } -#else - /* No need to lock. */ - rtree_leaf_elm_slab_write(tsdn, rtree, elm, false, slab); - rtree_leaf_elm_szind_write(tsdn, rtree, elm, false, szind); -#endif + rtree_leaf_elm_slab_write(tsdn, rtree, elm, slab); + rtree_leaf_elm_szind_write(tsdn, rtree, elm, szind); } JEMALLOC_ALWAYS_INLINE rtree_leaf_elm_t * @@ -343,9 +258,8 @@ rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, return true; } - assert(rtree_leaf_elm_extent_read(tsdn, rtree, elm, false, false) == - NULL); - rtree_leaf_elm_write(tsdn, rtree, elm, false, extent, szind, slab); + assert(rtree_leaf_elm_extent_read(tsdn, rtree, elm, false) == NULL); + rtree_leaf_elm_write(tsdn, rtree, elm, extent, szind, slab); return false; } @@ -370,7 +284,7 @@ rtree_extent_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, if (!dependent && elm == NULL) { return NULL; } - return rtree_leaf_elm_extent_read(tsdn, rtree, elm, false, dependent); + return rtree_leaf_elm_extent_read(tsdn, rtree, elm, dependent); } JEMALLOC_ALWAYS_INLINE szind_t @@ -381,7 +295,7 @@ rtree_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, if (!dependent && elm == NULL) { return NSIZES; } - return rtree_leaf_elm_szind_read(tsdn, rtree, elm, false, dependent); + return rtree_leaf_elm_szind_read(tsdn, rtree, elm, dependent); } /* @@ -397,10 +311,8 @@ rtree_extent_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, if (!dependent && elm == NULL) { return true; } - *r_extent = rtree_leaf_elm_extent_read(tsdn, rtree, elm, false, - dependent); - *r_szind = rtree_leaf_elm_szind_read(tsdn, rtree, elm, false, - dependent); + *r_extent = rtree_leaf_elm_extent_read(tsdn, rtree, elm, dependent); + *r_szind = rtree_leaf_elm_szind_read(tsdn, rtree, elm, dependent); return false; } @@ -412,63 +324,11 @@ rtree_szind_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, if (!dependent && elm == NULL) { return true; } - *r_szind = rtree_leaf_elm_szind_read(tsdn, rtree, elm, false, - dependent); - *r_slab = rtree_leaf_elm_slab_read(tsdn, rtree, elm, false, dependent); + *r_szind = rtree_leaf_elm_szind_read(tsdn, rtree, elm, dependent); + *r_slab = rtree_leaf_elm_slab_read(tsdn, rtree, elm, dependent); return false; } -static inline rtree_leaf_elm_t * -rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, - uintptr_t key, bool dependent, bool init_missing) { - rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, - key, dependent, init_missing); - if (!dependent && elm == NULL) { - return NULL; - } - assert(elm != NULL); - - spin_t spinner = SPIN_INITIALIZER; - while (true) { - /* The least significant bit serves as a lock. */ -#ifdef RTREE_LEAF_COMPACT -# define RTREE_FIELD_WITH_LOCK le_bits -#else -# define RTREE_FIELD_WITH_LOCK le_extent -#endif - void *bits = atomic_load_p(&elm->RTREE_FIELD_WITH_LOCK, - ATOMIC_RELAXED); - if (likely(((uintptr_t)bits & (uintptr_t)0x1) == 0)) { - void *locked = (void *)((uintptr_t)bits | - (uintptr_t)0x1); - if (likely(atomic_compare_exchange_strong_p( - &elm->RTREE_FIELD_WITH_LOCK, &bits, locked, - ATOMIC_ACQUIRE, ATOMIC_RELAXED))) { - break; - } - } - spin_adaptive(&spinner); -#undef RTREE_FIELD_WITH_LOCK - } - - if (config_debug) { - rtree_leaf_elm_witness_acquire(tsdn, rtree, key, elm); - } - - return elm; -} - -static inline void -rtree_leaf_elm_release(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm) { - extent_t *extent = rtree_leaf_elm_extent_read(tsdn, rtree, elm, true, - true); - rtree_leaf_elm_extent_lock_write(tsdn, rtree, elm, true, extent, false); - - if (config_debug) { - rtree_leaf_elm_witness_release(tsdn, rtree, elm); - } -} - static inline void rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key, szind_t szind, bool slab) { @@ -482,9 +342,9 @@ static inline void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key) { rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true); - assert(rtree_leaf_elm_extent_read(tsdn, rtree, elm, false, false) != + assert(rtree_leaf_elm_extent_read(tsdn, rtree, elm, false) != NULL); - rtree_leaf_elm_write(tsdn, rtree, elm, false, NULL, NSIZES, false); + rtree_leaf_elm_write(tsdn, rtree, elm, NULL, NSIZES, false); } #endif /* JEMALLOC_INTERNAL_RTREE_INLINES_H */ diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h index 4418934f..ba0f96d0 100644 --- a/include/jemalloc/internal/rtree_structs.h +++ b/include/jemalloc/internal/rtree_structs.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_RTREE_STRUCTS_H #include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/mutex_pool_structs.h" struct rtree_node_elm_s { atomic_p_t child; /* (rtree_{node,leaf}_elm_t *) */ @@ -18,13 +19,12 @@ struct rtree_leaf_elm_s { * x: index * e: extent * b: slab - * k: lock * - * 00000000 xxxxxxxx eeeeeeee [...] eeeeeeee eeee00bk + * 00000000 xxxxxxxx eeeeeeee [...] eeeeeeee eeee000b */ atomic_p_t le_bits; #else - atomic_p_t le_extent; /* (extent_t *), lock in low bit */ + atomic_p_t le_extent; /* (extent_t *) */ atomic_u_t le_szind; /* (szind_t) */ atomic_b_t le_slab; /* (bool) */ #endif diff --git a/include/jemalloc/internal/rtree_types.h b/include/jemalloc/internal/rtree_types.h index b465086d..fd0f1409 100644 --- a/include/jemalloc/internal/rtree_types.h +++ b/include/jemalloc/internal/rtree_types.h @@ -66,27 +66,4 @@ typedef struct rtree_s rtree_t; */ #define RTREE_CTX_ZERO_INITIALIZER {{{0}}} -/* - * Maximum number of concurrently acquired elements per thread. This controls - * how many witness_t structures are embedded in tsd. Ideally rtree_leaf_elm_t - * would have a witness_t directly embedded, but that would dramatically bloat - * the tree. This must contain enough entries to e.g. coalesce two extents. - */ -#define RTREE_ELM_ACQUIRE_MAX 4 - -/* Initializers for rtree_leaf_elm_witness_tsd_t. */ -#define RTREE_ELM_WITNESS_INITIALIZER { \ - NULL, \ - WITNESS_INITIALIZER("rtree_leaf_elm", WITNESS_RANK_RTREE_ELM) \ -} - -#define RTREE_ELM_WITNESS_TSD_INITIALIZER { \ - { \ - RTREE_ELM_WITNESS_INITIALIZER, \ - RTREE_ELM_WITNESS_INITIALIZER, \ - RTREE_ELM_WITNESS_INITIALIZER, \ - RTREE_ELM_WITNESS_INITIALIZER \ - } \ -} - #endif /* JEMALLOC_INTERNAL_RTREE_TYPES_H */ diff --git a/include/jemalloc/internal/rtree_witness.h b/include/jemalloc/internal/rtree_witness.h deleted file mode 100644 index 4a136203..00000000 --- a/include/jemalloc/internal/rtree_witness.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_RTREE_WITNESS_H -#define JEMALLOC_INTERNAL_RTREE_WITNESS_H - -#include "jemalloc/internal/rtree_types.h" -#include "jemalloc/internal/witness_types.h" -#include "jemalloc/internal/witness_structs.h" - -typedef struct rtree_leaf_elm_witness_s rtree_leaf_elm_witness_t; -struct rtree_leaf_elm_witness_s { - const rtree_leaf_elm_t *elm; - witness_t witness; -}; - -typedef struct rtree_leaf_elm_witness_tsd_s rtree_leaf_elm_witness_tsd_t; -struct rtree_leaf_elm_witness_tsd_s { - rtree_leaf_elm_witness_t witnesses[RTREE_ELM_ACQUIRE_MAX]; -}; - -#endif /* JEMALLOC_INTERNAL_RTREE_WITNESS_H */ diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h index 3d6576b4..1a269755 100644 --- a/include/jemalloc/internal/tsd.h +++ b/include/jemalloc/internal/tsd.h @@ -7,7 +7,6 @@ #include "jemalloc/internal/prof_types.h" #include "jemalloc/internal/ql.h" #include "jemalloc/internal/rtree_ctx.h" -#include "jemalloc/internal/rtree_witness.h" #include "jemalloc/internal/tcache_types.h" #include "jemalloc/internal/tcache_structs.h" #include "jemalloc/internal/util.h" @@ -76,7 +75,6 @@ typedef void (*test_callback_t)(int *); O(arenas_tdata, arena_tdata_t *) \ O(tcache, tcache_t) \ O(witnesses, witness_list_t) \ - O(rtree_leaf_elm_witnesses, rtree_leaf_elm_witness_tsd_t) \ O(witness_fork, bool) \ MALLOC_TEST_TSD @@ -95,7 +93,6 @@ typedef void (*test_callback_t)(int *); NULL, \ TCACHE_ZERO_INITIALIZER, \ ql_head_initializer(witnesses), \ - RTREE_ELM_WITNESS_TSD_INITIALIZER, \ false \ MALLOC_TEST_TSD_INITIALIZER \ } diff --git a/include/jemalloc/internal/witness_types.h b/include/jemalloc/internal/witness_types.h index d43a363b..f686702e 100644 --- a/include/jemalloc/internal/witness_types.h +++ b/include/jemalloc/internal/witness_types.h @@ -41,7 +41,7 @@ typedef int witness_comp_t (const witness_t *, void *, const witness_t *, #define WITNESS_RANK_EXTENTS 11U #define WITNESS_RANK_EXTENT_FREELIST 12U -#define WITNESS_RANK_RTREE_ELM 13U +#define WITNESS_RANK_EXTENT_POOL 13U #define WITNESS_RANK_RTREE 14U #define WITNESS_RANK_BASE 15U #define WITNESS_RANK_ARENA_LARGE 16U diff --git a/src/extent.c b/src/extent.c index 513d16d5..6503f2a1 100644 --- a/src/extent.c +++ b/src/extent.c @@ -5,11 +5,12 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/ph.h" - /******************************************************************************/ /* Data. */ rtree_t extents_rtree; +/* Keyed by the address of the extent_t being protected. */ +mutex_pool_t extent_mutex_pool; static const bitmap_info_t extents_bitmap_info = BITMAP_INFO_INITIALIZER(NPSIZES+1); @@ -95,6 +96,57 @@ static void extent_record(tsdn_t *tsdn, arena_t *arena, rb_gen(UNUSED, extent_avail_, extent_tree_t, extent_t, rb_link, extent_esnead_comp) +typedef enum { + lock_result_success, + lock_result_failure, + lock_result_no_extent +} lock_result_t; + +static lock_result_t +extent_rtree_leaf_elm_try_lock(tsdn_t *tsdn, rtree_leaf_elm_t *elm, + extent_t **result) { + extent_t *extent1 = rtree_leaf_elm_extent_read(tsdn, &extents_rtree, + elm, true); + + if (extent1 == NULL) { + return lock_result_no_extent; + } + /* + * It's possible that the extent changed out from under us, and with it + * the leaf->extent mapping. We have to recheck while holding the lock. + */ + extent_lock(tsdn, extent1); + extent_t *extent2 = rtree_leaf_elm_extent_read(tsdn, + &extents_rtree, elm, true); + + if (extent1 == extent2) { + *result = extent1; + return lock_result_success; + } else { + extent_unlock(tsdn, extent1); + return lock_result_failure; + } +} + +/* + * Returns a pool-locked extent_t * if there's one associated with the given + * address, and NULL otherwise. + */ +static extent_t * +extent_lock_from_addr(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, void *addr) { + extent_t *ret = NULL; + rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, &extents_rtree, + rtree_ctx, (uintptr_t)addr, false, false); + if (elm == NULL) { + return NULL; + } + lock_result_t lock_result; + do { + lock_result = extent_rtree_leaf_elm_try_lock(tsdn, elm, &ret); + } while (lock_result == lock_result_failure); + return ret; +} + extent_t * extent_alloc(tsdn_t *tsdn, arena_t *arena) { witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); @@ -508,28 +560,22 @@ extent_activate_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, } static bool -extent_rtree_acquire(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, +extent_rtree_leaf_elms_lookup(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, const extent_t *extent, bool dependent, bool init_missing, rtree_leaf_elm_t **r_elm_a, rtree_leaf_elm_t **r_elm_b) { - *r_elm_a = rtree_leaf_elm_acquire(tsdn, &extents_rtree, rtree_ctx, + *r_elm_a = rtree_leaf_elm_lookup(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_base_get(extent), dependent, init_missing); if (!dependent && *r_elm_a == NULL) { return true; } assert(*r_elm_a != NULL); - if (extent_size_get(extent) > PAGE) { - *r_elm_b = rtree_leaf_elm_acquire(tsdn, &extents_rtree, - rtree_ctx, (uintptr_t)extent_last_get(extent), dependent, - init_missing); - if (!dependent && *r_elm_b == NULL) { - rtree_leaf_elm_release(tsdn, &extents_rtree, *r_elm_a); - return true; - } - assert(*r_elm_b != NULL); - } else { - *r_elm_b = NULL; + *r_elm_b = rtree_leaf_elm_lookup(tsdn, &extents_rtree, rtree_ctx, + (uintptr_t)extent_last_get(extent), dependent, init_missing); + if (!dependent && *r_elm_b == NULL) { + return true; } + assert(*r_elm_b != NULL); return false; } @@ -537,20 +583,10 @@ extent_rtree_acquire(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, static void extent_rtree_write_acquired(tsdn_t *tsdn, rtree_leaf_elm_t *elm_a, rtree_leaf_elm_t *elm_b, extent_t *extent, szind_t szind, bool slab) { - rtree_leaf_elm_write(tsdn, &extents_rtree, elm_a, true, extent, szind, - slab); + rtree_leaf_elm_write(tsdn, &extents_rtree, elm_a, extent, szind, slab); if (elm_b != NULL) { - rtree_leaf_elm_write(tsdn, &extents_rtree, elm_b, true, extent, - szind, slab); - } -} - -static void -extent_rtree_release(tsdn_t *tsdn, rtree_leaf_elm_t *elm_a, - rtree_leaf_elm_t *elm_b) { - rtree_leaf_elm_release(tsdn, &extents_rtree, elm_a); - if (elm_b != NULL) { - rtree_leaf_elm_release(tsdn, &extents_rtree, elm_b); + rtree_leaf_elm_write(tsdn, &extents_rtree, elm_b, extent, szind, + slab); } } @@ -609,17 +645,25 @@ extent_register_impl(tsdn_t *tsdn, extent_t *extent, bool gdump_add) { rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_leaf_elm_t *elm_a, *elm_b; - if (extent_rtree_acquire(tsdn, rtree_ctx, extent, false, true, &elm_a, - &elm_b)) { + /* + * We need to hold the lock to protect against a concurrent coalesce + * operation that sees us in a partial state. + */ + extent_lock(tsdn, extent); + + if (extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, extent, false, true, + &elm_a, &elm_b)) { return true; } + szind_t szind = extent_szind_get_maybe_invalid(extent); bool slab = extent_slab_get(extent); extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent, szind, slab); if (slab) { extent_interior_register(tsdn, rtree_ctx, extent, szind); } - extent_rtree_release(tsdn, elm_a, elm_b); + + extent_unlock(tsdn, extent); if (config_prof && gdump_add) { extent_gdump_add(tsdn, extent); @@ -663,15 +707,18 @@ extent_deregister(tsdn_t *tsdn, extent_t *extent) { rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_leaf_elm_t *elm_a, *elm_b; + extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, extent, true, false, + &elm_a, &elm_b); + + extent_lock(tsdn, extent); - extent_rtree_acquire(tsdn, rtree_ctx, extent, true, false, &elm_a, - &elm_b); extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL, NSIZES, false); if (extent_slab_get(extent)) { extent_interior_deregister(tsdn, rtree_ctx, extent); extent_slab_set(extent, false); } - extent_rtree_release(tsdn, elm_a, elm_b); + + extent_unlock(tsdn, extent); if (config_prof) { extent_gdump_sub(tsdn, extent); @@ -717,24 +764,21 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, extent_hooks_assure_initialized(arena, r_extent_hooks); extent_t *extent; if (new_addr != NULL) { - rtree_leaf_elm_t *elm = rtree_leaf_elm_acquire(tsdn, - &extents_rtree, rtree_ctx, (uintptr_t)new_addr, false, - false); - if (elm != NULL) { - extent = rtree_leaf_elm_extent_read(tsdn, - &extents_rtree, elm, true, true); - if (extent != NULL) { - assert(extent_base_get(extent) == new_addr); - if (extent_arena_get(extent) != arena || - extent_size_get(extent) < esize || - extent_state_get(extent) != - extents_state_get(extents)) { - extent = NULL; - } + extent = extent_lock_from_addr(tsdn, rtree_ctx, new_addr); + if (extent != NULL) { + /* + * We might null-out extent to report an error, but we + * still need to unlock the associated mutex after. + */ + extent_t *unlock_extent = extent; + assert(extent_base_get(extent) == new_addr); + if (extent_arena_get(extent) != arena || + extent_size_get(extent) < esize || + extent_state_get(extent) != + extents_state_get(extents)) { + extent = NULL; } - rtree_leaf_elm_release(tsdn, &extents_rtree, elm); - } else { - extent = NULL; + extent_unlock(tsdn, unlock_extent); } } else { extent = extents_fit_locked(tsdn, arena, extents, alloc_size); @@ -1254,20 +1298,19 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, again = false; /* Try to coalesce forward. */ - rtree_leaf_elm_t *next_elm = rtree_leaf_elm_acquire(tsdn, - &extents_rtree, rtree_ctx, - (uintptr_t)extent_past_get(extent), false, false); - if (next_elm != NULL) { - extent_t *next = rtree_leaf_elm_extent_read(tsdn, - &extents_rtree, next_elm, true, true); + extent_t *next = extent_lock_from_addr(tsdn, rtree_ctx, + extent_past_get(extent)); + if (next != NULL) { /* * extents->mtx only protects against races for * like-state extents, so call extent_can_coalesce() - * before releasing the next_elm lock. + * before releasing next's pool lock. */ - bool can_coalesce = (next != NULL && - extent_can_coalesce(arena, extents, extent, next)); - rtree_leaf_elm_release(tsdn, &extents_rtree, next_elm); + bool can_coalesce = extent_can_coalesce(arena, extents, + extent, next); + + extent_unlock(tsdn, next); + if (can_coalesce && !extent_coalesce(tsdn, arena, r_extent_hooks, extents, extent, next, true)) { if (extents->delay_coalesce) { @@ -1280,15 +1323,13 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, } /* Try to coalesce backward. */ - rtree_leaf_elm_t *prev_elm = rtree_leaf_elm_acquire(tsdn, - &extents_rtree, rtree_ctx, - (uintptr_t)extent_before_get(extent), false, false); - if (prev_elm != NULL) { - extent_t *prev = rtree_leaf_elm_extent_read(tsdn, - &extents_rtree, prev_elm, true, true); - bool can_coalesce = (prev != NULL && - extent_can_coalesce(arena, extents, extent, prev)); - rtree_leaf_elm_release(tsdn, &extents_rtree, prev_elm); + extent_t *prev = extent_lock_from_addr(tsdn, rtree_ctx, + extent_before_get(extent)); + if (prev != NULL) { + bool can_coalesce = extent_can_coalesce(arena, extents, + extent, prev); + extent_unlock(tsdn, prev); + if (can_coalesce && !extent_coalesce(tsdn, arena, r_extent_hooks, extents, extent, prev, false)) { extent = prev; @@ -1610,22 +1651,25 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, assert(extent_size_get(extent) == size_a + size_b); witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); - extent_t *trail; - rtree_ctx_t rtree_ctx_fallback; - rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - rtree_leaf_elm_t *lead_elm_a, *lead_elm_b, *trail_elm_a, *trail_elm_b; - extent_hooks_assure_initialized(arena, r_extent_hooks); if ((*r_extent_hooks)->split == NULL) { return NULL; } - trail = extent_alloc(tsdn, arena); + extent_t *trail = extent_alloc(tsdn, arena); if (trail == NULL) { goto label_error_a; } + extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) + + size_a), size_b, slab_b, szind_b, extent_sn_get(extent), + extent_state_get(extent), extent_zeroed_get(extent), + extent_committed_get(extent)); + + rtree_ctx_t rtree_ctx_fallback; + rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); + rtree_leaf_elm_t *lead_elm_a, *lead_elm_b; { extent_t lead; @@ -1634,25 +1678,24 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_state_get(extent), extent_zeroed_get(extent), extent_committed_get(extent)); - if (extent_rtree_acquire(tsdn, rtree_ctx, &lead, false, true, - &lead_elm_a, &lead_elm_b)) { - goto label_error_b; - } + extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, &lead, false, + true, &lead_elm_a, &lead_elm_b); } + rtree_leaf_elm_t *trail_elm_a, *trail_elm_b; + extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, trail, false, true, + &trail_elm_a, &trail_elm_b); - extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) + - size_a), size_b, slab_b, szind_b, extent_sn_get(extent), - extent_state_get(extent), extent_zeroed_get(extent), - extent_committed_get(extent)); - if (extent_rtree_acquire(tsdn, rtree_ctx, trail, false, true, - &trail_elm_a, &trail_elm_b)) { - goto label_error_c; + if (lead_elm_a == NULL || lead_elm_b == NULL || trail_elm_a == NULL + || trail_elm_b == NULL) { + goto label_error_b; } + extent_lock2(tsdn, extent, trail); + if ((*r_extent_hooks)->split(*r_extent_hooks, extent_base_get(extent), size_a + size_b, size_a, size_b, extent_committed_get(extent), arena_ind_get(arena))) { - goto label_error_d; + goto label_error_c; } extent_size_set(extent, size_a); @@ -1663,14 +1706,11 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_rtree_write_acquired(tsdn, trail_elm_a, trail_elm_b, trail, szind_b, slab_b); - extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); - extent_rtree_release(tsdn, trail_elm_a, trail_elm_b); + extent_unlock2(tsdn, extent, trail); return trail; -label_error_d: - extent_rtree_release(tsdn, trail_elm_a, trail_elm_b); label_error_c: - extent_rtree_release(tsdn, lead_elm_a, lead_elm_b); + extent_unlock2(tsdn, extent, trail); label_error_b: extent_dalloc(tsdn, arena, trail); label_error_a: @@ -1734,20 +1774,20 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); rtree_leaf_elm_t *a_elm_a, *a_elm_b, *b_elm_a, *b_elm_b; - extent_rtree_acquire(tsdn, rtree_ctx, a, true, false, &a_elm_a, + extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, a, true, false, &a_elm_a, &a_elm_b); - extent_rtree_acquire(tsdn, rtree_ctx, b, true, false, &b_elm_a, + extent_rtree_leaf_elms_lookup(tsdn, rtree_ctx, b, true, false, &b_elm_a, &b_elm_b); + extent_lock2(tsdn, a, b); + if (a_elm_b != NULL) { - rtree_leaf_elm_write(tsdn, &extents_rtree, a_elm_b, true, NULL, + rtree_leaf_elm_write(tsdn, &extents_rtree, a_elm_b, NULL, NSIZES, false); - rtree_leaf_elm_release(tsdn, &extents_rtree, a_elm_b); } if (b_elm_b != NULL) { - rtree_leaf_elm_write(tsdn, &extents_rtree, b_elm_a, true, NULL, + rtree_leaf_elm_write(tsdn, &extents_rtree, b_elm_a, NULL, NSIZES, false); - rtree_leaf_elm_release(tsdn, &extents_rtree, b_elm_a); } else { b_elm_b = b_elm_a; } @@ -1759,7 +1799,8 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b)); extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a, NSIZES, false); - extent_rtree_release(tsdn, a_elm_a, b_elm_b); + + extent_unlock2(tsdn, a, b); extent_dalloc(tsdn, extent_arena_get(b), b); @@ -1772,6 +1813,11 @@ extent_boot(void) { return true; } + if (mutex_pool_init(&extent_mutex_pool, "extent_mutex_pool", + WITNESS_RANK_EXTENT_POOL)) { + return true; + } + if (have_dss) { extent_dss_boot(); } diff --git a/src/mutex_pool.c b/src/mutex_pool.c new file mode 100644 index 00000000..004d6d0f --- /dev/null +++ b/src/mutex_pool.c @@ -0,0 +1,15 @@ +#define JEMALLOC_MUTEX_POOL_C_ + +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" + +bool +mutex_pool_init(mutex_pool_t *pool, const char *name, witness_rank_t rank) { + for (int i = 0; i < MUTEX_POOL_SIZE; ++i) { + if (malloc_mutex_init(&pool->mutexes[i], name, rank, + malloc_mutex_address_ordered)) { + return true; + } + } + return false; +} diff --git a/src/rtree.c b/src/rtree.c index 6d4a71a2..637853c7 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -304,121 +304,6 @@ rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, not_reached(); } -static int -rtree_leaf_elm_witness_comp(const witness_t *a, void *oa, const witness_t *b, - void *ob) { - uintptr_t ka = (uintptr_t)oa; - uintptr_t kb = (uintptr_t)ob; - - assert(ka != 0); - assert(kb != 0); - - return (ka > kb) - (ka < kb); -} - -static witness_t * -rtree_leaf_elm_witness_alloc(tsd_t *tsd, uintptr_t key, - const rtree_leaf_elm_t *elm) { - witness_t *witness; - size_t i; - rtree_leaf_elm_witness_tsd_t *witnesses = - tsd_rtree_leaf_elm_witnessesp_get(tsd); - - /* Iterate over entire array to detect double allocation attempts. */ - witness = NULL; - for (i = 0; i < RTREE_ELM_ACQUIRE_MAX; i++) { - rtree_leaf_elm_witness_t *rew = &witnesses->witnesses[i]; - - assert(rew->elm != elm); - if (rew->elm == NULL && witness == NULL) { - rew->elm = elm; - witness = &rew->witness; - witness_init(witness, "rtree_leaf_elm", - WITNESS_RANK_RTREE_ELM, rtree_leaf_elm_witness_comp, - (void *)key); - } - } - assert(witness != NULL); - return witness; -} - -static witness_t * -rtree_leaf_elm_witness_find(tsd_t *tsd, const rtree_leaf_elm_t *elm) { - size_t i; - rtree_leaf_elm_witness_tsd_t *witnesses = - tsd_rtree_leaf_elm_witnessesp_get(tsd); - - for (i = 0; i < RTREE_ELM_ACQUIRE_MAX; i++) { - rtree_leaf_elm_witness_t *rew = &witnesses->witnesses[i]; - - if (rew->elm == elm) { - return &rew->witness; - } - } - not_reached(); -} - -static void -rtree_leaf_elm_witness_dalloc(tsd_t *tsd, witness_t *witness, - const rtree_leaf_elm_t *elm) { - size_t i; - rtree_leaf_elm_witness_tsd_t *witnesses = - tsd_rtree_leaf_elm_witnessesp_get(tsd); - - for (i = 0; i < RTREE_ELM_ACQUIRE_MAX; i++) { - rtree_leaf_elm_witness_t *rew = &witnesses->witnesses[i]; - - if (rew->elm == elm) { - rew->elm = NULL; - witness_init(&rew->witness, "rtree_leaf_elm", - WITNESS_RANK_RTREE_ELM, rtree_leaf_elm_witness_comp, - NULL); - return; - } - } - not_reached(); -} - -void -rtree_leaf_elm_witness_acquire(tsdn_t *tsdn, const rtree_t *rtree, - uintptr_t key, const rtree_leaf_elm_t *elm) { - witness_t *witness; - - if (tsdn_null(tsdn)) { - return; - } - - witness = rtree_leaf_elm_witness_alloc(tsdn_tsd(tsdn), key, elm); - witness_lock(tsdn, witness); -} - -void -rtree_leaf_elm_witness_access(tsdn_t *tsdn, const rtree_t *rtree, - const rtree_leaf_elm_t *elm) { - witness_t *witness; - - if (tsdn_null(tsdn)) { - return; - } - - witness = rtree_leaf_elm_witness_find(tsdn_tsd(tsdn), elm); - witness_assert_owner(tsdn, witness); -} - -void -rtree_leaf_elm_witness_release(tsdn_t *tsdn, const rtree_t *rtree, - const rtree_leaf_elm_t *elm) { - witness_t *witness; - - if (tsdn_null(tsdn)) { - return; - } - - witness = rtree_leaf_elm_witness_find(tsdn_tsd(tsdn), elm); - witness_unlock(tsdn, witness); - rtree_leaf_elm_witness_dalloc(tsdn_tsd(tsdn), witness, elm); -} - void rtree_ctx_data_init(rtree_ctx_t *ctx) { for (unsigned i = 0; i < RTREE_CTX_NCACHE; i++) { diff --git a/test/unit/rtree.c b/test/unit/rtree.c index 3c5b2df4..b854afd7 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -77,90 +77,6 @@ TEST_BEGIN(test_rtree_read_empty) { } TEST_END -#define NTHREADS 8 -#define MAX_NBITS 30 -#define NITERS 1000 -#define SEED 42 - -typedef struct { - rtree_t *rtree; - uint32_t seed; -} thd_start_arg_t; - -static void * -thd_start(void *varg) { - thd_start_arg_t *arg = (thd_start_arg_t *)varg; - rtree_ctx_t rtree_ctx; - rtree_ctx_data_init(&rtree_ctx); - sfmt_t *sfmt; - extent_t *extent; - tsdn_t *tsdn; - unsigned i; - - sfmt = init_gen_rand(arg->seed); - extent = (extent_t *)malloc(sizeof(extent)); - assert_ptr_not_null(extent, "Unexpected malloc() failure"); - extent_init(extent, NULL, NULL, 0, false, NSIZES, 0, - extent_state_active, false, false); - tsdn = tsdn_fetch(); - - for (i = 0; i < NITERS; i++) { - uintptr_t key = (uintptr_t)(gen_rand64(sfmt) & ((ZU(1) << - MAX_NBITS) - ZU(1))); - if (i % 2 == 0) { - rtree_leaf_elm_t *elm = rtree_leaf_elm_acquire(tsdn, - arg->rtree, &rtree_ctx, key, false, true); - assert_ptr_not_null(elm, - "Unexpected rtree_leaf_elm_acquire() failure"); - rtree_leaf_elm_write(tsdn, arg->rtree, elm, true, - extent, NSIZES, false); - rtree_leaf_elm_release(tsdn, arg->rtree, elm); - - elm = rtree_leaf_elm_acquire(tsdn, arg->rtree, - &rtree_ctx, key, true, false); - assert_ptr_not_null(elm, - "Unexpected rtree_leaf_elm_acquire() failure"); - rtree_leaf_elm_extent_read(tsdn, arg->rtree, elm, true, - true); - rtree_leaf_elm_szind_read(tsdn, arg->rtree, elm, true, - true); - rtree_leaf_elm_slab_read(tsdn, arg->rtree, elm, true, - true); - rtree_leaf_elm_release(tsdn, arg->rtree, elm); - } else { - rtree_extent_read(tsdn, arg->rtree, &rtree_ctx, key, - false); - } - } - - free(extent); - fini_gen_rand(sfmt); - return NULL; -} - -TEST_BEGIN(test_rtree_concurrent) { - thd_start_arg_t arg; - thd_t thds[NTHREADS]; - sfmt_t *sfmt; - tsdn_t *tsdn; - - sfmt = init_gen_rand(SEED); - tsdn = tsdn_fetch(); - arg.rtree = &test_rtree; - assert_false(rtree_new(arg.rtree, false), - "Unexpected rtree_new() failure"); - arg.seed = gen_rand32(sfmt); - for (unsigned i = 0; i < NTHREADS; i++) { - thd_create(&thds[i], thd_start, (void *)&arg); - } - for (unsigned i = 0; i < NTHREADS; i++) { - thd_join(thds[i], NULL); - } - rtree_delete(tsdn, arg.rtree); - fini_gen_rand(sfmt); -} -TEST_END - #undef NTHREADS #undef NITERS #undef SEED @@ -254,13 +170,11 @@ TEST_BEGIN(test_rtree_random) { for (unsigned i = 0; i < NSET; i++) { keys[i] = (uintptr_t)gen_rand64(sfmt); - rtree_leaf_elm_t *elm = rtree_leaf_elm_acquire(tsdn, rtree, + rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, &rtree_ctx, keys[i], false, true); assert_ptr_not_null(elm, - "Unexpected rtree_leaf_elm_acquire() failure"); - rtree_leaf_elm_write(tsdn, rtree, elm, true, &extent, NSIZES, - false); - rtree_leaf_elm_release(tsdn, rtree, elm); + "Unexpected rtree_leaf_elm_lookup() failure"); + rtree_leaf_elm_write(tsdn, rtree, elm, &extent, NSIZES, false); assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx, keys[i], true), &extent, "rtree_extent_read() should return previously set value"); @@ -304,7 +218,6 @@ main(void) { return test( test_rtree_read_empty, - test_rtree_concurrent, test_rtree_extrema, test_rtree_bits, test_rtree_random); -- GitLab From b693c7868ea965407aca4cb01fdb8fe9af14adce Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 17 Mar 2017 12:42:33 -0700 Subject: [PATCH 484/544] Implementing opt.background_thread. Added opt.background_thread to enable background threads, which handles purging currently. When enabled, decay ticks will not trigger purging (which will be left to the background threads). We limit the max number of threads to NCPUs. When percpu arena is enabled, set CPU affinity for the background threads as well. The sleep interval of background threads is dynamic and determined by computing number of pages to purge in the future (based on backlog). --- Makefile.in | 1 + configure.ac | 32 +- include/jemalloc/internal/arena_externs.h | 83 +-- include/jemalloc/internal/arena_inlines_b.h | 2 +- .../internal/background_thread_externs.h | 29 + .../internal/background_thread_inlines.h | 21 + .../internal/background_thread_structs.h | 25 + .../internal/jemalloc_internal_defs.h.in | 9 + .../internal/jemalloc_internal_includes.h | 3 + .../jemalloc/internal/jemalloc_preamble.h.in | 13 + include/jemalloc/internal/smoothstep.h | 402 ++++++------ include/jemalloc/internal/smoothstep.sh | 6 +- include/jemalloc/internal/witness_types.h | 32 +- src/arena.c | 156 +++-- src/background_thread.c | 572 ++++++++++++++++++ src/ctl.c | 92 ++- src/jemalloc.c | 53 +- src/mutex.c | 19 +- src/stats.c | 1 + test/integration/extent.c | 14 + test/unit/decay.c | 20 + test/unit/smoothstep.c | 2 +- test/unit/stats.c | 6 +- 23 files changed, 1245 insertions(+), 348 deletions(-) create mode 100644 include/jemalloc/internal/background_thread_externs.h create mode 100644 include/jemalloc/internal/background_thread_inlines.h create mode 100644 include/jemalloc/internal/background_thread_structs.h create mode 100644 src/background_thread.c diff --git a/Makefile.in b/Makefile.in index 264b077c..aa6f3f62 100644 --- a/Makefile.in +++ b/Makefile.in @@ -91,6 +91,7 @@ BINS := $(objroot)bin/jemalloc-config $(objroot)bin/jemalloc.sh $(objroot)bin/je C_HDRS := $(objroot)include/jemalloc/jemalloc$(install_suffix).h C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/arena.c \ + $(srcroot)src/background_thread.c \ $(srcroot)src/base.c \ $(srcroot)src/bitmap.c \ $(srcroot)src/ckh.c \ diff --git a/configure.ac b/configure.ac index 6c1d4ffc..8be4be45 100644 --- a/configure.ac +++ b/configure.ac @@ -1443,12 +1443,23 @@ dnl ============================================================================ dnl Configure pthreads. if test "x$abi" != "xpecoff" ; then + AC_DEFINE([JEMALLOC_HAVE_PTHREAD], [ ]) AC_CHECK_HEADERS([pthread.h], , [AC_MSG_ERROR([pthread.h is missing])]) dnl Some systems may embed pthreads functionality in libc; check for libpthread dnl first, but try libc too before failing. AC_CHECK_LIB([pthread], [pthread_create], [JE_APPEND_VS(LIBS, -lpthread)], [AC_SEARCH_LIBS([pthread_create], , , AC_MSG_ERROR([libpthread is missing]))]) + wrap_syms="${wrap_syms} pthread_create" + dnl Check if we have dlsym support. + have_dlsym="1" + AC_CHECK_HEADERS([dlfcn.h], + AC_CHECK_FUNC([dlsym], [], + [AC_CHECK_LIB([dl], [dlsym], [LIBS="$LIBS -ldl"], [have_dlsym="0"])]), + [have_dlsym="0"]) + if test "x$have_dlsym" = "x1" ; then + AC_DEFINE([JEMALLOC_HAVE_DLSYM], [ ]) + fi JE_COMPILABLE([pthread_atfork(3)], [ #include ], [ @@ -1563,6 +1574,15 @@ if test "x$have_sched_getcpu" = "x1" ; then AC_DEFINE([JEMALLOC_HAVE_SCHED_GETCPU], [ ]) fi +dnl Check if the GNU-specific sched_setaffinity function exists. +AC_CHECK_FUNC([sched_setaffinity], + [have_sched_setaffinity="1"], + [have_sched_setaffinity="0"] + ) +if test "x$have_sched_setaffinity" = "x1" ; then + AC_DEFINE([JEMALLOC_HAVE_SCHED_SETAFFINITY], [ ]) +fi + dnl Check if the Solaris/BSD issetugid function exists. AC_CHECK_FUNC([issetugid], [have_issetugid="1"], @@ -1623,15 +1643,11 @@ if test "x${enable_lazy_lock}" = "x1" -a "x${abi}" = "xpecoff" ; then enable_lazy_lock="0" fi if test "x$enable_lazy_lock" = "x1" ; then - if test "x$abi" != "xpecoff" ; then - AC_CHECK_HEADERS([dlfcn.h], , [AC_MSG_ERROR([dlfcn.h is missing])]) - AC_CHECK_FUNC([dlsym], [], - [AC_CHECK_LIB([dl], [dlsym], [JE_APPEND_VS(LIBS, -ldl)], - [AC_MSG_ERROR([libdl is missing])]) - ]) + if test "x$have_dlsym" = "x1" ; then + AC_DEFINE([JEMALLOC_LAZY_LOCK], [ ]) + else + AC_MSG_ERROR([Missing dlsym support: lazy-lock cannot be enabled.]) fi - AC_DEFINE([JEMALLOC_LAZY_LOCK], [ ]) - wrap_syms="${wrap_syms} pthread_create" fi AC_SUBST([enable_lazy_lock]) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 292b8d6d..273705f7 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -5,7 +5,7 @@ #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/stats.h" -static const size_t large_pad = +static const size_t large_pad = #ifdef JEMALLOC_CACHE_OBLIVIOUS PAGE #else @@ -13,88 +13,91 @@ static const size_t large_pad = #endif ; -extern ssize_t opt_dirty_decay_ms; -extern ssize_t opt_muzzy_decay_ms; +extern ssize_t opt_dirty_decay_ms; +extern ssize_t opt_muzzy_decay_ms; -extern const arena_bin_info_t arena_bin_info[NBINS]; +extern const arena_bin_info_t arena_bin_info[NBINS]; -extern percpu_arena_mode_t percpu_arena_mode; +extern percpu_arena_mode_t percpu_arena_mode; extern const char *opt_percpu_arena; extern const char *percpu_arena_mode_names[]; +extern const uint64_t h_steps[SMOOTHSTEP_NSTEPS]; + void arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats, szind_t szind, uint64_t nrequests); void arena_stats_mapped_add(tsdn_t *tsdn, arena_stats_t *arena_stats, size_t size); -void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, +void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms, size_t *nactive, size_t *ndirty, size_t *nmuzzy); void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms, size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats, malloc_bin_stats_t *bstats, malloc_large_stats_t *lstats); -void arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena, +void arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent); #ifdef JEMALLOC_JET -size_t arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr); +size_t arena_slab_regind(extent_t *slab, szind_t binind, const void *ptr); #endif -extent_t *arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, +extent_t *arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero); -void arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena, +void arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena, extent_t *extent); -void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, +void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); -void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, +void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, extent_t *extent, size_t oldsize); ssize_t arena_dirty_decay_ms_get(arena_t *arena); bool arena_dirty_decay_ms_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_ms); ssize_t arena_muzzy_decay_ms_get(arena_t *arena); bool arena_muzzy_decay_ms_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_ms); -void arena_decay(tsdn_t *tsdn, arena_t *arena, bool all); -void arena_reset(tsd_t *tsd, arena_t *arena); -void arena_destroy(tsd_t *tsd, arena_t *arena); -void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, +void arena_decay(tsdn_t *tsdn, arena_t *arena, bool is_background_thread, + bool all); +void arena_reset(tsd_t *tsd, arena_t *arena); +void arena_destroy(tsd_t *tsd, arena_t *arena); +void arena_tcache_fill_small(tsdn_t *tsdn, arena_t *arena, tcache_t *tcache, tcache_bin_t *tbin, szind_t binind, uint64_t prof_accumbytes); -void arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, +void arena_alloc_junk_small(void *ptr, const arena_bin_info_t *bin_info, bool zero); typedef void (arena_dalloc_junk_small_t)(void *, const arena_bin_info_t *); extern arena_dalloc_junk_small_t *JET_MUTABLE arena_dalloc_junk_small; -void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, +void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero); -void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, +void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero, tcache_t *tcache); -void arena_prof_promote(tsdn_t *tsdn, const void *ptr, size_t usize); -void arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache, +void arena_prof_promote(tsdn_t *tsdn, const void *ptr, size_t usize); +void arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path); -void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, +void arena_dalloc_bin_junked_locked(tsdn_t *tsdn, arena_t *arena, extent_t *extent, void *ptr); -void arena_dalloc_small(tsdn_t *tsdn, void *ptr); +void arena_dalloc_small(tsdn_t *tsdn, void *ptr); bool arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, bool zero); void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache); -dss_prec_t arena_dss_prec_get(arena_t *arena); -bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec); +dss_prec_t arena_dss_prec_get(arena_t *arena); +bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec); ssize_t arena_dirty_decay_ms_default_get(void); bool arena_dirty_decay_ms_default_set(ssize_t decay_ms); ssize_t arena_muzzy_decay_ms_default_get(void); bool arena_muzzy_decay_ms_default_set(ssize_t decay_ms); -unsigned arena_nthreads_get(arena_t *arena, bool internal); -void arena_nthreads_inc(arena_t *arena, bool internal); -void arena_nthreads_dec(arena_t *arena, bool internal); -size_t arena_extent_sn_next(arena_t *arena); -arena_t *arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); -void arena_boot(void); -void arena_prefork0(tsdn_t *tsdn, arena_t *arena); -void arena_prefork1(tsdn_t *tsdn, arena_t *arena); -void arena_prefork2(tsdn_t *tsdn, arena_t *arena); -void arena_prefork3(tsdn_t *tsdn, arena_t *arena); -void arena_prefork4(tsdn_t *tsdn, arena_t *arena); -void arena_prefork5(tsdn_t *tsdn, arena_t *arena); -void arena_prefork6(tsdn_t *tsdn, arena_t *arena); -void arena_postfork_parent(tsdn_t *tsdn, arena_t *arena); -void arena_postfork_child(tsdn_t *tsdn, arena_t *arena); +unsigned arena_nthreads_get(arena_t *arena, bool internal); +void arena_nthreads_inc(arena_t *arena, bool internal); +void arena_nthreads_dec(arena_t *arena, bool internal); +size_t arena_extent_sn_next(arena_t *arena); +arena_t *arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks); +void arena_boot(void); +void arena_prefork0(tsdn_t *tsdn, arena_t *arena); +void arena_prefork1(tsdn_t *tsdn, arena_t *arena); +void arena_prefork2(tsdn_t *tsdn, arena_t *arena); +void arena_prefork3(tsdn_t *tsdn, arena_t *arena); +void arena_prefork4(tsdn_t *tsdn, arena_t *arena); +void arena_prefork5(tsdn_t *tsdn, arena_t *arena); +void arena_prefork6(tsdn_t *tsdn, arena_t *arena); +void arena_postfork_parent(tsdn_t *tsdn, arena_t *arena); +void arena_postfork_child(tsdn_t *tsdn, arena_t *arena); #endif /* JEMALLOC_INTERNAL_ARENA_EXTERNS_H */ diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index ca7af7fd..a1057184 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -75,7 +75,7 @@ arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks) { return; } if (unlikely(ticker_ticks(decay_ticker, nticks))) { - arena_decay(tsdn, arena, false); + arena_decay(tsdn, arena, false, false); } } diff --git a/include/jemalloc/internal/background_thread_externs.h b/include/jemalloc/internal/background_thread_externs.h new file mode 100644 index 00000000..993f0e3b --- /dev/null +++ b/include/jemalloc/internal/background_thread_externs.h @@ -0,0 +1,29 @@ +#ifndef JEMALLOC_INTERNAL_BACKGROUND_THREAD_EXTERNS_H +#define JEMALLOC_INTERNAL_BACKGROUND_THREAD_EXTERNS_H + +extern bool opt_background_thread; +extern malloc_mutex_t background_thread_lock; +extern atomic_b_t background_thread_enabled_state; +extern size_t n_background_threads; +extern background_thread_info_t *background_thread_info; + +bool background_thread_create(tsd_t *tsd, unsigned arena_ind); +bool background_threads_init(tsd_t *tsd); +bool background_threads_enable(tsd_t *tsd); +bool background_threads_disable(tsd_t *tsd); +bool background_threads_disable_single(tsd_t *tsd, + background_thread_info_t *info); +void background_thread_interval_check(tsdn_t *tsdn, arena_t *arena, + arena_decay_t *decay, size_t npages_new); +void background_thread_prefork0(tsdn_t *tsdn); +void background_thread_prefork1(tsdn_t *tsdn); +void background_thread_postfork_parent(tsdn_t *tsdn); +void background_thread_postfork_child(tsdn_t *tsdn); + +#if defined(JEMALLOC_BACKGROUND_THREAD) || defined(JEMALLOC_LAZY_LOCK) +extern int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *, + void *(*)(void *), void *__restrict); +void *load_pthread_create_fptr(void); +#endif + +#endif /* JEMALLOC_INTERNAL_BACKGROUND_THREAD_EXTERNS_H */ diff --git a/include/jemalloc/internal/background_thread_inlines.h b/include/jemalloc/internal/background_thread_inlines.h new file mode 100644 index 00000000..2709ae31 --- /dev/null +++ b/include/jemalloc/internal/background_thread_inlines.h @@ -0,0 +1,21 @@ +#ifndef JEMALLOC_INTERNAL_BACKGROUND_THREAD_INLINES_H +#define JEMALLOC_INTERNAL_BACKGROUND_THREAD_INLINES_H + +JEMALLOC_ALWAYS_INLINE bool +background_thread_enabled(void) { + return atomic_load_b(&background_thread_enabled_state, ATOMIC_RELAXED); +} + +JEMALLOC_ALWAYS_INLINE void +background_thread_enabled_set(tsdn_t *tsdn, bool state) { + malloc_mutex_assert_owner(tsdn, &background_thread_lock); + atomic_store_b(&background_thread_enabled_state, state, ATOMIC_RELAXED); +} + +JEMALLOC_ALWAYS_INLINE background_thread_info_t * +arena_background_thread_info_get(arena_t *arena) { + unsigned arena_ind = arena_ind_get(arena); + return &background_thread_info[arena_ind % ncpus]; +} + +#endif /* JEMALLOC_INTERNAL_BACKGROUND_THREAD_INLINES_H */ diff --git a/include/jemalloc/internal/background_thread_structs.h b/include/jemalloc/internal/background_thread_structs.h new file mode 100644 index 00000000..a43d600d --- /dev/null +++ b/include/jemalloc/internal/background_thread_structs.h @@ -0,0 +1,25 @@ +#ifndef JEMALLOC_INTERNAL_BACKGROUND_THREAD_STRUCTS_H +#define JEMALLOC_INTERNAL_BACKGROUND_THREAD_STRUCTS_H + +struct background_thread_info_s { + malloc_mutex_t mtx; +#ifdef JEMALLOC_BACKGROUND_THREAD + /* Background thread is pthread specific. */ + pthread_cond_t cond; + pthread_t thread; + /* Whether the thread has been created. */ + bool started; + /* Next scheduled wakeup time (absolute time). */ + nstime_t next_wakeup; + /* + * Since the last background thread run, newly added number of pages + * that need to be purged by the next wakeup. This is adjusted on + * epoch advance, and is used to determine whether we should signal the + * background thread to wake up earlier. + */ + size_t npages_to_purge_new; +#endif /* ifdef JEMALLOC_BACKGROUND_THREAD */ +}; +typedef struct background_thread_info_s background_thread_info_t; + +#endif /* JEMALLOC_INTERNAL_BACKGROUND_THREAD_STRUCTS_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 78ddd376..75576a56 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -301,12 +301,21 @@ /* glibc memalign hook. */ #undef JEMALLOC_GLIBC_MEMALIGN_HOOK +/* pthread support */ +#undef JEMALLOC_HAVE_PTHREAD + +/* dlsym() support */ +#undef JEMALLOC_HAVE_DLSYM + /* Adaptive mutex support in pthreads. */ #undef JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP /* GNU specific sched_getcpu support */ #undef JEMALLOC_HAVE_SCHED_GETCPU +/* GNU specific sched_setaffinity support */ +#undef JEMALLOC_HAVE_SCHED_SETAFFINITY + /* * If defined, jemalloc symbols are not exported (doesn't work when * JEMALLOC_PREFIX is not defined). diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index cf321c12..45e648bc 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -65,6 +65,7 @@ #include "jemalloc/internal/arena_structs_b.h" #include "jemalloc/internal/rtree_structs.h" #include "jemalloc/internal/tcache_structs.h" +#include "jemalloc/internal/background_thread_structs.h" /******************************************************************************/ /* EXTERNS */ @@ -82,6 +83,7 @@ #include "jemalloc/internal/large_externs.h" #include "jemalloc/internal/tcache_externs.h" #include "jemalloc/internal/prof_externs.h" +#include "jemalloc/internal/background_thread_externs.h" /******************************************************************************/ /* INLINES */ @@ -105,5 +107,6 @@ #include "jemalloc/internal/arena_inlines_b.h" #include "jemalloc/internal/jemalloc_internal_inlines_c.h" #include "jemalloc/internal/prof_inlines_b.h" +#include "jemalloc/internal/background_thread_inlines.h" #endif /* JEMALLOC_INTERNAL_INCLUDES_H */ diff --git a/include/jemalloc/internal/jemalloc_preamble.h.in b/include/jemalloc/internal/jemalloc_preamble.h.in index 9e9225ef..0e876103 100644 --- a/include/jemalloc/internal/jemalloc_preamble.h.in +++ b/include/jemalloc/internal/jemalloc_preamble.h.in @@ -169,4 +169,17 @@ static const bool force_ivsalloc = #endif ; +#if (defined(JEMALLOC_HAVE_PTHREAD) && defined(JEMALLOC_HAVE_DLSYM) \ + && !defined(JEMALLOC_OSSPIN) && !defined(JEMALLOC_OS_UNFAIR_LOCK)) +/* Currently background thread supports pthread only. */ +#define JEMALLOC_BACKGROUND_THREAD +#endif +static const bool have_background_thread = +#ifdef JEMALLOC_BACKGROUND_THREAD + true +#else + false +#endif + ; + #endif /* JEMALLOC_PREAMBLE_H */ diff --git a/include/jemalloc/internal/smoothstep.h b/include/jemalloc/internal/smoothstep.h index 2e14430f..5bca6e8c 100644 --- a/include/jemalloc/internal/smoothstep.h +++ b/include/jemalloc/internal/smoothstep.h @@ -27,206 +27,206 @@ #define SMOOTHSTEP_NSTEPS 200 #define SMOOTHSTEP_BFP 24 #define SMOOTHSTEP \ - /* STEP(step, h, x, y) */ \ - STEP( 1, UINT64_C(0x0000000000000014), 0.005, 0.000001240643750) \ - STEP( 2, UINT64_C(0x00000000000000a5), 0.010, 0.000009850600000) \ - STEP( 3, UINT64_C(0x0000000000000229), 0.015, 0.000032995181250) \ - STEP( 4, UINT64_C(0x0000000000000516), 0.020, 0.000077619200000) \ - STEP( 5, UINT64_C(0x00000000000009dc), 0.025, 0.000150449218750) \ - STEP( 6, UINT64_C(0x00000000000010e8), 0.030, 0.000257995800000) \ - STEP( 7, UINT64_C(0x0000000000001aa4), 0.035, 0.000406555756250) \ - STEP( 8, UINT64_C(0x0000000000002777), 0.040, 0.000602214400000) \ - STEP( 9, UINT64_C(0x00000000000037c2), 0.045, 0.000850847793750) \ - STEP( 10, UINT64_C(0x0000000000004be6), 0.050, 0.001158125000000) \ - STEP( 11, UINT64_C(0x000000000000643c), 0.055, 0.001529510331250) \ - STEP( 12, UINT64_C(0x000000000000811f), 0.060, 0.001970265600000) \ - STEP( 13, UINT64_C(0x000000000000a2e2), 0.065, 0.002485452368750) \ - STEP( 14, UINT64_C(0x000000000000c9d8), 0.070, 0.003079934200000) \ - STEP( 15, UINT64_C(0x000000000000f64f), 0.075, 0.003758378906250) \ - STEP( 16, UINT64_C(0x0000000000012891), 0.080, 0.004525260800000) \ - STEP( 17, UINT64_C(0x00000000000160e7), 0.085, 0.005384862943750) \ - STEP( 18, UINT64_C(0x0000000000019f95), 0.090, 0.006341279400000) \ - STEP( 19, UINT64_C(0x000000000001e4dc), 0.095, 0.007398417481250) \ - STEP( 20, UINT64_C(0x00000000000230fc), 0.100, 0.008560000000000) \ - STEP( 21, UINT64_C(0x0000000000028430), 0.105, 0.009829567518750) \ - STEP( 22, UINT64_C(0x000000000002deb0), 0.110, 0.011210480600000) \ - STEP( 23, UINT64_C(0x00000000000340b1), 0.115, 0.012705922056250) \ - STEP( 24, UINT64_C(0x000000000003aa67), 0.120, 0.014318899200000) \ - STEP( 25, UINT64_C(0x0000000000041c00), 0.125, 0.016052246093750) \ - STEP( 26, UINT64_C(0x00000000000495a8), 0.130, 0.017908625800000) \ - STEP( 27, UINT64_C(0x000000000005178b), 0.135, 0.019890532631250) \ - STEP( 28, UINT64_C(0x000000000005a1cf), 0.140, 0.022000294400000) \ - STEP( 29, UINT64_C(0x0000000000063498), 0.145, 0.024240074668750) \ - STEP( 30, UINT64_C(0x000000000006d009), 0.150, 0.026611875000000) \ - STEP( 31, UINT64_C(0x000000000007743f), 0.155, 0.029117537206250) \ - STEP( 32, UINT64_C(0x0000000000082157), 0.160, 0.031758745600000) \ - STEP( 33, UINT64_C(0x000000000008d76b), 0.165, 0.034537029243750) \ - STEP( 34, UINT64_C(0x0000000000099691), 0.170, 0.037453764200000) \ - STEP( 35, UINT64_C(0x00000000000a5edf), 0.175, 0.040510175781250) \ - STEP( 36, UINT64_C(0x00000000000b3067), 0.180, 0.043707340800000) \ - STEP( 37, UINT64_C(0x00000000000c0b38), 0.185, 0.047046189818750) \ - STEP( 38, UINT64_C(0x00000000000cef5e), 0.190, 0.050527509400000) \ - STEP( 39, UINT64_C(0x00000000000ddce6), 0.195, 0.054151944356250) \ - STEP( 40, UINT64_C(0x00000000000ed3d8), 0.200, 0.057920000000000) \ - STEP( 41, UINT64_C(0x00000000000fd439), 0.205, 0.061832044393750) \ - STEP( 42, UINT64_C(0x000000000010de0e), 0.210, 0.065888310600000) \ - STEP( 43, UINT64_C(0x000000000011f158), 0.215, 0.070088898931250) \ - STEP( 44, UINT64_C(0x0000000000130e17), 0.220, 0.074433779200000) \ - STEP( 45, UINT64_C(0x0000000000143448), 0.225, 0.078922792968750) \ - STEP( 46, UINT64_C(0x00000000001563e7), 0.230, 0.083555655800000) \ - STEP( 47, UINT64_C(0x0000000000169cec), 0.235, 0.088331959506250) \ - STEP( 48, UINT64_C(0x000000000017df4f), 0.240, 0.093251174400000) \ - STEP( 49, UINT64_C(0x0000000000192b04), 0.245, 0.098312651543750) \ - STEP( 50, UINT64_C(0x00000000001a8000), 0.250, 0.103515625000000) \ - STEP( 51, UINT64_C(0x00000000001bde32), 0.255, 0.108859214081250) \ - STEP( 52, UINT64_C(0x00000000001d458b), 0.260, 0.114342425600000) \ - STEP( 53, UINT64_C(0x00000000001eb5f8), 0.265, 0.119964156118750) \ - STEP( 54, UINT64_C(0x0000000000202f65), 0.270, 0.125723194200000) \ - STEP( 55, UINT64_C(0x000000000021b1bb), 0.275, 0.131618222656250) \ - STEP( 56, UINT64_C(0x0000000000233ce3), 0.280, 0.137647820800000) \ - STEP( 57, UINT64_C(0x000000000024d0c3), 0.285, 0.143810466693750) \ - STEP( 58, UINT64_C(0x0000000000266d40), 0.290, 0.150104539400000) \ - STEP( 59, UINT64_C(0x000000000028123d), 0.295, 0.156528321231250) \ - STEP( 60, UINT64_C(0x000000000029bf9c), 0.300, 0.163080000000000) \ - STEP( 61, UINT64_C(0x00000000002b753d), 0.305, 0.169757671268750) \ - STEP( 62, UINT64_C(0x00000000002d32fe), 0.310, 0.176559340600000) \ - STEP( 63, UINT64_C(0x00000000002ef8bc), 0.315, 0.183482925806250) \ - STEP( 64, UINT64_C(0x000000000030c654), 0.320, 0.190526259200000) \ - STEP( 65, UINT64_C(0x0000000000329b9f), 0.325, 0.197687089843750) \ - STEP( 66, UINT64_C(0x0000000000347875), 0.330, 0.204963085800000) \ - STEP( 67, UINT64_C(0x0000000000365cb0), 0.335, 0.212351836381250) \ - STEP( 68, UINT64_C(0x0000000000384825), 0.340, 0.219850854400000) \ - STEP( 69, UINT64_C(0x00000000003a3aa8), 0.345, 0.227457578418750) \ - STEP( 70, UINT64_C(0x00000000003c340f), 0.350, 0.235169375000000) \ - STEP( 71, UINT64_C(0x00000000003e342b), 0.355, 0.242983540956250) \ - STEP( 72, UINT64_C(0x0000000000403ace), 0.360, 0.250897305600000) \ - STEP( 73, UINT64_C(0x00000000004247c8), 0.365, 0.258907832993750) \ - STEP( 74, UINT64_C(0x0000000000445ae9), 0.370, 0.267012224200000) \ - STEP( 75, UINT64_C(0x0000000000467400), 0.375, 0.275207519531250) \ - STEP( 76, UINT64_C(0x00000000004892d8), 0.380, 0.283490700800000) \ - STEP( 77, UINT64_C(0x00000000004ab740), 0.385, 0.291858693568750) \ - STEP( 78, UINT64_C(0x00000000004ce102), 0.390, 0.300308369400000) \ - STEP( 79, UINT64_C(0x00000000004f0fe9), 0.395, 0.308836548106250) \ - STEP( 80, UINT64_C(0x00000000005143bf), 0.400, 0.317440000000000) \ - STEP( 81, UINT64_C(0x0000000000537c4d), 0.405, 0.326115448143750) \ - STEP( 82, UINT64_C(0x000000000055b95b), 0.410, 0.334859570600000) \ - STEP( 83, UINT64_C(0x000000000057fab1), 0.415, 0.343669002681250) \ - STEP( 84, UINT64_C(0x00000000005a4015), 0.420, 0.352540339200000) \ - STEP( 85, UINT64_C(0x00000000005c894e), 0.425, 0.361470136718750) \ - STEP( 86, UINT64_C(0x00000000005ed622), 0.430, 0.370454915800000) \ - STEP( 87, UINT64_C(0x0000000000612655), 0.435, 0.379491163256250) \ - STEP( 88, UINT64_C(0x00000000006379ac), 0.440, 0.388575334400000) \ - STEP( 89, UINT64_C(0x000000000065cfeb), 0.445, 0.397703855293750) \ - STEP( 90, UINT64_C(0x00000000006828d6), 0.450, 0.406873125000000) \ - STEP( 91, UINT64_C(0x00000000006a842f), 0.455, 0.416079517831250) \ - STEP( 92, UINT64_C(0x00000000006ce1bb), 0.460, 0.425319385600000) \ - STEP( 93, UINT64_C(0x00000000006f413a), 0.465, 0.434589059868750) \ - STEP( 94, UINT64_C(0x000000000071a270), 0.470, 0.443884854200000) \ - STEP( 95, UINT64_C(0x000000000074051d), 0.475, 0.453203066406250) \ - STEP( 96, UINT64_C(0x0000000000766905), 0.480, 0.462539980800000) \ - STEP( 97, UINT64_C(0x000000000078cde7), 0.485, 0.471891870443750) \ - STEP( 98, UINT64_C(0x00000000007b3387), 0.490, 0.481254999400000) \ - STEP( 99, UINT64_C(0x00000000007d99a4), 0.495, 0.490625624981250) \ - STEP( 100, UINT64_C(0x0000000000800000), 0.500, 0.500000000000000) \ - STEP( 101, UINT64_C(0x000000000082665b), 0.505, 0.509374375018750) \ - STEP( 102, UINT64_C(0x000000000084cc78), 0.510, 0.518745000600000) \ - STEP( 103, UINT64_C(0x0000000000873218), 0.515, 0.528108129556250) \ - STEP( 104, UINT64_C(0x00000000008996fa), 0.520, 0.537460019200000) \ - STEP( 105, UINT64_C(0x00000000008bfae2), 0.525, 0.546796933593750) \ - STEP( 106, UINT64_C(0x00000000008e5d8f), 0.530, 0.556115145800000) \ - STEP( 107, UINT64_C(0x000000000090bec5), 0.535, 0.565410940131250) \ - STEP( 108, UINT64_C(0x0000000000931e44), 0.540, 0.574680614400000) \ - STEP( 109, UINT64_C(0x0000000000957bd0), 0.545, 0.583920482168750) \ - STEP( 110, UINT64_C(0x000000000097d729), 0.550, 0.593126875000000) \ - STEP( 111, UINT64_C(0x00000000009a3014), 0.555, 0.602296144706250) \ - STEP( 112, UINT64_C(0x00000000009c8653), 0.560, 0.611424665600000) \ - STEP( 113, UINT64_C(0x00000000009ed9aa), 0.565, 0.620508836743750) \ - STEP( 114, UINT64_C(0x0000000000a129dd), 0.570, 0.629545084200000) \ - STEP( 115, UINT64_C(0x0000000000a376b1), 0.575, 0.638529863281250) \ - STEP( 116, UINT64_C(0x0000000000a5bfea), 0.580, 0.647459660800000) \ - STEP( 117, UINT64_C(0x0000000000a8054e), 0.585, 0.656330997318750) \ - STEP( 118, UINT64_C(0x0000000000aa46a4), 0.590, 0.665140429400000) \ - STEP( 119, UINT64_C(0x0000000000ac83b2), 0.595, 0.673884551856250) \ - STEP( 120, UINT64_C(0x0000000000aebc40), 0.600, 0.682560000000000) \ - STEP( 121, UINT64_C(0x0000000000b0f016), 0.605, 0.691163451893750) \ - STEP( 122, UINT64_C(0x0000000000b31efd), 0.610, 0.699691630600000) \ - STEP( 123, UINT64_C(0x0000000000b548bf), 0.615, 0.708141306431250) \ - STEP( 124, UINT64_C(0x0000000000b76d27), 0.620, 0.716509299200000) \ - STEP( 125, UINT64_C(0x0000000000b98c00), 0.625, 0.724792480468750) \ - STEP( 126, UINT64_C(0x0000000000bba516), 0.630, 0.732987775800000) \ - STEP( 127, UINT64_C(0x0000000000bdb837), 0.635, 0.741092167006250) \ - STEP( 128, UINT64_C(0x0000000000bfc531), 0.640, 0.749102694400000) \ - STEP( 129, UINT64_C(0x0000000000c1cbd4), 0.645, 0.757016459043750) \ - STEP( 130, UINT64_C(0x0000000000c3cbf0), 0.650, 0.764830625000000) \ - STEP( 131, UINT64_C(0x0000000000c5c557), 0.655, 0.772542421581250) \ - STEP( 132, UINT64_C(0x0000000000c7b7da), 0.660, 0.780149145600000) \ - STEP( 133, UINT64_C(0x0000000000c9a34f), 0.665, 0.787648163618750) \ - STEP( 134, UINT64_C(0x0000000000cb878a), 0.670, 0.795036914200000) \ - STEP( 135, UINT64_C(0x0000000000cd6460), 0.675, 0.802312910156250) \ - STEP( 136, UINT64_C(0x0000000000cf39ab), 0.680, 0.809473740800000) \ - STEP( 137, UINT64_C(0x0000000000d10743), 0.685, 0.816517074193750) \ - STEP( 138, UINT64_C(0x0000000000d2cd01), 0.690, 0.823440659400000) \ - STEP( 139, UINT64_C(0x0000000000d48ac2), 0.695, 0.830242328731250) \ - STEP( 140, UINT64_C(0x0000000000d64063), 0.700, 0.836920000000000) \ - STEP( 141, UINT64_C(0x0000000000d7edc2), 0.705, 0.843471678768750) \ - STEP( 142, UINT64_C(0x0000000000d992bf), 0.710, 0.849895460600000) \ - STEP( 143, UINT64_C(0x0000000000db2f3c), 0.715, 0.856189533306250) \ - STEP( 144, UINT64_C(0x0000000000dcc31c), 0.720, 0.862352179200000) \ - STEP( 145, UINT64_C(0x0000000000de4e44), 0.725, 0.868381777343750) \ - STEP( 146, UINT64_C(0x0000000000dfd09a), 0.730, 0.874276805800000) \ - STEP( 147, UINT64_C(0x0000000000e14a07), 0.735, 0.880035843881250) \ - STEP( 148, UINT64_C(0x0000000000e2ba74), 0.740, 0.885657574400000) \ - STEP( 149, UINT64_C(0x0000000000e421cd), 0.745, 0.891140785918750) \ - STEP( 150, UINT64_C(0x0000000000e58000), 0.750, 0.896484375000000) \ - STEP( 151, UINT64_C(0x0000000000e6d4fb), 0.755, 0.901687348456250) \ - STEP( 152, UINT64_C(0x0000000000e820b0), 0.760, 0.906748825600000) \ - STEP( 153, UINT64_C(0x0000000000e96313), 0.765, 0.911668040493750) \ - STEP( 154, UINT64_C(0x0000000000ea9c18), 0.770, 0.916444344200000) \ - STEP( 155, UINT64_C(0x0000000000ebcbb7), 0.775, 0.921077207031250) \ - STEP( 156, UINT64_C(0x0000000000ecf1e8), 0.780, 0.925566220800000) \ - STEP( 157, UINT64_C(0x0000000000ee0ea7), 0.785, 0.929911101068750) \ - STEP( 158, UINT64_C(0x0000000000ef21f1), 0.790, 0.934111689400000) \ - STEP( 159, UINT64_C(0x0000000000f02bc6), 0.795, 0.938167955606250) \ - STEP( 160, UINT64_C(0x0000000000f12c27), 0.800, 0.942080000000000) \ - STEP( 161, UINT64_C(0x0000000000f22319), 0.805, 0.945848055643750) \ - STEP( 162, UINT64_C(0x0000000000f310a1), 0.810, 0.949472490600000) \ - STEP( 163, UINT64_C(0x0000000000f3f4c7), 0.815, 0.952953810181250) \ - STEP( 164, UINT64_C(0x0000000000f4cf98), 0.820, 0.956292659200000) \ - STEP( 165, UINT64_C(0x0000000000f5a120), 0.825, 0.959489824218750) \ - STEP( 166, UINT64_C(0x0000000000f6696e), 0.830, 0.962546235800000) \ - STEP( 167, UINT64_C(0x0000000000f72894), 0.835, 0.965462970756250) \ - STEP( 168, UINT64_C(0x0000000000f7dea8), 0.840, 0.968241254400000) \ - STEP( 169, UINT64_C(0x0000000000f88bc0), 0.845, 0.970882462793750) \ - STEP( 170, UINT64_C(0x0000000000f92ff6), 0.850, 0.973388125000000) \ - STEP( 171, UINT64_C(0x0000000000f9cb67), 0.855, 0.975759925331250) \ - STEP( 172, UINT64_C(0x0000000000fa5e30), 0.860, 0.977999705600000) \ - STEP( 173, UINT64_C(0x0000000000fae874), 0.865, 0.980109467368750) \ - STEP( 174, UINT64_C(0x0000000000fb6a57), 0.870, 0.982091374200000) \ - STEP( 175, UINT64_C(0x0000000000fbe400), 0.875, 0.983947753906250) \ - STEP( 176, UINT64_C(0x0000000000fc5598), 0.880, 0.985681100800000) \ - STEP( 177, UINT64_C(0x0000000000fcbf4e), 0.885, 0.987294077943750) \ - STEP( 178, UINT64_C(0x0000000000fd214f), 0.890, 0.988789519400000) \ - STEP( 179, UINT64_C(0x0000000000fd7bcf), 0.895, 0.990170432481250) \ - STEP( 180, UINT64_C(0x0000000000fdcf03), 0.900, 0.991440000000000) \ - STEP( 181, UINT64_C(0x0000000000fe1b23), 0.905, 0.992601582518750) \ - STEP( 182, UINT64_C(0x0000000000fe606a), 0.910, 0.993658720600000) \ - STEP( 183, UINT64_C(0x0000000000fe9f18), 0.915, 0.994615137056250) \ - STEP( 184, UINT64_C(0x0000000000fed76e), 0.920, 0.995474739200000) \ - STEP( 185, UINT64_C(0x0000000000ff09b0), 0.925, 0.996241621093750) \ - STEP( 186, UINT64_C(0x0000000000ff3627), 0.930, 0.996920065800000) \ - STEP( 187, UINT64_C(0x0000000000ff5d1d), 0.935, 0.997514547631250) \ - STEP( 188, UINT64_C(0x0000000000ff7ee0), 0.940, 0.998029734400000) \ - STEP( 189, UINT64_C(0x0000000000ff9bc3), 0.945, 0.998470489668750) \ - STEP( 190, UINT64_C(0x0000000000ffb419), 0.950, 0.998841875000000) \ - STEP( 191, UINT64_C(0x0000000000ffc83d), 0.955, 0.999149152206250) \ - STEP( 192, UINT64_C(0x0000000000ffd888), 0.960, 0.999397785600000) \ - STEP( 193, UINT64_C(0x0000000000ffe55b), 0.965, 0.999593444243750) \ - STEP( 194, UINT64_C(0x0000000000ffef17), 0.970, 0.999742004200000) \ - STEP( 195, UINT64_C(0x0000000000fff623), 0.975, 0.999849550781250) \ - STEP( 196, UINT64_C(0x0000000000fffae9), 0.980, 0.999922380800000) \ - STEP( 197, UINT64_C(0x0000000000fffdd6), 0.985, 0.999967004818750) \ - STEP( 198, UINT64_C(0x0000000000ffff5a), 0.990, 0.999990149400000) \ - STEP( 199, UINT64_C(0x0000000000ffffeb), 0.995, 0.999998759356250) \ - STEP( 200, UINT64_C(0x0000000001000000), 1.000, 1.000000000000000) \ + /* STEP(step, h, x, y, h_sum) */ \ + STEP( 1, UINT64_C(0x0000000000000014), 0.005, 0.000001240643750, UINT64_C(0x0000000000000014)) \ + STEP( 2, UINT64_C(0x00000000000000a5), 0.010, 0.000009850600000, UINT64_C(0x00000000000000b9)) \ + STEP( 3, UINT64_C(0x0000000000000229), 0.015, 0.000032995181250, UINT64_C(0x00000000000002e2)) \ + STEP( 4, UINT64_C(0x0000000000000516), 0.020, 0.000077619200000, UINT64_C(0x00000000000007f8)) \ + STEP( 5, UINT64_C(0x00000000000009dc), 0.025, 0.000150449218750, UINT64_C(0x00000000000011d4)) \ + STEP( 6, UINT64_C(0x00000000000010e8), 0.030, 0.000257995800000, UINT64_C(0x00000000000022bc)) \ + STEP( 7, UINT64_C(0x0000000000001aa4), 0.035, 0.000406555756250, UINT64_C(0x0000000000003d60)) \ + STEP( 8, UINT64_C(0x0000000000002777), 0.040, 0.000602214400000, UINT64_C(0x00000000000064d7)) \ + STEP( 9, UINT64_C(0x00000000000037c2), 0.045, 0.000850847793750, UINT64_C(0x0000000000009c99)) \ + STEP( 10, UINT64_C(0x0000000000004be6), 0.050, 0.001158125000000, UINT64_C(0x000000000000e87f)) \ + STEP( 11, UINT64_C(0x000000000000643c), 0.055, 0.001529510331250, UINT64_C(0x0000000000014cbb)) \ + STEP( 12, UINT64_C(0x000000000000811f), 0.060, 0.001970265600000, UINT64_C(0x000000000001cdda)) \ + STEP( 13, UINT64_C(0x000000000000a2e2), 0.065, 0.002485452368750, UINT64_C(0x00000000000270bc)) \ + STEP( 14, UINT64_C(0x000000000000c9d8), 0.070, 0.003079934200000, UINT64_C(0x0000000000033a94)) \ + STEP( 15, UINT64_C(0x000000000000f64f), 0.075, 0.003758378906250, UINT64_C(0x00000000000430e3)) \ + STEP( 16, UINT64_C(0x0000000000012891), 0.080, 0.004525260800000, UINT64_C(0x0000000000055974)) \ + STEP( 17, UINT64_C(0x00000000000160e7), 0.085, 0.005384862943750, UINT64_C(0x000000000006ba5b)) \ + STEP( 18, UINT64_C(0x0000000000019f95), 0.090, 0.006341279400000, UINT64_C(0x00000000000859f0)) \ + STEP( 19, UINT64_C(0x000000000001e4dc), 0.095, 0.007398417481250, UINT64_C(0x00000000000a3ecc)) \ + STEP( 20, UINT64_C(0x00000000000230fc), 0.100, 0.008560000000000, UINT64_C(0x00000000000c6fc8)) \ + STEP( 21, UINT64_C(0x0000000000028430), 0.105, 0.009829567518750, UINT64_C(0x00000000000ef3f8)) \ + STEP( 22, UINT64_C(0x000000000002deb0), 0.110, 0.011210480600000, UINT64_C(0x000000000011d2a8)) \ + STEP( 23, UINT64_C(0x00000000000340b1), 0.115, 0.012705922056250, UINT64_C(0x0000000000151359)) \ + STEP( 24, UINT64_C(0x000000000003aa67), 0.120, 0.014318899200000, UINT64_C(0x000000000018bdc0)) \ + STEP( 25, UINT64_C(0x0000000000041c00), 0.125, 0.016052246093750, UINT64_C(0x00000000001cd9c0)) \ + STEP( 26, UINT64_C(0x00000000000495a8), 0.130, 0.017908625800000, UINT64_C(0x0000000000216f68)) \ + STEP( 27, UINT64_C(0x000000000005178b), 0.135, 0.019890532631250, UINT64_C(0x00000000002686f3)) \ + STEP( 28, UINT64_C(0x000000000005a1cf), 0.140, 0.022000294400000, UINT64_C(0x00000000002c28c2)) \ + STEP( 29, UINT64_C(0x0000000000063498), 0.145, 0.024240074668750, UINT64_C(0x0000000000325d5a)) \ + STEP( 30, UINT64_C(0x000000000006d009), 0.150, 0.026611875000000, UINT64_C(0x0000000000392d63)) \ + STEP( 31, UINT64_C(0x000000000007743f), 0.155, 0.029117537206250, UINT64_C(0x000000000040a1a2)) \ + STEP( 32, UINT64_C(0x0000000000082157), 0.160, 0.031758745600000, UINT64_C(0x000000000048c2f9)) \ + STEP( 33, UINT64_C(0x000000000008d76b), 0.165, 0.034537029243750, UINT64_C(0x0000000000519a64)) \ + STEP( 34, UINT64_C(0x0000000000099691), 0.170, 0.037453764200000, UINT64_C(0x00000000005b30f5)) \ + STEP( 35, UINT64_C(0x00000000000a5edf), 0.175, 0.040510175781250, UINT64_C(0x0000000000658fd4)) \ + STEP( 36, UINT64_C(0x00000000000b3067), 0.180, 0.043707340800000, UINT64_C(0x000000000070c03b)) \ + STEP( 37, UINT64_C(0x00000000000c0b38), 0.185, 0.047046189818750, UINT64_C(0x00000000007ccb73)) \ + STEP( 38, UINT64_C(0x00000000000cef5e), 0.190, 0.050527509400000, UINT64_C(0x000000000089bad1)) \ + STEP( 39, UINT64_C(0x00000000000ddce6), 0.195, 0.054151944356250, UINT64_C(0x00000000009797b7)) \ + STEP( 40, UINT64_C(0x00000000000ed3d8), 0.200, 0.057920000000000, UINT64_C(0x0000000000a66b8f)) \ + STEP( 41, UINT64_C(0x00000000000fd439), 0.205, 0.061832044393750, UINT64_C(0x0000000000b63fc8)) \ + STEP( 42, UINT64_C(0x000000000010de0e), 0.210, 0.065888310600000, UINT64_C(0x0000000000c71dd6)) \ + STEP( 43, UINT64_C(0x000000000011f158), 0.215, 0.070088898931250, UINT64_C(0x0000000000d90f2e)) \ + STEP( 44, UINT64_C(0x0000000000130e17), 0.220, 0.074433779200000, UINT64_C(0x0000000000ec1d45)) \ + STEP( 45, UINT64_C(0x0000000000143448), 0.225, 0.078922792968750, UINT64_C(0x000000000100518d)) \ + STEP( 46, UINT64_C(0x00000000001563e7), 0.230, 0.083555655800000, UINT64_C(0x000000000115b574)) \ + STEP( 47, UINT64_C(0x0000000000169cec), 0.235, 0.088331959506250, UINT64_C(0x00000000012c5260)) \ + STEP( 48, UINT64_C(0x000000000017df4f), 0.240, 0.093251174400000, UINT64_C(0x00000000014431af)) \ + STEP( 49, UINT64_C(0x0000000000192b04), 0.245, 0.098312651543750, UINT64_C(0x00000000015d5cb3)) \ + STEP( 50, UINT64_C(0x00000000001a8000), 0.250, 0.103515625000000, UINT64_C(0x000000000177dcb3)) \ + STEP( 51, UINT64_C(0x00000000001bde32), 0.255, 0.108859214081250, UINT64_C(0x000000000193bae5)) \ + STEP( 52, UINT64_C(0x00000000001d458b), 0.260, 0.114342425600000, UINT64_C(0x0000000001b10070)) \ + STEP( 53, UINT64_C(0x00000000001eb5f8), 0.265, 0.119964156118750, UINT64_C(0x0000000001cfb668)) \ + STEP( 54, UINT64_C(0x0000000000202f65), 0.270, 0.125723194200000, UINT64_C(0x0000000001efe5cd)) \ + STEP( 55, UINT64_C(0x000000000021b1bb), 0.275, 0.131618222656250, UINT64_C(0x0000000002119788)) \ + STEP( 56, UINT64_C(0x0000000000233ce3), 0.280, 0.137647820800000, UINT64_C(0x000000000234d46b)) \ + STEP( 57, UINT64_C(0x000000000024d0c3), 0.285, 0.143810466693750, UINT64_C(0x000000000259a52e)) \ + STEP( 58, UINT64_C(0x0000000000266d40), 0.290, 0.150104539400000, UINT64_C(0x000000000280126e)) \ + STEP( 59, UINT64_C(0x000000000028123d), 0.295, 0.156528321231250, UINT64_C(0x0000000002a824ab)) \ + STEP( 60, UINT64_C(0x000000000029bf9c), 0.300, 0.163080000000000, UINT64_C(0x0000000002d1e447)) \ + STEP( 61, UINT64_C(0x00000000002b753d), 0.305, 0.169757671268750, UINT64_C(0x0000000002fd5984)) \ + STEP( 62, UINT64_C(0x00000000002d32fe), 0.310, 0.176559340600000, UINT64_C(0x00000000032a8c82)) \ + STEP( 63, UINT64_C(0x00000000002ef8bc), 0.315, 0.183482925806250, UINT64_C(0x000000000359853e)) \ + STEP( 64, UINT64_C(0x000000000030c654), 0.320, 0.190526259200000, UINT64_C(0x00000000038a4b92)) \ + STEP( 65, UINT64_C(0x0000000000329b9f), 0.325, 0.197687089843750, UINT64_C(0x0000000003bce731)) \ + STEP( 66, UINT64_C(0x0000000000347875), 0.330, 0.204963085800000, UINT64_C(0x0000000003f15fa6)) \ + STEP( 67, UINT64_C(0x0000000000365cb0), 0.335, 0.212351836381250, UINT64_C(0x000000000427bc56)) \ + STEP( 68, UINT64_C(0x0000000000384825), 0.340, 0.219850854400000, UINT64_C(0x000000000460047b)) \ + STEP( 69, UINT64_C(0x00000000003a3aa8), 0.345, 0.227457578418750, UINT64_C(0x00000000049a3f23)) \ + STEP( 70, UINT64_C(0x00000000003c340f), 0.350, 0.235169375000000, UINT64_C(0x0000000004d67332)) \ + STEP( 71, UINT64_C(0x00000000003e342b), 0.355, 0.242983540956250, UINT64_C(0x000000000514a75d)) \ + STEP( 72, UINT64_C(0x0000000000403ace), 0.360, 0.250897305600000, UINT64_C(0x000000000554e22b)) \ + STEP( 73, UINT64_C(0x00000000004247c8), 0.365, 0.258907832993750, UINT64_C(0x00000000059729f3)) \ + STEP( 74, UINT64_C(0x0000000000445ae9), 0.370, 0.267012224200000, UINT64_C(0x0000000005db84dc)) \ + STEP( 75, UINT64_C(0x0000000000467400), 0.375, 0.275207519531250, UINT64_C(0x000000000621f8dc)) \ + STEP( 76, UINT64_C(0x00000000004892d8), 0.380, 0.283490700800000, UINT64_C(0x00000000066a8bb4)) \ + STEP( 77, UINT64_C(0x00000000004ab740), 0.385, 0.291858693568750, UINT64_C(0x0000000006b542f4)) \ + STEP( 78, UINT64_C(0x00000000004ce102), 0.390, 0.300308369400000, UINT64_C(0x00000000070223f6)) \ + STEP( 79, UINT64_C(0x00000000004f0fe9), 0.395, 0.308836548106250, UINT64_C(0x00000000075133df)) \ + STEP( 80, UINT64_C(0x00000000005143bf), 0.400, 0.317440000000000, UINT64_C(0x0000000007a2779e)) \ + STEP( 81, UINT64_C(0x0000000000537c4d), 0.405, 0.326115448143750, UINT64_C(0x0000000007f5f3eb)) \ + STEP( 82, UINT64_C(0x000000000055b95b), 0.410, 0.334859570600000, UINT64_C(0x00000000084bad46)) \ + STEP( 83, UINT64_C(0x000000000057fab1), 0.415, 0.343669002681250, UINT64_C(0x0000000008a3a7f7)) \ + STEP( 84, UINT64_C(0x00000000005a4015), 0.420, 0.352540339200000, UINT64_C(0x0000000008fde80c)) \ + STEP( 85, UINT64_C(0x00000000005c894e), 0.425, 0.361470136718750, UINT64_C(0x00000000095a715a)) \ + STEP( 86, UINT64_C(0x00000000005ed622), 0.430, 0.370454915800000, UINT64_C(0x0000000009b9477c)) \ + STEP( 87, UINT64_C(0x0000000000612655), 0.435, 0.379491163256250, UINT64_C(0x000000000a1a6dd1)) \ + STEP( 88, UINT64_C(0x00000000006379ac), 0.440, 0.388575334400000, UINT64_C(0x000000000a7de77d)) \ + STEP( 89, UINT64_C(0x000000000065cfeb), 0.445, 0.397703855293750, UINT64_C(0x000000000ae3b768)) \ + STEP( 90, UINT64_C(0x00000000006828d6), 0.450, 0.406873125000000, UINT64_C(0x000000000b4be03e)) \ + STEP( 91, UINT64_C(0x00000000006a842f), 0.455, 0.416079517831250, UINT64_C(0x000000000bb6646d)) \ + STEP( 92, UINT64_C(0x00000000006ce1bb), 0.460, 0.425319385600000, UINT64_C(0x000000000c234628)) \ + STEP( 93, UINT64_C(0x00000000006f413a), 0.465, 0.434589059868750, UINT64_C(0x000000000c928762)) \ + STEP( 94, UINT64_C(0x000000000071a270), 0.470, 0.443884854200000, UINT64_C(0x000000000d0429d2)) \ + STEP( 95, UINT64_C(0x000000000074051d), 0.475, 0.453203066406250, UINT64_C(0x000000000d782eef)) \ + STEP( 96, UINT64_C(0x0000000000766905), 0.480, 0.462539980800000, UINT64_C(0x000000000dee97f4)) \ + STEP( 97, UINT64_C(0x000000000078cde7), 0.485, 0.471891870443750, UINT64_C(0x000000000e6765db)) \ + STEP( 98, UINT64_C(0x00000000007b3387), 0.490, 0.481254999400000, UINT64_C(0x000000000ee29962)) \ + STEP( 99, UINT64_C(0x00000000007d99a4), 0.495, 0.490625624981250, UINT64_C(0x000000000f603306)) \ + STEP( 100, UINT64_C(0x0000000000800000), 0.500, 0.500000000000000, UINT64_C(0x000000000fe03306)) \ + STEP( 101, UINT64_C(0x000000000082665b), 0.505, 0.509374375018750, UINT64_C(0x0000000010629961)) \ + STEP( 102, UINT64_C(0x000000000084cc78), 0.510, 0.518745000600000, UINT64_C(0x0000000010e765d9)) \ + STEP( 103, UINT64_C(0x0000000000873218), 0.515, 0.528108129556250, UINT64_C(0x00000000116e97f1)) \ + STEP( 104, UINT64_C(0x00000000008996fa), 0.520, 0.537460019200000, UINT64_C(0x0000000011f82eeb)) \ + STEP( 105, UINT64_C(0x00000000008bfae2), 0.525, 0.546796933593750, UINT64_C(0x00000000128429cd)) \ + STEP( 106, UINT64_C(0x00000000008e5d8f), 0.530, 0.556115145800000, UINT64_C(0x000000001312875c)) \ + STEP( 107, UINT64_C(0x000000000090bec5), 0.535, 0.565410940131250, UINT64_C(0x0000000013a34621)) \ + STEP( 108, UINT64_C(0x0000000000931e44), 0.540, 0.574680614400000, UINT64_C(0x0000000014366465)) \ + STEP( 109, UINT64_C(0x0000000000957bd0), 0.545, 0.583920482168750, UINT64_C(0x0000000014cbe035)) \ + STEP( 110, UINT64_C(0x000000000097d729), 0.550, 0.593126875000000, UINT64_C(0x000000001563b75e)) \ + STEP( 111, UINT64_C(0x00000000009a3014), 0.555, 0.602296144706250, UINT64_C(0x0000000015fde772)) \ + STEP( 112, UINT64_C(0x00000000009c8653), 0.560, 0.611424665600000, UINT64_C(0x00000000169a6dc5)) \ + STEP( 113, UINT64_C(0x00000000009ed9aa), 0.565, 0.620508836743750, UINT64_C(0x000000001739476f)) \ + STEP( 114, UINT64_C(0x0000000000a129dd), 0.570, 0.629545084200000, UINT64_C(0x0000000017da714c)) \ + STEP( 115, UINT64_C(0x0000000000a376b1), 0.575, 0.638529863281250, UINT64_C(0x00000000187de7fd)) \ + STEP( 116, UINT64_C(0x0000000000a5bfea), 0.580, 0.647459660800000, UINT64_C(0x000000001923a7e7)) \ + STEP( 117, UINT64_C(0x0000000000a8054e), 0.585, 0.656330997318750, UINT64_C(0x0000000019cbad35)) \ + STEP( 118, UINT64_C(0x0000000000aa46a4), 0.590, 0.665140429400000, UINT64_C(0x000000001a75f3d9)) \ + STEP( 119, UINT64_C(0x0000000000ac83b2), 0.595, 0.673884551856250, UINT64_C(0x000000001b22778b)) \ + STEP( 120, UINT64_C(0x0000000000aebc40), 0.600, 0.682560000000000, UINT64_C(0x000000001bd133cb)) \ + STEP( 121, UINT64_C(0x0000000000b0f016), 0.605, 0.691163451893750, UINT64_C(0x000000001c8223e1)) \ + STEP( 122, UINT64_C(0x0000000000b31efd), 0.610, 0.699691630600000, UINT64_C(0x000000001d3542de)) \ + STEP( 123, UINT64_C(0x0000000000b548bf), 0.615, 0.708141306431250, UINT64_C(0x000000001dea8b9d)) \ + STEP( 124, UINT64_C(0x0000000000b76d27), 0.620, 0.716509299200000, UINT64_C(0x000000001ea1f8c4)) \ + STEP( 125, UINT64_C(0x0000000000b98c00), 0.625, 0.724792480468750, UINT64_C(0x000000001f5b84c4)) \ + STEP( 126, UINT64_C(0x0000000000bba516), 0.630, 0.732987775800000, UINT64_C(0x00000000201729da)) \ + STEP( 127, UINT64_C(0x0000000000bdb837), 0.635, 0.741092167006250, UINT64_C(0x0000000020d4e211)) \ + STEP( 128, UINT64_C(0x0000000000bfc531), 0.640, 0.749102694400000, UINT64_C(0x000000002194a742)) \ + STEP( 129, UINT64_C(0x0000000000c1cbd4), 0.645, 0.757016459043750, UINT64_C(0x0000000022567316)) \ + STEP( 130, UINT64_C(0x0000000000c3cbf0), 0.650, 0.764830625000000, UINT64_C(0x00000000231a3f06)) \ + STEP( 131, UINT64_C(0x0000000000c5c557), 0.655, 0.772542421581250, UINT64_C(0x0000000023e0045d)) \ + STEP( 132, UINT64_C(0x0000000000c7b7da), 0.660, 0.780149145600000, UINT64_C(0x0000000024a7bc37)) \ + STEP( 133, UINT64_C(0x0000000000c9a34f), 0.665, 0.787648163618750, UINT64_C(0x0000000025715f86)) \ + STEP( 134, UINT64_C(0x0000000000cb878a), 0.670, 0.795036914200000, UINT64_C(0x00000000263ce710)) \ + STEP( 135, UINT64_C(0x0000000000cd6460), 0.675, 0.802312910156250, UINT64_C(0x00000000270a4b70)) \ + STEP( 136, UINT64_C(0x0000000000cf39ab), 0.680, 0.809473740800000, UINT64_C(0x0000000027d9851b)) \ + STEP( 137, UINT64_C(0x0000000000d10743), 0.685, 0.816517074193750, UINT64_C(0x0000000028aa8c5e)) \ + STEP( 138, UINT64_C(0x0000000000d2cd01), 0.690, 0.823440659400000, UINT64_C(0x00000000297d595f)) \ + STEP( 139, UINT64_C(0x0000000000d48ac2), 0.695, 0.830242328731250, UINT64_C(0x000000002a51e421)) \ + STEP( 140, UINT64_C(0x0000000000d64063), 0.700, 0.836920000000000, UINT64_C(0x000000002b282484)) \ + STEP( 141, UINT64_C(0x0000000000d7edc2), 0.705, 0.843471678768750, UINT64_C(0x000000002c001246)) \ + STEP( 142, UINT64_C(0x0000000000d992bf), 0.710, 0.849895460600000, UINT64_C(0x000000002cd9a505)) \ + STEP( 143, UINT64_C(0x0000000000db2f3c), 0.715, 0.856189533306250, UINT64_C(0x000000002db4d441)) \ + STEP( 144, UINT64_C(0x0000000000dcc31c), 0.720, 0.862352179200000, UINT64_C(0x000000002e91975d)) \ + STEP( 145, UINT64_C(0x0000000000de4e44), 0.725, 0.868381777343750, UINT64_C(0x000000002f6fe5a1)) \ + STEP( 146, UINT64_C(0x0000000000dfd09a), 0.730, 0.874276805800000, UINT64_C(0x00000000304fb63b)) \ + STEP( 147, UINT64_C(0x0000000000e14a07), 0.735, 0.880035843881250, UINT64_C(0x0000000031310042)) \ + STEP( 148, UINT64_C(0x0000000000e2ba74), 0.740, 0.885657574400000, UINT64_C(0x000000003213bab6)) \ + STEP( 149, UINT64_C(0x0000000000e421cd), 0.745, 0.891140785918750, UINT64_C(0x0000000032f7dc83)) \ + STEP( 150, UINT64_C(0x0000000000e58000), 0.750, 0.896484375000000, UINT64_C(0x0000000033dd5c83)) \ + STEP( 151, UINT64_C(0x0000000000e6d4fb), 0.755, 0.901687348456250, UINT64_C(0x0000000034c4317e)) \ + STEP( 152, UINT64_C(0x0000000000e820b0), 0.760, 0.906748825600000, UINT64_C(0x0000000035ac522e)) \ + STEP( 153, UINT64_C(0x0000000000e96313), 0.765, 0.911668040493750, UINT64_C(0x000000003695b541)) \ + STEP( 154, UINT64_C(0x0000000000ea9c18), 0.770, 0.916444344200000, UINT64_C(0x0000000037805159)) \ + STEP( 155, UINT64_C(0x0000000000ebcbb7), 0.775, 0.921077207031250, UINT64_C(0x00000000386c1d10)) \ + STEP( 156, UINT64_C(0x0000000000ecf1e8), 0.780, 0.925566220800000, UINT64_C(0x0000000039590ef8)) \ + STEP( 157, UINT64_C(0x0000000000ee0ea7), 0.785, 0.929911101068750, UINT64_C(0x000000003a471d9f)) \ + STEP( 158, UINT64_C(0x0000000000ef21f1), 0.790, 0.934111689400000, UINT64_C(0x000000003b363f90)) \ + STEP( 159, UINT64_C(0x0000000000f02bc6), 0.795, 0.938167955606250, UINT64_C(0x000000003c266b56)) \ + STEP( 160, UINT64_C(0x0000000000f12c27), 0.800, 0.942080000000000, UINT64_C(0x000000003d17977d)) \ + STEP( 161, UINT64_C(0x0000000000f22319), 0.805, 0.945848055643750, UINT64_C(0x000000003e09ba96)) \ + STEP( 162, UINT64_C(0x0000000000f310a1), 0.810, 0.949472490600000, UINT64_C(0x000000003efccb37)) \ + STEP( 163, UINT64_C(0x0000000000f3f4c7), 0.815, 0.952953810181250, UINT64_C(0x000000003ff0bffe)) \ + STEP( 164, UINT64_C(0x0000000000f4cf98), 0.820, 0.956292659200000, UINT64_C(0x0000000040e58f96)) \ + STEP( 165, UINT64_C(0x0000000000f5a120), 0.825, 0.959489824218750, UINT64_C(0x0000000041db30b6)) \ + STEP( 166, UINT64_C(0x0000000000f6696e), 0.830, 0.962546235800000, UINT64_C(0x0000000042d19a24)) \ + STEP( 167, UINT64_C(0x0000000000f72894), 0.835, 0.965462970756250, UINT64_C(0x0000000043c8c2b8)) \ + STEP( 168, UINT64_C(0x0000000000f7dea8), 0.840, 0.968241254400000, UINT64_C(0x0000000044c0a160)) \ + STEP( 169, UINT64_C(0x0000000000f88bc0), 0.845, 0.970882462793750, UINT64_C(0x0000000045b92d20)) \ + STEP( 170, UINT64_C(0x0000000000f92ff6), 0.850, 0.973388125000000, UINT64_C(0x0000000046b25d16)) \ + STEP( 171, UINT64_C(0x0000000000f9cb67), 0.855, 0.975759925331250, UINT64_C(0x0000000047ac287d)) \ + STEP( 172, UINT64_C(0x0000000000fa5e30), 0.860, 0.977999705600000, UINT64_C(0x0000000048a686ad)) \ + STEP( 173, UINT64_C(0x0000000000fae874), 0.865, 0.980109467368750, UINT64_C(0x0000000049a16f21)) \ + STEP( 174, UINT64_C(0x0000000000fb6a57), 0.870, 0.982091374200000, UINT64_C(0x000000004a9cd978)) \ + STEP( 175, UINT64_C(0x0000000000fbe400), 0.875, 0.983947753906250, UINT64_C(0x000000004b98bd78)) \ + STEP( 176, UINT64_C(0x0000000000fc5598), 0.880, 0.985681100800000, UINT64_C(0x000000004c951310)) \ + STEP( 177, UINT64_C(0x0000000000fcbf4e), 0.885, 0.987294077943750, UINT64_C(0x000000004d91d25e)) \ + STEP( 178, UINT64_C(0x0000000000fd214f), 0.890, 0.988789519400000, UINT64_C(0x000000004e8ef3ad)) \ + STEP( 179, UINT64_C(0x0000000000fd7bcf), 0.895, 0.990170432481250, UINT64_C(0x000000004f8c6f7c)) \ + STEP( 180, UINT64_C(0x0000000000fdcf03), 0.900, 0.991440000000000, UINT64_C(0x00000000508a3e7f)) \ + STEP( 181, UINT64_C(0x0000000000fe1b23), 0.905, 0.992601582518750, UINT64_C(0x00000000518859a2)) \ + STEP( 182, UINT64_C(0x0000000000fe606a), 0.910, 0.993658720600000, UINT64_C(0x000000005286ba0c)) \ + STEP( 183, UINT64_C(0x0000000000fe9f18), 0.915, 0.994615137056250, UINT64_C(0x0000000053855924)) \ + STEP( 184, UINT64_C(0x0000000000fed76e), 0.920, 0.995474739200000, UINT64_C(0x0000000054843092)) \ + STEP( 185, UINT64_C(0x0000000000ff09b0), 0.925, 0.996241621093750, UINT64_C(0x0000000055833a42)) \ + STEP( 186, UINT64_C(0x0000000000ff3627), 0.930, 0.996920065800000, UINT64_C(0x0000000056827069)) \ + STEP( 187, UINT64_C(0x0000000000ff5d1d), 0.935, 0.997514547631250, UINT64_C(0x000000005781cd86)) \ + STEP( 188, UINT64_C(0x0000000000ff7ee0), 0.940, 0.998029734400000, UINT64_C(0x0000000058814c66)) \ + STEP( 189, UINT64_C(0x0000000000ff9bc3), 0.945, 0.998470489668750, UINT64_C(0x000000005980e829)) \ + STEP( 190, UINT64_C(0x0000000000ffb419), 0.950, 0.998841875000000, UINT64_C(0x000000005a809c42)) \ + STEP( 191, UINT64_C(0x0000000000ffc83d), 0.955, 0.999149152206250, UINT64_C(0x000000005b80647f)) \ + STEP( 192, UINT64_C(0x0000000000ffd888), 0.960, 0.999397785600000, UINT64_C(0x000000005c803d07)) \ + STEP( 193, UINT64_C(0x0000000000ffe55b), 0.965, 0.999593444243750, UINT64_C(0x000000005d802262)) \ + STEP( 194, UINT64_C(0x0000000000ffef17), 0.970, 0.999742004200000, UINT64_C(0x000000005e801179)) \ + STEP( 195, UINT64_C(0x0000000000fff623), 0.975, 0.999849550781250, UINT64_C(0x000000005f80079c)) \ + STEP( 196, UINT64_C(0x0000000000fffae9), 0.980, 0.999922380800000, UINT64_C(0x0000000060800285)) \ + STEP( 197, UINT64_C(0x0000000000fffdd6), 0.985, 0.999967004818750, UINT64_C(0x000000006180005b)) \ + STEP( 198, UINT64_C(0x0000000000ffff5a), 0.990, 0.999990149400000, UINT64_C(0x00000000627fffb5)) \ + STEP( 199, UINT64_C(0x0000000000ffffeb), 0.995, 0.999998759356250, UINT64_C(0x00000000637fffa0)) \ + STEP( 200, UINT64_C(0x0000000001000000), 1.000, 1.000000000000000, UINT64_C(0x00000000647fffa0)) \ #endif /* JEMALLOC_INTERNAL_SMOOTHSTEP_H */ diff --git a/include/jemalloc/internal/smoothstep.sh b/include/jemalloc/internal/smoothstep.sh index 65de97bf..41164615 100755 --- a/include/jemalloc/internal/smoothstep.sh +++ b/include/jemalloc/internal/smoothstep.sh @@ -83,14 +83,16 @@ cat <extents_dirty, extent); if (arena_dirty_decay_ms_get(arena) == 0) { - arena_decay_dirty(tsdn, arena, true); + arena_decay_dirty(tsdn, arena, false, true); } } @@ -606,12 +613,6 @@ arena_decay_deadline_reached(const arena_decay_t *decay, const nstime_t *time) { static size_t arena_decay_backlog_npages_limit(const arena_decay_t *decay) { - static const uint64_t h_steps[] = { -#define STEP(step, h, x, y) \ - h, - SMOOTHSTEP -#undef STEP - }; uint64_t sum; size_t npages_limit_backlog; unsigned i; @@ -660,17 +661,27 @@ arena_decay_backlog_update(arena_decay_t *decay, extents_t *extents, arena_decay_backlog_update_last(decay, extents); } +static void +arena_decay_try_purge(tsdn_t *tsdn, arena_t *arena, + arena_decay_t *decay, extents_t *extents) { + size_t npages_limit = arena_decay_backlog_npages_limit(decay); + + if (extents_npages_get(extents) > npages_limit) { + arena_decay_to_limit(tsdn, arena, decay, extents, false, + npages_limit); + } +} + static void arena_decay_epoch_advance_helper(arena_decay_t *decay, extents_t *extents, const nstime_t *time) { - uint64_t nadvance_u64; - nstime_t delta; - assert(arena_decay_deadline_reached(decay, time)); + nstime_t delta; nstime_copy(&delta, time); nstime_subtract(&delta, &decay->epoch); - nadvance_u64 = nstime_divide(&delta, &decay->interval); + + uint64_t nadvance_u64 = nstime_divide(&delta, &decay->interval); assert(nadvance_u64 > 0); /* Add nadvance_u64 decay intervals to epoch. */ @@ -686,14 +697,13 @@ arena_decay_epoch_advance_helper(arena_decay_t *decay, extents_t *extents, } static void -arena_decay_epoch_advance_purge(tsdn_t *tsdn, arena_t *arena, - arena_decay_t *decay, extents_t *extents) { - size_t npages_limit = arena_decay_backlog_npages_limit(decay); - - if (extents_npages_get(extents) > npages_limit) { - arena_decay_to_limit(tsdn, arena, decay, extents, false, - npages_limit); +arena_decay_epoch_advance(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, + extents_t *extents, const nstime_t *time, bool purge) { + arena_decay_epoch_advance_helper(decay, extents, time); + if (purge) { + arena_decay_try_purge(tsdn, arena, decay, extents); } + /* * There may be concurrent ndirty fluctuation between the purge above * and the nunpurged update below, but this is inconsequential to decay @@ -702,13 +712,6 @@ arena_decay_epoch_advance_purge(tsdn_t *tsdn, arena_t *arena, decay->nunpurged = extents_npages_get(extents); } -static void -arena_decay_epoch_advance(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, - extents_t *extents, const nstime_t *time) { - arena_decay_epoch_advance_helper(decay, extents, time); - arena_decay_epoch_advance_purge(tsdn, arena, decay, extents); -} - static void arena_decay_reinit(arena_decay_t *decay, extents_t *extents, ssize_t decay_ms) { arena_decay_ms_write(decay, decay_ms); @@ -759,9 +762,9 @@ arena_decay_ms_valid(ssize_t decay_ms) { return false; } -static void +static bool arena_maybe_decay(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, - extents_t *extents) { + extents_t *extents, bool is_background_thread) { malloc_mutex_assert_owner(tsdn, &decay->mtx); /* Purge all or nothing if the option is disabled. */ @@ -771,7 +774,7 @@ arena_maybe_decay(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, arena_decay_to_limit(tsdn, arena, decay, extents, false, 0); } - return; + return false; } nstime_t time; @@ -799,11 +802,20 @@ arena_maybe_decay(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, * If the deadline has been reached, advance to the current epoch and * purge to the new limit if necessary. Note that dirty pages created * during the current epoch are not subject to purge until a future - * epoch, so as a result purging only happens during epoch advances. + * epoch, so as a result purging only happens during epoch advances, or + * being triggered by background threads (scheduled event). */ - if (arena_decay_deadline_reached(decay, &time)) { - arena_decay_epoch_advance(tsdn, arena, decay, extents, &time); + bool advance_epoch = arena_decay_deadline_reached(decay, &time); + if (advance_epoch) { + bool should_purge = is_background_thread || + !background_thread_enabled(); + arena_decay_epoch_advance(tsdn, arena, decay, extents, &time, + should_purge); + } else if (is_background_thread) { + arena_decay_try_purge(tsdn, arena, decay, extents); } + + return advance_epoch; } static ssize_t @@ -838,7 +850,7 @@ arena_decay_ms_set(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, * arbitrary change during initial arena configuration. */ arena_decay_reinit(decay, extents, decay_ms); - arena_maybe_decay(tsdn, arena, decay, extents); + arena_maybe_decay(tsdn, arena, decay, extents, false); malloc_mutex_unlock(tsdn, &decay->mtx); return false; @@ -974,40 +986,57 @@ arena_decay_to_limit(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, static bool arena_decay_impl(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, - extents_t *extents, bool all) { + extents_t *extents, bool is_background_thread, bool all) { if (all) { malloc_mutex_lock(tsdn, &decay->mtx); arena_decay_to_limit(tsdn, arena, decay, extents, all, 0); - } else { - if (malloc_mutex_trylock(tsdn, &decay->mtx)) { - /* No need to wait if another thread is in progress. */ - return true; - } - arena_maybe_decay(tsdn, arena, decay, extents); + malloc_mutex_unlock(tsdn, &decay->mtx); + + return false; + } + + if (malloc_mutex_trylock(tsdn, &decay->mtx)) { + /* No need to wait if another thread is in progress. */ + return true; + } + + bool epoch_advanced = arena_maybe_decay(tsdn, arena, decay, extents, + is_background_thread); + size_t npages_new; + if (epoch_advanced) { + /* Backlog is updated on epoch advance. */ + npages_new = decay->backlog[SMOOTHSTEP_NSTEPS-1]; } malloc_mutex_unlock(tsdn, &decay->mtx); + if (have_background_thread && background_thread_enabled() && + epoch_advanced && !is_background_thread) { + background_thread_interval_check(tsdn, arena, decay, npages_new); + } + return false; } static bool -arena_decay_dirty(tsdn_t *tsdn, arena_t *arena, bool all) { +arena_decay_dirty(tsdn_t *tsdn, arena_t *arena, bool is_background_thread, + bool all) { return arena_decay_impl(tsdn, arena, &arena->decay_dirty, - &arena->extents_dirty, all); + &arena->extents_dirty, is_background_thread, all); } static bool -arena_decay_muzzy(tsdn_t *tsdn, arena_t *arena, bool all) { +arena_decay_muzzy(tsdn_t *tsdn, arena_t *arena, bool is_background_thread, + bool all) { return arena_decay_impl(tsdn, arena, &arena->decay_muzzy, - &arena->extents_muzzy, all); + &arena->extents_muzzy, is_background_thread, all); } void -arena_decay(tsdn_t *tsdn, arena_t *arena, bool all) { - if (arena_decay_dirty(tsdn, arena, all)) { +arena_decay(tsdn_t *tsdn, arena_t *arena, bool is_background_thread, bool all) { + if (arena_decay_dirty(tsdn, arena, is_background_thread, all)) { return; } - arena_decay_muzzy(tsdn, arena, all); + arena_decay_muzzy(tsdn, arena, is_background_thread, all); } static void @@ -1173,6 +1202,7 @@ arena_destroy(tsd_t *tsd, arena_t *arena) { * extents, so only retained extents may remain. */ assert(extents_npages_get(&arena->extents_dirty) == 0); + assert(extents_npages_get(&arena->extents_muzzy) == 0); /* Deallocate retained memory. */ arena_destroy_retained(tsd_tsdn(tsd), arena); @@ -1971,19 +2001,35 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { } arena->base = base; + /* Set arena before creating background threads. */ + arena_set(ind, arena); nstime_init(&arena->create_time, 0); nstime_update(&arena->create_time); - /* We don't support reetrancy for arena 0 bootstrapping. */ - if (ind != 0 && hooks_arena_new_hook) { + /* We don't support reentrancy for arena 0 bootstrapping. */ + if (ind != 0) { /* * If we're here, then arena 0 already exists, so bootstrapping * is done enough that we should have tsd. */ + assert(!tsdn_null(tsdn)); pre_reentrancy(tsdn_tsd(tsdn)); - hooks_arena_new_hook(); + if (hooks_arena_new_hook) { + hooks_arena_new_hook(); + } post_reentrancy(tsdn_tsd(tsdn)); + + /* background_thread_create() handles reentrancy internally. */ + if (have_background_thread) { + bool err; + malloc_mutex_lock(tsdn, &background_thread_lock); + err = background_thread_create(tsdn_tsd(tsdn), ind); + malloc_mutex_unlock(tsdn, &background_thread_lock); + if (err) { + goto label_error; + } + } } return arena; diff --git a/src/background_thread.c b/src/background_thread.c new file mode 100644 index 00000000..671e57f7 --- /dev/null +++ b/src/background_thread.c @@ -0,0 +1,572 @@ +#define JEMALLOC_BACKGROUND_THREAD_C_ +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/jemalloc_internal_includes.h" + +#include "jemalloc/internal/assert.h" + +/******************************************************************************/ +/* Data. */ + +/* This option should be opt-in only. */ +#define BACKGROUND_THREAD_DEFAULT false +/* Read-only after initialization. */ +bool opt_background_thread = BACKGROUND_THREAD_DEFAULT; + +/* Used for thread creation, termination and stats. */ +malloc_mutex_t background_thread_lock; +/* Indicates global state. Atomic because decay reads this w/o locking. */ +atomic_b_t background_thread_enabled_state; +size_t n_background_threads; +/* Thread info per-index. */ +background_thread_info_t *background_thread_info; + +/******************************************************************************/ + +#ifndef JEMALLOC_BACKGROUND_THREAD +#define NOT_REACHED { not_reached(); } +bool background_thread_create(tsd_t *tsd, unsigned arena_ind) NOT_REACHED +bool background_threads_init(tsd_t *tsd) NOT_REACHED +bool background_threads_enable(tsd_t *tsd) NOT_REACHED +bool background_threads_disable(tsd_t *tsd) NOT_REACHED +bool background_threads_disable_single(tsd_t *tsd, + background_thread_info_t *info) NOT_REACHED +void background_thread_interval_check(tsdn_t *tsdn, arena_t *arena, + arena_decay_t *decay, size_t npages_new) NOT_REACHED +void background_thread_prefork0(tsdn_t *tsdn) NOT_REACHED +void background_thread_prefork1(tsdn_t *tsdn) NOT_REACHED +void background_thread_postfork_parent(tsdn_t *tsdn) NOT_REACHED +void background_thread_postfork_child(tsdn_t *tsdn) NOT_REACHED +#undef NOT_REACHED +#else +bool +background_threads_init(tsd_t *tsd) { + assert(have_background_thread); + assert(narenas_total_get() > 0); + + background_thread_enabled_set(tsd_tsdn(tsd), opt_background_thread); + if (malloc_mutex_init(&background_thread_lock, + "background_thread_global", + WITNESS_RANK_BACKGROUND_THREAD_GLOBAL, + malloc_mutex_rank_exclusive)) { + return true; + } + background_thread_info = (background_thread_info_t *)base_alloc( + tsd_tsdn(tsd), b0get(), ncpus * sizeof(background_thread_info_t), + CACHELINE); + if (background_thread_info == NULL) { + return true; + } + + for (unsigned i = 0; i < ncpus; i++) { + background_thread_info_t *info = &background_thread_info[i]; + if (malloc_mutex_init(&info->mtx, "background_thread", + WITNESS_RANK_BACKGROUND_THREAD, + malloc_mutex_rank_exclusive)) { + return true; + } + if (pthread_cond_init(&info->cond, NULL)) { + return true; + } + info->started = false; + nstime_init(&info->next_wakeup, 0); + info->npages_to_purge_new = 0; + } + + return false; +} + +static inline bool +set_current_thread_affinity(UNUSED int cpu) { +#if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY) + cpu_set_t cpuset; + CPU_ZERO(&cpuset); + CPU_SET(cpu, &cpuset); + int ret = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); + + return (ret != 0); +#else + return false; +#endif +} + +/* Threshold for determining when to wake up the background thread. */ +#define BACKGROUND_THREAD_NPAGES_THRESHOLD UINT64_C(1024) +#define BILLION UINT64_C(1000000000) +/* Minimal sleep interval 100 ms. */ +#define BACKGROUND_THREAD_MIN_INTERVAL_NS (BILLION / 10) +#define BACKGROUND_THREAD_INDEFINITE_SLEEP UINT64_MAX + +static inline size_t +decay_npurge_after_interval(arena_decay_t *decay, size_t interval) { + size_t i; + uint64_t sum = 0; + for (i = 0; i < interval; i++) { + sum += decay->backlog[i] * h_steps[i]; + } + for (; i < SMOOTHSTEP_NSTEPS; i++) { + sum += decay->backlog[i] * (h_steps[i] - h_steps[i - interval]); + } + + return (size_t)(sum >> SMOOTHSTEP_BFP); +} + +static uint64_t +arena_decay_compute_purge_interval_impl(tsdn_t *tsdn, arena_decay_t *decay, + extents_t *extents) { + if (malloc_mutex_trylock(tsdn, &decay->mtx)) { + /* Use minimal interval if decay is contended. */ + return BACKGROUND_THREAD_MIN_INTERVAL_NS; + } + + uint64_t interval; + ssize_t decay_time = atomic_load_zd(&decay->time_ms, ATOMIC_RELAXED); + if (decay_time <= 0) { + /* Purging is eagerly done or disabled currently. */ + interval = BACKGROUND_THREAD_INDEFINITE_SLEEP; + goto label_done; + } + + uint64_t decay_interval_ns = nstime_ns(&decay->interval); + assert(decay_interval_ns > 0); + size_t npages = extents_npages_get(extents); + if (npages == 0) { + unsigned i; + for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) { + if (decay->backlog[i] > 0) { + break; + } + } + if (i == SMOOTHSTEP_NSTEPS) { + /* No dirty pages recorded. Sleep indefinitely. */ + interval = BACKGROUND_THREAD_INDEFINITE_SLEEP; + goto label_done; + } + } + if (npages <= BACKGROUND_THREAD_NPAGES_THRESHOLD) { + /* Use max interval. */ + interval = decay_interval_ns * SMOOTHSTEP_NSTEPS; + goto label_done; + } + + size_t lb = BACKGROUND_THREAD_MIN_INTERVAL_NS / decay_interval_ns; + size_t ub = SMOOTHSTEP_NSTEPS; + /* Minimal 2 intervals to ensure reaching next epoch deadline. */ + lb = (lb < 2) ? 2 : lb; + if ((decay_interval_ns * ub <= BACKGROUND_THREAD_MIN_INTERVAL_NS) || + (lb + 2 > ub)) { + interval = BACKGROUND_THREAD_MIN_INTERVAL_NS; + goto label_done; + } + + assert(lb + 2 <= ub); + size_t npurge_lb, npurge_ub; + npurge_lb = decay_npurge_after_interval(decay, lb); + if (npurge_lb > BACKGROUND_THREAD_NPAGES_THRESHOLD) { + interval = decay_interval_ns * lb; + goto label_done; + } + npurge_ub = decay_npurge_after_interval(decay, ub); + if (npurge_ub < BACKGROUND_THREAD_NPAGES_THRESHOLD) { + interval = decay_interval_ns * ub; + goto label_done; + } + + unsigned n_search = 0; + size_t target, npurge; + while ((npurge_lb + BACKGROUND_THREAD_NPAGES_THRESHOLD < npurge_ub) + && (lb + 2 < ub)) { + target = (lb + ub) / 2; + npurge = decay_npurge_after_interval(decay, target); + if (npurge > BACKGROUND_THREAD_NPAGES_THRESHOLD) { + ub = target; + npurge_ub = npurge; + } else { + lb = target; + npurge_lb = npurge; + } + assert(n_search++ < lg_floor(SMOOTHSTEP_NSTEPS) + 1); + } + interval = decay_interval_ns * (ub + lb) / 2; +label_done: + interval = (interval < BACKGROUND_THREAD_MIN_INTERVAL_NS) ? + BACKGROUND_THREAD_MIN_INTERVAL_NS : interval; + malloc_mutex_unlock(tsdn, &decay->mtx); + + return interval; +} + +/* Compute purge interval for background threads. */ +static uint64_t +arena_decay_compute_purge_interval(tsdn_t *tsdn, arena_t *arena) { + uint64_t i1, i2; + i1 = arena_decay_compute_purge_interval_impl(tsdn, &arena->decay_dirty, + &arena->extents_dirty); + if (i1 == BACKGROUND_THREAD_MIN_INTERVAL_NS) { + return i1; + } + i2 = arena_decay_compute_purge_interval_impl(tsdn, &arena->decay_muzzy, + &arena->extents_muzzy); + + return i1 < i2 ? i1 : i2; +} + +static inline uint64_t +background_work_once(tsdn_t *tsdn, unsigned ind) { + arena_t *arena; + unsigned i, narenas; + uint64_t min_interval; + + min_interval = BACKGROUND_THREAD_INDEFINITE_SLEEP; + narenas = narenas_total_get(); + for (i = ind; i < narenas; i += ncpus) { + arena = arena_get(tsdn, i, false); + if (!arena) { + continue; + } + + arena_decay(tsdn, arena, true, false); + uint64_t interval = arena_decay_compute_purge_interval(tsdn, + arena); + if (interval == BACKGROUND_THREAD_MIN_INTERVAL_NS) { + return interval; + } + + assert(interval > BACKGROUND_THREAD_MIN_INTERVAL_NS); + if (min_interval > interval) { + min_interval = interval; + } + } + + return min_interval; +} + +static void +background_work(tsdn_t *tsdn, unsigned ind) { + int ret; + background_thread_info_t *info = &background_thread_info[ind]; + + malloc_mutex_lock(tsdn, &info->mtx); + while (info->started) { + uint64_t interval = background_work_once(tsdn, ind); + info->npages_to_purge_new = 0; + + if (interval == BACKGROUND_THREAD_INDEFINITE_SLEEP) { + nstime_init(&info->next_wakeup, + BACKGROUND_THREAD_INDEFINITE_SLEEP); + ret = pthread_cond_wait(&info->cond, &info->mtx.lock); + assert(ret == 0); + continue; + } + + assert(interval >= BACKGROUND_THREAD_MIN_INTERVAL_NS && + interval <= BACKGROUND_THREAD_INDEFINITE_SLEEP); + nstime_init(&info->next_wakeup, 0); + nstime_update(&info->next_wakeup); + info->next_wakeup.ns += interval; + + nstime_t ts_wakeup; + struct timeval tv; + gettimeofday(&tv, NULL); + nstime_init2(&ts_wakeup, tv.tv_sec, + tv.tv_usec * 1000 + interval); + struct timespec ts; + ts.tv_sec = (size_t)nstime_sec(&ts_wakeup); + ts.tv_nsec = (size_t)nstime_nsec(&ts_wakeup); + ret = pthread_cond_timedwait(&info->cond, &info->mtx.lock, + &ts); + assert(ret == ETIMEDOUT || ret == 0); + } + malloc_mutex_unlock(tsdn, &info->mtx); +} + +static void * +background_thread_entry(void *ind_arg) { + unsigned thread_ind = (unsigned)(uintptr_t)ind_arg; + assert(thread_ind < narenas_total_get() && thread_ind < ncpus); + + if (opt_percpu_arena != percpu_arena_disabled) { + set_current_thread_affinity((int)thread_ind); + } + /* + * Start periodic background work. We avoid fetching tsd to keep the + * background thread "outside", since there may be side effects, for + * example triggering new arena creation (which in turn triggers + * background thread creation). + */ + background_work(TSDN_NULL, thread_ind); + assert(pthread_equal(pthread_self(), + background_thread_info[thread_ind].thread)); + + return NULL; +} + +/* Create a new background thread if needed. */ +bool +background_thread_create(tsd_t *tsd, unsigned arena_ind) { + assert(have_background_thread); + malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock); + + /* We create at most NCPUs threads. */ + size_t thread_ind = arena_ind % ncpus; + background_thread_info_t *info = &background_thread_info[thread_ind]; + + bool need_new_thread; + malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); + need_new_thread = background_thread_enabled() && !info->started; + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); + if (!need_new_thread) { + return false; + } + + pre_reentrancy(tsd); + int err; + load_pthread_create_fptr(); + if ((err = pthread_create(&info->thread, NULL, + background_thread_entry, (void *)thread_ind)) != 0) { + malloc_printf(": arena %u background thread creation " + "failed (%d).\n", arena_ind, err); + } + post_reentrancy(tsd); + + malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); + assert(info->started == false); + if (err == 0) { + info->started = true; + n_background_threads++; + } + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); + + return (err != 0); +} + +bool +background_threads_enable(tsd_t *tsd) { + assert(n_background_threads == 0); + assert(background_thread_enabled()); + malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock); + + VARIABLE_ARRAY(bool, created, ncpus); + unsigned i, ncreated; + for (i = 0; i < ncpus; i++) { + created[i] = false; + } + ncreated = 0; + + unsigned n = narenas_total_get(); + for (i = 0; i < n; i++) { + if (created[i % ncpus] || + arena_get(tsd_tsdn(tsd), i, false) == NULL) { + continue; + } + if (background_thread_create(tsd, i)) { + return true; + } + created[i % ncpus] = true; + if (++ncreated == ncpus) { + break; + } + } + + return false; +} + +bool +background_threads_disable_single(tsd_t *tsd, background_thread_info_t *info) { + malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock); + pre_reentrancy(tsd); + + bool has_thread; + malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); + if (info->started) { + has_thread = true; + info->started = false; + pthread_cond_signal(&info->cond); + } else { + has_thread = false; + } + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); + + if (!has_thread) { + post_reentrancy(tsd); + return false; + } + void *ret; + if (pthread_join(info->thread, &ret)) { + post_reentrancy(tsd); + return true; + } + assert(ret == NULL); + n_background_threads--; + post_reentrancy(tsd); + + return false; +} + +bool +background_threads_disable(tsd_t *tsd) { + assert(!background_thread_enabled()); + for (unsigned i = 0; i < ncpus; i++) { + background_thread_info_t *info = &background_thread_info[i]; + if (background_threads_disable_single(tsd, info)) { + return true; + } + } + assert(n_background_threads == 0); + + return false; +} + +/* Check if we need to signal the background thread early. */ +void +background_thread_interval_check(tsdn_t *tsdn, arena_t *arena, + arena_decay_t *decay, size_t npages_new) { + background_thread_info_t *info = arena_background_thread_info_get( + arena); + + if (malloc_mutex_trylock(tsdn, &info->mtx)) { + /* + * Background thread may hold the mutex for a long period of + * time. We'd like to avoid the variance on application + * threads. So keep this non-blocking, and leave the work to a + * future epoch. + */ + return; + } + + if (!info->started) { + goto label_done; + } + if (malloc_mutex_trylock(tsdn, &decay->mtx)) { + goto label_done; + } + + ssize_t decay_time = atomic_load_zd(&decay->time_ms, ATOMIC_RELAXED); + if (decay_time <= 0) { + /* Purging is eagerly done or disabled currently. */ + goto label_done_unlock2; + } + if (nstime_compare(&info->next_wakeup, &decay->epoch) <= 0) { + goto label_done_unlock2; + } + + uint64_t decay_interval_ns = nstime_ns(&decay->interval); + assert(decay_interval_ns > 0); + nstime_t diff; + nstime_copy(&diff, &info->next_wakeup); + nstime_subtract(&diff, &decay->epoch); + if (nstime_ns(&diff) < BACKGROUND_THREAD_MIN_INTERVAL_NS) { + goto label_done_unlock2; + } + + if (npages_new > 0) { + size_t n_epoch = (size_t)(nstime_ns(&diff) / decay_interval_ns); + /* + * Compute how many new pages we would need to purge by the next + * wakeup, which is used to determine if we should signal the + * background thread. + */ + uint64_t npurge_new; + if (n_epoch >= SMOOTHSTEP_NSTEPS) { + npurge_new = npages_new; + } else { + uint64_t h_steps_max = h_steps[SMOOTHSTEP_NSTEPS - 1]; + assert(h_steps_max >= + h_steps[SMOOTHSTEP_NSTEPS - 1 - n_epoch]); + npurge_new = npages_new * (h_steps_max - + h_steps[SMOOTHSTEP_NSTEPS - 1 - n_epoch]); + npurge_new >>= SMOOTHSTEP_BFP; + } + info->npages_to_purge_new += npurge_new; + } + + if (info->npages_to_purge_new > BACKGROUND_THREAD_NPAGES_THRESHOLD || + (nstime_ns(&info->next_wakeup) == + BACKGROUND_THREAD_INDEFINITE_SLEEP && info->npages_to_purge_new > 0)) { + info->npages_to_purge_new = 0; + pthread_cond_signal(&info->cond); + } +label_done_unlock2: + malloc_mutex_unlock(tsdn, &decay->mtx); +label_done: + malloc_mutex_unlock(tsdn, &info->mtx); +} + +void +background_thread_prefork0(tsdn_t *tsdn) { + malloc_mutex_prefork(tsdn, &background_thread_lock); + if (background_thread_enabled()) { + background_thread_enabled_set(tsdn, false); + background_threads_disable(tsdn_tsd(tsdn)); + /* Enable again to re-create threads after fork. */ + background_thread_enabled_set(tsdn, true); + } + assert(n_background_threads == 0); +} + +void +background_thread_prefork1(tsdn_t *tsdn) { + for (unsigned i = 0; i < ncpus; i++) { + malloc_mutex_prefork(tsdn, &background_thread_info[i].mtx); + } +} + +static void +background_thread_postfork_init(tsdn_t *tsdn) { + if (background_thread_enabled()) { + background_threads_enable(tsdn_tsd(tsdn)); + } +} + +void +background_thread_postfork_parent(tsdn_t *tsdn) { + for (unsigned i = 0; i < ncpus; i++) { + malloc_mutex_postfork_parent(tsdn, + &background_thread_info[i].mtx); + } + background_thread_postfork_init(tsdn); + malloc_mutex_postfork_parent(tsdn, &background_thread_lock); +} + +void +background_thread_postfork_child(tsdn_t *tsdn) { + for (unsigned i = 0; i < ncpus; i++) { + malloc_mutex_postfork_child(tsdn, + &background_thread_info[i].mtx); + } + malloc_mutex_postfork_child(tsdn, &background_thread_lock); + + malloc_mutex_lock(tsdn, &background_thread_lock); + background_thread_postfork_init(tsdn); + malloc_mutex_unlock(tsdn, &background_thread_lock); +} + +#undef BACKGROUND_THREAD_NPAGES_THRESHOLD +#undef BILLION +#undef BACKGROUND_THREAD_MIN_INTERVAL_NS +#undef BACKGROUND_THREAD_INDEFINITE_SLEEP + +#endif /* defined(JEMALLOC_BACKGROUND_THREAD) */ + +#if defined(JEMALLOC_BACKGROUND_THREAD) || defined(JEMALLOC_LAZY_LOCK) +#include + +int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *, + void *(*)(void *), void *__restrict); + +void * +load_pthread_create_fptr(void) { + if (pthread_create_fptr) { + return pthread_create_fptr; + } + + pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create"); + if (pthread_create_fptr == NULL) { + malloc_write(": Error in dlsym(RTLD_NEXT, " + "\"pthread_create\")\n"); + abort(); + } + + return pthread_create_fptr; +} + +#endif diff --git a/src/ctl.c b/src/ctl.c index 7f69f151..ee0979a8 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -53,6 +53,7 @@ static const ctl_named_node_t *n##_index(tsdn_t *tsdn, \ CTL_PROTO(version) CTL_PROTO(epoch) +CTL_PROTO(background_thread) CTL_PROTO(thread_tcache_enabled) CTL_PROTO(thread_tcache_flush) CTL_PROTO(thread_prof_name) @@ -78,6 +79,7 @@ CTL_PROTO(opt_retain) CTL_PROTO(opt_dss) CTL_PROTO(opt_narenas) CTL_PROTO(opt_percpu_arena) +CTL_PROTO(opt_background_thread) CTL_PROTO(opt_dirty_decay_ms) CTL_PROTO(opt_muzzy_decay_ms) CTL_PROTO(opt_stats_print) @@ -265,6 +267,7 @@ static const ctl_named_node_t opt_node[] = { {NAME("dss"), CTL(opt_dss)}, {NAME("narenas"), CTL(opt_narenas)}, {NAME("percpu_arena"), CTL(opt_percpu_arena)}, + {NAME("background_thread"), CTL(opt_background_thread)}, {NAME("dirty_decay_ms"), CTL(opt_dirty_decay_ms)}, {NAME("muzzy_decay_ms"), CTL(opt_muzzy_decay_ms)}, {NAME("stats_print"), CTL(opt_stats_print)}, @@ -501,6 +504,7 @@ static const ctl_named_node_t stats_node[] = { static const ctl_named_node_t root_node[] = { {NAME("version"), CTL(version)}, {NAME("epoch"), CTL(epoch)}, + {NAME("background_thread"), CTL(background_thread)}, {NAME("thread"), CHILD(named, thread)}, {NAME("config"), CHILD(named, config)}, {NAME("opt"), CHILD(named, opt)}, @@ -1445,6 +1449,53 @@ label_return: return ret; } +static int +background_thread_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, + void *oldp, size_t *oldlenp, void *newp, size_t newlen) { + int ret; + bool oldval; + + if (!have_background_thread) { + return ENOENT; + } + + malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock); + if (newp == NULL) { + oldval = background_thread_enabled(); + READ(oldval, bool); + } else { + if (newlen != sizeof(bool)) { + ret = EINVAL; + goto label_return; + } + oldval = background_thread_enabled(); + READ(oldval, bool); + + bool newval = *(bool *)newp; + if (newval == oldval) { + ret = 0; + goto label_return; + } + + background_thread_enabled_set(tsd_tsdn(tsd), newval); + if (newval) { + if (background_threads_enable(tsd)) { + ret = EFAULT; + goto label_return; + } + } else { + if (background_threads_disable(tsd)) { + ret = EFAULT; + goto label_return; + } + } + } + ret = 0; +label_return: + malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock); + return ret; +} + /******************************************************************************/ CTL_RO_CONFIG_GEN(config_cache_oblivious, bool) @@ -1466,6 +1517,7 @@ CTL_RO_NL_GEN(opt_retain, opt_retain, bool) CTL_RO_NL_GEN(opt_dss, opt_dss, const char *) CTL_RO_NL_GEN(opt_narenas, opt_narenas, unsigned) CTL_RO_NL_GEN(opt_percpu_arena, opt_percpu_arena, const char *) +CTL_RO_NL_GEN(opt_background_thread, opt_background_thread, bool) CTL_RO_NL_GEN(opt_dirty_decay_ms, opt_dirty_decay_ms, ssize_t) CTL_RO_NL_GEN(opt_muzzy_decay_ms, opt_muzzy_decay_ms, ssize_t) CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool) @@ -1764,7 +1816,8 @@ arena_i_decay(tsdn_t *tsdn, unsigned arena_ind, bool all) { for (i = 0; i < narenas; i++) { if (tarenas[i] != NULL) { - arena_decay(tsdn, tarenas[i], all); + arena_decay(tsdn, tarenas[i], false, + all); } } } else { @@ -1778,7 +1831,7 @@ arena_i_decay(tsdn_t *tsdn, unsigned arena_ind, bool all) { malloc_mutex_unlock(tsdn, &ctl_mtx); if (tarena != NULL) { - arena_decay(tsdn, tarena, all); + arena_decay(tsdn, tarena, false, all); } } } @@ -1837,6 +1890,35 @@ label_return: return ret; } +static void +arena_reset_prepare_background_thread(tsd_t *tsd, unsigned arena_ind) { + /* Temporarily disable the background thread during arena reset. */ + if (have_background_thread) { + malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock); + if (background_thread_enabled()) { + unsigned ind = arena_ind % ncpus; + background_thread_info_t *info = + &background_thread_info[ind]; + assert(info->started); + background_threads_disable_single(tsd, info); + } + } +} + +static void +arena_reset_finish_background_thread(tsd_t *tsd, unsigned arena_ind) { + if (have_background_thread) { + if (background_thread_enabled()) { + unsigned ind = arena_ind % ncpus; + background_thread_info_t *info = + &background_thread_info[ind]; + assert(!info->started); + background_thread_create(tsd, ind); + } + malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock); + } +} + static int arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { @@ -1850,7 +1932,9 @@ arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, return ret; } + arena_reset_prepare_background_thread(tsd, arena_ind); arena_reset(tsd, arena); + arena_reset_finish_background_thread(tsd, arena_ind); return ret; } @@ -1875,9 +1959,10 @@ arena_i_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, goto label_return; } + arena_reset_prepare_background_thread(tsd, arena_ind); /* Merge stats after resetting and purging arena. */ arena_reset(tsd, arena); - arena_decay(tsd_tsdn(tsd), arena, true); + arena_decay(tsd_tsdn(tsd), arena, false, true); ctl_darena = arenas_i(MALLCTL_ARENAS_DESTROYED); ctl_darena->initialized = true; ctl_arena_refresh(tsd_tsdn(tsd), arena, ctl_darena, arena_ind, true); @@ -1888,6 +1973,7 @@ arena_i_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, /* Record arena index for later recycling via arenas.create. */ ql_elm_new(ctl_arena, destroyed_link); ql_tail_insert(&ctl_arenas->destroyed, ctl_arena, destroyed_link); + arena_reset_finish_background_thread(tsd, arena_ind); assert(ret == 0); label_return: diff --git a/src/jemalloc.c b/src/jemalloc.c index 56aef5b0..b03e5f48 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -420,7 +420,7 @@ arena_init_locked(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { /* Actually initialize the arena. */ arena = arena_new(tsdn, ind, extent_hooks); - arena_set(ind, arena); + return arena; } @@ -1140,6 +1140,8 @@ malloc_conf_init(void) { } continue; } + CONF_HANDLE_BOOL(opt_background_thread, + "background_thread"); if (config_prof) { CONF_HANDLE_BOOL(opt_prof, "prof") CONF_HANDLE_CHAR_P(opt_prof_prefix, @@ -1380,6 +1382,22 @@ malloc_init_narenas(void) { return false; } +static bool +malloc_init_background_threads(tsd_t *tsd) { + malloc_mutex_assert_owner(tsd_tsdn(tsd), &init_lock); + if (!have_background_thread) { + if (opt_background_thread) { + malloc_printf(": option background_thread " + "currently supports pthread only. \n"); + return true; + } else { + return false; + } + } + + return background_threads_init(tsd); +} + static bool malloc_init_hard_finish(void) { if (malloc_mutex_boot()) @@ -1421,8 +1439,8 @@ malloc_init_hard(void) { } malloc_mutex_lock(tsd_tsdn(tsd), &init_lock); - /* Need this before prof_boot2 (for allocation). */ - if (malloc_init_narenas()) { + /* Initialize narenas before prof_boot2 (for allocation). */ + if (malloc_init_narenas() || malloc_init_background_threads(tsd)) { malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); return true; } @@ -1439,6 +1457,23 @@ malloc_init_hard(void) { malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); malloc_tsd_boot1(); + + /* Update TSD after tsd_boot1. */ + tsd = tsd_fetch(); + if (opt_background_thread) { + assert(have_background_thread); + /* + * Need to finish init & unlock first before creating background + * threads (pthread_create depends on malloc). + */ + malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock); + bool err = background_thread_create(tsd, 0); + malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock); + if (err) { + return true; + } + } + return false; } @@ -2970,7 +3005,13 @@ _malloc_prefork(void) ctl_prefork(tsd_tsdn(tsd)); tcache_prefork(tsd_tsdn(tsd)); malloc_mutex_prefork(tsd_tsdn(tsd), &arenas_lock); + if (have_background_thread) { + background_thread_prefork0(tsd_tsdn(tsd)); + } prof_prefork0(tsd_tsdn(tsd)); + if (have_background_thread) { + background_thread_prefork1(tsd_tsdn(tsd)); + } /* Break arena prefork into stages to preserve lock order. */ for (i = 0; i < 7; i++) { for (j = 0; j < narenas; j++) { @@ -3036,6 +3077,9 @@ _malloc_postfork(void) } } prof_postfork_parent(tsd_tsdn(tsd)); + if (have_background_thread) { + background_thread_postfork_parent(tsd_tsdn(tsd)); + } malloc_mutex_postfork_parent(tsd_tsdn(tsd), &arenas_lock); tcache_postfork_parent(tsd_tsdn(tsd)); ctl_postfork_parent(tsd_tsdn(tsd)); @@ -3060,6 +3104,9 @@ jemalloc_postfork_child(void) { } } prof_postfork_child(tsd_tsdn(tsd)); + if (have_background_thread) { + background_thread_postfork_child(tsd_tsdn(tsd)); + } malloc_mutex_postfork_child(tsd_tsdn(tsd), &arenas_lock); tcache_postfork_child(tsd_tsdn(tsd)); ctl_postfork_child(tsd_tsdn(tsd)); diff --git a/src/mutex.c b/src/mutex.c index b15bbf6e..c92ddd72 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -5,10 +5,6 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/malloc_io.h" -#if defined(JEMALLOC_LAZY_LOCK) && !defined(_WIN32) -#include -#endif - #ifndef _CRT_SPINCOUNT #define _CRT_SPINCOUNT 4000 #endif @@ -24,10 +20,6 @@ static bool postpone_init = true; static malloc_mutex_t *postponed_mutexes = NULL; #endif -#if defined(JEMALLOC_LAZY_LOCK) && !defined(_WIN32) -static void pthread_create_once(void); -#endif - /******************************************************************************/ /* * We intercept pthread_create() calls in order to toggle isthreaded if the @@ -35,18 +27,9 @@ static void pthread_create_once(void); */ #if defined(JEMALLOC_LAZY_LOCK) && !defined(_WIN32) -static int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *, - void *(*)(void *), void *__restrict); - static void pthread_create_once(void) { - pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create"); - if (pthread_create_fptr == NULL) { - malloc_write(": Error in dlsym(RTLD_NEXT, " - "\"pthread_create\")\n"); - abort(); - } - + pthread_create_fptr = load_pthread_create_fptr(); isthreaded = true; } diff --git a/src/stats.c b/src/stats.c index 3c9eb35a..f98b8ece 100644 --- a/src/stats.c +++ b/src/stats.c @@ -816,6 +816,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, OPT_WRITE_CHAR_P(dss, ",") OPT_WRITE_UNSIGNED(narenas, ",") OPT_WRITE_CHAR_P(percpu_arena, ",") + OPT_WRITE_BOOL_MUTABLE(background_thread, background_thread, ",") OPT_WRITE_SSIZE_T_MUTABLE(dirty_decay_ms, arenas.dirty_decay_ms, ",") OPT_WRITE_SSIZE_T_MUTABLE(muzzy_decay_ms, arenas.muzzy_decay_ms, ",") OPT_WRITE_CHAR_P(junk, ",") diff --git a/test/integration/extent.c b/test/integration/extent.c index 32432af9..7262b803 100644 --- a/test/integration/extent.c +++ b/test/integration/extent.c @@ -2,6 +2,18 @@ #include "test/extent_hooks.h" +static bool +check_background_thread_enabled(void) { + bool enabled; + size_t sz = sizeof(bool); + int ret = mallctl("background_thread", (void *)&enabled, &sz, NULL,0); + if (ret == ENOENT) { + return false; + } + assert_d_eq(ret, 0, "Unexpected mallctl error"); + return enabled; +} + static void test_extent_body(unsigned arena_ind) { void *p; @@ -124,6 +136,7 @@ TEST_BEGIN(test_extent_manual_hook) { assert_ptr_ne(old_hooks->merge, extent_merge_hook, "Unexpected extent_hooks error"); + test_skip_if(check_background_thread_enabled()); test_extent_body(arena_ind); /* Restore extent hooks. */ @@ -164,6 +177,7 @@ TEST_BEGIN(test_extent_auto_hook) { assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, (void *)&new_hooks, new_size), 0, "Unexpected mallctl() failure"); + test_skip_if(check_background_thread_enabled()); test_extent_body(arena_ind); } TEST_END diff --git a/test/unit/decay.c b/test/unit/decay.c index 19f76fa5..f727bf93 100644 --- a/test/unit/decay.c +++ b/test/unit/decay.c @@ -9,6 +9,18 @@ static unsigned nupdates_mock; static nstime_t time_mock; static bool monotonic_mock; +static bool +check_background_thread_enabled(void) { + bool enabled; + size_t sz = sizeof(bool); + int ret = mallctl("background_thread", (void *)&enabled, &sz, NULL,0); + if (ret == ENOENT) { + return false; + } + assert_d_eq(ret, 0, "Unexpected mallctl error"); + return enabled; +} + static bool nstime_monotonic_mock(void) { return monotonic_mock; @@ -167,6 +179,8 @@ generate_dirty(unsigned arena_ind, size_t size) { } TEST_BEGIN(test_decay_ticks) { + test_skip_if(check_background_thread_enabled()); + ticker_t *decay_ticker; unsigned tick0, tick1, arena_ind; size_t sz, large0; @@ -405,6 +419,7 @@ decay_ticker_helper(unsigned arena_ind, int flags, bool dirty, ssize_t dt, } TEST_BEGIN(test_decay_ticker) { + test_skip_if(check_background_thread_enabled()); #define NPS 2048 ssize_t ddt = opt_dirty_decay_ms; ssize_t mdt = opt_muzzy_decay_ms; @@ -466,6 +481,7 @@ TEST_BEGIN(test_decay_ticker) { TEST_END TEST_BEGIN(test_decay_nonmonotonic) { + test_skip_if(check_background_thread_enabled()); #define NPS (SMOOTHSTEP_NSTEPS + 1) int flags = (MALLOCX_ARENA(0) | MALLOCX_TCACHE_NONE); void *ps[NPS]; @@ -523,6 +539,8 @@ TEST_BEGIN(test_decay_nonmonotonic) { TEST_END TEST_BEGIN(test_decay_now) { + test_skip_if(check_background_thread_enabled()); + unsigned arena_ind = do_arena_create(0, 0); assert_zu_eq(get_arena_pdirty(arena_ind), 0, "Unexpected dirty pages"); assert_zu_eq(get_arena_pmuzzy(arena_ind), 0, "Unexpected muzzy pages"); @@ -541,6 +559,8 @@ TEST_BEGIN(test_decay_now) { TEST_END TEST_BEGIN(test_decay_never) { + test_skip_if(check_background_thread_enabled()); + unsigned arena_ind = do_arena_create(-1, -1); int flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; assert_zu_eq(get_arena_pdirty(arena_ind), 0, "Unexpected dirty pages"); diff --git a/test/unit/smoothstep.c b/test/unit/smoothstep.c index 6e3eb0f9..549aed12 100644 --- a/test/unit/smoothstep.c +++ b/test/unit/smoothstep.c @@ -1,7 +1,7 @@ #include "test/jemalloc_test.h" static const uint64_t smoothstep_tab[] = { -#define STEP(step, h, x, y) \ +#define STEP(step, h, x, y, h_sum) \ h, SMOOTHSTEP #undef STEP diff --git a/test/unit/stats.c b/test/unit/stats.c index f5ee1287..d9849d80 100644 --- a/test/unit/stats.c +++ b/test/unit/stats.c @@ -115,8 +115,10 @@ TEST_BEGIN(test_stats_arenas_summary) { "Unexepected mallctl() result"); if (config_stats) { - assert_u64_gt(dirty_npurge + muzzy_npurge, 0, - "At least one purge should have occurred"); + if (!background_thread_enabled()) { + assert_u64_gt(dirty_npurge + muzzy_npurge, 0, + "At least one purge should have occurred"); + } assert_u64_le(dirty_nmadvise, dirty_purged, "dirty_nmadvise should be no greater than dirty_purged"); assert_u64_le(muzzy_nmadvise, muzzy_purged, -- GitLab From 2bee0c6251856f48ed6882df2f02a060c0a14829 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 12 May 2017 12:30:33 -0700 Subject: [PATCH 485/544] Add background thread related stats. --- .../internal/background_thread_externs.h | 2 + .../internal/background_thread_structs.h | 11 +++ include/jemalloc/internal/ctl.h | 1 + include/jemalloc/internal/nstime.h | 2 + src/background_thread.c | 99 +++++++++++++++---- src/ctl.c | 30 ++++++ src/nstime.c | 14 +++ src/stats.c | 40 +++++++- test/unit/nstime.c | 36 +++++++ 9 files changed, 214 insertions(+), 21 deletions(-) diff --git a/include/jemalloc/internal/background_thread_externs.h b/include/jemalloc/internal/background_thread_externs.h index 993f0e3b..fe25acfe 100644 --- a/include/jemalloc/internal/background_thread_externs.h +++ b/include/jemalloc/internal/background_thread_externs.h @@ -19,6 +19,8 @@ void background_thread_prefork0(tsdn_t *tsdn); void background_thread_prefork1(tsdn_t *tsdn); void background_thread_postfork_parent(tsdn_t *tsdn); void background_thread_postfork_child(tsdn_t *tsdn); +bool background_thread_stats_read(tsdn_t *tsdn, + background_thread_stats_t *stats); #if defined(JEMALLOC_BACKGROUND_THREAD) || defined(JEMALLOC_LAZY_LOCK) extern int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *, diff --git a/include/jemalloc/internal/background_thread_structs.h b/include/jemalloc/internal/background_thread_structs.h index a43d600d..c4eb8273 100644 --- a/include/jemalloc/internal/background_thread_structs.h +++ b/include/jemalloc/internal/background_thread_structs.h @@ -18,8 +18,19 @@ struct background_thread_info_s { * background thread to wake up earlier. */ size_t npages_to_purge_new; + /* Stats: total number of runs since started. */ + uint64_t tot_n_runs; + /* Stats: total sleep time since started. */ + nstime_t tot_sleep_time; #endif /* ifdef JEMALLOC_BACKGROUND_THREAD */ }; typedef struct background_thread_info_s background_thread_info_t; +struct background_thread_stats_s { + size_t num_threads; + uint64_t num_runs; + nstime_t run_interval; +}; +typedef struct background_thread_stats_s background_thread_stats_t; + #endif /* JEMALLOC_INTERNAL_BACKGROUND_THREAD_STRUCTS_H */ diff --git a/include/jemalloc/internal/ctl.h b/include/jemalloc/internal/ctl.h index 60b3979f..f159383d 100644 --- a/include/jemalloc/internal/ctl.h +++ b/include/jemalloc/internal/ctl.h @@ -52,6 +52,7 @@ typedef struct ctl_stats_s { size_t mapped; size_t retained; + background_thread_stats_t background_thread; mutex_prof_data_t mutex_prof_data[mutex_prof_num_global_mutexes]; } ctl_stats_t; diff --git a/include/jemalloc/internal/nstime.h b/include/jemalloc/internal/nstime.h index ad7efb89..17c177c7 100644 --- a/include/jemalloc/internal/nstime.h +++ b/include/jemalloc/internal/nstime.h @@ -18,7 +18,9 @@ uint64_t nstime_nsec(const nstime_t *time); void nstime_copy(nstime_t *time, const nstime_t *source); int nstime_compare(const nstime_t *a, const nstime_t *b); void nstime_add(nstime_t *time, const nstime_t *addend); +void nstime_iadd(nstime_t *time, uint64_t addend); void nstime_subtract(nstime_t *time, const nstime_t *subtrahend); +void nstime_isubtract(nstime_t *time, uint64_t subtrahend); void nstime_imultiply(nstime_t *time, uint64_t multiplier); void nstime_idivide(nstime_t *time, uint64_t divisor); uint64_t nstime_divide(const nstime_t *time, const nstime_t *divisor); diff --git a/src/background_thread.c b/src/background_thread.c index 671e57f7..076d9815 100644 --- a/src/background_thread.c +++ b/src/background_thread.c @@ -36,8 +36,21 @@ void background_thread_prefork0(tsdn_t *tsdn) NOT_REACHED void background_thread_prefork1(tsdn_t *tsdn) NOT_REACHED void background_thread_postfork_parent(tsdn_t *tsdn) NOT_REACHED void background_thread_postfork_child(tsdn_t *tsdn) NOT_REACHED +bool background_thread_stats_read(tsdn_t *tsdn, + background_thread_stats_t *stats) NOT_REACHED #undef NOT_REACHED #else + +static void +background_thread_info_reinit(background_thread_info_t *info) { + nstime_init(&info->next_wakeup, 0); + info->npages_to_purge_new = 0; + if (config_stats) { + info->tot_n_runs = 0; + nstime_init(&info->tot_sleep_time, 0); + } +} + bool background_threads_init(tsd_t *tsd) { assert(have_background_thread); @@ -68,8 +81,7 @@ background_threads_init(tsd_t *tsd) { return true; } info->started = false; - nstime_init(&info->next_wakeup, 0); - info->npages_to_purge_new = 0; + background_thread_info_reinit(info); } return false; @@ -248,33 +260,49 @@ background_work(tsdn_t *tsdn, unsigned ind) { malloc_mutex_lock(tsdn, &info->mtx); while (info->started) { uint64_t interval = background_work_once(tsdn, ind); + if (config_stats) { + info->tot_n_runs++; + } info->npages_to_purge_new = 0; + struct timeval tv; + gettimeofday(&tv, NULL); + nstime_t before_sleep; + nstime_init2(&before_sleep, tv.tv_sec, tv.tv_usec * 1000); + if (interval == BACKGROUND_THREAD_INDEFINITE_SLEEP) { nstime_init(&info->next_wakeup, BACKGROUND_THREAD_INDEFINITE_SLEEP); ret = pthread_cond_wait(&info->cond, &info->mtx.lock); assert(ret == 0); - continue; + } else { + assert(interval >= BACKGROUND_THREAD_MIN_INTERVAL_NS && + interval <= BACKGROUND_THREAD_INDEFINITE_SLEEP); + nstime_init(&info->next_wakeup, 0); + nstime_update(&info->next_wakeup); + nstime_iadd(&info->next_wakeup, interval); + + nstime_t ts_wakeup; + nstime_copy(&ts_wakeup, &before_sleep); + nstime_iadd(&ts_wakeup, interval); + struct timespec ts; + ts.tv_sec = (size_t)nstime_sec(&ts_wakeup); + ts.tv_nsec = (size_t)nstime_nsec(&ts_wakeup); + + ret = pthread_cond_timedwait(&info->cond, + &info->mtx.lock, &ts); + assert(ret == ETIMEDOUT || ret == 0); } - assert(interval >= BACKGROUND_THREAD_MIN_INTERVAL_NS && - interval <= BACKGROUND_THREAD_INDEFINITE_SLEEP); - nstime_init(&info->next_wakeup, 0); - nstime_update(&info->next_wakeup); - info->next_wakeup.ns += interval; - - nstime_t ts_wakeup; - struct timeval tv; - gettimeofday(&tv, NULL); - nstime_init2(&ts_wakeup, tv.tv_sec, - tv.tv_usec * 1000 + interval); - struct timespec ts; - ts.tv_sec = (size_t)nstime_sec(&ts_wakeup); - ts.tv_nsec = (size_t)nstime_nsec(&ts_wakeup); - ret = pthread_cond_timedwait(&info->cond, &info->mtx.lock, - &ts); - assert(ret == ETIMEDOUT || ret == 0); + if (config_stats) { + gettimeofday(&tv, NULL); + nstime_t after_sleep; + nstime_init2(&after_sleep, tv.tv_sec, tv.tv_usec * 1000); + if (nstime_compare(&after_sleep, &before_sleep) > 0) { + nstime_subtract(&after_sleep, &before_sleep); + nstime_add(&info->tot_sleep_time, &after_sleep); + } + } } malloc_mutex_unlock(tsdn, &info->mtx); } @@ -332,6 +360,7 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) { assert(info->started == false); if (err == 0) { info->started = true; + background_thread_info_reinit(info); n_background_threads++; } malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); @@ -540,6 +569,36 @@ background_thread_postfork_child(tsdn_t *tsdn) { malloc_mutex_unlock(tsdn, &background_thread_lock); } +bool +background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats) { + assert(config_stats); + malloc_mutex_lock(tsdn, &background_thread_lock); + if (!background_thread_enabled()) { + malloc_mutex_unlock(tsdn, &background_thread_lock); + return true; + } + + stats->num_threads = n_background_threads; + uint64_t num_runs = 0; + nstime_init(&stats->run_interval, 0); + for (unsigned i = 0; i < ncpus; i++) { + background_thread_info_t *info = &background_thread_info[i]; + malloc_mutex_lock(tsdn, &info->mtx); + if (info->started) { + num_runs += info->tot_n_runs; + nstime_add(&stats->run_interval, &info->tot_sleep_time); + } + malloc_mutex_unlock(tsdn, &info->mtx); + } + stats->num_runs = num_runs; + if (num_runs > 0) { + nstime_idivide(&stats->run_interval, num_runs); + } + malloc_mutex_unlock(tsdn, &background_thread_lock); + + return false; +} + #undef BACKGROUND_THREAD_NPAGES_THRESHOLD #undef BILLION #undef BACKGROUND_THREAD_MIN_INTERVAL_NS diff --git a/src/ctl.c b/src/ctl.c index ee0979a8..caa9f3e8 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -181,6 +181,9 @@ CTL_PROTO(stats_arenas_i_resident) INDEX_PROTO(stats_arenas_i) CTL_PROTO(stats_allocated) CTL_PROTO(stats_active) +CTL_PROTO(stats_background_thread_num_threads) +CTL_PROTO(stats_background_thread_num_runs) +CTL_PROTO(stats_background_thread_run_interval) CTL_PROTO(stats_metadata) CTL_PROTO(stats_resident) CTL_PROTO(stats_mapped) @@ -478,6 +481,12 @@ static const ctl_indexed_node_t stats_arenas_node[] = { {INDEX(stats_arenas_i)} }; +static const ctl_named_node_t stats_background_thread_node[] = { + {NAME("num_threads"), CTL(stats_background_thread_num_threads)}, + {NAME("num_runs"), CTL(stats_background_thread_num_runs)}, + {NAME("run_interval"), CTL(stats_background_thread_run_interval)} +}; + #define OP(mtx) MUTEX_PROF_DATA_NODE(mutexes_##mtx) MUTEX_PROF_GLOBAL_MUTEXES #undef OP @@ -497,6 +506,8 @@ static const ctl_named_node_t stats_node[] = { {NAME("resident"), CTL(stats_resident)}, {NAME("mapped"), CTL(stats_mapped)}, {NAME("retained"), CTL(stats_retained)}, + {NAME("background_thread"), + CHILD(named, stats_background_thread)}, {NAME("mutexes"), CHILD(named, stats_mutexes)}, {NAME("arenas"), CHILD(indexed, stats_arenas)} }; @@ -872,6 +883,16 @@ ctl_arena_init(tsdn_t *tsdn, extent_hooks_t *extent_hooks) { return arena_ind; } +static void +ctl_background_thread_stats_read(tsdn_t *tsdn) { + background_thread_stats_t *stats = &ctl_stats->background_thread; + if (!have_background_thread || + background_thread_stats_read(tsdn, stats)) { + memset(stats, 0, sizeof(background_thread_stats_t)); + nstime_init(&stats->run_interval, 0); + } +} + static void ctl_refresh(tsdn_t *tsdn) { unsigned i; @@ -915,6 +936,8 @@ ctl_refresh(tsdn_t *tsdn) { ctl_stats->retained = atomic_load_zu( &ctl_sarena->astats->astats.retained, ATOMIC_RELAXED); + ctl_background_thread_stats_read(tsdn); + #define READ_GLOBAL_MUTEX_PROF_DATA(i, mtx) \ malloc_mutex_lock(tsdn, &mtx); \ malloc_mutex_prof_read(tsdn, &ctl_stats->mutex_prof_data[i], &mtx); \ @@ -2403,6 +2426,13 @@ CTL_RO_CGEN(config_stats, stats_resident, ctl_stats->resident, size_t) CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats->mapped, size_t) CTL_RO_CGEN(config_stats, stats_retained, ctl_stats->retained, size_t) +CTL_RO_CGEN(config_stats, stats_background_thread_num_threads, + ctl_stats->background_thread.num_threads, size_t) +CTL_RO_CGEN(config_stats, stats_background_thread_num_runs, + ctl_stats->background_thread.num_runs, uint64_t) +CTL_RO_CGEN(config_stats, stats_background_thread_run_interval, + nstime_ns(&ctl_stats->background_thread.run_interval), uint64_t) + CTL_RO_GEN(stats_arenas_i_dss, arenas_i(mib[2])->dss, const char *) CTL_RO_GEN(stats_arenas_i_dirty_decay_ms, arenas_i(mib[2])->dirty_decay_ms, ssize_t) diff --git a/src/nstime.c b/src/nstime.c index e5412274..71db3539 100644 --- a/src/nstime.c +++ b/src/nstime.c @@ -55,6 +55,13 @@ nstime_add(nstime_t *time, const nstime_t *addend) { time->ns += addend->ns; } +void +nstime_iadd(nstime_t *time, uint64_t addend) { + assert(UINT64_MAX - time->ns >= addend); + + time->ns += addend; +} + void nstime_subtract(nstime_t *time, const nstime_t *subtrahend) { assert(nstime_compare(time, subtrahend) >= 0); @@ -62,6 +69,13 @@ nstime_subtract(nstime_t *time, const nstime_t *subtrahend) { time->ns -= subtrahend->ns; } +void +nstime_isubtract(nstime_t *time, uint64_t subtrahend) { + assert(time->ns >= subtrahend); + + time->ns -= subtrahend; +} + void nstime_imultiply(nstime_t *time, uint64_t multiplier) { assert((((time->ns | multiplier) & (UINT64_MAX << (sizeof(uint64_t) << diff --git a/src/stats.c b/src/stats.c index f98b8ece..fd108162 100644 --- a/src/stats.c +++ b/src/stats.c @@ -1013,6 +1013,8 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, bool json, bool merged, bool destroyed, bool unmerged, bool bins, bool large, bool mutex) { size_t allocated, active, metadata, resident, mapped, retained; + size_t num_background_threads; + uint64_t background_thread_num_runs, background_thread_run_interval; CTL_GET("stats.allocated", &allocated, size_t); CTL_GET("stats.active", &active, size_t); @@ -1026,6 +1028,19 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, read_global_mutex_stats(mutex_stats); } + if (have_background_thread) { + CTL_GET("stats.background_thread.num_threads", + &num_background_threads, size_t); + CTL_GET("stats.background_thread.num_runs", + &background_thread_num_runs, uint64_t); + CTL_GET("stats.background_thread.run_interval", + &background_thread_run_interval, uint64_t); + } else { + num_background_threads = 0; + background_thread_num_runs = 0; + background_thread_run_interval = 0; + } + if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t\"stats\": {\n"); @@ -1041,7 +1056,21 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, malloc_cprintf(write_cb, cbopaque, "\t\t\t\"mapped\": %zu,\n", mapped); malloc_cprintf(write_cb, cbopaque, - "\t\t\t\"retained\": %zu%s\n", retained, mutex ? "," : ""); + "\t\t\t\"retained\": %zu,\n", retained); + + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\"background_thread\": {\n"); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"num_threads\": %zu,\n", num_background_threads); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"num_runs\": %"FMTu64",\n", + background_thread_num_runs); + malloc_cprintf(write_cb, cbopaque, + "\t\t\t\t\"run_interval\": %"FMTu64"\n", + background_thread_run_interval); + malloc_cprintf(write_cb, cbopaque, "\t\t\t}%s\n", + mutex ? "," : ""); + if (mutex) { malloc_cprintf(write_cb, cbopaque, "\t\t\t\"mutexes\": {\n"); @@ -1061,6 +1090,15 @@ stats_print_helper(void (*write_cb)(void *, const char *), void *cbopaque, "Allocated: %zu, active: %zu, metadata: %zu," " resident: %zu, mapped: %zu, retained: %zu\n", allocated, active, metadata, resident, mapped, retained); + + if (have_background_thread && num_background_threads > 0) { + malloc_cprintf(write_cb, cbopaque, + "Background threads: %zu, num_runs: %"FMTu64", " + "run_interval: %"FMTu64" ns\n", + num_background_threads, + background_thread_num_runs, + background_thread_run_interval); + } if (mutex) { mutex_prof_global_ind_t i; for (i = 0; i < mutex_prof_num_global_mutexes; i++) { diff --git a/test/unit/nstime.c b/test/unit/nstime.c index f8384f5a..f3137805 100644 --- a/test/unit/nstime.c +++ b/test/unit/nstime.c @@ -85,6 +85,23 @@ TEST_BEGIN(test_nstime_add) { } TEST_END +TEST_BEGIN(test_nstime_iadd) { + nstime_t nsta, nstb; + + nstime_init2(&nsta, 42, BILLION - 1); + nstime_iadd(&nsta, 1); + nstime_init2(&nstb, 43, 0); + assert_d_eq(nstime_compare(&nsta, &nstb), 0, + "Incorrect addition result"); + + nstime_init2(&nsta, 42, 1); + nstime_iadd(&nsta, BILLION + 1); + nstime_init2(&nstb, 43, 2); + assert_d_eq(nstime_compare(&nsta, &nstb), 0, + "Incorrect addition result"); +} +TEST_END + TEST_BEGIN(test_nstime_subtract) { nstime_t nsta, nstb; @@ -104,6 +121,23 @@ TEST_BEGIN(test_nstime_subtract) { } TEST_END +TEST_BEGIN(test_nstime_isubtract) { + nstime_t nsta, nstb; + + nstime_init2(&nsta, 42, 43); + nstime_isubtract(&nsta, 42*BILLION + 43); + nstime_init(&nstb, 0); + assert_d_eq(nstime_compare(&nsta, &nstb), 0, + "Incorrect subtraction result"); + + nstime_init2(&nsta, 42, 43); + nstime_isubtract(&nsta, 41*BILLION + 44); + nstime_init2(&nstb, 0, BILLION - 1); + assert_d_eq(nstime_compare(&nsta, &nstb), 0, + "Incorrect subtraction result"); +} +TEST_END + TEST_BEGIN(test_nstime_imultiply) { nstime_t nsta, nstb; @@ -204,7 +238,9 @@ main(void) { test_nstime_copy, test_nstime_compare, test_nstime_add, + test_nstime_iadd, test_nstime_subtract, + test_nstime_isubtract, test_nstime_imultiply, test_nstime_idivide, test_nstime_divide, -- GitLab From 5f5ed2198e47f3e904cbf1aff7c124e196855272 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 12 May 2017 16:26:59 -0700 Subject: [PATCH 486/544] Add profiling for the background thread mutex. --- include/jemalloc/internal/mutex_externs.h | 12 ++++++------ include/jemalloc/internal/mutex_prof.h | 1 + src/ctl.c | 12 ++++++++++++ src/mutex.c | 2 ++ 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/include/jemalloc/internal/mutex_externs.h b/include/jemalloc/internal/mutex_externs.h index c9a817fb..d0139f2e 100644 --- a/include/jemalloc/internal/mutex_externs.h +++ b/include/jemalloc/internal/mutex_externs.h @@ -10,12 +10,12 @@ extern bool isthreaded; # define isthreaded true #endif -bool malloc_mutex_init(malloc_mutex_t *mutex, const char *name, +bool malloc_mutex_init(malloc_mutex_t *mutex, const char *name, witness_rank_t rank, malloc_mutex_lock_order_t lock_order); -void malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex); -void malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex); -void malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex); -bool malloc_mutex_boot(void); -void malloc_mutex_prof_data_reset(tsdn_t *tsdn, malloc_mutex_t *mutex); +void malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex); +void malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex); +void malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex); +bool malloc_mutex_boot(void); +void malloc_mutex_prof_data_reset(tsdn_t *tsdn, malloc_mutex_t *mutex); #endif /* JEMALLOC_INTERNAL_MUTEX_EXTERNS_H */ diff --git a/include/jemalloc/internal/mutex_prof.h b/include/jemalloc/internal/mutex_prof.h index 1cc198d6..3358bcf5 100644 --- a/include/jemalloc/internal/mutex_prof.h +++ b/include/jemalloc/internal/mutex_prof.h @@ -6,6 +6,7 @@ #include "jemalloc/internal/tsd_types.h" #define MUTEX_PROF_GLOBAL_MUTEXES \ + OP(background_thread) \ OP(ctl) \ OP(prof) diff --git a/src/ctl.c b/src/ctl.c index caa9f3e8..da5e1710 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -947,6 +947,15 @@ ctl_refresh(tsdn_t *tsdn) { READ_GLOBAL_MUTEX_PROF_DATA(global_prof_mutex_prof, bt2gctx_mtx); } + if (have_background_thread) { + READ_GLOBAL_MUTEX_PROF_DATA( + global_prof_mutex_background_thread, + background_thread_lock); + } else { + memset(&ctl_stats->mutex_prof_data[ + global_prof_mutex_background_thread], 0, + sizeof(mutex_prof_data_t)); + } /* We own ctl mutex already. */ malloc_mutex_prof_read(tsdn, &ctl_stats->mutex_prof_data[global_prof_mutex_ctl], @@ -2557,6 +2566,9 @@ stats_mutexes_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, /* Global mutexes: ctl and prof. */ MUTEX_PROF_RESET(ctl_mtx); + if (have_background_thread) { + MUTEX_PROF_RESET(background_thread_lock); + } if (config_prof && opt_prof) { MUTEX_PROF_RESET(bt2gctx_mtx); } diff --git a/src/mutex.c b/src/mutex.c index c92ddd72..48e2940a 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -112,6 +112,8 @@ label_spin_done: static void mutex_prof_data_init(mutex_prof_data_t *data) { memset(data, 0, sizeof(mutex_prof_data_t)); + nstime_init(&data->max_wait_time, 0); + nstime_init(&data->tot_wait_time, 0); data->prev_owner = NULL; } -- GitLab From 44559e7cf179d1e9eddcc681d961e076511ee857 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 15 May 2017 13:50:42 -0700 Subject: [PATCH 487/544] Add documentation for background_thread related options. --- doc/jemalloc.xml.in | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index be018bfb..57f5b0ba 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -737,6 +737,25 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", detecting whether another thread caused a refresh. + + + background_thread + (bool) + rw + + Enable/disable internal background worker threads. When + set to true, background threads are created on demand (the number of + background threads will be no more than the number of CPUs or active + arenas). Threads run periodically, and handle purging asynchronously. When switching + off, background threads are terminated synchronously. See stats.background_thread + for related stats. opt.background_thread + can be used to set the default option. This option is only available on + selected pthread-based platforms. + + config.cache_oblivious @@ -937,6 +956,18 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", percpu. + + + opt.background_thread + (const bool) + r- + + Internal background worker threads enabled/disabled. See + background_thread for dynamic + control options and details. This option is disabled by + default. + + opt.dirty_decay_ms @@ -2158,6 +2189,39 @@ struct extent_hooks_s { + + + stats.background_thread.num_threads + (size_t) + r- + [] + + Number of background + threads running currently. + + + + + stats.background_thread.num_runs + (uint64_t) + r- + [] + + Total number of runs from all background threads. + + + + + stats.background_thread.run_interval + (uint64_t) + r- + [] + + Average run interval in nanoseconds of background threads. + + stats.mutexes.ctl.{counter}; @@ -2210,6 +2274,20 @@ struct extent_hooks_s { + + + stats.mutexes.background_thread.{counter} + (counter specific type) r- + [] + + Statistics on background_thread mutex + (global scope; background_thread + related). {counter} is one of the counters in mutex profiling + counters. + + stats.mutexes.prof.{counter} -- GitLab From 2c368284d2485bda47002f22dace6c0b55e4701e Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 15 May 2017 17:44:13 -0700 Subject: [PATCH 488/544] Add tests for background threads. --- Makefile.in | 1 + test/unit/background_thread.c | 117 ++++++++++++++++++++++++++++++++++ test/unit/mallctl.c | 1 + 3 files changed, 119 insertions(+) create mode 100644 test/unit/background_thread.c diff --git a/Makefile.in b/Makefile.in index aa6f3f62..16fe30fd 100644 --- a/Makefile.in +++ b/Makefile.in @@ -158,6 +158,7 @@ TESTS_UNIT := \ $(srcroot)test/unit/a0.c \ $(srcroot)test/unit/arena_reset.c \ $(srcroot)test/unit/atomic.c \ + $(srcroot)test/unit/background_thread.c \ $(srcroot)test/unit/base.c \ $(srcroot)test/unit/bitmap.c \ $(srcroot)test/unit/ckh.c \ diff --git a/test/unit/background_thread.c b/test/unit/background_thread.c new file mode 100644 index 00000000..05089c28 --- /dev/null +++ b/test/unit/background_thread.c @@ -0,0 +1,117 @@ +#include "test/jemalloc_test.h" + +#include "jemalloc/internal/util.h" + +static void +test_switch_background_thread_ctl(bool new_val) { + bool e0, e1; + size_t sz = sizeof(bool); + + e1 = new_val; + assert_d_eq(mallctl("background_thread", (void *)&e0, &sz, + &e1, sz), 0, "Unexpected mallctl() failure"); + assert_b_eq(e0, !e1, + "background_thread should be %d before.\n", !e1); + if (e1) { + assert_zu_gt(n_background_threads, 0, + "Number of background threads should be non zero.\n"); + } else { + assert_zu_eq(n_background_threads, 0, + "Number of background threads should be zero.\n"); + } +} + +static void +test_repeat_background_thread_ctl(bool before) { + bool e0, e1; + size_t sz = sizeof(bool); + + e1 = before; + assert_d_eq(mallctl("background_thread", (void *)&e0, &sz, + &e1, sz), 0, "Unexpected mallctl() failure"); + assert_b_eq(e0, before, + "background_thread should be %d.\n", before); + if (e1) { + assert_zu_gt(n_background_threads, 0, + "Number of background threads should be non zero.\n"); + } else { + assert_zu_eq(n_background_threads, 0, + "Number of background threads should be zero.\n"); + } +} + +TEST_BEGIN(test_background_thread_ctl) { + test_skip_if(!have_background_thread); + + bool e0, e1; + size_t sz = sizeof(bool); + + assert_d_eq(mallctl("opt.background_thread", (void *)&e0, &sz, + NULL, 0), 0, "Unexpected mallctl() failure"); + assert_d_eq(mallctl("background_thread", (void *)&e1, &sz, + NULL, 0), 0, "Unexpected mallctl() failure"); + assert_b_eq(e0, e1, + "Default and opt.background_thread does not match.\n"); + if (e0) { + test_switch_background_thread_ctl(false); + } + assert_zu_eq(n_background_threads, 0, + "Number of background threads should be 0.\n"); + + for (unsigned i = 0; i < 4; i++) { + test_switch_background_thread_ctl(true); + test_repeat_background_thread_ctl(true); + test_repeat_background_thread_ctl(true); + + test_switch_background_thread_ctl(false); + test_repeat_background_thread_ctl(false); + test_repeat_background_thread_ctl(false); + } +} +TEST_END + +TEST_BEGIN(test_background_thread_running) { + test_skip_if(!have_background_thread); + test_skip_if(!config_stats); + +#if defined(JEMALLOC_BACKGROUND_THREAD) + tsd_t *tsd = tsd_fetch(); + background_thread_info_t *info = &background_thread_info[0]; + + test_repeat_background_thread_ctl(false); + test_switch_background_thread_ctl(true); + + nstime_t start, now; + nstime_init(&start, 0); + nstime_update(&start); + + bool ran = false; + while (true) { + malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); + if (info->tot_n_runs > 0) { + ran = true; + } + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); + if (ran) { + break; + } + + nstime_init(&now, 0); + nstime_update(&now); + nstime_subtract(&now, &start); + assert_u64_lt(nstime_sec(&now), 10, + "Background threads did not run for 10 seconds."); + usleep(10000); + } + test_switch_background_thread_ctl(false); +#endif +} +TEST_END + +int +main(void) { + /* Background_thread creation tests reentrancy naturally. */ + return test_no_reentrancy( + test_background_thread_ctl, + test_background_thread_running); +} diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index f721c21d..8339e8c5 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -161,6 +161,7 @@ TEST_BEGIN(test_mallctl_opt) { TEST_MALLCTL_OPT(const char *, dss, always); TEST_MALLCTL_OPT(unsigned, narenas, always); TEST_MALLCTL_OPT(const char *, percpu_arena, always); + TEST_MALLCTL_OPT(bool, background_thread, always); TEST_MALLCTL_OPT(ssize_t, dirty_decay_ms, always); TEST_MALLCTL_OPT(ssize_t, muzzy_decay_ms, always); TEST_MALLCTL_OPT(bool, stats_print, always); -- GitLab From 0eae838b0d4343b09d80dee00f20a39ce709ca8f Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 22 May 2017 15:26:25 -0700 Subject: [PATCH 489/544] Check for background thread inactivity on extents_dalloc. To avoid background threads sleeping forever with idle arenas, we eagerly check background threads' sleep time after extents_dalloc, and signal the thread if necessary. --- .../internal/background_thread_inlines.h | 35 +++++++++++ .../internal/background_thread_structs.h | 14 +++-- src/arena.c | 4 ++ src/background_thread.c | 61 +++++++++++++------ 4 files changed, 91 insertions(+), 23 deletions(-) diff --git a/include/jemalloc/internal/background_thread_inlines.h b/include/jemalloc/internal/background_thread_inlines.h index 2709ae31..fd5095f2 100644 --- a/include/jemalloc/internal/background_thread_inlines.h +++ b/include/jemalloc/internal/background_thread_inlines.h @@ -18,4 +18,39 @@ arena_background_thread_info_get(arena_t *arena) { return &background_thread_info[arena_ind % ncpus]; } +JEMALLOC_ALWAYS_INLINE uint64_t +background_thread_wakeup_time_get(background_thread_info_t *info) { + uint64_t next_wakeup = nstime_ns(&info->next_wakeup); + assert(atomic_load_b(&info->indefinite_sleep, ATOMIC_ACQUIRE) == + (next_wakeup == BACKGROUND_THREAD_INDEFINITE_SLEEP)); + return next_wakeup; +} + +JEMALLOC_ALWAYS_INLINE void +background_thread_wakeup_time_set(tsdn_t *tsdn, background_thread_info_t *info, + uint64_t wakeup_time) { + malloc_mutex_assert_owner(tsdn, &info->mtx); + atomic_store_b(&info->indefinite_sleep, + wakeup_time == BACKGROUND_THREAD_INDEFINITE_SLEEP, ATOMIC_RELEASE); + nstime_init(&info->next_wakeup, wakeup_time); +} + +JEMALLOC_ALWAYS_INLINE bool +background_thread_indefinite_sleep(background_thread_info_t *info) { + return atomic_load_b(&info->indefinite_sleep, ATOMIC_ACQUIRE); +} + +JEMALLOC_ALWAYS_INLINE void +arena_background_thread_inactivity_check(tsdn_t *tsdn, arena_t *arena) { + if (!background_thread_enabled()) { + return; + } + background_thread_info_t *info = + arena_background_thread_info_get(arena); + if (background_thread_indefinite_sleep(info)) { + background_thread_interval_check(tsdn, arena, + &arena->decay_dirty, 0); + } +} + #endif /* JEMALLOC_INTERNAL_BACKGROUND_THREAD_INLINES_H */ diff --git a/include/jemalloc/internal/background_thread_structs.h b/include/jemalloc/internal/background_thread_structs.h index c4eb8273..9507abcd 100644 --- a/include/jemalloc/internal/background_thread_structs.h +++ b/include/jemalloc/internal/background_thread_structs.h @@ -1,15 +1,22 @@ #ifndef JEMALLOC_INTERNAL_BACKGROUND_THREAD_STRUCTS_H #define JEMALLOC_INTERNAL_BACKGROUND_THREAD_STRUCTS_H +/* This file really combines "structs" and "types", but only transitionally. */ + +#define BACKGROUND_THREAD_INDEFINITE_SLEEP UINT64_MAX + struct background_thread_info_s { - malloc_mutex_t mtx; #ifdef JEMALLOC_BACKGROUND_THREAD /* Background thread is pthread specific. */ - pthread_cond_t cond; pthread_t thread; + pthread_cond_t cond; +#endif + malloc_mutex_t mtx; /* Whether the thread has been created. */ bool started; - /* Next scheduled wakeup time (absolute time). */ + /* When true, it means no wakeup scheduled. */ + atomic_b_t indefinite_sleep; + /* Next scheduled wakeup time (absolute time in ns). */ nstime_t next_wakeup; /* * Since the last background thread run, newly added number of pages @@ -22,7 +29,6 @@ struct background_thread_info_s { uint64_t tot_n_runs; /* Stats: total sleep time since started. */ nstime_t tot_sleep_time; -#endif /* ifdef JEMALLOC_BACKGROUND_THREAD */ }; typedef struct background_thread_info_s background_thread_info_t; diff --git a/src/arena.c b/src/arena.c index 0bd82dbc..7f75b642 100644 --- a/src/arena.c +++ b/src/arena.c @@ -367,6 +367,8 @@ arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena, extent); if (arena_dirty_decay_ms_get(arena) == 0) { arena_decay_dirty(tsdn, arena, false, true); + } else { + arena_background_thread_inactivity_check(tsdn, arena); } } @@ -919,6 +921,8 @@ arena_decay_stashed(tsdn_t *tsdn, arena_t *arena, extent_size_get(extent))) { extents_dalloc(tsdn, arena, r_extent_hooks, &arena->extents_muzzy, extent); + arena_background_thread_inactivity_check(tsdn, + arena); break; } /* Fall through. */ diff --git a/src/background_thread.c b/src/background_thread.c index 076d9815..1e725b4e 100644 --- a/src/background_thread.c +++ b/src/background_thread.c @@ -42,8 +42,8 @@ bool background_thread_stats_read(tsdn_t *tsdn, #else static void -background_thread_info_reinit(background_thread_info_t *info) { - nstime_init(&info->next_wakeup, 0); +background_thread_info_reinit(tsdn_t *tsdn, background_thread_info_t *info) { + background_thread_wakeup_time_set(tsdn, info, 0); info->npages_to_purge_new = 0; if (config_stats) { info->tot_n_runs = 0; @@ -80,8 +80,10 @@ background_threads_init(tsd_t *tsd) { if (pthread_cond_init(&info->cond, NULL)) { return true; } + malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); info->started = false; - background_thread_info_reinit(info); + background_thread_info_reinit(tsd_tsdn(tsd), info); + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); } return false; @@ -106,7 +108,6 @@ set_current_thread_affinity(UNUSED int cpu) { #define BILLION UINT64_C(1000000000) /* Minimal sleep interval 100 ms. */ #define BACKGROUND_THREAD_MIN_INTERVAL_NS (BILLION / 10) -#define BACKGROUND_THREAD_INDEFINITE_SLEEP UINT64_MAX static inline size_t decay_npurge_after_interval(arena_decay_t *decay, size_t interval) { @@ -258,6 +259,8 @@ background_work(tsdn_t *tsdn, unsigned ind) { background_thread_info_t *info = &background_thread_info[ind]; malloc_mutex_lock(tsdn, &info->mtx); + background_thread_wakeup_time_set(tsdn, info, + BACKGROUND_THREAD_INDEFINITE_SLEEP); while (info->started) { uint64_t interval = background_work_once(tsdn, ind); if (config_stats) { @@ -266,21 +269,27 @@ background_work(tsdn_t *tsdn, unsigned ind) { info->npages_to_purge_new = 0; struct timeval tv; + /* Specific clock required by timedwait. */ gettimeofday(&tv, NULL); nstime_t before_sleep; nstime_init2(&before_sleep, tv.tv_sec, tv.tv_usec * 1000); if (interval == BACKGROUND_THREAD_INDEFINITE_SLEEP) { - nstime_init(&info->next_wakeup, - BACKGROUND_THREAD_INDEFINITE_SLEEP); + assert(background_thread_indefinite_sleep(info)); ret = pthread_cond_wait(&info->cond, &info->mtx.lock); assert(ret == 0); } else { assert(interval >= BACKGROUND_THREAD_MIN_INTERVAL_NS && interval <= BACKGROUND_THREAD_INDEFINITE_SLEEP); - nstime_init(&info->next_wakeup, 0); - nstime_update(&info->next_wakeup); - nstime_iadd(&info->next_wakeup, interval); + /* We need malloc clock (can be different from tv). */ + nstime_t next_wakeup; + nstime_init(&next_wakeup, 0); + nstime_update(&next_wakeup); + nstime_iadd(&next_wakeup, interval); + assert(nstime_ns(&next_wakeup) < + BACKGROUND_THREAD_INDEFINITE_SLEEP); + background_thread_wakeup_time_set(tsdn, info, + nstime_ns(&next_wakeup)); nstime_t ts_wakeup; nstime_copy(&ts_wakeup, &before_sleep); @@ -289,9 +298,12 @@ background_work(tsdn_t *tsdn, unsigned ind) { ts.tv_sec = (size_t)nstime_sec(&ts_wakeup); ts.tv_nsec = (size_t)nstime_nsec(&ts_wakeup); + assert(!background_thread_indefinite_sleep(info)); ret = pthread_cond_timedwait(&info->cond, &info->mtx.lock, &ts); assert(ret == ETIMEDOUT || ret == 0); + background_thread_wakeup_time_set(tsdn, info, + BACKGROUND_THREAD_INDEFINITE_SLEEP); } if (config_stats) { @@ -304,6 +316,7 @@ background_work(tsdn_t *tsdn, unsigned ind) { } } } + background_thread_wakeup_time_set(tsdn, info, 0); malloc_mutex_unlock(tsdn, &info->mtx); } @@ -360,7 +373,7 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) { assert(info->started == false); if (err == 0) { info->started = true; - background_thread_info_reinit(info); + background_thread_info_reinit(tsd_tsdn(tsd), info); n_background_threads++; } malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); @@ -465,6 +478,7 @@ background_thread_interval_check(tsdn_t *tsdn, arena_t *arena, if (!info->started) { goto label_done; } + assert(background_thread_enabled()); if (malloc_mutex_trylock(tsdn, &decay->mtx)) { goto label_done; } @@ -474,14 +488,14 @@ background_thread_interval_check(tsdn_t *tsdn, arena_t *arena, /* Purging is eagerly done or disabled currently. */ goto label_done_unlock2; } - if (nstime_compare(&info->next_wakeup, &decay->epoch) <= 0) { - goto label_done_unlock2; - } - uint64_t decay_interval_ns = nstime_ns(&decay->interval); assert(decay_interval_ns > 0); + nstime_t diff; - nstime_copy(&diff, &info->next_wakeup); + nstime_init(&diff, background_thread_wakeup_time_get(info)); + if (nstime_compare(&diff, &decay->epoch) <= 0) { + goto label_done_unlock2; + } nstime_subtract(&diff, &decay->epoch); if (nstime_ns(&diff) < BACKGROUND_THREAD_MIN_INTERVAL_NS) { goto label_done_unlock2; @@ -508,9 +522,19 @@ background_thread_interval_check(tsdn_t *tsdn, arena_t *arena, info->npages_to_purge_new += npurge_new; } - if (info->npages_to_purge_new > BACKGROUND_THREAD_NPAGES_THRESHOLD || - (nstime_ns(&info->next_wakeup) == - BACKGROUND_THREAD_INDEFINITE_SLEEP && info->npages_to_purge_new > 0)) { + bool should_signal; + if (info->npages_to_purge_new > BACKGROUND_THREAD_NPAGES_THRESHOLD) { + should_signal = true; + } else if (unlikely(background_thread_indefinite_sleep(info)) && + (extents_npages_get(&arena->extents_dirty) > 0 || + extents_npages_get(&arena->extents_muzzy) > 0 || + info->npages_to_purge_new > 0)) { + should_signal = true; + } else { + should_signal = false; + } + + if (should_signal) { info->npages_to_purge_new = 0; pthread_cond_signal(&info->cond); } @@ -602,7 +626,6 @@ background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats) { #undef BACKGROUND_THREAD_NPAGES_THRESHOLD #undef BILLION #undef BACKGROUND_THREAD_MIN_INTERVAL_NS -#undef BACKGROUND_THREAD_INDEFINITE_SLEEP #endif /* defined(JEMALLOC_BACKGROUND_THREAD) */ -- GitLab From eeefdf3ce89e09ce7cc5c58d2a3730b83045eec1 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 22 May 2017 13:09:17 -0700 Subject: [PATCH 490/544] Fix # of unpurged pages in decay algorithm. When # of dirty pages move below npages_limit (e.g. they are reused), we should not lower number of unpurged pages because that would cause the reused pages to be double counted in the backlog (as a result, decay happen slower than it should). Instead, set number of unpurged to the greater of current npages and npages_limit. Added an assertion: the ceiling # of pages should be greater than npages_limit. --- include/jemalloc/internal/arena_structs_b.h | 2 ++ src/arena.c | 36 +++++++++++++++------ 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 459dd89d..95680c0f 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -103,6 +103,8 @@ struct arena_decay_s { * * Synchronization: Same as associated arena's stats field. */ decay_stats_t *stats; + /* Peak number of pages in associated extents. Used for debug only. */ + uint64_t ceil_npages; }; struct arena_bin_s { diff --git a/src/arena.c b/src/arena.c index 7f75b642..48d536e2 100644 --- a/src/arena.c +++ b/src/arena.c @@ -639,6 +639,17 @@ arena_decay_backlog_update_last(arena_decay_t *decay, extents_t *extents) { size_t ndirty_delta = (ndirty > decay->nunpurged) ? ndirty - decay->nunpurged : 0; decay->backlog[SMOOTHSTEP_NSTEPS-1] = ndirty_delta; + + if (config_debug) { + if (ndirty > decay->ceil_npages) { + decay->ceil_npages = ndirty; + } + size_t npages_limit = arena_decay_backlog_npages_limit(decay); + assert(decay->ceil_npages >= npages_limit); + if (decay->ceil_npages > npages_limit) { + decay->ceil_npages = npages_limit; + } + } } static void @@ -664,11 +675,9 @@ arena_decay_backlog_update(arena_decay_t *decay, extents_t *extents, } static void -arena_decay_try_purge(tsdn_t *tsdn, arena_t *arena, - arena_decay_t *decay, extents_t *extents) { - size_t npages_limit = arena_decay_backlog_npages_limit(decay); - - if (extents_npages_get(extents) > npages_limit) { +arena_decay_try_purge(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, + extents_t *extents, size_t current_npages, size_t npages_limit) { + if (current_npages > npages_limit) { arena_decay_to_limit(tsdn, arena, decay, extents, false, npages_limit); } @@ -702,16 +711,20 @@ static void arena_decay_epoch_advance(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, extents_t *extents, const nstime_t *time, bool purge) { arena_decay_epoch_advance_helper(decay, extents, time); + + size_t current_npages = extents_npages_get(extents); + size_t npages_limit = arena_decay_backlog_npages_limit(decay); if (purge) { - arena_decay_try_purge(tsdn, arena, decay, extents); + arena_decay_try_purge(tsdn, arena, decay, extents, + current_npages, npages_limit); } - /* * There may be concurrent ndirty fluctuation between the purge above * and the nunpurged update below, but this is inconsequential to decay * machinery correctness. */ - decay->nunpurged = extents_npages_get(extents); + decay->nunpurged = (npages_limit > current_npages) ? npages_limit : + current_npages; } static void @@ -727,7 +740,7 @@ arena_decay_reinit(arena_decay_t *decay, extents_t *extents, ssize_t decay_ms) { nstime_update(&decay->epoch); decay->jitter_state = (uint64_t)(uintptr_t)decay; arena_decay_deadline_init(decay); - decay->nunpurged = extents_npages_get(extents); + decay->nunpurged = 0; memset(decay->backlog, 0, SMOOTHSTEP_NSTEPS * sizeof(size_t)); } @@ -738,6 +751,7 @@ arena_decay_init(arena_decay_t *decay, extents_t *extents, ssize_t decay_ms, for (size_t i = 0; i < sizeof(arena_decay_t); i++) { assert(((char *)decay)[i] == 0); } + decay->ceil_npages = 0; } if (malloc_mutex_init(&decay->mtx, "decay", WITNESS_RANK_DECAY, malloc_mutex_rank_exclusive)) { @@ -814,7 +828,9 @@ arena_maybe_decay(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, arena_decay_epoch_advance(tsdn, arena, decay, extents, &time, should_purge); } else if (is_background_thread) { - arena_decay_try_purge(tsdn, arena, decay, extents); + arena_decay_try_purge(tsdn, arena, decay, extents, + extents_npages_get(extents), + arena_decay_backlog_npages_limit(decay)); } return advance_epoch; -- GitLab From 9b1038d19c998b8c219eb08d083ca0328b7941f1 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 22 May 2017 17:08:21 -0700 Subject: [PATCH 491/544] Do not hold the base mutex while calling extent hooks. Drop the base mutex while allocating new base blocks, because extent allocation can enter code that prohibits holding non-core mutexes, e.g. the extent_[d]alloc() and extent_purge_forced_wrapper() calls in extent_alloc_dss(). This partially resolves #802. --- src/base.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/base.c b/src/base.c index 7502a657..dd4b109d 100644 --- a/src/base.c +++ b/src/base.c @@ -199,8 +199,14 @@ base_extent_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) { malloc_mutex_assert_owner(tsdn, &base->mtx); extent_hooks_t *extent_hooks = base_extent_hooks_get(base); + /* + * Drop mutex during base_block_alloc(), because an extent hook will be + * called. + */ + malloc_mutex_unlock(tsdn, &base->mtx); base_block_t *block = base_block_alloc(extent_hooks, base_ind_get(base), &base->pind_last, &base->extent_sn_next, size, alignment); + malloc_mutex_lock(tsdn, &base->mtx); if (block == NULL) { return NULL; } -- GitLab From 067b97013018211b39e9911ae528ff54edd8fe5e Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 22 May 2017 17:15:57 -0700 Subject: [PATCH 492/544] Add dss:primary testing. Generalize the run_tests.sh and .travis.yml test generation to handle combinations of arguments to the --with-malloc-conf configure option, and merge "dss:primary" into the existing "tcache:false" testing. --- .travis.yml | 18 ++++++++++++++++ scripts/gen_run_tests.py | 45 ++++++++++++++++++++++++---------------- scripts/gen_travis.py | 16 ++++++++++++-- 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4838cb37..6ca3ac44 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,8 @@ matrix: env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx @@ -46,6 +48,8 @@ matrix: env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds" addons: @@ -70,18 +74,32 @@ matrix: apt: packages: - gcc-multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + addons: + apt: + packages: + - gcc-multilib - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" before_script: diff --git a/scripts/gen_run_tests.py b/scripts/gen_run_tests.py index 0446c65c..9fbf71e5 100755 --- a/scripts/gen_run_tests.py +++ b/scripts/gen_run_tests.py @@ -20,6 +20,10 @@ possible_config_opts = [ '--disable-stats', '--with-malloc-conf=tcache:false', ] +possible_malloc_conf_opts = [ + 'tcache:false', + 'dss:primary', +] print 'set -e' print 'autoconf' @@ -28,21 +32,26 @@ print 'unamestr=`uname`' for cc, cxx in possible_compilers: for compiler_opts in powerset(possible_compiler_opts): for config_opts in powerset(possible_config_opts): - if cc is 'clang' \ - and '-m32' in possible_compiler_opts \ - and '--enable-prof' in config_opts: - continue - config_line = ( - 'EXTRA_CFLAGS=-Werror EXTRA_CXXFLAGS=-Werror ./configure ' - + 'CC="{} {}" '.format(cc, " ".join(compiler_opts)) - + 'CXX="{} {}" '.format(cxx, " ".join(compiler_opts)) - + " ".join(config_opts) - ) - # Heap profiling is not supported on OS X. - if '--enable-prof' in config_opts: - print 'if [[ "$unamestr" != "Darwin" ]]; then' - print config_line - print "make clean" - print "make -j" + str(MAKE_J_VAL) + " check" - if '--enable-prof' in config_opts: - print 'fi' + for malloc_conf_opts in powerset(possible_malloc_conf_opts): + if cc is 'clang' \ + and '-m32' in possible_compiler_opts \ + and '--enable-prof' in config_opts: + continue + config_line = ( + 'EXTRA_CFLAGS=-Werror EXTRA_CXXFLAGS=-Werror ./configure ' + + 'CC="{} {}" '.format(cc, " ".join(compiler_opts)) + + 'CXX="{} {}" '.format(cxx, " ".join(compiler_opts)) + + " ".join(config_opts) + (' --with-malloc-conf=' + + ",".join(malloc_conf_opts) if len(malloc_conf_opts) > 0 + else '') + ) + # Heap profiling and dss are not supported on OS X. + darwin_unsupported = ('--enable-prof' in config_opts or \ + 'dss:primary' in malloc_conf_opts) + if darwin_unsupported: + print 'if [[ "$unamestr" != "Darwin" ]]; then' + print config_line + print "make clean" + print "make -j" + str(MAKE_J_VAL) + " check" + if darwin_unsupported: + print 'fi' diff --git a/scripts/gen_travis.py b/scripts/gen_travis.py index 4649cb71..4a4c2144 100755 --- a/scripts/gen_travis.py +++ b/scripts/gen_travis.py @@ -43,12 +43,16 @@ configure_flag_unusuals = [ '--enable-debug', '--enable-prof', '--disable-stats', - '--with-malloc-conf=tcache:false', +] + +malloc_conf_unusuals = [ + 'tcache:false', + 'dss:primary', ] all_unusuals = ( [os_unusual] + [compilers_unusual] + compiler_flag_unusuals - + configure_flag_unusuals + + configure_flag_unusuals + malloc_conf_unusuals ) unusual_combinations_to_test = [] @@ -71,6 +75,14 @@ for unusual_combination in unusual_combinations_to_test: configure_flags = [ x for x in unusual_combination if x in configure_flag_unusuals] + malloc_conf = [ + x for x in unusual_combination if x in malloc_conf_unusuals] + # Filter out an unsupported configuration - dss on OS X. + if os == 'osx' and 'dss:primary' in malloc_conf: + continue + if len(malloc_conf) > 0: + configure_flags.append('--with-malloc-conf=' + ",".join(malloc_conf)) + # Filter out an unsupported configuration - heap profiling on OS X. if os == 'osx' and '--enable-prof' in configure_flags: continue -- GitLab From 196a53c2aec9fd9fbd17af6803d75c7f631c1ae3 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 16 May 2017 13:25:17 -0700 Subject: [PATCH 493/544] Do not assume dss never decreases. An sbrk() caller outside jemalloc can decrease the dss, so add a separate atomic boolean to explicitly track whether jemalloc is concurrently calling sbrk(), rather than depending on state outside jemalloc's full control. This resolves #802. --- src/extent_dss.c | 72 +++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/src/extent_dss.c b/src/extent_dss.c index 6b5d066f..8e0ca654 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -28,6 +28,8 @@ static atomic_u_t dss_prec_default = ATOMIC_INIT( /* Base address of the DSS. */ static void *dss_base; +/* Atomic boolean indicating whether a thread is currently extending DSS. */ +static atomic_b_t dss_extending; /* Atomic boolean indicating whether the DSS is exhausted. */ static atomic_b_t dss_exhausted; /* Atomic current upper limit on DSS addresses. */ @@ -65,37 +67,41 @@ extent_dss_prec_set(dss_prec_t dss_prec) { return false; } +static void +extent_dss_extending_start(void) { + spin_t spinner = SPIN_INITIALIZER; + while (true) { + bool expected = false; + if (atomic_compare_exchange_weak_b(&dss_extending, &expected, + true, ATOMIC_ACQ_REL, ATOMIC_RELAXED)) { + break; + } + spin_adaptive(&spinner); + } +} + +static void +extent_dss_extending_finish(void) { + assert(atomic_load_b(&dss_extending, ATOMIC_RELAXED)); + + atomic_store_b(&dss_extending, false, ATOMIC_RELEASE); +} + static void * extent_dss_max_update(void *new_addr) { - void *max_cur; - /* * Get the current end of the DSS as max_cur and assure that dss_max is * up to date. */ - spin_t spinner = SPIN_INITIALIZER; - while (true) { - void *max_prev = atomic_load_p(&dss_max, ATOMIC_RELAXED); - - max_cur = extent_dss_sbrk(0); - if ((uintptr_t)max_prev > (uintptr_t)max_cur) { - /* - * Another thread optimistically updated dss_max. Wait - * for it to finish. - */ - spin_adaptive(&spinner); - continue; - } - if (atomic_compare_exchange_weak_p(&dss_max, &max_prev, - max_cur, ATOMIC_ACQ_REL, ATOMIC_RELAXED)) { - break; - } + void *max_cur = extent_dss_sbrk(0); + if (max_cur == (void *)-1) { + return NULL; } + atomic_store_p(&dss_max, max_cur, ATOMIC_RELEASE); /* Fixed new_addr can only be supported if it is at the edge of DSS. */ if (new_addr != NULL && max_cur != new_addr) { return NULL; } - return max_cur; } @@ -121,6 +127,7 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, return NULL; } + extent_dss_extending_start(); if (!atomic_load_b(&dss_exhausted, ATOMIC_ACQUIRE)) { /* * The loop is necessary to recover from races with other @@ -168,21 +175,14 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, assert((uintptr_t)max_cur + incr == (uintptr_t)ret + size); - /* - * Optimistically update dss_max, and roll back below if - * sbrk() fails. No other thread will try to extend the - * DSS while dss_max is greater than the current DSS - * max reported by sbrk(0). - */ - if (!atomic_compare_exchange_weak_p(&dss_max, &max_cur, - dss_next, ATOMIC_ACQ_REL, ATOMIC_RELAXED)) { - continue; - } - /* Try to allocate. */ void *dss_prev = extent_dss_sbrk(incr); if (dss_prev == max_cur) { /* Success. */ + atomic_store_p(&dss_max, dss_next, + ATOMIC_RELEASE); + extent_dss_extending_finish(); + if (gap_size_page != 0) { extent_dalloc_gap(tsdn, arena, gap); } else { @@ -209,14 +209,8 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, } /* * Failure, whether due to OOM or a race with a raw - * sbrk() call from outside the allocator. Try to roll - * back optimistic dss_max update; if rollback fails, - * it's due to another caller of this function having - * succeeded since this invocation started, in which - * case rollback is not necessary. + * sbrk() call from outside the allocator. */ - atomic_compare_exchange_strong_p(&dss_max, &dss_next, - max_cur, ATOMIC_ACQ_REL, ATOMIC_RELAXED); if (dss_prev == (void *)-1) { /* OOM. */ atomic_store_b(&dss_exhausted, true, @@ -226,6 +220,7 @@ extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, size_t size, } } label_oom: + extent_dss_extending_finish(); extent_dalloc(tsdn, arena, gap); return NULL; } @@ -265,6 +260,7 @@ extent_dss_boot(void) { cassert(have_dss); dss_base = extent_dss_sbrk(0); + atomic_store_b(&dss_extending, false, ATOMIC_RELAXED); atomic_store_b(&dss_exhausted, dss_base == (void *)-1, ATOMIC_RELAXED); atomic_store_p(&dss_max, dss_base, ATOMIC_RELAXED); } -- GitLab From 36195c8f4dc536f3609de539c5f26cdd44514800 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 23 May 2017 10:53:36 -0700 Subject: [PATCH 494/544] Disable percpu_arena by default. --- .travis.yml | 20 ++++++++++++++++++++ doc/jemalloc.xml.in | 4 ++-- include/jemalloc/internal/arena_types.h | 5 ----- scripts/gen_run_tests.py | 12 ++++++++++-- scripts/gen_travis.py | 6 ++++-- 5 files changed, 36 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6ca3ac44..917314fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,6 +24,8 @@ matrix: env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx @@ -50,6 +52,8 @@ matrix: env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds" addons: @@ -80,6 +84,12 @@ matrix: apt: packages: - gcc-multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + addons: + apt: + packages: + - gcc-multilib - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux @@ -88,18 +98,28 @@ matrix: env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary,percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" before_script: diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 57f5b0ba..16d9ce4e 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -952,8 +952,8 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", same CPU share one arena. Note that no runtime checking regarding the availability of hyper threading is done at the moment. When set to disabled, narenas and thread to arena association will - not be impacted by this option. The default is - percpu. + not be impacted by this option. The default is disabled. + diff --git a/include/jemalloc/internal/arena_types.h b/include/jemalloc/internal/arena_types.h index 34d4f6f2..1374eeca 100644 --- a/include/jemalloc/internal/arena_types.h +++ b/include/jemalloc/internal/arena_types.h @@ -29,12 +29,7 @@ typedef enum { percpu_arena_mode_limit = 3 } percpu_arena_mode_t; -#ifdef JEMALLOC_PERCPU_ARENA -#define PERCPU_ARENA_MODE_DEFAULT percpu_arena -#define OPT_PERCPU_ARENA_DEFAULT "percpu" -#else #define PERCPU_ARENA_MODE_DEFAULT percpu_arena_disabled #define OPT_PERCPU_ARENA_DEFAULT "disabled" -#endif #endif /* JEMALLOC_INTERNAL_ARENA_TYPES_H */ diff --git a/scripts/gen_run_tests.py b/scripts/gen_run_tests.py index 9fbf71e5..875c6d03 100755 --- a/scripts/gen_run_tests.py +++ b/scripts/gen_run_tests.py @@ -23,6 +23,7 @@ possible_config_opts = [ possible_malloc_conf_opts = [ 'tcache:false', 'dss:primary', + 'percpu_arena:percpu', ] print 'set -e' @@ -45,13 +46,20 @@ for cc, cxx in possible_compilers: ",".join(malloc_conf_opts) if len(malloc_conf_opts) > 0 else '') ) + + # Per CPU arenas are only supported on Linux. + linux_supported = ('percpu_arena:percpu' in malloc_conf_opts) # Heap profiling and dss are not supported on OS X. darwin_unsupported = ('--enable-prof' in config_opts or \ 'dss:primary' in malloc_conf_opts) - if darwin_unsupported: + if linux_supported: + print 'if [[ "$unamestr" = "Linux" ]]; then' + elif darwin_unsupported: print 'if [[ "$unamestr" != "Darwin" ]]; then' + print config_line print "make clean" print "make -j" + str(MAKE_J_VAL) + " check" - if darwin_unsupported: + + if linux_supported or darwin_unsupported: print 'fi' diff --git a/scripts/gen_travis.py b/scripts/gen_travis.py index 4a4c2144..26997b25 100755 --- a/scripts/gen_travis.py +++ b/scripts/gen_travis.py @@ -48,6 +48,7 @@ configure_flag_unusuals = [ malloc_conf_unusuals = [ 'tcache:false', 'dss:primary', + 'percpu_arena:percpu', ] all_unusuals = ( @@ -77,8 +78,9 @@ for unusual_combination in unusual_combinations_to_test: malloc_conf = [ x for x in unusual_combination if x in malloc_conf_unusuals] - # Filter out an unsupported configuration - dss on OS X. - if os == 'osx' and 'dss:primary' in malloc_conf: + # Filter out unsupported configurations on OS X. + if os == 'osx' and ('dss:primary' in malloc_conf or \ + 'percpu_arena:percpu' in malloc_conf): continue if len(malloc_conf) > 0: configure_flags.append('--with-malloc-conf=' + ",".join(malloc_conf)) -- GitLab From 9f822a1fd70a676d810a4c621346d6484b29cb77 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Mon, 22 May 2017 19:32:04 -0700 Subject: [PATCH 495/544] Header refactoring: unify and de-catchall witness code. --- .../internal/jemalloc_internal_includes.h | 4 - .../internal/jemalloc_internal_inlines_c.h | 22 +- include/jemalloc/internal/mutex_inlines.h | 14 +- .../jemalloc/internal/mutex_pool_inlines.h | 1 + include/jemalloc/internal/mutex_structs.h | 3 +- include/jemalloc/internal/tsd.h | 98 ++--- include/jemalloc/internal/witness.h | 345 ++++++++++++++++++ include/jemalloc/internal/witness_externs.h | 25 -- include/jemalloc/internal/witness_inlines.h | 188 ---------- include/jemalloc/internal/witness_structs.h | 28 -- include/jemalloc/internal/witness_types.h | 70 ---- src/arena.c | 18 +- src/extent.c | 54 ++- src/jemalloc.c | 78 ++-- src/tcache.c | 4 +- src/tsd.c | 2 +- src/witness.c | 18 +- test/unit/witness.c | 172 ++++----- 18 files changed, 604 insertions(+), 540 deletions(-) create mode 100644 include/jemalloc/internal/witness.h delete mode 100644 include/jemalloc/internal/witness_externs.h delete mode 100644 include/jemalloc/internal/witness_inlines.h delete mode 100644 include/jemalloc/internal/witness_structs.h delete mode 100644 include/jemalloc/internal/witness_types.h diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 45e648bc..2abc4781 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -40,7 +40,6 @@ /* TYPES */ /******************************************************************************/ -#include "jemalloc/internal/witness_types.h" #include "jemalloc/internal/mutex_types.h" #include "jemalloc/internal/extent_types.h" #include "jemalloc/internal/extent_dss_types.h" @@ -54,7 +53,6 @@ /* STRUCTS */ /******************************************************************************/ -#include "jemalloc/internal/witness_structs.h" #include "jemalloc/internal/mutex_structs.h" #include "jemalloc/internal/mutex_pool_structs.h" #include "jemalloc/internal/arena_structs_a.h" @@ -72,7 +70,6 @@ /******************************************************************************/ #include "jemalloc/internal/jemalloc_internal_externs.h" -#include "jemalloc/internal/witness_externs.h" #include "jemalloc/internal/mutex_externs.h" #include "jemalloc/internal/extent_externs.h" #include "jemalloc/internal/extent_dss_externs.h" @@ -89,7 +86,6 @@ /* INLINES */ /******************************************************************************/ -#include "jemalloc/internal/witness_inlines.h" #include "jemalloc/internal/mutex_inlines.h" #include "jemalloc/internal/mutex_pool_inlines.h" #include "jemalloc/internal/jemalloc_internal_inlines_a.h" diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_c.h b/include/jemalloc/internal/jemalloc_internal_inlines_c.h index 415c503b..80dfbeff 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_c.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_c.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_INLINES_C_H #include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/witness.h" JEMALLOC_ALWAYS_INLINE arena_t * iaalloc(tsdn_t *tsdn, const void *ptr) { @@ -25,7 +26,8 @@ iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache, assert(size != 0); assert(!is_internal || tcache == NULL); assert(!is_internal || arena == NULL || arena_is_auto(arena)); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); ret = arena_malloc(tsdn, arena, size, ind, zero, tcache, slow_path); if (config_stats && is_internal && likely(ret != NULL)) { @@ -49,7 +51,8 @@ ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, assert(usize == sa2u(usize, alignment)); assert(!is_internal || tcache == NULL); assert(!is_internal || arena == NULL || arena_is_auto(arena)); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); ret = arena_palloc(tsdn, arena, usize, alignment, zero, tcache); assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret); @@ -82,7 +85,8 @@ idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache, alloc_ctx_t *alloc_ctx, assert(ptr != NULL); assert(!is_internal || tcache == NULL); assert(!is_internal || arena_is_auto(iaalloc(tsdn, ptr))); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); if (config_stats && is_internal) { arena_internal_sub(iaalloc(tsdn, ptr), isalloc(tsdn, ptr)); } @@ -100,7 +104,8 @@ idalloc(tsd_t *tsd, void *ptr) { JEMALLOC_ALWAYS_INLINE void isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, alloc_ctx_t *alloc_ctx, bool slow_path) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); arena_sdalloc(tsdn, ptr, size, tcache, alloc_ctx, slow_path); } @@ -108,7 +113,8 @@ JEMALLOC_ALWAYS_INLINE void * iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); void *p; size_t usize, copysize; @@ -146,7 +152,8 @@ iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena) { assert(ptr != NULL); assert(size != 0); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1)) != 0) { @@ -174,7 +181,8 @@ ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra, size_t alignment, bool zero) { assert(ptr != NULL); assert(size != 0); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1)) != 0) { diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h index babe8d3a..b86a4ad4 100644 --- a/include/jemalloc/internal/mutex_inlines.h +++ b/include/jemalloc/internal/mutex_inlines.h @@ -31,14 +31,14 @@ mutex_owner_stats_update(tsdn_t *tsdn, malloc_mutex_t *mutex) { /* Trylock: return false if the lock is successfully acquired. */ static inline bool malloc_mutex_trylock(tsdn_t *tsdn, malloc_mutex_t *mutex) { - witness_assert_not_owner(tsdn, &mutex->witness); + witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness); if (isthreaded) { if (malloc_mutex_trylock_final(mutex)) { return true; } mutex_owner_stats_update(tsdn, mutex); } - witness_lock(tsdn, &mutex->witness); + witness_lock(tsdn_witness_tsdp_get(tsdn), &mutex->witness); return false; } @@ -69,19 +69,19 @@ malloc_mutex_prof_merge(mutex_prof_data_t *sum, mutex_prof_data_t *data) { static inline void malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) { - witness_assert_not_owner(tsdn, &mutex->witness); + witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness); if (isthreaded) { if (malloc_mutex_trylock_final(mutex)) { malloc_mutex_lock_slow(mutex); } mutex_owner_stats_update(tsdn, mutex); } - witness_lock(tsdn, &mutex->witness); + witness_lock(tsdn_witness_tsdp_get(tsdn), &mutex->witness); } static inline void malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) { - witness_unlock(tsdn, &mutex->witness); + witness_unlock(tsdn_witness_tsdp_get(tsdn), &mutex->witness); if (isthreaded) { MALLOC_MUTEX_UNLOCK(mutex); } @@ -89,12 +89,12 @@ malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) { static inline void malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { - witness_assert_owner(tsdn, &mutex->witness); + witness_assert_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness); } static inline void malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { - witness_assert_not_owner(tsdn, &mutex->witness); + witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness); } /* Copy the prof data from mutex for processing. */ diff --git a/include/jemalloc/internal/mutex_pool_inlines.h b/include/jemalloc/internal/mutex_pool_inlines.h index 0b667aaa..bc257ea8 100644 --- a/include/jemalloc/internal/mutex_pool_inlines.h +++ b/include/jemalloc/internal/mutex_pool_inlines.h @@ -4,6 +4,7 @@ #include "jemalloc/internal/hash.h" #include "jemalloc/internal/mutex_inlines.h" #include "jemalloc/internal/mutex_pool_structs.h" +#include "jemalloc/internal/witness.h" /* * This file really combines "inlines" and "externs", but only transitionally. diff --git a/include/jemalloc/internal/mutex_structs.h b/include/jemalloc/internal/mutex_structs.h index 92f41676..c1b65522 100644 --- a/include/jemalloc/internal/mutex_structs.h +++ b/include/jemalloc/internal/mutex_structs.h @@ -3,8 +3,7 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/mutex_prof.h" -#include "jemalloc/internal/witness_types.h" -#include "jemalloc/internal/witness_structs.h" +#include "jemalloc/internal/witness.h" struct malloc_mutex_s { union { diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h index 1a269755..c192a6ca 100644 --- a/include/jemalloc/internal/tsd.h +++ b/include/jemalloc/internal/tsd.h @@ -10,8 +10,7 @@ #include "jemalloc/internal/tcache_types.h" #include "jemalloc/internal/tcache_structs.h" #include "jemalloc/internal/util.h" -#include "jemalloc/internal/witness_types.h" -#include "jemalloc/internal/witness_structs.h" +#include "jemalloc/internal/witness.h" /* * Thread-Specific-Data layout @@ -52,30 +51,29 @@ typedef void (*test_callback_t)(int *); # define MALLOC_TSD_TEST_DATA_INIT 0x72b65c10 # define MALLOC_TEST_TSD \ - O(test_data, int) \ - O(test_callback, test_callback_t) + O(test_data, int, int) \ + O(test_callback, test_callback_t, int) # define MALLOC_TEST_TSD_INITIALIZER , MALLOC_TSD_TEST_DATA_INIT, NULL #else # define MALLOC_TEST_TSD # define MALLOC_TEST_TSD_INITIALIZER #endif +/* O(name, type, nullable type */ #define MALLOC_TSD \ -/* O(name, type) */ \ - O(tcache_enabled, bool) \ - O(arenas_tdata_bypass, bool) \ - O(reentrancy_level, int8_t) \ - O(narenas_tdata, uint32_t) \ - O(thread_allocated, uint64_t) \ - O(thread_deallocated, uint64_t) \ - O(prof_tdata, prof_tdata_t *) \ - O(rtree_ctx, rtree_ctx_t) \ - O(iarena, arena_t *) \ - O(arena, arena_t *) \ - O(arenas_tdata, arena_tdata_t *) \ - O(tcache, tcache_t) \ - O(witnesses, witness_list_t) \ - O(witness_fork, bool) \ + O(tcache_enabled, bool, bool) \ + O(arenas_tdata_bypass, bool, bool) \ + O(reentrancy_level, int8_t, int8_t) \ + O(narenas_tdata, uint32_t, uint32_t) \ + O(thread_allocated, uint64_t, uint64_t) \ + O(thread_deallocated, uint64_t, uint64_t) \ + O(prof_tdata, prof_tdata_t *, prof_tdata_t *) \ + O(rtree_ctx, rtree_ctx_t, rtree_ctx_t) \ + O(iarena, arena_t *, arena_t *) \ + O(arena, arena_t *, arena_t *) \ + O(arenas_tdata, arena_tdata_t *, arena_tdata_t *)\ + O(tcache, tcache_t, tcache_t) \ + O(witness_tsd, witness_tsd_t, witness_tsdn_t) \ MALLOC_TEST_TSD #define TSD_INITIALIZER { \ @@ -92,8 +90,7 @@ typedef void (*test_callback_t)(int *); NULL, \ NULL, \ TCACHE_ZERO_INITIALIZER, \ - ql_head_initializer(witnesses), \ - false \ + WITNESS_TSD_INITIALIZER \ MALLOC_TEST_TSD_INITIALIZER \ } @@ -119,7 +116,7 @@ struct tsd_s { * setters below. */ tsd_state_t state; -#define O(n, t) \ +#define O(n, t, nt) \ t use_a_getter_or_setter_instead_##n; MALLOC_TSD #undef O @@ -135,6 +132,22 @@ struct tsdn_s { tsd_t tsd; }; #define TSDN_NULL ((tsdn_t *)0) +JEMALLOC_ALWAYS_INLINE tsdn_t * +tsd_tsdn(tsd_t *tsd) { + return (tsdn_t *)tsd; +} + +JEMALLOC_ALWAYS_INLINE bool +tsdn_null(const tsdn_t *tsdn) { + return tsdn == NULL; +} + +JEMALLOC_ALWAYS_INLINE tsd_t * +tsdn_tsd(tsdn_t *tsdn) { + assert(!tsdn_null(tsdn)); + + return &tsdn->tsd; +} void *malloc_tsd_malloc(size_t size); void malloc_tsd_dalloc(void *wrapper); @@ -166,7 +179,7 @@ void tsd_slow_update(tsd_t *tsd); * foo. This omits some safety checks, and so can be used during tsd * initialization and cleanup. */ -#define O(n, t) \ +#define O(n, t, nt) \ JEMALLOC_ALWAYS_INLINE t * \ tsd_##n##p_get_unsafe(tsd_t *tsd) { \ return &tsd->use_a_getter_or_setter_instead_##n; \ @@ -175,7 +188,7 @@ MALLOC_TSD #undef O /* tsd_foop_get(tsd) returns a pointer to the thread-local instance of foo. */ -#define O(n, t) \ +#define O(n, t, nt) \ JEMALLOC_ALWAYS_INLINE t * \ tsd_##n##p_get(tsd_t *tsd) { \ assert(tsd->state == tsd_state_nominal || \ @@ -186,8 +199,24 @@ tsd_##n##p_get(tsd_t *tsd) { \ MALLOC_TSD #undef O +/* + * tsdn_foop_get(tsdn) returns either the thread-local instance of foo (if tsdn + * isn't NULL), or NULL (if tsdn is NULL), cast to the nullable pointer type. + */ +#define O(n, t, nt) \ +JEMALLOC_ALWAYS_INLINE nt * \ +tsdn_##n##p_get(tsdn_t *tsdn) { \ + if (tsdn_null(tsdn)) { \ + return NULL; \ + } \ + tsd_t *tsd = tsdn_tsd(tsdn); \ + return (nt *)tsd_##n##p_get(tsd); \ +} +MALLOC_TSD +#undef O + /* tsd_foo_get(tsd) returns the value of the thread-local instance of foo. */ -#define O(n, t) \ +#define O(n, t, nt) \ JEMALLOC_ALWAYS_INLINE t \ tsd_##n##_get(tsd_t *tsd) { \ return *tsd_##n##p_get(tsd); \ @@ -196,7 +225,7 @@ MALLOC_TSD #undef O /* tsd_foo_set(tsd, val) updates the thread-local instance of foo to be val. */ -#define O(n, t) \ +#define O(n, t, nt) \ JEMALLOC_ALWAYS_INLINE void \ tsd_##n##_set(tsd_t *tsd, t val) { \ *tsd_##n##p_get(tsd) = val; \ @@ -243,11 +272,6 @@ tsd_fetch(void) { return tsd_fetch_impl(true); } -JEMALLOC_ALWAYS_INLINE tsdn_t * -tsd_tsdn(tsd_t *tsd) { - return (tsdn_t *)tsd; -} - static inline bool tsd_nominal(tsd_t *tsd) { return (tsd->state <= tsd_state_nominal_max); @@ -262,18 +286,6 @@ tsdn_fetch(void) { return tsd_tsdn(tsd_fetch_impl(false)); } -JEMALLOC_ALWAYS_INLINE bool -tsdn_null(const tsdn_t *tsdn) { - return tsdn == NULL; -} - -JEMALLOC_ALWAYS_INLINE tsd_t * -tsdn_tsd(tsdn_t *tsdn) { - assert(!tsdn_null(tsdn)); - - return &tsdn->tsd; -} - JEMALLOC_ALWAYS_INLINE rtree_ctx_t * tsd_rtree_ctx(tsd_t *tsd) { return tsd_rtree_ctxp_get(tsd); diff --git a/include/jemalloc/internal/witness.h b/include/jemalloc/internal/witness.h new file mode 100644 index 00000000..c71911f2 --- /dev/null +++ b/include/jemalloc/internal/witness.h @@ -0,0 +1,345 @@ +#ifndef JEMALLOC_INTERNAL_WITNESS_H +#define JEMALLOC_INTERNAL_WITNESS_H + +#include "jemalloc/internal/ql.h" + +/******************************************************************************/ +/* LOCK RANKS */ +/******************************************************************************/ + +/* + * Witnesses with rank WITNESS_RANK_OMIT are completely ignored by the witness + * machinery. + */ + +#define WITNESS_RANK_OMIT 0U + +#define WITNESS_RANK_MIN 1U + +#define WITNESS_RANK_INIT 1U +#define WITNESS_RANK_CTL 1U +#define WITNESS_RANK_TCACHES 2U +#define WITNESS_RANK_ARENAS 3U + +#define WITNESS_RANK_BACKGROUND_THREAD_GLOBAL 4U + +#define WITNESS_RANK_PROF_DUMP 5U +#define WITNESS_RANK_PROF_BT2GCTX 6U +#define WITNESS_RANK_PROF_TDATAS 7U +#define WITNESS_RANK_PROF_TDATA 8U +#define WITNESS_RANK_PROF_GCTX 9U + +#define WITNESS_RANK_BACKGROUND_THREAD 10U + +/* + * Used as an argument to witness_assert_depth_to_rank() in order to validate + * depth excluding non-core locks with lower ranks. Since the rank argument to + * witness_assert_depth_to_rank() is inclusive rather than exclusive, this + * definition can have the same value as the minimally ranked core lock. + */ +#define WITNESS_RANK_CORE 11U + +#define WITNESS_RANK_DECAY 11U +#define WITNESS_RANK_TCACHE_QL 12U +#define WITNESS_RANK_EXTENTS 13U +#define WITNESS_RANK_EXTENT_FREELIST 14U + +#define WITNESS_RANK_EXTENT_POOL 15U +#define WITNESS_RANK_RTREE 16U +#define WITNESS_RANK_BASE 17U +#define WITNESS_RANK_ARENA_LARGE 18U + +#define WITNESS_RANK_LEAF 0xffffffffU +#define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF +#define WITNESS_RANK_ARENA_STATS WITNESS_RANK_LEAF +#define WITNESS_RANK_DSS WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_ACTIVE WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_ACCUM WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_DUMP_SEQ WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_GDUMP WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_NEXT_THR_UID WITNESS_RANK_LEAF +#define WITNESS_RANK_PROF_THREAD_ACTIVE_INIT WITNESS_RANK_LEAF + +/******************************************************************************/ +/* PER-WITNESS DATA */ +/******************************************************************************/ +#if defined(JEMALLOC_DEBUG) +# define WITNESS_INITIALIZER(name, rank) {name, rank, NULL, NULL, {NULL, NULL}} +#else +# define WITNESS_INITIALIZER(name, rank) +#endif + +typedef struct witness_s witness_t; +typedef unsigned witness_rank_t; +typedef ql_head(witness_t) witness_list_t; +typedef int witness_comp_t (const witness_t *, void *, const witness_t *, + void *); + +struct witness_s { + /* Name, used for printing lock order reversal messages. */ + const char *name; + + /* + * Witness rank, where 0 is lowest and UINT_MAX is highest. Witnesses + * must be acquired in order of increasing rank. + */ + witness_rank_t rank; + + /* + * If two witnesses are of equal rank and they have the samp comp + * function pointer, it is called as a last attempt to differentiate + * between witnesses of equal rank. + */ + witness_comp_t *comp; + + /* Opaque data, passed to comp(). */ + void *opaque; + + /* Linkage for thread's currently owned locks. */ + ql_elm(witness_t) link; +}; + +/******************************************************************************/ +/* PER-THREAD DATA */ +/******************************************************************************/ +typedef struct witness_tsd_s witness_tsd_t; +struct witness_tsd_s { + witness_list_t witnesses; + bool forking; +}; + +#define WITNESS_TSD_INITIALIZER { ql_head_initializer(witnesses), false } +#define WITNESS_TSDN_NULL ((witness_tsdn_t *)0) + +/******************************************************************************/ +/* (PER-THREAD) NULLABILITY HELPERS */ +/******************************************************************************/ +typedef struct witness_tsdn_s witness_tsdn_t; +struct witness_tsdn_s { + witness_tsd_t witness_tsd; +}; + +JEMALLOC_ALWAYS_INLINE witness_tsdn_t * +witness_tsd_tsdn(witness_tsd_t *witness_tsd) { + return (witness_tsdn_t *)witness_tsd; +} + +JEMALLOC_ALWAYS_INLINE bool +witness_tsdn_null(witness_tsdn_t *witness_tsdn) { + return witness_tsdn == NULL; +} + +JEMALLOC_ALWAYS_INLINE witness_tsd_t * +witness_tsdn_tsd(witness_tsdn_t *witness_tsdn) { + assert(!witness_tsdn_null(witness_tsdn)); + return &witness_tsdn->witness_tsd; +} + +/******************************************************************************/ +/* API */ +/******************************************************************************/ +void witness_init(witness_t *witness, const char *name, witness_rank_t rank, + witness_comp_t *comp, void *opaque); + +typedef void (witness_lock_error_t)(const witness_list_t *, const witness_t *); +extern witness_lock_error_t *JET_MUTABLE witness_lock_error; + +typedef void (witness_owner_error_t)(const witness_t *); +extern witness_owner_error_t *JET_MUTABLE witness_owner_error; + +typedef void (witness_not_owner_error_t)(const witness_t *); +extern witness_not_owner_error_t *JET_MUTABLE witness_not_owner_error; + +typedef void (witness_depth_error_t)(const witness_list_t *, + witness_rank_t rank_inclusive, unsigned depth); +extern witness_depth_error_t *JET_MUTABLE witness_depth_error; + +void witnesses_cleanup(witness_tsd_t *witness_tsd); +void witness_prefork(witness_tsd_t *witness_tsd); +void witness_postfork_parent(witness_tsd_t *witness_tsd); +void witness_postfork_child(witness_tsd_t *witness_tsd); + +/* Helper, not intended for direct use. */ +static inline bool +witness_owner(witness_tsd_t *witness_tsd, const witness_t *witness) { + witness_list_t *witnesses; + witness_t *w; + + cassert(config_debug); + + witnesses = &witness_tsd->witnesses; + ql_foreach(w, witnesses, link) { + if (w == witness) { + return true; + } + } + + return false; +} + +static inline void +witness_assert_owner(witness_tsdn_t *witness_tsdn, const witness_t *witness) { + witness_tsd_t *witness_tsd; + + if (!config_debug) { + return; + } + + if (witness_tsdn_null(witness_tsdn)) { + return; + } + witness_tsd = witness_tsdn_tsd(witness_tsdn); + if (witness->rank == WITNESS_RANK_OMIT) { + return; + } + + if (witness_owner(witness_tsd, witness)) { + return; + } + witness_owner_error(witness); +} + +static inline void +witness_assert_not_owner(witness_tsdn_t *witness_tsdn, + const witness_t *witness) { + witness_tsd_t *witness_tsd; + witness_list_t *witnesses; + witness_t *w; + + if (!config_debug) { + return; + } + + if (witness_tsdn_null(witness_tsdn)) { + return; + } + witness_tsd = witness_tsdn_tsd(witness_tsdn); + if (witness->rank == WITNESS_RANK_OMIT) { + return; + } + + witnesses = &witness_tsd->witnesses; + ql_foreach(w, witnesses, link) { + if (w == witness) { + witness_not_owner_error(witness); + } + } +} + +static inline void +witness_assert_depth_to_rank(witness_tsdn_t *witness_tsdn, + witness_rank_t rank_inclusive, unsigned depth) { + witness_tsd_t *witness_tsd; + unsigned d; + witness_list_t *witnesses; + witness_t *w; + + if (!config_debug) { + return; + } + + if (witness_tsdn_null(witness_tsdn)) { + return; + } + witness_tsd = witness_tsdn_tsd(witness_tsdn); + + d = 0; + witnesses = &witness_tsd->witnesses; + w = ql_last(witnesses, link); + if (w != NULL) { + ql_reverse_foreach(w, witnesses, link) { + if (w->rank < rank_inclusive) { + break; + } + d++; + } + } + if (d != depth) { + witness_depth_error(witnesses, rank_inclusive, depth); + } +} + +static inline void +witness_assert_depth(witness_tsdn_t *witness_tsdn, unsigned depth) { + witness_assert_depth_to_rank(witness_tsdn, WITNESS_RANK_MIN, depth); +} + +static inline void +witness_assert_lockless(witness_tsdn_t *witness_tsdn) { + witness_assert_depth(witness_tsdn, 0); +} + +static inline void +witness_lock(witness_tsdn_t *witness_tsdn, witness_t *witness) { + witness_tsd_t *witness_tsd; + witness_list_t *witnesses; + witness_t *w; + + if (!config_debug) { + return; + } + + if (witness_tsdn_null(witness_tsdn)) { + return; + } + witness_tsd = witness_tsdn_tsd(witness_tsdn); + if (witness->rank == WITNESS_RANK_OMIT) { + return; + } + + witness_assert_not_owner(witness_tsdn, witness); + + witnesses = &witness_tsd->witnesses; + w = ql_last(witnesses, link); + if (w == NULL) { + /* No other locks; do nothing. */ + } else if (witness_tsd->forking && w->rank <= witness->rank) { + /* Forking, and relaxed ranking satisfied. */ + } else if (w->rank > witness->rank) { + /* Not forking, rank order reversal. */ + witness_lock_error(witnesses, witness); + } else if (w->rank == witness->rank && (w->comp == NULL || w->comp != + witness->comp || w->comp(w, w->opaque, witness, witness->opaque) > + 0)) { + /* + * Missing/incompatible comparison function, or comparison + * function indicates rank order reversal. + */ + witness_lock_error(witnesses, witness); + } + + ql_elm_new(witness, link); + ql_tail_insert(witnesses, witness, link); +} + +static inline void +witness_unlock(witness_tsdn_t *witness_tsdn, witness_t *witness) { + witness_tsd_t *witness_tsd; + witness_list_t *witnesses; + + if (!config_debug) { + return; + } + + if (witness_tsdn_null(witness_tsdn)) { + return; + } + witness_tsd = witness_tsdn_tsd(witness_tsdn); + if (witness->rank == WITNESS_RANK_OMIT) { + return; + } + + /* + * Check whether owner before removal, rather than relying on + * witness_assert_owner() to abort, so that unit tests can test this + * function's failure mode without causing undefined behavior. + */ + if (witness_owner(witness_tsd, witness)) { + witnesses = &witness_tsd->witnesses; + ql_remove(witnesses, witness, link); + } else { + witness_assert_owner(witness_tsdn, witness); + } +} + +#endif /* JEMALLOC_INTERNAL_WITNESS_H */ diff --git a/include/jemalloc/internal/witness_externs.h b/include/jemalloc/internal/witness_externs.h deleted file mode 100644 index 99df4c50..00000000 --- a/include/jemalloc/internal/witness_externs.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_WITNESS_EXTERNS_H -#define JEMALLOC_INTERNAL_WITNESS_EXTERNS_H - -void witness_init(witness_t *witness, const char *name, witness_rank_t rank, - witness_comp_t *comp, void *opaque); - -typedef void (witness_lock_error_t)(const witness_list_t *, const witness_t *); -extern witness_lock_error_t *JET_MUTABLE witness_lock_error; - -typedef void (witness_owner_error_t)(const witness_t *); -extern witness_owner_error_t *JET_MUTABLE witness_owner_error; - -typedef void (witness_not_owner_error_t)(const witness_t *); -extern witness_not_owner_error_t *JET_MUTABLE witness_not_owner_error; - -typedef void (witness_depth_error_t)(const witness_list_t *, - witness_rank_t rank_inclusive, unsigned depth); -extern witness_depth_error_t *JET_MUTABLE witness_depth_error; - -void witnesses_cleanup(tsd_t *tsd); -void witness_prefork(tsd_t *tsd); -void witness_postfork_parent(tsd_t *tsd); -void witness_postfork_child(tsd_t *tsd); - -#endif /* JEMALLOC_INTERNAL_WITNESS_EXTERNS_H */ diff --git a/include/jemalloc/internal/witness_inlines.h b/include/jemalloc/internal/witness_inlines.h deleted file mode 100644 index 51d1af38..00000000 --- a/include/jemalloc/internal/witness_inlines.h +++ /dev/null @@ -1,188 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_WITNESS_INLINES_H -#define JEMALLOC_INTERNAL_WITNESS_INLINES_H - -#include "jemalloc/internal/ql.h" - -/* Helper, not intended for direct use. */ -static inline bool -witness_owner(tsd_t *tsd, const witness_t *witness) { - witness_list_t *witnesses; - witness_t *w; - - cassert(config_debug); - - witnesses = tsd_witnessesp_get(tsd); - ql_foreach(w, witnesses, link) { - if (w == witness) { - return true; - } - } - - return false; -} - -static inline void -witness_assert_owner(tsdn_t *tsdn, const witness_t *witness) { - tsd_t *tsd; - - if (!config_debug) { - return; - } - - if (tsdn_null(tsdn)) { - return; - } - tsd = tsdn_tsd(tsdn); - if (witness->rank == WITNESS_RANK_OMIT) { - return; - } - - if (witness_owner(tsd, witness)) { - return; - } - witness_owner_error(witness); -} - -static inline void -witness_assert_not_owner(tsdn_t *tsdn, const witness_t *witness) { - tsd_t *tsd; - witness_list_t *witnesses; - witness_t *w; - - if (!config_debug) { - return; - } - - if (tsdn_null(tsdn)) { - return; - } - tsd = tsdn_tsd(tsdn); - if (witness->rank == WITNESS_RANK_OMIT) { - return; - } - - witnesses = tsd_witnessesp_get(tsd); - ql_foreach(w, witnesses, link) { - if (w == witness) { - witness_not_owner_error(witness); - } - } -} - -static inline void -witness_assert_depth_to_rank(tsdn_t *tsdn, witness_rank_t rank_inclusive, - unsigned depth) { - tsd_t *tsd; - unsigned d; - witness_list_t *witnesses; - witness_t *w; - - if (!config_debug) { - return; - } - - if (tsdn_null(tsdn)) { - return; - } - tsd = tsdn_tsd(tsdn); - - d = 0; - witnesses = tsd_witnessesp_get(tsd); - w = ql_last(witnesses, link); - if (w != NULL) { - ql_reverse_foreach(w, witnesses, link) { - if (w->rank < rank_inclusive) { - break; - } - d++; - } - } - if (d != depth) { - witness_depth_error(witnesses, rank_inclusive, depth); - } -} - -static inline void -witness_assert_depth(tsdn_t *tsdn, unsigned depth) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_MIN, depth); -} - -static inline void -witness_assert_lockless(tsdn_t *tsdn) { - witness_assert_depth(tsdn, 0); -} - -static inline void -witness_lock(tsdn_t *tsdn, witness_t *witness) { - tsd_t *tsd; - witness_list_t *witnesses; - witness_t *w; - - if (!config_debug) { - return; - } - - if (tsdn_null(tsdn)) { - return; - } - tsd = tsdn_tsd(tsdn); - if (witness->rank == WITNESS_RANK_OMIT) { - return; - } - - witness_assert_not_owner(tsdn, witness); - - witnesses = tsd_witnessesp_get(tsd); - w = ql_last(witnesses, link); - if (w == NULL) { - /* No other locks; do nothing. */ - } else if (tsd_witness_fork_get(tsd) && w->rank <= witness->rank) { - /* Forking, and relaxed ranking satisfied. */ - } else if (w->rank > witness->rank) { - /* Not forking, rank order reversal. */ - witness_lock_error(witnesses, witness); - } else if (w->rank == witness->rank && (w->comp == NULL || w->comp != - witness->comp || w->comp(w, w->opaque, witness, witness->opaque) > - 0)) { - /* - * Missing/incompatible comparison function, or comparison - * function indicates rank order reversal. - */ - witness_lock_error(witnesses, witness); - } - - ql_elm_new(witness, link); - ql_tail_insert(witnesses, witness, link); -} - -static inline void -witness_unlock(tsdn_t *tsdn, witness_t *witness) { - tsd_t *tsd; - witness_list_t *witnesses; - - if (!config_debug) { - return; - } - - if (tsdn_null(tsdn)) { - return; - } - tsd = tsdn_tsd(tsdn); - if (witness->rank == WITNESS_RANK_OMIT) { - return; - } - - /* - * Check whether owner before removal, rather than relying on - * witness_assert_owner() to abort, so that unit tests can test this - * function's failure mode without causing undefined behavior. - */ - if (witness_owner(tsd, witness)) { - witnesses = tsd_witnessesp_get(tsd); - ql_remove(witnesses, witness, link); - } else { - witness_assert_owner(tsdn, witness); - } -} - -#endif /* JEMALLOC_INTERNAL_WITNESS_INLINES_H */ diff --git a/include/jemalloc/internal/witness_structs.h b/include/jemalloc/internal/witness_structs.h deleted file mode 100644 index 95d19706..00000000 --- a/include/jemalloc/internal/witness_structs.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_WITNESS_STRUCTS_H -#define JEMALLOC_INTERNAL_WITNESS_STRUCTS_H - -struct witness_s { - /* Name, used for printing lock order reversal messages. */ - const char *name; - - /* - * Witness rank, where 0 is lowest and UINT_MAX is highest. Witnesses - * must be acquired in order of increasing rank. - */ - witness_rank_t rank; - - /* - * If two witnesses are of equal rank and they have the samp comp - * function pointer, it is called as a last attempt to differentiate - * between witnesses of equal rank. - */ - witness_comp_t *comp; - - /* Opaque data, passed to comp(). */ - void *opaque; - - /* Linkage for thread's currently owned locks. */ - ql_elm(witness_t) link; -}; - -#endif /* JEMALLOC_INTERNAL_WITNESS_STRUCTS_H */ diff --git a/include/jemalloc/internal/witness_types.h b/include/jemalloc/internal/witness_types.h deleted file mode 100644 index 28ec7c8c..00000000 --- a/include/jemalloc/internal/witness_types.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_WITNESS_TYPES_H -#define JEMALLOC_INTERNAL_WITNESS_TYPES_H - -#include "jemalloc/internal/ql.h" - -typedef struct witness_s witness_t; -typedef unsigned witness_rank_t; -typedef ql_head(witness_t) witness_list_t; -typedef int witness_comp_t (const witness_t *, void *, const witness_t *, - void *); - -/* - * Lock ranks. Witnesses with rank WITNESS_RANK_OMIT are completely ignored by - * the witness machinery. - */ -#define WITNESS_RANK_OMIT 0U - -#define WITNESS_RANK_MIN 1U - -#define WITNESS_RANK_INIT 1U -#define WITNESS_RANK_CTL 1U -#define WITNESS_RANK_TCACHES 2U -#define WITNESS_RANK_ARENAS 3U - -#define WITNESS_RANK_BACKGROUND_THREAD_GLOBAL 4U - -#define WITNESS_RANK_PROF_DUMP 5U -#define WITNESS_RANK_PROF_BT2GCTX 6U -#define WITNESS_RANK_PROF_TDATAS 7U -#define WITNESS_RANK_PROF_TDATA 8U -#define WITNESS_RANK_PROF_GCTX 9U - -#define WITNESS_RANK_BACKGROUND_THREAD 10U - -/* - * Used as an argument to witness_assert_depth_to_rank() in order to validate - * depth excluding non-core locks with lower ranks. Since the rank argument to - * witness_assert_depth_to_rank() is inclusive rather than exclusive, this - * definition can have the same value as the minimally ranked core lock. - */ -#define WITNESS_RANK_CORE 11U - -#define WITNESS_RANK_DECAY 11U -#define WITNESS_RANK_TCACHE_QL 12U -#define WITNESS_RANK_EXTENTS 13U -#define WITNESS_RANK_EXTENT_FREELIST 14U - -#define WITNESS_RANK_EXTENT_POOL 15U -#define WITNESS_RANK_RTREE 16U -#define WITNESS_RANK_BASE 17U -#define WITNESS_RANK_ARENA_LARGE 18U - -#define WITNESS_RANK_LEAF 0xffffffffU -#define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF -#define WITNESS_RANK_ARENA_STATS WITNESS_RANK_LEAF -#define WITNESS_RANK_DSS WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_ACTIVE WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_ACCUM WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_DUMP_SEQ WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_GDUMP WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_NEXT_THR_UID WITNESS_RANK_LEAF -#define WITNESS_RANK_PROF_THREAD_ACTIVE_INIT WITNESS_RANK_LEAF - -#if defined(JEMALLOC_DEBUG) -# define WITNESS_INITIALIZER(name, rank) {name, rank, NULL, NULL, {NULL, NULL}} -#else -# define WITNESS_INITIALIZER(name, rank) -#endif - -#endif /* JEMALLOC_INTERNAL_WITNESS_TYPES_H */ diff --git a/src/arena.c b/src/arena.c index 48d536e2..35b4e5a7 100644 --- a/src/arena.c +++ b/src/arena.c @@ -361,7 +361,8 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, void arena_extents_dirty_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); extents_dalloc(tsdn, arena, r_extent_hooks, &arena->extents_dirty, extent); @@ -497,7 +498,8 @@ arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool *zero) { extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); szind_t szind = size2index(usize); size_t mapped_add; @@ -892,7 +894,8 @@ static size_t arena_stash_decayed(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extents_t *extents, size_t npages_limit, extent_list_t *decay_extents) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); /* Stash extents according to npages_limit. */ size_t nstashed = 0; @@ -978,7 +981,8 @@ arena_decay_stashed(tsdn_t *tsdn, arena_t *arena, static void arena_decay_to_limit(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, extents_t *extents, bool all, size_t npages_limit) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 1); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 1); malloc_mutex_assert_owner(tsdn, &decay->mtx); if (decay->purging) { @@ -1253,7 +1257,8 @@ arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, extent_t *slab; bool zero, commit; - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); zero = false; commit = true; @@ -1271,7 +1276,8 @@ arena_slab_alloc_hard(tsdn_t *tsdn, arena_t *arena, static extent_t * arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, const arena_bin_info_t *bin_info) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; szind_t szind = size2index(bin_info->reg_size); diff --git a/src/extent.c b/src/extent.c index 6503f2a1..ff09f7fb 100644 --- a/src/extent.c +++ b/src/extent.c @@ -149,7 +149,8 @@ extent_lock_from_addr(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, void *addr) { extent_t * extent_alloc(tsdn_t *tsdn, arena_t *arena) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); malloc_mutex_lock(tsdn, &arena->extent_avail_mtx); extent_t *extent = extent_avail_first(&arena->extent_avail); @@ -164,7 +165,8 @@ extent_alloc(tsdn_t *tsdn, arena_t *arena) { void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); malloc_mutex_lock(tsdn, &arena->extent_avail_mtx); extent_avail_insert(&arena->extent_avail, extent); @@ -415,7 +417,8 @@ extents_alloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) { assert(size + pad != 0); assert(alignment != 0); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); return extent_recycle(tsdn, arena, r_extent_hooks, extents, new_addr, size, pad, alignment, slab, szind, zero, commit); @@ -426,7 +429,8 @@ extents_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extents_t *extents, extent_t *extent) { assert(extent_base_get(extent) != NULL); assert(extent_size_get(extent) != 0); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); extent_addr_set(extent, extent_base_get(extent)); extent_zeroed_set(extent, false); @@ -607,7 +611,8 @@ static void extent_gdump_add(tsdn_t *tsdn, const extent_t *extent) { cassert(config_prof); /* prof_gdump() requirement. */ - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); if (opt_prof && extent_state_get(extent) == extent_state_active) { size_t nadd = extent_size_get(extent) >> LG_PAGE; @@ -730,7 +735,8 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, bool locked, void *new_addr, size_t size, size_t pad, size_t alignment, bool slab, bool *zero, bool *commit) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, locked ? 1 : 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, locked ? 1 : 0); if (locked) { malloc_mutex_assert_owner(tsdn, &extents->mtx); } @@ -869,7 +875,8 @@ static extent_t * extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extents_t *extents, void *new_addr, size_t size, size_t pad, size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); assert(new_addr == NULL || !slab); assert(pad == 0 || !slab); assert(!*zero || !slab); @@ -1219,7 +1226,8 @@ extent_t * extent_alloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, size_t pad, size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); extent_hooks_assure_initialized(arena, r_extent_hooks); @@ -1385,7 +1393,8 @@ void extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); if (extent_register(tsdn, extent)) { extents_leak(tsdn, arena, &extent_hooks, @@ -1418,7 +1427,8 @@ extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, assert(extent_base_get(extent) != NULL); assert(extent_size_get(extent) != 0); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); extent_addr_set(extent, extent_base_get(extent)); @@ -1445,7 +1455,8 @@ extent_dalloc_wrapper_try(tsdn_t *tsdn, arena_t *arena, void extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); /* * Deregister first to avoid a race with other allocating threads, and @@ -1508,7 +1519,8 @@ extent_destroy_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent) { assert(extent_base_get(extent) != NULL); assert(extent_size_get(extent) != 0); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); /* Deregister first to avoid a race with other allocating threads. */ extent_deregister(tsdn, extent); @@ -1543,7 +1555,8 @@ bool extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); extent_hooks_assure_initialized(arena, r_extent_hooks); bool err = ((*r_extent_hooks)->commit == NULL || @@ -1566,7 +1579,8 @@ bool extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); extent_hooks_assure_initialized(arena, r_extent_hooks); @@ -1597,7 +1611,8 @@ bool extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); extent_hooks_assure_initialized(arena, r_extent_hooks); return ((*r_extent_hooks)->purge_lazy == NULL || @@ -1625,7 +1640,8 @@ bool extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, size_t length) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); extent_hooks_assure_initialized(arena, r_extent_hooks); return ((*r_extent_hooks)->purge_forced == NULL || @@ -1649,7 +1665,8 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a, szind_t szind_a, bool slab_a, size_t size_b, szind_t szind_b, bool slab_b) { assert(extent_size_get(extent) == size_a + size_b); - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); extent_hooks_assure_initialized(arena, r_extent_hooks); @@ -1742,7 +1759,8 @@ extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b) { - witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0); + witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), + WITNESS_RANK_CORE, 0); extent_hooks_assure_initialized(arena, r_extent_hooks); diff --git a/src/jemalloc.c b/src/jemalloc.c index b03e5f48..f083adc4 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1755,7 +1755,7 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) { */ reentrancy_level = tsd_reentrancy_level_get(tsd); if (reentrancy_level == 0) { - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); } if (sopts->slow && unlikely(reentrancy_level > 0)) { /* @@ -1832,7 +1832,7 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) { /* Success! */ if (reentrancy_level == 0) { - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); } *dopts->result = allocation; return 0; @@ -1847,7 +1847,7 @@ label_oom: UTRACE(NULL, size, NULL); } - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); if (sopts->set_errno_on_error) { set_errno(ENOMEM); @@ -1878,7 +1878,7 @@ label_invalid_alignment: UTRACE(NULL, size, NULL); } - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); if (sopts->null_out_result_on_error) { *dopts->result = NULL; @@ -2080,7 +2080,7 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { tsd_assert_fast(tsd); } if (tsd_reentrancy_level_get(tsd) == 0) { - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); } else { assert(slow_path); } @@ -2120,7 +2120,7 @@ isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) { tsd_assert_fast(tsd); } if (tsd_reentrancy_level_get(tsd) == 0) { - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); } else { assert(slow_path); } @@ -2181,7 +2181,7 @@ je_realloc(void *ptr, size_t size) { assert(malloc_initialized() || IS_INITIALIZER); tsd_t *tsd = tsd_fetch(); - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); alloc_ctx_t alloc_ctx; rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd); @@ -2224,7 +2224,7 @@ je_realloc(void *ptr, size_t size) { *tsd_thread_deallocatedp_get(tsd) += old_usize; } UTRACE(ptr, size, ret); - witness_assert_lockless(tsdn); + witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); return ret; } @@ -2234,7 +2234,8 @@ je_free(void *ptr) { if (likely(ptr != NULL)) { tsd_t *tsd = tsd_fetch(); if (tsd_reentrancy_level_get(tsd) == 0) { - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn( + tsd))); } tcache_t *tcache; @@ -2252,7 +2253,8 @@ je_free(void *ptr) { ifree(tsd, ptr, tcache, true); } if (tsd_reentrancy_level_get(tsd) == 0) { - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn( + tsd))); } } } @@ -2513,7 +2515,7 @@ je_rallocx(void *ptr, size_t size, int flags) { assert(size != 0); assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); if (unlikely((flags & MALLOCX_ARENA_MASK) != 0)) { unsigned arena_ind = MALLOCX_ARENA_GET(flags); @@ -2569,7 +2571,7 @@ je_rallocx(void *ptr, size_t size, int flags) { *tsd_thread_deallocatedp_get(tsd) += old_usize; } UTRACE(ptr, size, p); - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); return p; label_oom: if (config_xmalloc && unlikely(opt_xmalloc)) { @@ -2577,7 +2579,7 @@ label_oom: abort(); } UTRACE(ptr, size, 0); - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); return NULL; } @@ -2669,7 +2671,7 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) { assert(SIZE_T_MAX - size >= extra); assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); alloc_ctx_t alloc_ctx; rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd); @@ -2712,7 +2714,7 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) { } label_not_resized: UTRACE(ptr, size, ptr); - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); return usize; } @@ -2726,7 +2728,7 @@ je_sallocx(const void *ptr, int flags) { assert(ptr != NULL); tsdn = tsdn_fetch(); - witness_assert_lockless(tsdn); + witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); if (config_debug || force_ivsalloc) { usize = ivsalloc(tsdn, ptr); @@ -2735,7 +2737,7 @@ je_sallocx(const void *ptr, int flags) { usize = isalloc(tsdn, ptr); } - witness_assert_lockless(tsdn); + witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); return usize; } @@ -2746,7 +2748,7 @@ je_dallocx(void *ptr, int flags) { tsd_t *tsd = tsd_fetch(); bool fast = tsd_fast(tsd); - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); tcache_t *tcache; if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { @@ -2777,12 +2779,12 @@ je_dallocx(void *ptr, int flags) { } else { ifree(tsd, ptr, tcache, true); } - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); } JEMALLOC_ALWAYS_INLINE size_t inallocx(tsdn_t *tsdn, size_t size, int flags) { - witness_assert_lockless(tsdn); + witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); size_t usize; if (likely((flags & MALLOCX_LG_ALIGN_MASK) == 0)) { @@ -2790,7 +2792,7 @@ inallocx(tsdn_t *tsdn, size_t size, int flags) { } else { usize = sa2u(size, MALLOCX_ALIGN_GET_SPECIFIED(flags)); } - witness_assert_lockless(tsdn); + witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); return usize; } @@ -2803,7 +2805,7 @@ je_sdallocx(void *ptr, size_t size, int flags) { bool fast = tsd_fast(tsd); size_t usize = inallocx(tsd_tsdn(tsd), size, flags); assert(usize == isalloc(tsd_tsdn(tsd), ptr)); - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); tcache_t *tcache; if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { @@ -2834,7 +2836,7 @@ je_sdallocx(void *ptr, size_t size, int flags) { } else { isfree(tsd, ptr, usize, tcache, true); } - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); } JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW @@ -2850,14 +2852,14 @@ je_nallocx(size_t size, int flags) { } tsdn = tsdn_fetch(); - witness_assert_lockless(tsdn); + witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); usize = inallocx(tsdn, size, flags); if (unlikely(usize > LARGE_MAXCLASS)) { return 0; } - witness_assert_lockless(tsdn); + witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); return usize; } @@ -2872,9 +2874,9 @@ je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, } tsd = tsd_fetch(); - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); ret = ctl_byname(tsd, name, oldp, oldlenp, newp, newlen); - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); return ret; } @@ -2888,9 +2890,9 @@ je_mallctlnametomib(const char *name, size_t *mibp, size_t *miblenp) { } tsdn = tsdn_fetch(); - witness_assert_lockless(tsdn); + witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); ret = ctl_nametomib(tsdn, name, mibp, miblenp); - witness_assert_lockless(tsdn); + witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); return ret; } @@ -2905,9 +2907,9 @@ je_mallctlbymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, } tsd = tsd_fetch(); - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); ret = ctl_bymib(tsd, mib, miblen, oldp, oldlenp, newp, newlen); - witness_assert_lockless(tsd_tsdn(tsd)); + witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); return ret; } @@ -2917,9 +2919,9 @@ je_malloc_stats_print(void (*write_cb)(void *, const char *), void *cbopaque, tsdn_t *tsdn; tsdn = tsdn_fetch(); - witness_assert_lockless(tsdn); + witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); stats_print(write_cb, cbopaque, opts); - witness_assert_lockless(tsdn); + witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); } JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW @@ -2930,7 +2932,7 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) { assert(malloc_initialized() || IS_INITIALIZER); tsdn = tsdn_fetch(); - witness_assert_lockless(tsdn); + witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); if (unlikely(ptr == NULL)) { ret = 0; @@ -2943,7 +2945,7 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) { } } - witness_assert_lockless(tsdn); + witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); return ret; } @@ -3000,7 +3002,7 @@ _malloc_prefork(void) narenas = narenas_total_get(); - witness_prefork(tsd); + witness_prefork(tsd_witness_tsdp_get(tsd)); /* Acquire all mutexes in a safe order. */ ctl_prefork(tsd_tsdn(tsd)); tcache_prefork(tsd_tsdn(tsd)); @@ -3067,7 +3069,7 @@ _malloc_postfork(void) tsd = tsd_fetch(); - witness_postfork_parent(tsd); + witness_postfork_parent(tsd_witness_tsdp_get(tsd)); /* Release all mutexes, now that fork() has completed. */ for (i = 0, narenas = narenas_total_get(); i < narenas; i++) { arena_t *arena; @@ -3094,7 +3096,7 @@ jemalloc_postfork_child(void) { tsd = tsd_fetch(); - witness_postfork_child(tsd); + witness_postfork_child(tsd_witness_tsdp_get(tsd)); /* Release all mutexes, now that fork() has completed. */ for (i = 0, narenas = narenas_total_get(); i < narenas; i++) { arena_t *arena; diff --git a/src/tcache.c b/src/tcache.c index d9f5e7cb..4bb2fb86 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -568,7 +568,7 @@ label_return: bool tcaches_create(tsd_t *tsd, unsigned *r_ind) { - witness_assert_depth(tsd_tsdn(tsd), 0); + witness_assert_depth(tsdn_witness_tsdp_get(tsd_tsdn(tsd)), 0); bool err; @@ -600,7 +600,7 @@ tcaches_create(tsd_t *tsd, unsigned *r_ind) { err = false; label_return: - witness_assert_depth(tsd_tsdn(tsd), 0); + witness_assert_depth(tsdn_witness_tsdp_get(tsd_tsdn(tsd)), 0); return err; } diff --git a/src/tsd.c b/src/tsd.c index 612f7523..801d8127 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -140,7 +140,7 @@ tsd_do_data_cleanup(tsd_t *tsd) { arena_cleanup(tsd); arenas_tdata_cleanup(tsd); tcache_cleanup(tsd); - witnesses_cleanup(tsd); + witnesses_cleanup(tsd_witness_tsdp_get_unsafe(tsd)); } void diff --git a/src/witness.c b/src/witness.c index 0e910dca..f42b72ad 100644 --- a/src/witness.c +++ b/src/witness.c @@ -63,38 +63,38 @@ witness_depth_error_t *JET_MUTABLE witness_depth_error = witness_depth_error_impl; void -witnesses_cleanup(tsd_t *tsd) { - witness_assert_lockless(tsd_tsdn(tsd)); +witnesses_cleanup(witness_tsd_t *witness_tsd) { + witness_assert_lockless(witness_tsd_tsdn(witness_tsd)); /* Do nothing. */ } void -witness_prefork(tsd_t *tsd) { +witness_prefork(witness_tsd_t *witness_tsd) { if (!config_debug) { return; } - tsd_witness_fork_set(tsd, true); + witness_tsd->forking = true; } void -witness_postfork_parent(tsd_t *tsd) { +witness_postfork_parent(witness_tsd_t *witness_tsd) { if (!config_debug) { return; } - tsd_witness_fork_set(tsd, false); + witness_tsd->forking = false; } void -witness_postfork_child(tsd_t *tsd) { +witness_postfork_child(witness_tsd_t *witness_tsd) { if (!config_debug) { return; } #ifndef JEMALLOC_MUTEX_INIT_CB witness_list_t *witnesses; - witnesses = tsd_witnessesp_get(tsd); + witnesses = &witness_tsd->witnesses; ql_new(witnesses); #endif - tsd_witness_fork_set(tsd, false); + witness_tsd->forking = false; } diff --git a/test/unit/witness.c b/test/unit/witness.c index de2e6028..5986da40 100644 --- a/test/unit/witness.c +++ b/test/unit/witness.c @@ -55,95 +55,91 @@ witness_comp_reverse(const witness_t *a, void *oa, const witness_t *b, TEST_BEGIN(test_witness) { witness_t a, b; - tsdn_t *tsdn; + witness_tsdn_t witness_tsdn = { WITNESS_TSD_INITIALIZER }; test_skip_if(!config_debug); - tsdn = tsdn_fetch(); - - witness_assert_lockless(tsdn); - witness_assert_depth(tsdn, 0); - witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 0); + witness_assert_lockless(&witness_tsdn); + witness_assert_depth(&witness_tsdn, 0); + witness_assert_depth_to_rank(&witness_tsdn, (witness_rank_t)1U, 0); witness_init(&a, "a", 1, NULL, NULL); - witness_assert_not_owner(tsdn, &a); - witness_lock(tsdn, &a); - witness_assert_owner(tsdn, &a); - witness_assert_depth(tsdn, 1); - witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 1); - witness_assert_depth_to_rank(tsdn, (witness_rank_t)2U, 0); + witness_assert_not_owner(&witness_tsdn, &a); + witness_lock(&witness_tsdn, &a); + witness_assert_owner(&witness_tsdn, &a); + witness_assert_depth(&witness_tsdn, 1); + witness_assert_depth_to_rank(&witness_tsdn, (witness_rank_t)1U, 1); + witness_assert_depth_to_rank(&witness_tsdn, (witness_rank_t)2U, 0); witness_init(&b, "b", 2, NULL, NULL); - witness_assert_not_owner(tsdn, &b); - witness_lock(tsdn, &b); - witness_assert_owner(tsdn, &b); - witness_assert_depth(tsdn, 2); - witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 2); - witness_assert_depth_to_rank(tsdn, (witness_rank_t)2U, 1); - witness_assert_depth_to_rank(tsdn, (witness_rank_t)3U, 0); - - witness_unlock(tsdn, &a); - witness_assert_depth(tsdn, 1); - witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 1); - witness_assert_depth_to_rank(tsdn, (witness_rank_t)2U, 1); - witness_assert_depth_to_rank(tsdn, (witness_rank_t)3U, 0); - witness_unlock(tsdn, &b); - - witness_assert_lockless(tsdn); - witness_assert_depth(tsdn, 0); - witness_assert_depth_to_rank(tsdn, (witness_rank_t)1U, 0); + witness_assert_not_owner(&witness_tsdn, &b); + witness_lock(&witness_tsdn, &b); + witness_assert_owner(&witness_tsdn, &b); + witness_assert_depth(&witness_tsdn, 2); + witness_assert_depth_to_rank(&witness_tsdn, (witness_rank_t)1U, 2); + witness_assert_depth_to_rank(&witness_tsdn, (witness_rank_t)2U, 1); + witness_assert_depth_to_rank(&witness_tsdn, (witness_rank_t)3U, 0); + + witness_unlock(&witness_tsdn, &a); + witness_assert_depth(&witness_tsdn, 1); + witness_assert_depth_to_rank(&witness_tsdn, (witness_rank_t)1U, 1); + witness_assert_depth_to_rank(&witness_tsdn, (witness_rank_t)2U, 1); + witness_assert_depth_to_rank(&witness_tsdn, (witness_rank_t)3U, 0); + witness_unlock(&witness_tsdn, &b); + + witness_assert_lockless(&witness_tsdn); + witness_assert_depth(&witness_tsdn, 0); + witness_assert_depth_to_rank(&witness_tsdn, (witness_rank_t)1U, 0); } TEST_END TEST_BEGIN(test_witness_comp) { witness_t a, b, c, d; - tsdn_t *tsdn; + witness_tsdn_t witness_tsdn = { WITNESS_TSD_INITIALIZER }; test_skip_if(!config_debug); - tsdn = tsdn_fetch(); - - witness_assert_lockless(tsdn); + witness_assert_lockless(&witness_tsdn); witness_init(&a, "a", 1, witness_comp, &a); - witness_assert_not_owner(tsdn, &a); - witness_lock(tsdn, &a); - witness_assert_owner(tsdn, &a); - witness_assert_depth(tsdn, 1); + witness_assert_not_owner(&witness_tsdn, &a); + witness_lock(&witness_tsdn, &a); + witness_assert_owner(&witness_tsdn, &a); + witness_assert_depth(&witness_tsdn, 1); witness_init(&b, "b", 1, witness_comp, &b); - witness_assert_not_owner(tsdn, &b); - witness_lock(tsdn, &b); - witness_assert_owner(tsdn, &b); - witness_assert_depth(tsdn, 2); - witness_unlock(tsdn, &b); - witness_assert_depth(tsdn, 1); + witness_assert_not_owner(&witness_tsdn, &b); + witness_lock(&witness_tsdn, &b); + witness_assert_owner(&witness_tsdn, &b); + witness_assert_depth(&witness_tsdn, 2); + witness_unlock(&witness_tsdn, &b); + witness_assert_depth(&witness_tsdn, 1); witness_lock_error_orig = witness_lock_error; witness_lock_error = witness_lock_error_intercept; saw_lock_error = false; witness_init(&c, "c", 1, witness_comp_reverse, &c); - witness_assert_not_owner(tsdn, &c); + witness_assert_not_owner(&witness_tsdn, &c); assert_false(saw_lock_error, "Unexpected witness lock error"); - witness_lock(tsdn, &c); + witness_lock(&witness_tsdn, &c); assert_true(saw_lock_error, "Expected witness lock error"); - witness_unlock(tsdn, &c); - witness_assert_depth(tsdn, 1); + witness_unlock(&witness_tsdn, &c); + witness_assert_depth(&witness_tsdn, 1); saw_lock_error = false; witness_init(&d, "d", 1, NULL, NULL); - witness_assert_not_owner(tsdn, &d); + witness_assert_not_owner(&witness_tsdn, &d); assert_false(saw_lock_error, "Unexpected witness lock error"); - witness_lock(tsdn, &d); + witness_lock(&witness_tsdn, &d); assert_true(saw_lock_error, "Expected witness lock error"); - witness_unlock(tsdn, &d); - witness_assert_depth(tsdn, 1); + witness_unlock(&witness_tsdn, &d); + witness_assert_depth(&witness_tsdn, 1); - witness_unlock(tsdn, &a); + witness_unlock(&witness_tsdn, &a); - witness_assert_lockless(tsdn); + witness_assert_lockless(&witness_tsdn); witness_lock_error = witness_lock_error_orig; } @@ -151,7 +147,7 @@ TEST_END TEST_BEGIN(test_witness_reversal) { witness_t a, b; - tsdn_t *tsdn; + witness_tsdn_t witness_tsdn = { WITNESS_TSD_INITIALIZER }; test_skip_if(!config_debug); @@ -159,24 +155,22 @@ TEST_BEGIN(test_witness_reversal) { witness_lock_error = witness_lock_error_intercept; saw_lock_error = false; - tsdn = tsdn_fetch(); - - witness_assert_lockless(tsdn); + witness_assert_lockless(&witness_tsdn); witness_init(&a, "a", 1, NULL, NULL); witness_init(&b, "b", 2, NULL, NULL); - witness_lock(tsdn, &b); - witness_assert_depth(tsdn, 1); + witness_lock(&witness_tsdn, &b); + witness_assert_depth(&witness_tsdn, 1); assert_false(saw_lock_error, "Unexpected witness lock error"); - witness_lock(tsdn, &a); + witness_lock(&witness_tsdn, &a); assert_true(saw_lock_error, "Expected witness lock error"); - witness_unlock(tsdn, &a); - witness_assert_depth(tsdn, 1); - witness_unlock(tsdn, &b); + witness_unlock(&witness_tsdn, &a); + witness_assert_depth(&witness_tsdn, 1); + witness_unlock(&witness_tsdn, &b); - witness_assert_lockless(tsdn); + witness_assert_lockless(&witness_tsdn); witness_lock_error = witness_lock_error_orig; } @@ -184,7 +178,7 @@ TEST_END TEST_BEGIN(test_witness_recursive) { witness_t a; - tsdn_t *tsdn; + witness_tsdn_t witness_tsdn = { WITNESS_TSD_INITIALIZER }; test_skip_if(!config_debug); @@ -196,22 +190,20 @@ TEST_BEGIN(test_witness_recursive) { witness_lock_error = witness_lock_error_intercept; saw_lock_error = false; - tsdn = tsdn_fetch(); - - witness_assert_lockless(tsdn); + witness_assert_lockless(&witness_tsdn); witness_init(&a, "a", 1, NULL, NULL); - witness_lock(tsdn, &a); + witness_lock(&witness_tsdn, &a); assert_false(saw_lock_error, "Unexpected witness lock error"); assert_false(saw_not_owner_error, "Unexpected witness not owner error"); - witness_lock(tsdn, &a); + witness_lock(&witness_tsdn, &a); assert_true(saw_lock_error, "Expected witness lock error"); assert_true(saw_not_owner_error, "Expected witness not owner error"); - witness_unlock(tsdn, &a); + witness_unlock(&witness_tsdn, &a); - witness_assert_lockless(tsdn); + witness_assert_lockless(&witness_tsdn); witness_owner_error = witness_owner_error_orig; witness_lock_error = witness_lock_error_orig; @@ -221,7 +213,7 @@ TEST_END TEST_BEGIN(test_witness_unlock_not_owned) { witness_t a; - tsdn_t *tsdn; + witness_tsdn_t witness_tsdn = { WITNESS_TSD_INITIALIZER }; test_skip_if(!config_debug); @@ -229,17 +221,15 @@ TEST_BEGIN(test_witness_unlock_not_owned) { witness_owner_error = witness_owner_error_intercept; saw_owner_error = false; - tsdn = tsdn_fetch(); - - witness_assert_lockless(tsdn); + witness_assert_lockless(&witness_tsdn); witness_init(&a, "a", 1, NULL, NULL); assert_false(saw_owner_error, "Unexpected owner error"); - witness_unlock(tsdn, &a); + witness_unlock(&witness_tsdn, &a); assert_true(saw_owner_error, "Expected owner error"); - witness_assert_lockless(tsdn); + witness_assert_lockless(&witness_tsdn); witness_owner_error = witness_owner_error_orig; } @@ -247,7 +237,7 @@ TEST_END TEST_BEGIN(test_witness_depth) { witness_t a; - tsdn_t *tsdn; + witness_tsdn_t witness_tsdn = { WITNESS_TSD_INITIALIZER }; test_skip_if(!config_debug); @@ -255,26 +245,24 @@ TEST_BEGIN(test_witness_depth) { witness_depth_error = witness_depth_error_intercept; saw_depth_error = false; - tsdn = tsdn_fetch(); - - witness_assert_lockless(tsdn); - witness_assert_depth(tsdn, 0); + witness_assert_lockless(&witness_tsdn); + witness_assert_depth(&witness_tsdn, 0); witness_init(&a, "a", 1, NULL, NULL); assert_false(saw_depth_error, "Unexpected depth error"); - witness_assert_lockless(tsdn); - witness_assert_depth(tsdn, 0); + witness_assert_lockless(&witness_tsdn); + witness_assert_depth(&witness_tsdn, 0); - witness_lock(tsdn, &a); - witness_assert_lockless(tsdn); - witness_assert_depth(tsdn, 0); + witness_lock(&witness_tsdn, &a); + witness_assert_lockless(&witness_tsdn); + witness_assert_depth(&witness_tsdn, 0); assert_true(saw_depth_error, "Expected depth error"); - witness_unlock(tsdn, &a); + witness_unlock(&witness_tsdn, &a); - witness_assert_lockless(tsdn); - witness_assert_depth(tsdn, 0); + witness_assert_lockless(&witness_tsdn); + witness_assert_depth(&witness_tsdn, 0); witness_depth_error = witness_depth_error_orig; } -- GitLab From 18ecbfa89e7dd39a802f52bcd461184b8065e97e Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 23 May 2017 12:28:19 -0700 Subject: [PATCH 496/544] Header refactoring: unify and de-catchall mutex module --- include/jemalloc/internal/arena_inlines_b.h | 1 + include/jemalloc/internal/arena_structs_b.h | 1 + include/jemalloc/internal/base_structs.h | 1 + include/jemalloc/internal/extent_externs.h | 3 +- include/jemalloc/internal/extent_inlines.h | 1 + include/jemalloc/internal/extent_structs.h | 1 + .../internal/jemalloc_internal_includes.h | 4 - include/jemalloc/internal/mutex.h | 248 ++++++++++++++++++ include/jemalloc/internal/mutex_externs.h | 21 -- include/jemalloc/internal/mutex_inlines.h | 118 --------- .../jemalloc/internal/mutex_pool_inlines.h | 2 +- .../jemalloc/internal/mutex_pool_structs.h | 2 + include/jemalloc/internal/mutex_structs.h | 55 ---- include/jemalloc/internal/mutex_types.h | 71 ----- include/jemalloc/internal/prof_externs.h | 2 + include/jemalloc/internal/prof_inlines_a.h | 2 + include/jemalloc/internal/prof_structs.h | 1 + include/jemalloc/internal/rtree_structs.h | 2 +- include/jemalloc/internal/stats.h | 12 +- include/jemalloc/internal/stats_tsd.h | 12 + include/jemalloc/internal/tcache_structs.h | 2 +- include/jemalloc/internal/tsd_generic.h | 5 +- src/arena.c | 1 + src/base.c | 1 + src/ctl.c | 1 + src/extent.c | 1 + src/jemalloc.c | 1 + src/large.c | 1 + src/mutex_pool.c | 2 + src/prof.c | 1 + src/rtree.c | 1 + src/stats.c | 1 + src/tcache.c | 1 + src/tsd.c | 12 + 34 files changed, 304 insertions(+), 287 deletions(-) create mode 100644 include/jemalloc/internal/mutex.h delete mode 100644 include/jemalloc/internal/mutex_externs.h delete mode 100644 include/jemalloc/internal/mutex_inlines.h delete mode 100644 include/jemalloc/internal/mutex_structs.h delete mode 100644 include/jemalloc/internal/mutex_types.h create mode 100644 include/jemalloc/internal/stats_tsd.h diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index a1057184..8db6e9a8 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_ARENA_INLINES_B_H #include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/ticker.h" diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 95680c0f..f98f45c1 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -4,6 +4,7 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/bitmap.h" #include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/nstime.h" #include "jemalloc/internal/ql.h" #include "jemalloc/internal/size_classes.h" diff --git a/include/jemalloc/internal/base_structs.h b/include/jemalloc/internal/base_structs.h index 1d0a1f3a..18e227bd 100644 --- a/include/jemalloc/internal/base_structs.h +++ b/include/jemalloc/internal/base_structs.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_BASE_STRUCTS_H #include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/size_classes.h" /* Embedded at the beginning of every block of base-managed virtual memory. */ diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index 7a5b38c6..9d5daf5b 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -1,8 +1,9 @@ #ifndef JEMALLOC_INTERNAL_EXTENT_EXTERNS_H #define JEMALLOC_INTERNAL_EXTENT_EXTERNS_H -#include "jemalloc/internal/rb.h" +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/ph.h" +#include "jemalloc/internal/rb.h" extern rtree_t extents_rtree; extern const extent_hooks_t extent_hooks_default; diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index 2ebd9452..a99a6351 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -1,6 +1,7 @@ #ifndef JEMALLOC_INTERNAL_EXTENT_INLINES_H #define JEMALLOC_INTERNAL_EXTENT_INLINES_H +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/mutex_pool_inlines.h" #include "jemalloc/internal/pages.h" #include "jemalloc/internal/prng.h" diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 62bae39a..457891df 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -3,6 +3,7 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/bitmap.h" +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/ql.h" #include "jemalloc/internal/rb.h" #include "jemalloc/internal/ph.h" diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 2abc4781..b1a6f17d 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -40,7 +40,6 @@ /* TYPES */ /******************************************************************************/ -#include "jemalloc/internal/mutex_types.h" #include "jemalloc/internal/extent_types.h" #include "jemalloc/internal/extent_dss_types.h" #include "jemalloc/internal/base_types.h" @@ -53,7 +52,6 @@ /* STRUCTS */ /******************************************************************************/ -#include "jemalloc/internal/mutex_structs.h" #include "jemalloc/internal/mutex_pool_structs.h" #include "jemalloc/internal/arena_structs_a.h" #include "jemalloc/internal/extent_structs.h" @@ -70,7 +68,6 @@ /******************************************************************************/ #include "jemalloc/internal/jemalloc_internal_externs.h" -#include "jemalloc/internal/mutex_externs.h" #include "jemalloc/internal/extent_externs.h" #include "jemalloc/internal/extent_dss_externs.h" #include "jemalloc/internal/extent_mmap_externs.h" @@ -86,7 +83,6 @@ /* INLINES */ /******************************************************************************/ -#include "jemalloc/internal/mutex_inlines.h" #include "jemalloc/internal/mutex_pool_inlines.h" #include "jemalloc/internal/jemalloc_internal_inlines_a.h" #include "jemalloc/internal/rtree_inlines.h" diff --git a/include/jemalloc/internal/mutex.h b/include/jemalloc/internal/mutex.h new file mode 100644 index 00000000..6520c251 --- /dev/null +++ b/include/jemalloc/internal/mutex.h @@ -0,0 +1,248 @@ +#ifndef JEMALLOC_INTERNAL_MUTEX_H +#define JEMALLOC_INTERNAL_MUTEX_H + +#include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/mutex_prof.h" +#include "jemalloc/internal/tsd.h" +#include "jemalloc/internal/witness.h" + +typedef enum { + /* Can only acquire one mutex of a given witness rank at a time. */ + malloc_mutex_rank_exclusive, + /* + * Can acquire multiple mutexes of the same witness rank, but in + * address-ascending order only. + */ + malloc_mutex_address_ordered +} malloc_mutex_lock_order_t; + +typedef struct malloc_mutex_s malloc_mutex_t; +struct malloc_mutex_s { + union { + struct { + /* + * prof_data is defined first to reduce cacheline + * bouncing: the data is not touched by the mutex holder + * during unlocking, while might be modified by + * contenders. Having it before the mutex itself could + * avoid prefetching a modified cacheline (for the + * unlocking thread). + */ + mutex_prof_data_t prof_data; +#ifdef _WIN32 +# if _WIN32_WINNT >= 0x0600 + SRWLOCK lock; +# else + CRITICAL_SECTION lock; +# endif +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) + os_unfair_lock lock; +#elif (defined(JEMALLOC_OSSPIN)) + OSSpinLock lock; +#elif (defined(JEMALLOC_MUTEX_INIT_CB)) + pthread_mutex_t lock; + malloc_mutex_t *postponed_next; +#else + pthread_mutex_t lock; +#endif + }; + /* + * We only touch witness when configured w/ debug. However we + * keep the field in a union when !debug so that we don't have + * to pollute the code base with #ifdefs, while avoid paying the + * memory cost. + */ +#if !defined(JEMALLOC_DEBUG) + witness_t witness; + malloc_mutex_lock_order_t lock_order; +#endif + }; + +#if defined(JEMALLOC_DEBUG) + witness_t witness; + malloc_mutex_lock_order_t lock_order; +#endif +}; + +/* + * Based on benchmark results, a fixed spin with this amount of retries works + * well for our critical sections. + */ +#define MALLOC_MUTEX_MAX_SPIN 250 + +#ifdef _WIN32 +# if _WIN32_WINNT >= 0x0600 +# define MALLOC_MUTEX_LOCK(m) AcquireSRWLockExclusive(&(m)->lock) +# define MALLOC_MUTEX_UNLOCK(m) ReleaseSRWLockExclusive(&(m)->lock) +# define MALLOC_MUTEX_TRYLOCK(m) (!TryAcquireSRWLockExclusive(&(m)->lock)) +# else +# define MALLOC_MUTEX_LOCK(m) EnterCriticalSection(&(m)->lock) +# define MALLOC_MUTEX_UNLOCK(m) LeaveCriticalSection(&(m)->lock) +# define MALLOC_MUTEX_TRYLOCK(m) (!TryEnterCriticalSection(&(m)->lock)) +# endif +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) +# define MALLOC_MUTEX_LOCK(m) os_unfair_lock_lock(&(m)->lock) +# define MALLOC_MUTEX_UNLOCK(m) os_unfair_lock_unlock(&(m)->lock) +# define MALLOC_MUTEX_TRYLOCK(m) (!os_unfair_lock_trylock(&(m)->lock)) +#elif (defined(JEMALLOC_OSSPIN)) +# define MALLOC_MUTEX_LOCK(m) OSSpinLockLock(&(m)->lock) +# define MALLOC_MUTEX_UNLOCK(m) OSSpinLockUnlock(&(m)->lock) +# define MALLOC_MUTEX_TRYLOCK(m) (!OSSpinLockTry(&(m)->lock)) +#else +# define MALLOC_MUTEX_LOCK(m) pthread_mutex_lock(&(m)->lock) +# define MALLOC_MUTEX_UNLOCK(m) pthread_mutex_unlock(&(m)->lock) +# define MALLOC_MUTEX_TRYLOCK(m) (pthread_mutex_trylock(&(m)->lock) != 0) +#endif + +#define LOCK_PROF_DATA_INITIALIZER \ + {NSTIME_ZERO_INITIALIZER, NSTIME_ZERO_INITIALIZER, 0, 0, 0, \ + ATOMIC_INIT(0), 0, NULL, 0} + +#ifdef _WIN32 +# define MALLOC_MUTEX_INITIALIZER +#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) +# define MALLOC_MUTEX_INITIALIZER \ + {{{LOCK_PROF_DATA_INITIALIZER, OS_UNFAIR_LOCK_INIT}}, \ + WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} +#elif (defined(JEMALLOC_OSSPIN)) +# define MALLOC_MUTEX_INITIALIZER \ + {{{LOCK_PROF_DATA_INITIALIZER, 0}}, \ + WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} +#elif (defined(JEMALLOC_MUTEX_INIT_CB)) +# define MALLOC_MUTEX_INITIALIZER \ + {{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, NULL}}, \ + WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} +#else +# define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT +# define MALLOC_MUTEX_INITIALIZER \ + {{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER}}, \ + WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} +#endif + +#ifdef JEMALLOC_LAZY_LOCK +extern bool isthreaded; +#else +# undef isthreaded /* Undo private_namespace.h definition. */ +# define isthreaded true +#endif + +bool malloc_mutex_init(malloc_mutex_t *mutex, const char *name, + witness_rank_t rank, malloc_mutex_lock_order_t lock_order); +void malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex); +void malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex); +void malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex); +bool malloc_mutex_boot(void); +void malloc_mutex_prof_data_reset(tsdn_t *tsdn, malloc_mutex_t *mutex); + +void malloc_mutex_lock_slow(malloc_mutex_t *mutex); + +static inline void +malloc_mutex_lock_final(malloc_mutex_t *mutex) { + MALLOC_MUTEX_LOCK(mutex); +} + +static inline bool +malloc_mutex_trylock_final(malloc_mutex_t *mutex) { + return MALLOC_MUTEX_TRYLOCK(mutex); +} + +static inline void +mutex_owner_stats_update(tsdn_t *tsdn, malloc_mutex_t *mutex) { + if (config_stats) { + mutex_prof_data_t *data = &mutex->prof_data; + data->n_lock_ops++; + if (data->prev_owner != tsdn) { + data->prev_owner = tsdn; + data->n_owner_switches++; + } + } +} + +/* Trylock: return false if the lock is successfully acquired. */ +static inline bool +malloc_mutex_trylock(tsdn_t *tsdn, malloc_mutex_t *mutex) { + witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness); + if (isthreaded) { + if (malloc_mutex_trylock_final(mutex)) { + return true; + } + mutex_owner_stats_update(tsdn, mutex); + } + witness_lock(tsdn_witness_tsdp_get(tsdn), &mutex->witness); + + return false; +} + +/* Aggregate lock prof data. */ +static inline void +malloc_mutex_prof_merge(mutex_prof_data_t *sum, mutex_prof_data_t *data) { + nstime_add(&sum->tot_wait_time, &data->tot_wait_time); + if (nstime_compare(&sum->max_wait_time, &data->max_wait_time) < 0) { + nstime_copy(&sum->max_wait_time, &data->max_wait_time); + } + + sum->n_wait_times += data->n_wait_times; + sum->n_spin_acquired += data->n_spin_acquired; + + if (sum->max_n_thds < data->max_n_thds) { + sum->max_n_thds = data->max_n_thds; + } + uint32_t cur_n_waiting_thds = atomic_load_u32(&sum->n_waiting_thds, + ATOMIC_RELAXED); + uint32_t new_n_waiting_thds = cur_n_waiting_thds + atomic_load_u32( + &data->n_waiting_thds, ATOMIC_RELAXED); + atomic_store_u32(&sum->n_waiting_thds, new_n_waiting_thds, + ATOMIC_RELAXED); + sum->n_owner_switches += data->n_owner_switches; + sum->n_lock_ops += data->n_lock_ops; +} + +static inline void +malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) { + witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness); + if (isthreaded) { + if (malloc_mutex_trylock_final(mutex)) { + malloc_mutex_lock_slow(mutex); + } + mutex_owner_stats_update(tsdn, mutex); + } + witness_lock(tsdn_witness_tsdp_get(tsdn), &mutex->witness); +} + +static inline void +malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) { + witness_unlock(tsdn_witness_tsdp_get(tsdn), &mutex->witness); + if (isthreaded) { + MALLOC_MUTEX_UNLOCK(mutex); + } +} + +static inline void +malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { + witness_assert_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness); +} + +static inline void +malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { + witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness); +} + +/* Copy the prof data from mutex for processing. */ +static inline void +malloc_mutex_prof_read(tsdn_t *tsdn, mutex_prof_data_t *data, + malloc_mutex_t *mutex) { + mutex_prof_data_t *source = &mutex->prof_data; + /* Can only read holding the mutex. */ + malloc_mutex_assert_owner(tsdn, mutex); + + /* + * Not *really* allowed (we shouldn't be doing non-atomic loads of + * atomic data), but the mutex protection makes this safe, and writing + * a member-for-member copy is tedious for this situation. + */ + *data = *source; + /* n_wait_thds is not reported (modified w/o locking). */ + atomic_store_u32(&data->n_waiting_thds, 0, ATOMIC_RELAXED); +} + +#endif /* JEMALLOC_INTERNAL_MUTEX_H */ diff --git a/include/jemalloc/internal/mutex_externs.h b/include/jemalloc/internal/mutex_externs.h deleted file mode 100644 index d0139f2e..00000000 --- a/include/jemalloc/internal/mutex_externs.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_MUTEX_EXTERNS_H -#define JEMALLOC_INTERNAL_MUTEX_EXTERNS_H - -#include "jemalloc/internal/tsd_types.h" - -#ifdef JEMALLOC_LAZY_LOCK -extern bool isthreaded; -#else -# undef isthreaded /* Undo private_namespace.h definition. */ -# define isthreaded true -#endif - -bool malloc_mutex_init(malloc_mutex_t *mutex, const char *name, - witness_rank_t rank, malloc_mutex_lock_order_t lock_order); -void malloc_mutex_prefork(tsdn_t *tsdn, malloc_mutex_t *mutex); -void malloc_mutex_postfork_parent(tsdn_t *tsdn, malloc_mutex_t *mutex); -void malloc_mutex_postfork_child(tsdn_t *tsdn, malloc_mutex_t *mutex); -bool malloc_mutex_boot(void); -void malloc_mutex_prof_data_reset(tsdn_t *tsdn, malloc_mutex_t *mutex); - -#endif /* JEMALLOC_INTERNAL_MUTEX_EXTERNS_H */ diff --git a/include/jemalloc/internal/mutex_inlines.h b/include/jemalloc/internal/mutex_inlines.h deleted file mode 100644 index b86a4ad4..00000000 --- a/include/jemalloc/internal/mutex_inlines.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_MUTEX_INLINES_H -#define JEMALLOC_INTERNAL_MUTEX_INLINES_H - -#include "jemalloc/internal/nstime.h" -#include "jemalloc/internal/tsd_types.h" - -void malloc_mutex_lock_slow(malloc_mutex_t *mutex); - -static inline void -malloc_mutex_lock_final(malloc_mutex_t *mutex) { - MALLOC_MUTEX_LOCK(mutex); -} - -static inline bool -malloc_mutex_trylock_final(malloc_mutex_t *mutex) { - return MALLOC_MUTEX_TRYLOCK(mutex); -} - -static inline void -mutex_owner_stats_update(tsdn_t *tsdn, malloc_mutex_t *mutex) { - if (config_stats) { - mutex_prof_data_t *data = &mutex->prof_data; - data->n_lock_ops++; - if (data->prev_owner != tsdn) { - data->prev_owner = tsdn; - data->n_owner_switches++; - } - } -} - -/* Trylock: return false if the lock is successfully acquired. */ -static inline bool -malloc_mutex_trylock(tsdn_t *tsdn, malloc_mutex_t *mutex) { - witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness); - if (isthreaded) { - if (malloc_mutex_trylock_final(mutex)) { - return true; - } - mutex_owner_stats_update(tsdn, mutex); - } - witness_lock(tsdn_witness_tsdp_get(tsdn), &mutex->witness); - - return false; -} - -/* Aggregate lock prof data. */ -static inline void -malloc_mutex_prof_merge(mutex_prof_data_t *sum, mutex_prof_data_t *data) { - nstime_add(&sum->tot_wait_time, &data->tot_wait_time); - if (nstime_compare(&sum->max_wait_time, &data->max_wait_time) < 0) { - nstime_copy(&sum->max_wait_time, &data->max_wait_time); - } - - sum->n_wait_times += data->n_wait_times; - sum->n_spin_acquired += data->n_spin_acquired; - - if (sum->max_n_thds < data->max_n_thds) { - sum->max_n_thds = data->max_n_thds; - } - uint32_t cur_n_waiting_thds = atomic_load_u32(&sum->n_waiting_thds, - ATOMIC_RELAXED); - uint32_t new_n_waiting_thds = cur_n_waiting_thds + atomic_load_u32( - &data->n_waiting_thds, ATOMIC_RELAXED); - atomic_store_u32(&sum->n_waiting_thds, new_n_waiting_thds, - ATOMIC_RELAXED); - sum->n_owner_switches += data->n_owner_switches; - sum->n_lock_ops += data->n_lock_ops; -} - -static inline void -malloc_mutex_lock(tsdn_t *tsdn, malloc_mutex_t *mutex) { - witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness); - if (isthreaded) { - if (malloc_mutex_trylock_final(mutex)) { - malloc_mutex_lock_slow(mutex); - } - mutex_owner_stats_update(tsdn, mutex); - } - witness_lock(tsdn_witness_tsdp_get(tsdn), &mutex->witness); -} - -static inline void -malloc_mutex_unlock(tsdn_t *tsdn, malloc_mutex_t *mutex) { - witness_unlock(tsdn_witness_tsdp_get(tsdn), &mutex->witness); - if (isthreaded) { - MALLOC_MUTEX_UNLOCK(mutex); - } -} - -static inline void -malloc_mutex_assert_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { - witness_assert_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness); -} - -static inline void -malloc_mutex_assert_not_owner(tsdn_t *tsdn, malloc_mutex_t *mutex) { - witness_assert_not_owner(tsdn_witness_tsdp_get(tsdn), &mutex->witness); -} - -/* Copy the prof data from mutex for processing. */ -static inline void -malloc_mutex_prof_read(tsdn_t *tsdn, mutex_prof_data_t *data, - malloc_mutex_t *mutex) { - mutex_prof_data_t *source = &mutex->prof_data; - /* Can only read holding the mutex. */ - malloc_mutex_assert_owner(tsdn, mutex); - - /* - * Not *really* allowed (we shouldn't be doing non-atomic loads of - * atomic data), but the mutex protection makes this safe, and writing - * a member-for-member copy is tedious for this situation. - */ - *data = *source; - /* n_wait_thds is not reported (modified w/o locking). */ - atomic_store_u32(&data->n_waiting_thds, 0, ATOMIC_RELAXED); -} - -#endif /* JEMALLOC_INTERNAL_MUTEX_INLINES_H */ diff --git a/include/jemalloc/internal/mutex_pool_inlines.h b/include/jemalloc/internal/mutex_pool_inlines.h index bc257ea8..19b5ab4c 100644 --- a/include/jemalloc/internal/mutex_pool_inlines.h +++ b/include/jemalloc/internal/mutex_pool_inlines.h @@ -2,7 +2,7 @@ #define JEMALLOC_INTERNAL_MUTEX_POOL_INLINES_H #include "jemalloc/internal/hash.h" -#include "jemalloc/internal/mutex_inlines.h" +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/mutex_pool_structs.h" #include "jemalloc/internal/witness.h" diff --git a/include/jemalloc/internal/mutex_pool_structs.h b/include/jemalloc/internal/mutex_pool_structs.h index a662166c..b32fb5ac 100644 --- a/include/jemalloc/internal/mutex_pool_structs.h +++ b/include/jemalloc/internal/mutex_pool_structs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_MUTEX_POOL_STRUCTS_H #define JEMALLOC_INTERNAL_MUTEX_POOL_STRUCTS_H +#include "jemalloc/internal/mutex.h" + /* This file really combines "structs" and "types", but only transitionally. */ /* We do mod reductions by this value, so it should be kept a power of 2. */ diff --git a/include/jemalloc/internal/mutex_structs.h b/include/jemalloc/internal/mutex_structs.h deleted file mode 100644 index c1b65522..00000000 --- a/include/jemalloc/internal/mutex_structs.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_MUTEX_STRUCTS_H -#define JEMALLOC_INTERNAL_MUTEX_STRUCTS_H - -#include "jemalloc/internal/atomic.h" -#include "jemalloc/internal/mutex_prof.h" -#include "jemalloc/internal/witness.h" - -struct malloc_mutex_s { - union { - struct { - /* - * prof_data is defined first to reduce cacheline - * bouncing: the data is not touched by the mutex holder - * during unlocking, while might be modified by - * contenders. Having it before the mutex itself could - * avoid prefetching a modified cacheline (for the - * unlocking thread). - */ - mutex_prof_data_t prof_data; -#ifdef _WIN32 -# if _WIN32_WINNT >= 0x0600 - SRWLOCK lock; -# else - CRITICAL_SECTION lock; -# endif -#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) - os_unfair_lock lock; -#elif (defined(JEMALLOC_OSSPIN)) - OSSpinLock lock; -#elif (defined(JEMALLOC_MUTEX_INIT_CB)) - pthread_mutex_t lock; - malloc_mutex_t *postponed_next; -#else - pthread_mutex_t lock; -#endif - }; - /* - * We only touch witness when configured w/ debug. However we - * keep the field in a union when !debug so that we don't have - * to pollute the code base with #ifdefs, while avoid paying the - * memory cost. - */ -#if !defined(JEMALLOC_DEBUG) - witness_t witness; - malloc_mutex_lock_order_t lock_order; -#endif - }; - -#if defined(JEMALLOC_DEBUG) - witness_t witness; - malloc_mutex_lock_order_t lock_order; -#endif -}; - -#endif /* JEMALLOC_INTERNAL_MUTEX_STRUCTS_H */ diff --git a/include/jemalloc/internal/mutex_types.h b/include/jemalloc/internal/mutex_types.h deleted file mode 100644 index 65a9938d..00000000 --- a/include/jemalloc/internal/mutex_types.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_MUTEX_TYPES_H -#define JEMALLOC_INTERNAL_MUTEX_TYPES_H - -typedef struct malloc_mutex_s malloc_mutex_t; - -typedef enum { - /* Can only acquire one mutex of a given witness rank at a time. */ - malloc_mutex_rank_exclusive, - /* - * Can acquire multiple mutexes of the same witness rank, but in - * address-ascending order only. - */ - malloc_mutex_address_ordered -} malloc_mutex_lock_order_t; - -/* - * Based on benchmark results, a fixed spin with this amount of retries works - * well for our critical sections. - */ -#define MALLOC_MUTEX_MAX_SPIN 250 - -#ifdef _WIN32 -# if _WIN32_WINNT >= 0x0600 -# define MALLOC_MUTEX_LOCK(m) AcquireSRWLockExclusive(&(m)->lock) -# define MALLOC_MUTEX_UNLOCK(m) ReleaseSRWLockExclusive(&(m)->lock) -# define MALLOC_MUTEX_TRYLOCK(m) (!TryAcquireSRWLockExclusive(&(m)->lock)) -# else -# define MALLOC_MUTEX_LOCK(m) EnterCriticalSection(&(m)->lock) -# define MALLOC_MUTEX_UNLOCK(m) LeaveCriticalSection(&(m)->lock) -# define MALLOC_MUTEX_TRYLOCK(m) (!TryEnterCriticalSection(&(m)->lock)) -# endif -#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) -# define MALLOC_MUTEX_LOCK(m) os_unfair_lock_lock(&(m)->lock) -# define MALLOC_MUTEX_UNLOCK(m) os_unfair_lock_unlock(&(m)->lock) -# define MALLOC_MUTEX_TRYLOCK(m) (!os_unfair_lock_trylock(&(m)->lock)) -#elif (defined(JEMALLOC_OSSPIN)) -# define MALLOC_MUTEX_LOCK(m) OSSpinLockLock(&(m)->lock) -# define MALLOC_MUTEX_UNLOCK(m) OSSpinLockUnlock(&(m)->lock) -# define MALLOC_MUTEX_TRYLOCK(m) (!OSSpinLockTry(&(m)->lock)) -#else -# define MALLOC_MUTEX_LOCK(m) pthread_mutex_lock(&(m)->lock) -# define MALLOC_MUTEX_UNLOCK(m) pthread_mutex_unlock(&(m)->lock) -# define MALLOC_MUTEX_TRYLOCK(m) (pthread_mutex_trylock(&(m)->lock) != 0) -#endif - -#define LOCK_PROF_DATA_INITIALIZER \ - {NSTIME_ZERO_INITIALIZER, NSTIME_ZERO_INITIALIZER, 0, 0, 0, \ - ATOMIC_INIT(0), 0, NULL, 0} - -#ifdef _WIN32 -# define MALLOC_MUTEX_INITIALIZER -#elif (defined(JEMALLOC_OS_UNFAIR_LOCK)) -# define MALLOC_MUTEX_INITIALIZER \ - {{{LOCK_PROF_DATA_INITIALIZER, OS_UNFAIR_LOCK_INIT}}, \ - WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} -#elif (defined(JEMALLOC_OSSPIN)) -# define MALLOC_MUTEX_INITIALIZER \ - {{{LOCK_PROF_DATA_INITIALIZER, 0}}, \ - WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} -#elif (defined(JEMALLOC_MUTEX_INIT_CB)) -# define MALLOC_MUTEX_INITIALIZER \ - {{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, NULL}}, \ - WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} -#else -# define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT -# define MALLOC_MUTEX_INITIALIZER \ - {{{LOCK_PROF_DATA_INITIALIZER, PTHREAD_MUTEX_INITIALIZER}}, \ - WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)} -#endif - -#endif /* JEMALLOC_INTERNAL_MUTEX_TYPES_H */ diff --git a/include/jemalloc/internal/prof_externs.h b/include/jemalloc/internal/prof_externs.h index 2891b8bd..04348696 100644 --- a/include/jemalloc/internal/prof_externs.h +++ b/include/jemalloc/internal/prof_externs.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_PROF_EXTERNS_H #define JEMALLOC_INTERNAL_PROF_EXTERNS_H +#include "jemalloc/internal/mutex.h" + extern malloc_mutex_t bt2gctx_mtx; extern bool opt_prof; diff --git a/include/jemalloc/internal/prof_inlines_a.h b/include/jemalloc/internal/prof_inlines_a.h index 6203cbd9..eda6839a 100644 --- a/include/jemalloc/internal/prof_inlines_a.h +++ b/include/jemalloc/internal/prof_inlines_a.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_PROF_INLINES_A_H #define JEMALLOC_INTERNAL_PROF_INLINES_A_H +#include "jemalloc/internal/mutex.h" + static inline bool prof_accum_add(tsdn_t *tsdn, prof_accum_t *prof_accum, uint64_t accumbytes) { cassert(config_prof); diff --git a/include/jemalloc/internal/prof_structs.h b/include/jemalloc/internal/prof_structs.h index a26a0420..0d58ae10 100644 --- a/include/jemalloc/internal/prof_structs.h +++ b/include/jemalloc/internal/prof_structs.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_PROF_STRUCTS_H #include "jemalloc/internal/ckh.h" +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/prng.h" #include "jemalloc/internal/rb.h" diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h index ba0f96d0..a02a1f60 100644 --- a/include/jemalloc/internal/rtree_structs.h +++ b/include/jemalloc/internal/rtree_structs.h @@ -2,7 +2,7 @@ #define JEMALLOC_INTERNAL_RTREE_STRUCTS_H #include "jemalloc/internal/atomic.h" -#include "jemalloc/internal/mutex_pool_structs.h" +#include "jemalloc/internal/mutex.h" struct rtree_node_elm_s { atomic_p_t child; /* (rtree_{node,leaf}_elm_t *) */ diff --git a/include/jemalloc/internal/stats.h b/include/jemalloc/internal/stats.h index 3f5c20c7..47ca4f9e 100644 --- a/include/jemalloc/internal/stats.h +++ b/include/jemalloc/internal/stats.h @@ -3,9 +3,9 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/mutex_prof.h" -#include "jemalloc/internal/mutex_types.h" -#include "jemalloc/internal/mutex_structs.h" +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/size_classes.h" +#include "jemalloc/internal/stats_tsd.h" /* The opt.stats_print storage. */ extern bool opt_stats_print; @@ -26,14 +26,6 @@ typedef atomic_u64_t arena_stats_u64_t; typedef uint64_t arena_stats_u64_t; #endif -typedef struct tcache_bin_stats_s { - /* - * Number of allocation requests that corresponded to the size of this - * bin. - */ - uint64_t nrequests; -} tcache_bin_stats_t; - typedef struct malloc_bin_stats_s { /* * Total number of allocation/deallocation requests served directly by diff --git a/include/jemalloc/internal/stats_tsd.h b/include/jemalloc/internal/stats_tsd.h new file mode 100644 index 00000000..d0c3bbe4 --- /dev/null +++ b/include/jemalloc/internal/stats_tsd.h @@ -0,0 +1,12 @@ +#ifndef JEMALLOC_INTERNAL_STATS_TSD_H +#define JEMALLOC_INTERNAL_STATS_TSD_H + +typedef struct tcache_bin_stats_s { + /* + * Number of allocation requests that corresponded to the size of this + * bin. + */ + uint64_t nrequests; +} tcache_bin_stats_t; + +#endif /* JEMALLOC_INTERNAL_STATS_TSD_H */ diff --git a/include/jemalloc/internal/tcache_structs.h b/include/jemalloc/internal/tcache_structs.h index 7c0afb0a..7eb516fb 100644 --- a/include/jemalloc/internal/tcache_structs.h +++ b/include/jemalloc/internal/tcache_structs.h @@ -3,7 +3,7 @@ #include "jemalloc/internal/ql.h" #include "jemalloc/internal/size_classes.h" -#include "jemalloc/internal/stats.h" +#include "jemalloc/internal/stats_tsd.h" #include "jemalloc/internal/ticker.h" /* diff --git a/include/jemalloc/internal/tsd_generic.h b/include/jemalloc/internal/tsd_generic.h index d59cb743..1e52ef76 100644 --- a/include/jemalloc/internal/tsd_generic.h +++ b/include/jemalloc/internal/tsd_generic.h @@ -10,11 +10,8 @@ struct tsd_init_block_s { void *data; }; +/* Defined in tsd.c, to allow the mutex headers to have tsd dependencies. */ typedef struct tsd_init_head_s tsd_init_head_t; -struct tsd_init_head_s { - ql_head(tsd_init_block_t) blocks; - malloc_mutex_t lock; -}; typedef struct { bool initialized; diff --git a/src/arena.c b/src/arena.c index 35b4e5a7..bc8fd28f 100644 --- a/src/arena.c +++ b/src/arena.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/util.h" diff --git a/src/base.c b/src/base.c index dd4b109d..892c28dd 100644 --- a/src/base.c +++ b/src/base.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/mutex.h" /******************************************************************************/ /* Data. */ diff --git a/src/ctl.c b/src/ctl.c index da5e1710..30704edd 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/ctl.h" +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/nstime.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/util.h" diff --git a/src/extent.c b/src/extent.c index ff09f7fb..fee8198e 100644 --- a/src/extent.c +++ b/src/extent.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/ph.h" +#include "jemalloc/internal/mutex.h" /******************************************************************************/ /* Data. */ diff --git a/src/jemalloc.c b/src/jemalloc.c index f083adc4..517fbb99 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -7,6 +7,7 @@ #include "jemalloc/internal/ctl.h" #include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/malloc_io.h" +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/spin.h" #include "jemalloc/internal/ticker.h" diff --git a/src/large.c b/src/large.c index ed73dc22..55ee3524 100644 --- a/src/large.c +++ b/src/large.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/util.h" /******************************************************************************/ diff --git a/src/mutex_pool.c b/src/mutex_pool.c index 004d6d0f..95a45736 100644 --- a/src/mutex_pool.c +++ b/src/mutex_pool.c @@ -3,6 +3,8 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/mutex.h" + bool mutex_pool_init(mutex_pool_t *pool, const char *name, witness_rank_t rank) { for (int i = 0; i < MUTEX_POOL_SIZE; ++i) { diff --git a/src/prof.c b/src/prof.c index 18978810..639e5983 100644 --- a/src/prof.c +++ b/src/prof.c @@ -6,6 +6,7 @@ #include "jemalloc/internal/ckh.h" #include "jemalloc/internal/hash.h" #include "jemalloc/internal/malloc_io.h" +#include "jemalloc/internal/mutex.h" /******************************************************************************/ diff --git a/src/rtree.c b/src/rtree.c index 637853c7..53702cf7 100644 --- a/src/rtree.c +++ b/src/rtree.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/mutex.h" /* * Only the most significant bits of keys passed to rtree_{read,write}() are diff --git a/src/stats.c b/src/stats.c index fd108162..b67d46dc 100644 --- a/src/stats.c +++ b/src/stats.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/ctl.h" +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/mutex_prof.h" const char *global_mutex_names[mutex_prof_num_global_mutexes] = { diff --git a/src/tcache.c b/src/tcache.c index 4bb2fb86..96ebe677 100644 --- a/src/tcache.c +++ b/src/tcache.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/mutex.h" #include "jemalloc/internal/size_classes.h" /******************************************************************************/ diff --git a/src/tsd.c b/src/tsd.c index 801d8127..525432b6 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/mutex.h" /******************************************************************************/ /* Data. */ @@ -23,6 +24,17 @@ DWORD tsd_tsd; tsd_wrapper_t tsd_boot_wrapper = {false, TSD_INITIALIZER}; bool tsd_booted = false; #else + +/* + * This contains a mutex, but it's pretty convenient to allow the mutex code to + * have a dependency on tsd. So we define the struct here, and only refer to it + * by pointer in the header. + */ +struct tsd_init_head_s { + ql_head(tsd_init_block_t) blocks; + malloc_mutex_t lock; +}; + pthread_key_t tsd_tsd; tsd_init_head_t tsd_init_head = { ql_head_initializer(blocks), -- GitLab From 67c93c332aa5597e1331e20ac06dcfda74e60574 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 24 May 2017 11:33:06 -0700 Subject: [PATCH 497/544] Refactor run_tests to increase parallelism. Rather than relying on parallel make to build individual configurations one at a time, use xargs to build multiple configurations in parallel. This allows the configure scripts to run in parallel. On a 14-core system (28 hyperthreads), this increases average CPU utilization from ~20% to ~90%. --- scripts/gen_run_tests.py | 58 +++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/scripts/gen_run_tests.py b/scripts/gen_run_tests.py index 875c6d03..f9b00604 100755 --- a/scripts/gen_run_tests.py +++ b/scripts/gen_run_tests.py @@ -1,6 +1,12 @@ #!/usr/bin/env python from itertools import combinations +from os import uname +from multiprocessing import cpu_count + +nparallel = cpu_count() * 2 + +uname = uname()[0] def powerset(items): result = [] @@ -8,8 +14,6 @@ def powerset(items): result += combinations(items, i) return result -MAKE_J_VAL = 32 - possible_compilers = [('gcc', 'g++'), ('clang', 'clang++')] possible_compiler_opts = [ '-m32', @@ -28,8 +32,11 @@ possible_malloc_conf_opts = [ print 'set -e' print 'autoconf' -print 'unamestr=`uname`' +print 'rm -rf run_tests.out' +print 'mkdir run_tests.out' +print 'cd run_tests.out' +ind = 0 for cc, cxx in possible_compilers: for compiler_opts in powerset(possible_compiler_opts): for config_opts in powerset(possible_config_opts): @@ -39,9 +46,10 @@ for cc, cxx in possible_compilers: and '--enable-prof' in config_opts: continue config_line = ( - 'EXTRA_CFLAGS=-Werror EXTRA_CXXFLAGS=-Werror ./configure ' + 'EXTRA_CFLAGS=-Werror EXTRA_CXXFLAGS=-Werror ' + 'CC="{} {}" '.format(cc, " ".join(compiler_opts)) + 'CXX="{} {}" '.format(cxx, " ".join(compiler_opts)) + + '../../configure ' + " ".join(config_opts) + (' --with-malloc-conf=' + ",".join(malloc_conf_opts) if len(malloc_conf_opts) > 0 else '') @@ -52,14 +60,38 @@ for cc, cxx in possible_compilers: # Heap profiling and dss are not supported on OS X. darwin_unsupported = ('--enable-prof' in config_opts or \ 'dss:primary' in malloc_conf_opts) - if linux_supported: - print 'if [[ "$unamestr" = "Linux" ]]; then' - elif darwin_unsupported: - print 'if [[ "$unamestr" != "Darwin" ]]; then' + if uname is 'Linux' and linux_supported \ + or uname is not 'Darwin' \ + or not darwin_unsupported: + print """cat < run_test_%(ind)d.sh +#!/bin/sh + +set -e + +abort() { + echo "==> Error" >> run_test.log + echo "Error; see run_tests.out/run_test_%(ind)d.out/run_test.log" + exit 255 # Special exit code tells xargs to terminate. +} + +# Environment variables are not supported. +run_cmd() { + echo "==> \$@" >> run_test.log + \$@ >> run_test.log 2>&1 || abort +} + +echo "=> run_test_%(ind)d: %(config_line)s" +mkdir run_test_%(ind)d.out +cd run_test_%(ind)d.out + +echo "==> %(config_line)s" >> run_test.log +%(config_line)s >> run_test.log 2>&1 || abort - print config_line - print "make clean" - print "make -j" + str(MAKE_J_VAL) + " check" +run_cmd make all tests +run_cmd make check +run_cmd make distclean +EOF +chmod 755 run_test_%(ind)d.sh""" % {'ind': ind, 'config_line': config_line} + ind += 1 - if linux_supported or darwin_unsupported: - print 'fi' +print 'for i in `seq 0 %(last_ind)d` ; do echo run_test_${i}.sh ; done | xargs -P %(nparallel)d -n 1 sh' % {'last_ind': ind-1, 'nparallel': nparallel} -- GitLab From 1df18d7c83bdb1995c088c85818733f164ed0595 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 24 May 2017 12:44:53 -0700 Subject: [PATCH 498/544] Fix stats.mapped during deallocation. --- src/arena.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arena.c b/src/arena.c index bc8fd28f..fcbd57e1 100644 --- a/src/arena.c +++ b/src/arena.c @@ -968,7 +968,7 @@ arena_decay_stashed(tsdn_t *tsdn, arena_t *arena, arena_stats_add_u64(tsdn, &arena->stats, &decay->stats->purged, npurged); arena_stats_sub_zu(tsdn, &arena->stats, &arena->stats.mapped, - nunmapped); + nunmapped << LG_PAGE); arena_stats_unlock(tsdn, &arena->stats); } -- GitLab From 927239b910310f95aebb1f0ffc6fda53f93c8b7e Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Thu, 25 May 2017 13:33:34 -0700 Subject: [PATCH 499/544] Cleanup smoothstep.sh / .h. h_step_sum was used to compute moving sum. Not in use anymore. --- include/jemalloc/internal/smoothstep.h | 402 ++++++++++++------------ include/jemalloc/internal/smoothstep.sh | 6 +- src/arena.c | 2 +- test/unit/smoothstep.c | 2 +- 4 files changed, 205 insertions(+), 207 deletions(-) diff --git a/include/jemalloc/internal/smoothstep.h b/include/jemalloc/internal/smoothstep.h index 5bca6e8c..2e14430f 100644 --- a/include/jemalloc/internal/smoothstep.h +++ b/include/jemalloc/internal/smoothstep.h @@ -27,206 +27,206 @@ #define SMOOTHSTEP_NSTEPS 200 #define SMOOTHSTEP_BFP 24 #define SMOOTHSTEP \ - /* STEP(step, h, x, y, h_sum) */ \ - STEP( 1, UINT64_C(0x0000000000000014), 0.005, 0.000001240643750, UINT64_C(0x0000000000000014)) \ - STEP( 2, UINT64_C(0x00000000000000a5), 0.010, 0.000009850600000, UINT64_C(0x00000000000000b9)) \ - STEP( 3, UINT64_C(0x0000000000000229), 0.015, 0.000032995181250, UINT64_C(0x00000000000002e2)) \ - STEP( 4, UINT64_C(0x0000000000000516), 0.020, 0.000077619200000, UINT64_C(0x00000000000007f8)) \ - STEP( 5, UINT64_C(0x00000000000009dc), 0.025, 0.000150449218750, UINT64_C(0x00000000000011d4)) \ - STEP( 6, UINT64_C(0x00000000000010e8), 0.030, 0.000257995800000, UINT64_C(0x00000000000022bc)) \ - STEP( 7, UINT64_C(0x0000000000001aa4), 0.035, 0.000406555756250, UINT64_C(0x0000000000003d60)) \ - STEP( 8, UINT64_C(0x0000000000002777), 0.040, 0.000602214400000, UINT64_C(0x00000000000064d7)) \ - STEP( 9, UINT64_C(0x00000000000037c2), 0.045, 0.000850847793750, UINT64_C(0x0000000000009c99)) \ - STEP( 10, UINT64_C(0x0000000000004be6), 0.050, 0.001158125000000, UINT64_C(0x000000000000e87f)) \ - STEP( 11, UINT64_C(0x000000000000643c), 0.055, 0.001529510331250, UINT64_C(0x0000000000014cbb)) \ - STEP( 12, UINT64_C(0x000000000000811f), 0.060, 0.001970265600000, UINT64_C(0x000000000001cdda)) \ - STEP( 13, UINT64_C(0x000000000000a2e2), 0.065, 0.002485452368750, UINT64_C(0x00000000000270bc)) \ - STEP( 14, UINT64_C(0x000000000000c9d8), 0.070, 0.003079934200000, UINT64_C(0x0000000000033a94)) \ - STEP( 15, UINT64_C(0x000000000000f64f), 0.075, 0.003758378906250, UINT64_C(0x00000000000430e3)) \ - STEP( 16, UINT64_C(0x0000000000012891), 0.080, 0.004525260800000, UINT64_C(0x0000000000055974)) \ - STEP( 17, UINT64_C(0x00000000000160e7), 0.085, 0.005384862943750, UINT64_C(0x000000000006ba5b)) \ - STEP( 18, UINT64_C(0x0000000000019f95), 0.090, 0.006341279400000, UINT64_C(0x00000000000859f0)) \ - STEP( 19, UINT64_C(0x000000000001e4dc), 0.095, 0.007398417481250, UINT64_C(0x00000000000a3ecc)) \ - STEP( 20, UINT64_C(0x00000000000230fc), 0.100, 0.008560000000000, UINT64_C(0x00000000000c6fc8)) \ - STEP( 21, UINT64_C(0x0000000000028430), 0.105, 0.009829567518750, UINT64_C(0x00000000000ef3f8)) \ - STEP( 22, UINT64_C(0x000000000002deb0), 0.110, 0.011210480600000, UINT64_C(0x000000000011d2a8)) \ - STEP( 23, UINT64_C(0x00000000000340b1), 0.115, 0.012705922056250, UINT64_C(0x0000000000151359)) \ - STEP( 24, UINT64_C(0x000000000003aa67), 0.120, 0.014318899200000, UINT64_C(0x000000000018bdc0)) \ - STEP( 25, UINT64_C(0x0000000000041c00), 0.125, 0.016052246093750, UINT64_C(0x00000000001cd9c0)) \ - STEP( 26, UINT64_C(0x00000000000495a8), 0.130, 0.017908625800000, UINT64_C(0x0000000000216f68)) \ - STEP( 27, UINT64_C(0x000000000005178b), 0.135, 0.019890532631250, UINT64_C(0x00000000002686f3)) \ - STEP( 28, UINT64_C(0x000000000005a1cf), 0.140, 0.022000294400000, UINT64_C(0x00000000002c28c2)) \ - STEP( 29, UINT64_C(0x0000000000063498), 0.145, 0.024240074668750, UINT64_C(0x0000000000325d5a)) \ - STEP( 30, UINT64_C(0x000000000006d009), 0.150, 0.026611875000000, UINT64_C(0x0000000000392d63)) \ - STEP( 31, UINT64_C(0x000000000007743f), 0.155, 0.029117537206250, UINT64_C(0x000000000040a1a2)) \ - STEP( 32, UINT64_C(0x0000000000082157), 0.160, 0.031758745600000, UINT64_C(0x000000000048c2f9)) \ - STEP( 33, UINT64_C(0x000000000008d76b), 0.165, 0.034537029243750, UINT64_C(0x0000000000519a64)) \ - STEP( 34, UINT64_C(0x0000000000099691), 0.170, 0.037453764200000, UINT64_C(0x00000000005b30f5)) \ - STEP( 35, UINT64_C(0x00000000000a5edf), 0.175, 0.040510175781250, UINT64_C(0x0000000000658fd4)) \ - STEP( 36, UINT64_C(0x00000000000b3067), 0.180, 0.043707340800000, UINT64_C(0x000000000070c03b)) \ - STEP( 37, UINT64_C(0x00000000000c0b38), 0.185, 0.047046189818750, UINT64_C(0x00000000007ccb73)) \ - STEP( 38, UINT64_C(0x00000000000cef5e), 0.190, 0.050527509400000, UINT64_C(0x000000000089bad1)) \ - STEP( 39, UINT64_C(0x00000000000ddce6), 0.195, 0.054151944356250, UINT64_C(0x00000000009797b7)) \ - STEP( 40, UINT64_C(0x00000000000ed3d8), 0.200, 0.057920000000000, UINT64_C(0x0000000000a66b8f)) \ - STEP( 41, UINT64_C(0x00000000000fd439), 0.205, 0.061832044393750, UINT64_C(0x0000000000b63fc8)) \ - STEP( 42, UINT64_C(0x000000000010de0e), 0.210, 0.065888310600000, UINT64_C(0x0000000000c71dd6)) \ - STEP( 43, UINT64_C(0x000000000011f158), 0.215, 0.070088898931250, UINT64_C(0x0000000000d90f2e)) \ - STEP( 44, UINT64_C(0x0000000000130e17), 0.220, 0.074433779200000, UINT64_C(0x0000000000ec1d45)) \ - STEP( 45, UINT64_C(0x0000000000143448), 0.225, 0.078922792968750, UINT64_C(0x000000000100518d)) \ - STEP( 46, UINT64_C(0x00000000001563e7), 0.230, 0.083555655800000, UINT64_C(0x000000000115b574)) \ - STEP( 47, UINT64_C(0x0000000000169cec), 0.235, 0.088331959506250, UINT64_C(0x00000000012c5260)) \ - STEP( 48, UINT64_C(0x000000000017df4f), 0.240, 0.093251174400000, UINT64_C(0x00000000014431af)) \ - STEP( 49, UINT64_C(0x0000000000192b04), 0.245, 0.098312651543750, UINT64_C(0x00000000015d5cb3)) \ - STEP( 50, UINT64_C(0x00000000001a8000), 0.250, 0.103515625000000, UINT64_C(0x000000000177dcb3)) \ - STEP( 51, UINT64_C(0x00000000001bde32), 0.255, 0.108859214081250, UINT64_C(0x000000000193bae5)) \ - STEP( 52, UINT64_C(0x00000000001d458b), 0.260, 0.114342425600000, UINT64_C(0x0000000001b10070)) \ - STEP( 53, UINT64_C(0x00000000001eb5f8), 0.265, 0.119964156118750, UINT64_C(0x0000000001cfb668)) \ - STEP( 54, UINT64_C(0x0000000000202f65), 0.270, 0.125723194200000, UINT64_C(0x0000000001efe5cd)) \ - STEP( 55, UINT64_C(0x000000000021b1bb), 0.275, 0.131618222656250, UINT64_C(0x0000000002119788)) \ - STEP( 56, UINT64_C(0x0000000000233ce3), 0.280, 0.137647820800000, UINT64_C(0x000000000234d46b)) \ - STEP( 57, UINT64_C(0x000000000024d0c3), 0.285, 0.143810466693750, UINT64_C(0x000000000259a52e)) \ - STEP( 58, UINT64_C(0x0000000000266d40), 0.290, 0.150104539400000, UINT64_C(0x000000000280126e)) \ - STEP( 59, UINT64_C(0x000000000028123d), 0.295, 0.156528321231250, UINT64_C(0x0000000002a824ab)) \ - STEP( 60, UINT64_C(0x000000000029bf9c), 0.300, 0.163080000000000, UINT64_C(0x0000000002d1e447)) \ - STEP( 61, UINT64_C(0x00000000002b753d), 0.305, 0.169757671268750, UINT64_C(0x0000000002fd5984)) \ - STEP( 62, UINT64_C(0x00000000002d32fe), 0.310, 0.176559340600000, UINT64_C(0x00000000032a8c82)) \ - STEP( 63, UINT64_C(0x00000000002ef8bc), 0.315, 0.183482925806250, UINT64_C(0x000000000359853e)) \ - STEP( 64, UINT64_C(0x000000000030c654), 0.320, 0.190526259200000, UINT64_C(0x00000000038a4b92)) \ - STEP( 65, UINT64_C(0x0000000000329b9f), 0.325, 0.197687089843750, UINT64_C(0x0000000003bce731)) \ - STEP( 66, UINT64_C(0x0000000000347875), 0.330, 0.204963085800000, UINT64_C(0x0000000003f15fa6)) \ - STEP( 67, UINT64_C(0x0000000000365cb0), 0.335, 0.212351836381250, UINT64_C(0x000000000427bc56)) \ - STEP( 68, UINT64_C(0x0000000000384825), 0.340, 0.219850854400000, UINT64_C(0x000000000460047b)) \ - STEP( 69, UINT64_C(0x00000000003a3aa8), 0.345, 0.227457578418750, UINT64_C(0x00000000049a3f23)) \ - STEP( 70, UINT64_C(0x00000000003c340f), 0.350, 0.235169375000000, UINT64_C(0x0000000004d67332)) \ - STEP( 71, UINT64_C(0x00000000003e342b), 0.355, 0.242983540956250, UINT64_C(0x000000000514a75d)) \ - STEP( 72, UINT64_C(0x0000000000403ace), 0.360, 0.250897305600000, UINT64_C(0x000000000554e22b)) \ - STEP( 73, UINT64_C(0x00000000004247c8), 0.365, 0.258907832993750, UINT64_C(0x00000000059729f3)) \ - STEP( 74, UINT64_C(0x0000000000445ae9), 0.370, 0.267012224200000, UINT64_C(0x0000000005db84dc)) \ - STEP( 75, UINT64_C(0x0000000000467400), 0.375, 0.275207519531250, UINT64_C(0x000000000621f8dc)) \ - STEP( 76, UINT64_C(0x00000000004892d8), 0.380, 0.283490700800000, UINT64_C(0x00000000066a8bb4)) \ - STEP( 77, UINT64_C(0x00000000004ab740), 0.385, 0.291858693568750, UINT64_C(0x0000000006b542f4)) \ - STEP( 78, UINT64_C(0x00000000004ce102), 0.390, 0.300308369400000, UINT64_C(0x00000000070223f6)) \ - STEP( 79, UINT64_C(0x00000000004f0fe9), 0.395, 0.308836548106250, UINT64_C(0x00000000075133df)) \ - STEP( 80, UINT64_C(0x00000000005143bf), 0.400, 0.317440000000000, UINT64_C(0x0000000007a2779e)) \ - STEP( 81, UINT64_C(0x0000000000537c4d), 0.405, 0.326115448143750, UINT64_C(0x0000000007f5f3eb)) \ - STEP( 82, UINT64_C(0x000000000055b95b), 0.410, 0.334859570600000, UINT64_C(0x00000000084bad46)) \ - STEP( 83, UINT64_C(0x000000000057fab1), 0.415, 0.343669002681250, UINT64_C(0x0000000008a3a7f7)) \ - STEP( 84, UINT64_C(0x00000000005a4015), 0.420, 0.352540339200000, UINT64_C(0x0000000008fde80c)) \ - STEP( 85, UINT64_C(0x00000000005c894e), 0.425, 0.361470136718750, UINT64_C(0x00000000095a715a)) \ - STEP( 86, UINT64_C(0x00000000005ed622), 0.430, 0.370454915800000, UINT64_C(0x0000000009b9477c)) \ - STEP( 87, UINT64_C(0x0000000000612655), 0.435, 0.379491163256250, UINT64_C(0x000000000a1a6dd1)) \ - STEP( 88, UINT64_C(0x00000000006379ac), 0.440, 0.388575334400000, UINT64_C(0x000000000a7de77d)) \ - STEP( 89, UINT64_C(0x000000000065cfeb), 0.445, 0.397703855293750, UINT64_C(0x000000000ae3b768)) \ - STEP( 90, UINT64_C(0x00000000006828d6), 0.450, 0.406873125000000, UINT64_C(0x000000000b4be03e)) \ - STEP( 91, UINT64_C(0x00000000006a842f), 0.455, 0.416079517831250, UINT64_C(0x000000000bb6646d)) \ - STEP( 92, UINT64_C(0x00000000006ce1bb), 0.460, 0.425319385600000, UINT64_C(0x000000000c234628)) \ - STEP( 93, UINT64_C(0x00000000006f413a), 0.465, 0.434589059868750, UINT64_C(0x000000000c928762)) \ - STEP( 94, UINT64_C(0x000000000071a270), 0.470, 0.443884854200000, UINT64_C(0x000000000d0429d2)) \ - STEP( 95, UINT64_C(0x000000000074051d), 0.475, 0.453203066406250, UINT64_C(0x000000000d782eef)) \ - STEP( 96, UINT64_C(0x0000000000766905), 0.480, 0.462539980800000, UINT64_C(0x000000000dee97f4)) \ - STEP( 97, UINT64_C(0x000000000078cde7), 0.485, 0.471891870443750, UINT64_C(0x000000000e6765db)) \ - STEP( 98, UINT64_C(0x00000000007b3387), 0.490, 0.481254999400000, UINT64_C(0x000000000ee29962)) \ - STEP( 99, UINT64_C(0x00000000007d99a4), 0.495, 0.490625624981250, UINT64_C(0x000000000f603306)) \ - STEP( 100, UINT64_C(0x0000000000800000), 0.500, 0.500000000000000, UINT64_C(0x000000000fe03306)) \ - STEP( 101, UINT64_C(0x000000000082665b), 0.505, 0.509374375018750, UINT64_C(0x0000000010629961)) \ - STEP( 102, UINT64_C(0x000000000084cc78), 0.510, 0.518745000600000, UINT64_C(0x0000000010e765d9)) \ - STEP( 103, UINT64_C(0x0000000000873218), 0.515, 0.528108129556250, UINT64_C(0x00000000116e97f1)) \ - STEP( 104, UINT64_C(0x00000000008996fa), 0.520, 0.537460019200000, UINT64_C(0x0000000011f82eeb)) \ - STEP( 105, UINT64_C(0x00000000008bfae2), 0.525, 0.546796933593750, UINT64_C(0x00000000128429cd)) \ - STEP( 106, UINT64_C(0x00000000008e5d8f), 0.530, 0.556115145800000, UINT64_C(0x000000001312875c)) \ - STEP( 107, UINT64_C(0x000000000090bec5), 0.535, 0.565410940131250, UINT64_C(0x0000000013a34621)) \ - STEP( 108, UINT64_C(0x0000000000931e44), 0.540, 0.574680614400000, UINT64_C(0x0000000014366465)) \ - STEP( 109, UINT64_C(0x0000000000957bd0), 0.545, 0.583920482168750, UINT64_C(0x0000000014cbe035)) \ - STEP( 110, UINT64_C(0x000000000097d729), 0.550, 0.593126875000000, UINT64_C(0x000000001563b75e)) \ - STEP( 111, UINT64_C(0x00000000009a3014), 0.555, 0.602296144706250, UINT64_C(0x0000000015fde772)) \ - STEP( 112, UINT64_C(0x00000000009c8653), 0.560, 0.611424665600000, UINT64_C(0x00000000169a6dc5)) \ - STEP( 113, UINT64_C(0x00000000009ed9aa), 0.565, 0.620508836743750, UINT64_C(0x000000001739476f)) \ - STEP( 114, UINT64_C(0x0000000000a129dd), 0.570, 0.629545084200000, UINT64_C(0x0000000017da714c)) \ - STEP( 115, UINT64_C(0x0000000000a376b1), 0.575, 0.638529863281250, UINT64_C(0x00000000187de7fd)) \ - STEP( 116, UINT64_C(0x0000000000a5bfea), 0.580, 0.647459660800000, UINT64_C(0x000000001923a7e7)) \ - STEP( 117, UINT64_C(0x0000000000a8054e), 0.585, 0.656330997318750, UINT64_C(0x0000000019cbad35)) \ - STEP( 118, UINT64_C(0x0000000000aa46a4), 0.590, 0.665140429400000, UINT64_C(0x000000001a75f3d9)) \ - STEP( 119, UINT64_C(0x0000000000ac83b2), 0.595, 0.673884551856250, UINT64_C(0x000000001b22778b)) \ - STEP( 120, UINT64_C(0x0000000000aebc40), 0.600, 0.682560000000000, UINT64_C(0x000000001bd133cb)) \ - STEP( 121, UINT64_C(0x0000000000b0f016), 0.605, 0.691163451893750, UINT64_C(0x000000001c8223e1)) \ - STEP( 122, UINT64_C(0x0000000000b31efd), 0.610, 0.699691630600000, UINT64_C(0x000000001d3542de)) \ - STEP( 123, UINT64_C(0x0000000000b548bf), 0.615, 0.708141306431250, UINT64_C(0x000000001dea8b9d)) \ - STEP( 124, UINT64_C(0x0000000000b76d27), 0.620, 0.716509299200000, UINT64_C(0x000000001ea1f8c4)) \ - STEP( 125, UINT64_C(0x0000000000b98c00), 0.625, 0.724792480468750, UINT64_C(0x000000001f5b84c4)) \ - STEP( 126, UINT64_C(0x0000000000bba516), 0.630, 0.732987775800000, UINT64_C(0x00000000201729da)) \ - STEP( 127, UINT64_C(0x0000000000bdb837), 0.635, 0.741092167006250, UINT64_C(0x0000000020d4e211)) \ - STEP( 128, UINT64_C(0x0000000000bfc531), 0.640, 0.749102694400000, UINT64_C(0x000000002194a742)) \ - STEP( 129, UINT64_C(0x0000000000c1cbd4), 0.645, 0.757016459043750, UINT64_C(0x0000000022567316)) \ - STEP( 130, UINT64_C(0x0000000000c3cbf0), 0.650, 0.764830625000000, UINT64_C(0x00000000231a3f06)) \ - STEP( 131, UINT64_C(0x0000000000c5c557), 0.655, 0.772542421581250, UINT64_C(0x0000000023e0045d)) \ - STEP( 132, UINT64_C(0x0000000000c7b7da), 0.660, 0.780149145600000, UINT64_C(0x0000000024a7bc37)) \ - STEP( 133, UINT64_C(0x0000000000c9a34f), 0.665, 0.787648163618750, UINT64_C(0x0000000025715f86)) \ - STEP( 134, UINT64_C(0x0000000000cb878a), 0.670, 0.795036914200000, UINT64_C(0x00000000263ce710)) \ - STEP( 135, UINT64_C(0x0000000000cd6460), 0.675, 0.802312910156250, UINT64_C(0x00000000270a4b70)) \ - STEP( 136, UINT64_C(0x0000000000cf39ab), 0.680, 0.809473740800000, UINT64_C(0x0000000027d9851b)) \ - STEP( 137, UINT64_C(0x0000000000d10743), 0.685, 0.816517074193750, UINT64_C(0x0000000028aa8c5e)) \ - STEP( 138, UINT64_C(0x0000000000d2cd01), 0.690, 0.823440659400000, UINT64_C(0x00000000297d595f)) \ - STEP( 139, UINT64_C(0x0000000000d48ac2), 0.695, 0.830242328731250, UINT64_C(0x000000002a51e421)) \ - STEP( 140, UINT64_C(0x0000000000d64063), 0.700, 0.836920000000000, UINT64_C(0x000000002b282484)) \ - STEP( 141, UINT64_C(0x0000000000d7edc2), 0.705, 0.843471678768750, UINT64_C(0x000000002c001246)) \ - STEP( 142, UINT64_C(0x0000000000d992bf), 0.710, 0.849895460600000, UINT64_C(0x000000002cd9a505)) \ - STEP( 143, UINT64_C(0x0000000000db2f3c), 0.715, 0.856189533306250, UINT64_C(0x000000002db4d441)) \ - STEP( 144, UINT64_C(0x0000000000dcc31c), 0.720, 0.862352179200000, UINT64_C(0x000000002e91975d)) \ - STEP( 145, UINT64_C(0x0000000000de4e44), 0.725, 0.868381777343750, UINT64_C(0x000000002f6fe5a1)) \ - STEP( 146, UINT64_C(0x0000000000dfd09a), 0.730, 0.874276805800000, UINT64_C(0x00000000304fb63b)) \ - STEP( 147, UINT64_C(0x0000000000e14a07), 0.735, 0.880035843881250, UINT64_C(0x0000000031310042)) \ - STEP( 148, UINT64_C(0x0000000000e2ba74), 0.740, 0.885657574400000, UINT64_C(0x000000003213bab6)) \ - STEP( 149, UINT64_C(0x0000000000e421cd), 0.745, 0.891140785918750, UINT64_C(0x0000000032f7dc83)) \ - STEP( 150, UINT64_C(0x0000000000e58000), 0.750, 0.896484375000000, UINT64_C(0x0000000033dd5c83)) \ - STEP( 151, UINT64_C(0x0000000000e6d4fb), 0.755, 0.901687348456250, UINT64_C(0x0000000034c4317e)) \ - STEP( 152, UINT64_C(0x0000000000e820b0), 0.760, 0.906748825600000, UINT64_C(0x0000000035ac522e)) \ - STEP( 153, UINT64_C(0x0000000000e96313), 0.765, 0.911668040493750, UINT64_C(0x000000003695b541)) \ - STEP( 154, UINT64_C(0x0000000000ea9c18), 0.770, 0.916444344200000, UINT64_C(0x0000000037805159)) \ - STEP( 155, UINT64_C(0x0000000000ebcbb7), 0.775, 0.921077207031250, UINT64_C(0x00000000386c1d10)) \ - STEP( 156, UINT64_C(0x0000000000ecf1e8), 0.780, 0.925566220800000, UINT64_C(0x0000000039590ef8)) \ - STEP( 157, UINT64_C(0x0000000000ee0ea7), 0.785, 0.929911101068750, UINT64_C(0x000000003a471d9f)) \ - STEP( 158, UINT64_C(0x0000000000ef21f1), 0.790, 0.934111689400000, UINT64_C(0x000000003b363f90)) \ - STEP( 159, UINT64_C(0x0000000000f02bc6), 0.795, 0.938167955606250, UINT64_C(0x000000003c266b56)) \ - STEP( 160, UINT64_C(0x0000000000f12c27), 0.800, 0.942080000000000, UINT64_C(0x000000003d17977d)) \ - STEP( 161, UINT64_C(0x0000000000f22319), 0.805, 0.945848055643750, UINT64_C(0x000000003e09ba96)) \ - STEP( 162, UINT64_C(0x0000000000f310a1), 0.810, 0.949472490600000, UINT64_C(0x000000003efccb37)) \ - STEP( 163, UINT64_C(0x0000000000f3f4c7), 0.815, 0.952953810181250, UINT64_C(0x000000003ff0bffe)) \ - STEP( 164, UINT64_C(0x0000000000f4cf98), 0.820, 0.956292659200000, UINT64_C(0x0000000040e58f96)) \ - STEP( 165, UINT64_C(0x0000000000f5a120), 0.825, 0.959489824218750, UINT64_C(0x0000000041db30b6)) \ - STEP( 166, UINT64_C(0x0000000000f6696e), 0.830, 0.962546235800000, UINT64_C(0x0000000042d19a24)) \ - STEP( 167, UINT64_C(0x0000000000f72894), 0.835, 0.965462970756250, UINT64_C(0x0000000043c8c2b8)) \ - STEP( 168, UINT64_C(0x0000000000f7dea8), 0.840, 0.968241254400000, UINT64_C(0x0000000044c0a160)) \ - STEP( 169, UINT64_C(0x0000000000f88bc0), 0.845, 0.970882462793750, UINT64_C(0x0000000045b92d20)) \ - STEP( 170, UINT64_C(0x0000000000f92ff6), 0.850, 0.973388125000000, UINT64_C(0x0000000046b25d16)) \ - STEP( 171, UINT64_C(0x0000000000f9cb67), 0.855, 0.975759925331250, UINT64_C(0x0000000047ac287d)) \ - STEP( 172, UINT64_C(0x0000000000fa5e30), 0.860, 0.977999705600000, UINT64_C(0x0000000048a686ad)) \ - STEP( 173, UINT64_C(0x0000000000fae874), 0.865, 0.980109467368750, UINT64_C(0x0000000049a16f21)) \ - STEP( 174, UINT64_C(0x0000000000fb6a57), 0.870, 0.982091374200000, UINT64_C(0x000000004a9cd978)) \ - STEP( 175, UINT64_C(0x0000000000fbe400), 0.875, 0.983947753906250, UINT64_C(0x000000004b98bd78)) \ - STEP( 176, UINT64_C(0x0000000000fc5598), 0.880, 0.985681100800000, UINT64_C(0x000000004c951310)) \ - STEP( 177, UINT64_C(0x0000000000fcbf4e), 0.885, 0.987294077943750, UINT64_C(0x000000004d91d25e)) \ - STEP( 178, UINT64_C(0x0000000000fd214f), 0.890, 0.988789519400000, UINT64_C(0x000000004e8ef3ad)) \ - STEP( 179, UINT64_C(0x0000000000fd7bcf), 0.895, 0.990170432481250, UINT64_C(0x000000004f8c6f7c)) \ - STEP( 180, UINT64_C(0x0000000000fdcf03), 0.900, 0.991440000000000, UINT64_C(0x00000000508a3e7f)) \ - STEP( 181, UINT64_C(0x0000000000fe1b23), 0.905, 0.992601582518750, UINT64_C(0x00000000518859a2)) \ - STEP( 182, UINT64_C(0x0000000000fe606a), 0.910, 0.993658720600000, UINT64_C(0x000000005286ba0c)) \ - STEP( 183, UINT64_C(0x0000000000fe9f18), 0.915, 0.994615137056250, UINT64_C(0x0000000053855924)) \ - STEP( 184, UINT64_C(0x0000000000fed76e), 0.920, 0.995474739200000, UINT64_C(0x0000000054843092)) \ - STEP( 185, UINT64_C(0x0000000000ff09b0), 0.925, 0.996241621093750, UINT64_C(0x0000000055833a42)) \ - STEP( 186, UINT64_C(0x0000000000ff3627), 0.930, 0.996920065800000, UINT64_C(0x0000000056827069)) \ - STEP( 187, UINT64_C(0x0000000000ff5d1d), 0.935, 0.997514547631250, UINT64_C(0x000000005781cd86)) \ - STEP( 188, UINT64_C(0x0000000000ff7ee0), 0.940, 0.998029734400000, UINT64_C(0x0000000058814c66)) \ - STEP( 189, UINT64_C(0x0000000000ff9bc3), 0.945, 0.998470489668750, UINT64_C(0x000000005980e829)) \ - STEP( 190, UINT64_C(0x0000000000ffb419), 0.950, 0.998841875000000, UINT64_C(0x000000005a809c42)) \ - STEP( 191, UINT64_C(0x0000000000ffc83d), 0.955, 0.999149152206250, UINT64_C(0x000000005b80647f)) \ - STEP( 192, UINT64_C(0x0000000000ffd888), 0.960, 0.999397785600000, UINT64_C(0x000000005c803d07)) \ - STEP( 193, UINT64_C(0x0000000000ffe55b), 0.965, 0.999593444243750, UINT64_C(0x000000005d802262)) \ - STEP( 194, UINT64_C(0x0000000000ffef17), 0.970, 0.999742004200000, UINT64_C(0x000000005e801179)) \ - STEP( 195, UINT64_C(0x0000000000fff623), 0.975, 0.999849550781250, UINT64_C(0x000000005f80079c)) \ - STEP( 196, UINT64_C(0x0000000000fffae9), 0.980, 0.999922380800000, UINT64_C(0x0000000060800285)) \ - STEP( 197, UINT64_C(0x0000000000fffdd6), 0.985, 0.999967004818750, UINT64_C(0x000000006180005b)) \ - STEP( 198, UINT64_C(0x0000000000ffff5a), 0.990, 0.999990149400000, UINT64_C(0x00000000627fffb5)) \ - STEP( 199, UINT64_C(0x0000000000ffffeb), 0.995, 0.999998759356250, UINT64_C(0x00000000637fffa0)) \ - STEP( 200, UINT64_C(0x0000000001000000), 1.000, 1.000000000000000, UINT64_C(0x00000000647fffa0)) \ + /* STEP(step, h, x, y) */ \ + STEP( 1, UINT64_C(0x0000000000000014), 0.005, 0.000001240643750) \ + STEP( 2, UINT64_C(0x00000000000000a5), 0.010, 0.000009850600000) \ + STEP( 3, UINT64_C(0x0000000000000229), 0.015, 0.000032995181250) \ + STEP( 4, UINT64_C(0x0000000000000516), 0.020, 0.000077619200000) \ + STEP( 5, UINT64_C(0x00000000000009dc), 0.025, 0.000150449218750) \ + STEP( 6, UINT64_C(0x00000000000010e8), 0.030, 0.000257995800000) \ + STEP( 7, UINT64_C(0x0000000000001aa4), 0.035, 0.000406555756250) \ + STEP( 8, UINT64_C(0x0000000000002777), 0.040, 0.000602214400000) \ + STEP( 9, UINT64_C(0x00000000000037c2), 0.045, 0.000850847793750) \ + STEP( 10, UINT64_C(0x0000000000004be6), 0.050, 0.001158125000000) \ + STEP( 11, UINT64_C(0x000000000000643c), 0.055, 0.001529510331250) \ + STEP( 12, UINT64_C(0x000000000000811f), 0.060, 0.001970265600000) \ + STEP( 13, UINT64_C(0x000000000000a2e2), 0.065, 0.002485452368750) \ + STEP( 14, UINT64_C(0x000000000000c9d8), 0.070, 0.003079934200000) \ + STEP( 15, UINT64_C(0x000000000000f64f), 0.075, 0.003758378906250) \ + STEP( 16, UINT64_C(0x0000000000012891), 0.080, 0.004525260800000) \ + STEP( 17, UINT64_C(0x00000000000160e7), 0.085, 0.005384862943750) \ + STEP( 18, UINT64_C(0x0000000000019f95), 0.090, 0.006341279400000) \ + STEP( 19, UINT64_C(0x000000000001e4dc), 0.095, 0.007398417481250) \ + STEP( 20, UINT64_C(0x00000000000230fc), 0.100, 0.008560000000000) \ + STEP( 21, UINT64_C(0x0000000000028430), 0.105, 0.009829567518750) \ + STEP( 22, UINT64_C(0x000000000002deb0), 0.110, 0.011210480600000) \ + STEP( 23, UINT64_C(0x00000000000340b1), 0.115, 0.012705922056250) \ + STEP( 24, UINT64_C(0x000000000003aa67), 0.120, 0.014318899200000) \ + STEP( 25, UINT64_C(0x0000000000041c00), 0.125, 0.016052246093750) \ + STEP( 26, UINT64_C(0x00000000000495a8), 0.130, 0.017908625800000) \ + STEP( 27, UINT64_C(0x000000000005178b), 0.135, 0.019890532631250) \ + STEP( 28, UINT64_C(0x000000000005a1cf), 0.140, 0.022000294400000) \ + STEP( 29, UINT64_C(0x0000000000063498), 0.145, 0.024240074668750) \ + STEP( 30, UINT64_C(0x000000000006d009), 0.150, 0.026611875000000) \ + STEP( 31, UINT64_C(0x000000000007743f), 0.155, 0.029117537206250) \ + STEP( 32, UINT64_C(0x0000000000082157), 0.160, 0.031758745600000) \ + STEP( 33, UINT64_C(0x000000000008d76b), 0.165, 0.034537029243750) \ + STEP( 34, UINT64_C(0x0000000000099691), 0.170, 0.037453764200000) \ + STEP( 35, UINT64_C(0x00000000000a5edf), 0.175, 0.040510175781250) \ + STEP( 36, UINT64_C(0x00000000000b3067), 0.180, 0.043707340800000) \ + STEP( 37, UINT64_C(0x00000000000c0b38), 0.185, 0.047046189818750) \ + STEP( 38, UINT64_C(0x00000000000cef5e), 0.190, 0.050527509400000) \ + STEP( 39, UINT64_C(0x00000000000ddce6), 0.195, 0.054151944356250) \ + STEP( 40, UINT64_C(0x00000000000ed3d8), 0.200, 0.057920000000000) \ + STEP( 41, UINT64_C(0x00000000000fd439), 0.205, 0.061832044393750) \ + STEP( 42, UINT64_C(0x000000000010de0e), 0.210, 0.065888310600000) \ + STEP( 43, UINT64_C(0x000000000011f158), 0.215, 0.070088898931250) \ + STEP( 44, UINT64_C(0x0000000000130e17), 0.220, 0.074433779200000) \ + STEP( 45, UINT64_C(0x0000000000143448), 0.225, 0.078922792968750) \ + STEP( 46, UINT64_C(0x00000000001563e7), 0.230, 0.083555655800000) \ + STEP( 47, UINT64_C(0x0000000000169cec), 0.235, 0.088331959506250) \ + STEP( 48, UINT64_C(0x000000000017df4f), 0.240, 0.093251174400000) \ + STEP( 49, UINT64_C(0x0000000000192b04), 0.245, 0.098312651543750) \ + STEP( 50, UINT64_C(0x00000000001a8000), 0.250, 0.103515625000000) \ + STEP( 51, UINT64_C(0x00000000001bde32), 0.255, 0.108859214081250) \ + STEP( 52, UINT64_C(0x00000000001d458b), 0.260, 0.114342425600000) \ + STEP( 53, UINT64_C(0x00000000001eb5f8), 0.265, 0.119964156118750) \ + STEP( 54, UINT64_C(0x0000000000202f65), 0.270, 0.125723194200000) \ + STEP( 55, UINT64_C(0x000000000021b1bb), 0.275, 0.131618222656250) \ + STEP( 56, UINT64_C(0x0000000000233ce3), 0.280, 0.137647820800000) \ + STEP( 57, UINT64_C(0x000000000024d0c3), 0.285, 0.143810466693750) \ + STEP( 58, UINT64_C(0x0000000000266d40), 0.290, 0.150104539400000) \ + STEP( 59, UINT64_C(0x000000000028123d), 0.295, 0.156528321231250) \ + STEP( 60, UINT64_C(0x000000000029bf9c), 0.300, 0.163080000000000) \ + STEP( 61, UINT64_C(0x00000000002b753d), 0.305, 0.169757671268750) \ + STEP( 62, UINT64_C(0x00000000002d32fe), 0.310, 0.176559340600000) \ + STEP( 63, UINT64_C(0x00000000002ef8bc), 0.315, 0.183482925806250) \ + STEP( 64, UINT64_C(0x000000000030c654), 0.320, 0.190526259200000) \ + STEP( 65, UINT64_C(0x0000000000329b9f), 0.325, 0.197687089843750) \ + STEP( 66, UINT64_C(0x0000000000347875), 0.330, 0.204963085800000) \ + STEP( 67, UINT64_C(0x0000000000365cb0), 0.335, 0.212351836381250) \ + STEP( 68, UINT64_C(0x0000000000384825), 0.340, 0.219850854400000) \ + STEP( 69, UINT64_C(0x00000000003a3aa8), 0.345, 0.227457578418750) \ + STEP( 70, UINT64_C(0x00000000003c340f), 0.350, 0.235169375000000) \ + STEP( 71, UINT64_C(0x00000000003e342b), 0.355, 0.242983540956250) \ + STEP( 72, UINT64_C(0x0000000000403ace), 0.360, 0.250897305600000) \ + STEP( 73, UINT64_C(0x00000000004247c8), 0.365, 0.258907832993750) \ + STEP( 74, UINT64_C(0x0000000000445ae9), 0.370, 0.267012224200000) \ + STEP( 75, UINT64_C(0x0000000000467400), 0.375, 0.275207519531250) \ + STEP( 76, UINT64_C(0x00000000004892d8), 0.380, 0.283490700800000) \ + STEP( 77, UINT64_C(0x00000000004ab740), 0.385, 0.291858693568750) \ + STEP( 78, UINT64_C(0x00000000004ce102), 0.390, 0.300308369400000) \ + STEP( 79, UINT64_C(0x00000000004f0fe9), 0.395, 0.308836548106250) \ + STEP( 80, UINT64_C(0x00000000005143bf), 0.400, 0.317440000000000) \ + STEP( 81, UINT64_C(0x0000000000537c4d), 0.405, 0.326115448143750) \ + STEP( 82, UINT64_C(0x000000000055b95b), 0.410, 0.334859570600000) \ + STEP( 83, UINT64_C(0x000000000057fab1), 0.415, 0.343669002681250) \ + STEP( 84, UINT64_C(0x00000000005a4015), 0.420, 0.352540339200000) \ + STEP( 85, UINT64_C(0x00000000005c894e), 0.425, 0.361470136718750) \ + STEP( 86, UINT64_C(0x00000000005ed622), 0.430, 0.370454915800000) \ + STEP( 87, UINT64_C(0x0000000000612655), 0.435, 0.379491163256250) \ + STEP( 88, UINT64_C(0x00000000006379ac), 0.440, 0.388575334400000) \ + STEP( 89, UINT64_C(0x000000000065cfeb), 0.445, 0.397703855293750) \ + STEP( 90, UINT64_C(0x00000000006828d6), 0.450, 0.406873125000000) \ + STEP( 91, UINT64_C(0x00000000006a842f), 0.455, 0.416079517831250) \ + STEP( 92, UINT64_C(0x00000000006ce1bb), 0.460, 0.425319385600000) \ + STEP( 93, UINT64_C(0x00000000006f413a), 0.465, 0.434589059868750) \ + STEP( 94, UINT64_C(0x000000000071a270), 0.470, 0.443884854200000) \ + STEP( 95, UINT64_C(0x000000000074051d), 0.475, 0.453203066406250) \ + STEP( 96, UINT64_C(0x0000000000766905), 0.480, 0.462539980800000) \ + STEP( 97, UINT64_C(0x000000000078cde7), 0.485, 0.471891870443750) \ + STEP( 98, UINT64_C(0x00000000007b3387), 0.490, 0.481254999400000) \ + STEP( 99, UINT64_C(0x00000000007d99a4), 0.495, 0.490625624981250) \ + STEP( 100, UINT64_C(0x0000000000800000), 0.500, 0.500000000000000) \ + STEP( 101, UINT64_C(0x000000000082665b), 0.505, 0.509374375018750) \ + STEP( 102, UINT64_C(0x000000000084cc78), 0.510, 0.518745000600000) \ + STEP( 103, UINT64_C(0x0000000000873218), 0.515, 0.528108129556250) \ + STEP( 104, UINT64_C(0x00000000008996fa), 0.520, 0.537460019200000) \ + STEP( 105, UINT64_C(0x00000000008bfae2), 0.525, 0.546796933593750) \ + STEP( 106, UINT64_C(0x00000000008e5d8f), 0.530, 0.556115145800000) \ + STEP( 107, UINT64_C(0x000000000090bec5), 0.535, 0.565410940131250) \ + STEP( 108, UINT64_C(0x0000000000931e44), 0.540, 0.574680614400000) \ + STEP( 109, UINT64_C(0x0000000000957bd0), 0.545, 0.583920482168750) \ + STEP( 110, UINT64_C(0x000000000097d729), 0.550, 0.593126875000000) \ + STEP( 111, UINT64_C(0x00000000009a3014), 0.555, 0.602296144706250) \ + STEP( 112, UINT64_C(0x00000000009c8653), 0.560, 0.611424665600000) \ + STEP( 113, UINT64_C(0x00000000009ed9aa), 0.565, 0.620508836743750) \ + STEP( 114, UINT64_C(0x0000000000a129dd), 0.570, 0.629545084200000) \ + STEP( 115, UINT64_C(0x0000000000a376b1), 0.575, 0.638529863281250) \ + STEP( 116, UINT64_C(0x0000000000a5bfea), 0.580, 0.647459660800000) \ + STEP( 117, UINT64_C(0x0000000000a8054e), 0.585, 0.656330997318750) \ + STEP( 118, UINT64_C(0x0000000000aa46a4), 0.590, 0.665140429400000) \ + STEP( 119, UINT64_C(0x0000000000ac83b2), 0.595, 0.673884551856250) \ + STEP( 120, UINT64_C(0x0000000000aebc40), 0.600, 0.682560000000000) \ + STEP( 121, UINT64_C(0x0000000000b0f016), 0.605, 0.691163451893750) \ + STEP( 122, UINT64_C(0x0000000000b31efd), 0.610, 0.699691630600000) \ + STEP( 123, UINT64_C(0x0000000000b548bf), 0.615, 0.708141306431250) \ + STEP( 124, UINT64_C(0x0000000000b76d27), 0.620, 0.716509299200000) \ + STEP( 125, UINT64_C(0x0000000000b98c00), 0.625, 0.724792480468750) \ + STEP( 126, UINT64_C(0x0000000000bba516), 0.630, 0.732987775800000) \ + STEP( 127, UINT64_C(0x0000000000bdb837), 0.635, 0.741092167006250) \ + STEP( 128, UINT64_C(0x0000000000bfc531), 0.640, 0.749102694400000) \ + STEP( 129, UINT64_C(0x0000000000c1cbd4), 0.645, 0.757016459043750) \ + STEP( 130, UINT64_C(0x0000000000c3cbf0), 0.650, 0.764830625000000) \ + STEP( 131, UINT64_C(0x0000000000c5c557), 0.655, 0.772542421581250) \ + STEP( 132, UINT64_C(0x0000000000c7b7da), 0.660, 0.780149145600000) \ + STEP( 133, UINT64_C(0x0000000000c9a34f), 0.665, 0.787648163618750) \ + STEP( 134, UINT64_C(0x0000000000cb878a), 0.670, 0.795036914200000) \ + STEP( 135, UINT64_C(0x0000000000cd6460), 0.675, 0.802312910156250) \ + STEP( 136, UINT64_C(0x0000000000cf39ab), 0.680, 0.809473740800000) \ + STEP( 137, UINT64_C(0x0000000000d10743), 0.685, 0.816517074193750) \ + STEP( 138, UINT64_C(0x0000000000d2cd01), 0.690, 0.823440659400000) \ + STEP( 139, UINT64_C(0x0000000000d48ac2), 0.695, 0.830242328731250) \ + STEP( 140, UINT64_C(0x0000000000d64063), 0.700, 0.836920000000000) \ + STEP( 141, UINT64_C(0x0000000000d7edc2), 0.705, 0.843471678768750) \ + STEP( 142, UINT64_C(0x0000000000d992bf), 0.710, 0.849895460600000) \ + STEP( 143, UINT64_C(0x0000000000db2f3c), 0.715, 0.856189533306250) \ + STEP( 144, UINT64_C(0x0000000000dcc31c), 0.720, 0.862352179200000) \ + STEP( 145, UINT64_C(0x0000000000de4e44), 0.725, 0.868381777343750) \ + STEP( 146, UINT64_C(0x0000000000dfd09a), 0.730, 0.874276805800000) \ + STEP( 147, UINT64_C(0x0000000000e14a07), 0.735, 0.880035843881250) \ + STEP( 148, UINT64_C(0x0000000000e2ba74), 0.740, 0.885657574400000) \ + STEP( 149, UINT64_C(0x0000000000e421cd), 0.745, 0.891140785918750) \ + STEP( 150, UINT64_C(0x0000000000e58000), 0.750, 0.896484375000000) \ + STEP( 151, UINT64_C(0x0000000000e6d4fb), 0.755, 0.901687348456250) \ + STEP( 152, UINT64_C(0x0000000000e820b0), 0.760, 0.906748825600000) \ + STEP( 153, UINT64_C(0x0000000000e96313), 0.765, 0.911668040493750) \ + STEP( 154, UINT64_C(0x0000000000ea9c18), 0.770, 0.916444344200000) \ + STEP( 155, UINT64_C(0x0000000000ebcbb7), 0.775, 0.921077207031250) \ + STEP( 156, UINT64_C(0x0000000000ecf1e8), 0.780, 0.925566220800000) \ + STEP( 157, UINT64_C(0x0000000000ee0ea7), 0.785, 0.929911101068750) \ + STEP( 158, UINT64_C(0x0000000000ef21f1), 0.790, 0.934111689400000) \ + STEP( 159, UINT64_C(0x0000000000f02bc6), 0.795, 0.938167955606250) \ + STEP( 160, UINT64_C(0x0000000000f12c27), 0.800, 0.942080000000000) \ + STEP( 161, UINT64_C(0x0000000000f22319), 0.805, 0.945848055643750) \ + STEP( 162, UINT64_C(0x0000000000f310a1), 0.810, 0.949472490600000) \ + STEP( 163, UINT64_C(0x0000000000f3f4c7), 0.815, 0.952953810181250) \ + STEP( 164, UINT64_C(0x0000000000f4cf98), 0.820, 0.956292659200000) \ + STEP( 165, UINT64_C(0x0000000000f5a120), 0.825, 0.959489824218750) \ + STEP( 166, UINT64_C(0x0000000000f6696e), 0.830, 0.962546235800000) \ + STEP( 167, UINT64_C(0x0000000000f72894), 0.835, 0.965462970756250) \ + STEP( 168, UINT64_C(0x0000000000f7dea8), 0.840, 0.968241254400000) \ + STEP( 169, UINT64_C(0x0000000000f88bc0), 0.845, 0.970882462793750) \ + STEP( 170, UINT64_C(0x0000000000f92ff6), 0.850, 0.973388125000000) \ + STEP( 171, UINT64_C(0x0000000000f9cb67), 0.855, 0.975759925331250) \ + STEP( 172, UINT64_C(0x0000000000fa5e30), 0.860, 0.977999705600000) \ + STEP( 173, UINT64_C(0x0000000000fae874), 0.865, 0.980109467368750) \ + STEP( 174, UINT64_C(0x0000000000fb6a57), 0.870, 0.982091374200000) \ + STEP( 175, UINT64_C(0x0000000000fbe400), 0.875, 0.983947753906250) \ + STEP( 176, UINT64_C(0x0000000000fc5598), 0.880, 0.985681100800000) \ + STEP( 177, UINT64_C(0x0000000000fcbf4e), 0.885, 0.987294077943750) \ + STEP( 178, UINT64_C(0x0000000000fd214f), 0.890, 0.988789519400000) \ + STEP( 179, UINT64_C(0x0000000000fd7bcf), 0.895, 0.990170432481250) \ + STEP( 180, UINT64_C(0x0000000000fdcf03), 0.900, 0.991440000000000) \ + STEP( 181, UINT64_C(0x0000000000fe1b23), 0.905, 0.992601582518750) \ + STEP( 182, UINT64_C(0x0000000000fe606a), 0.910, 0.993658720600000) \ + STEP( 183, UINT64_C(0x0000000000fe9f18), 0.915, 0.994615137056250) \ + STEP( 184, UINT64_C(0x0000000000fed76e), 0.920, 0.995474739200000) \ + STEP( 185, UINT64_C(0x0000000000ff09b0), 0.925, 0.996241621093750) \ + STEP( 186, UINT64_C(0x0000000000ff3627), 0.930, 0.996920065800000) \ + STEP( 187, UINT64_C(0x0000000000ff5d1d), 0.935, 0.997514547631250) \ + STEP( 188, UINT64_C(0x0000000000ff7ee0), 0.940, 0.998029734400000) \ + STEP( 189, UINT64_C(0x0000000000ff9bc3), 0.945, 0.998470489668750) \ + STEP( 190, UINT64_C(0x0000000000ffb419), 0.950, 0.998841875000000) \ + STEP( 191, UINT64_C(0x0000000000ffc83d), 0.955, 0.999149152206250) \ + STEP( 192, UINT64_C(0x0000000000ffd888), 0.960, 0.999397785600000) \ + STEP( 193, UINT64_C(0x0000000000ffe55b), 0.965, 0.999593444243750) \ + STEP( 194, UINT64_C(0x0000000000ffef17), 0.970, 0.999742004200000) \ + STEP( 195, UINT64_C(0x0000000000fff623), 0.975, 0.999849550781250) \ + STEP( 196, UINT64_C(0x0000000000fffae9), 0.980, 0.999922380800000) \ + STEP( 197, UINT64_C(0x0000000000fffdd6), 0.985, 0.999967004818750) \ + STEP( 198, UINT64_C(0x0000000000ffff5a), 0.990, 0.999990149400000) \ + STEP( 199, UINT64_C(0x0000000000ffffeb), 0.995, 0.999998759356250) \ + STEP( 200, UINT64_C(0x0000000001000000), 1.000, 1.000000000000000) \ #endif /* JEMALLOC_INTERNAL_SMOOTHSTEP_H */ diff --git a/include/jemalloc/internal/smoothstep.sh b/include/jemalloc/internal/smoothstep.sh index 41164615..65de97bf 100755 --- a/include/jemalloc/internal/smoothstep.sh +++ b/include/jemalloc/internal/smoothstep.sh @@ -83,16 +83,14 @@ cat < Date: Fri, 26 May 2017 11:24:08 -0700 Subject: [PATCH 500/544] Fix run_tests to avoid percpu_arena on !Linux. --- scripts/gen_run_tests.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/gen_run_tests.py b/scripts/gen_run_tests.py index f9b00604..1d70057f 100755 --- a/scripts/gen_run_tests.py +++ b/scripts/gen_run_tests.py @@ -60,9 +60,9 @@ for cc, cxx in possible_compilers: # Heap profiling and dss are not supported on OS X. darwin_unsupported = ('--enable-prof' in config_opts or \ 'dss:primary' in malloc_conf_opts) - if uname is 'Linux' and linux_supported \ - or uname is not 'Darwin' \ - or not darwin_unsupported: + if (uname == 'Linux' and linux_supported) \ + or (not linux_supported and (uname != 'Darwin' or \ + not darwin_unsupported)): print """cat < run_test_%(ind)d.sh #!/bin/sh -- GitLab From b86d271cbfc7bdeb077b663a2e526cf19f7c1840 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Thu, 25 May 2017 15:30:11 -0700 Subject: [PATCH 501/544] Added opt_abort_conf: abort on invalid config options. --- doc/jemalloc.xml.in | 20 ++++++++++++- .../internal/jemalloc_internal_externs.h | 29 ++++++++++--------- src/ctl.c | 3 ++ src/jemalloc.c | 18 ++++++++++++ src/stats.c | 1 + 5 files changed, 56 insertions(+), 15 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 16d9ce4e..a45b3587 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -874,7 +874,25 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", r- Abort-on-warning enabled/disabled. If true, most - warnings are fatal. The process will call + warnings are fatal. Note that runtime option warnings are not included + (see opt.abort_conf for + that). The process will call + abort + 3 in these cases. This option is + disabled by default unless is + specified during configuration, in which case it is enabled by default. + + + + + + opt.abort_conf + (bool) + r- + + Abort-on-invalid-configuration enabled/disabled. If + true, invalid runtime options are fatal. The process will call abort 3 in these cases. This option is disabled by default unless is diff --git a/include/jemalloc/internal/jemalloc_internal_externs.h b/include/jemalloc/internal/jemalloc_internal_externs.h index 9a431fc1..11e16ecc 100644 --- a/include/jemalloc/internal/jemalloc_internal_externs.h +++ b/include/jemalloc/internal/jemalloc_internal_externs.h @@ -6,23 +6,24 @@ #include "jemalloc/internal/tsd_types.h" /* TSD checks this to set thread local slow state accordingly. */ -extern bool malloc_slow; +extern bool malloc_slow; /* Run-time options. */ -extern bool opt_abort; -extern const char *opt_junk; -extern bool opt_junk_alloc; -extern bool opt_junk_free; -extern bool opt_utrace; -extern bool opt_xmalloc; -extern bool opt_zero; -extern unsigned opt_narenas; +extern bool opt_abort; +extern bool opt_abort_conf; +extern const char *opt_junk; +extern bool opt_junk_alloc; +extern bool opt_junk_free; +extern bool opt_utrace; +extern bool opt_xmalloc; +extern bool opt_zero; +extern unsigned opt_narenas; /* Number of CPUs. */ -extern unsigned ncpus; +extern unsigned ncpus; /* Number of arenas used for automatic multiplexing of threads and arenas. */ -extern unsigned narenas_auto; +extern unsigned narenas_auto; /* * Arenas that are used to service external requests. Not all elements of the @@ -34,18 +35,18 @@ extern atomic_p_t arenas[]; * pind2sz_tab encodes the same information as could be computed by * pind2sz_compute(). */ -extern size_t const pind2sz_tab[NPSIZES+1]; +extern size_t const pind2sz_tab[NPSIZES+1]; /* * index2size_tab encodes the same information as could be computed (at * unacceptable cost in some code paths) by index2size_compute(). */ -extern size_t const index2size_tab[NSIZES]; +extern size_t const index2size_tab[NSIZES]; /* * size2index_tab is a compact lookup table that rounds request sizes up to * size classes. In order to reduce cache footprint, the table is compressed, * and all accesses are via size2index(). */ -extern uint8_t const size2index_tab[]; +extern uint8_t const size2index_tab[]; void *a0malloc(size_t size); void a0dalloc(void *ptr); diff --git a/src/ctl.c b/src/ctl.c index 30704edd..28f49398 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -76,6 +76,7 @@ CTL_PROTO(config_stats) CTL_PROTO(config_utrace) CTL_PROTO(config_xmalloc) CTL_PROTO(opt_abort) +CTL_PROTO(opt_abort_conf) CTL_PROTO(opt_retain) CTL_PROTO(opt_dss) CTL_PROTO(opt_narenas) @@ -267,6 +268,7 @@ static const ctl_named_node_t config_node[] = { static const ctl_named_node_t opt_node[] = { {NAME("abort"), CTL(opt_abort)}, + {NAME("abort_conf"), CTL(opt_abort_conf)}, {NAME("retain"), CTL(opt_retain)}, {NAME("dss"), CTL(opt_dss)}, {NAME("narenas"), CTL(opt_narenas)}, @@ -1546,6 +1548,7 @@ CTL_RO_CONFIG_GEN(config_xmalloc, bool) /******************************************************************************/ CTL_RO_NL_GEN(opt_abort, opt_abort, bool) +CTL_RO_NL_GEN(opt_abort_conf, opt_abort_conf, bool) CTL_RO_NL_GEN(opt_retain, opt_retain, bool) CTL_RO_NL_GEN(opt_dss, opt_dss, const char *) CTL_RO_NL_GEN(opt_narenas, opt_narenas, unsigned) diff --git a/src/jemalloc.c b/src/jemalloc.c index 517fbb99..dd8365f9 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -23,6 +23,13 @@ const char *je_malloc_conf #endif ; bool opt_abort = +#ifdef JEMALLOC_DEBUG + true +#else + false +#endif + ; +bool opt_abort_conf = #ifdef JEMALLOC_DEBUG true #else @@ -274,6 +281,9 @@ typedef struct { # define UTRACE(a, b, c) #endif +/* Whether encountered any invalid config options. */ +static bool had_conf_error = false; + /******************************************************************************/ /* * Function prototypes for static functions that are referenced prior to @@ -847,6 +857,10 @@ malloc_conf_error(const char *msg, const char *k, size_t klen, const char *v, size_t vlen) { malloc_printf(": %s: %.*s:%.*s\n", msg, (int)klen, k, (int)vlen, v); + had_conf_error = true; + if (opt_abort_conf) { + abort(); + } } static void @@ -1045,6 +1059,10 @@ malloc_conf_init(void) { } CONF_HANDLE_BOOL(opt_abort, "abort") + CONF_HANDLE_BOOL(opt_abort_conf, "abort_conf") + if (opt_abort_conf && had_conf_error) { + abort(); + } CONF_HANDLE_BOOL(opt_retain, "retain") if (strncmp("dss", k, klen) == 0) { int i; diff --git a/src/stats.c b/src/stats.c index b67d46dc..48d3f59b 100644 --- a/src/stats.c +++ b/src/stats.c @@ -813,6 +813,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, "Run-time option settings:\n"); } OPT_WRITE_BOOL(abort, ",") + OPT_WRITE_BOOL(abort_conf, ",") OPT_WRITE_BOOL(retain, ",") OPT_WRITE_CHAR_P(dss, ",") OPT_WRITE_UNSIGNED(narenas, ",") -- GitLab From 49505e558baade576bab40cbd3b9fdaa61ba77d2 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 26 May 2017 13:51:55 -0700 Subject: [PATCH 502/544] Make test/unit/background_thread not flaky. --- test/unit/background_thread.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/unit/background_thread.c b/test/unit/background_thread.c index 05089c28..81f8aeed 100644 --- a/test/unit/background_thread.c +++ b/test/unit/background_thread.c @@ -80,6 +80,8 @@ TEST_BEGIN(test_background_thread_running) { test_repeat_background_thread_ctl(false); test_switch_background_thread_ctl(true); + assert_b_eq(info->started, true, + "Background_thread did not start.\n"); nstime_t start, now; nstime_init(&start, 0); @@ -99,9 +101,9 @@ TEST_BEGIN(test_background_thread_running) { nstime_init(&now, 0); nstime_update(&now); nstime_subtract(&now, &start); - assert_u64_lt(nstime_sec(&now), 10, - "Background threads did not run for 10 seconds."); - usleep(10000); + assert_u64_lt(nstime_sec(&now), 1000, + "Background threads did not run for 1000 seconds."); + sleep(1); } test_switch_background_thread_ctl(false); #endif -- GitLab From d5ef5ae9344d72f39569a05e7c9349dded497e41 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Sat, 27 May 2017 15:35:36 -0700 Subject: [PATCH 503/544] Add opt.stats_print_opts. The value is passed to atexit(3)-triggered malloc_stats_print() calls. --- doc/jemalloc.xml.in | 23 +++++++++++- include/jemalloc/internal/stats.h | 21 ++++++++++- src/ctl.c | 3 ++ src/jemalloc.c | 31 +++++++++++++++- src/stats.c | 61 ++++++++++--------------------- 5 files changed, 94 insertions(+), 45 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index a45b3587..c2c0e925 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -410,6 +410,8 @@ for (i = 0; i < nbins; i++) { /* Do something with bin_size... */ }]]> + + The malloc_stats_print() function writes summary statistics via the write_cb callback function pointer and cbopaque data passed to @@ -1046,7 +1048,9 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", enabled, the malloc_stats_print() function is called at program exit via an atexit - 3 function. If + 3 function. opt.stats_print_opts + can be combined to specify output options. If is specified during configuration, this has the potential to cause deadlock for a multi-threaded process that exits while one or more threads are executing in the memory allocation @@ -1061,6 +1065,23 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", development. This option is disabled by default. + + + opt.stats_print_opts + (const char *) + r- + + Options (the opts string) to pass + to the malloc_stats_print() at exit (enabled + through opt.stats_print). See + available options in malloc_stats_print(). + Has no effect unless opt.stats_print is + enabled. The default is . + + opt.junk diff --git a/include/jemalloc/internal/stats.h b/include/jemalloc/internal/stats.h index 47ca4f9e..1198779a 100644 --- a/include/jemalloc/internal/stats.h +++ b/include/jemalloc/internal/stats.h @@ -7,8 +7,27 @@ #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/stats_tsd.h" -/* The opt.stats_print storage. */ +/* OPTION(opt, var_name, default, set_value_to) */ +#define STATS_PRINT_OPTIONS \ + OPTION('J', json, false, true) \ + OPTION('g', general, true, false) \ + OPTION('m', merged, config_stats, false) \ + OPTION('d', destroyed, config_stats, false) \ + OPTION('a', unmerged, config_stats, false) \ + OPTION('b', bins, true, false) \ + OPTION('l', large, true, false) \ + OPTION('x', mutex, true, false) + +enum { +#define OPTION(o, v, d, s) stats_print_option_num_##v, + STATS_PRINT_OPTIONS +#undef OPTION + stats_print_tot_num_options +}; + +/* Options for stats_print. */ extern bool opt_stats_print; +extern char opt_stats_print_opts[stats_print_tot_num_options+1]; /* Implements je_malloc_stats_print. */ void stats_print(void (*write_cb)(void *, const char *), void *cbopaque, diff --git a/src/ctl.c b/src/ctl.c index 28f49398..d10c39bb 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -85,6 +85,7 @@ CTL_PROTO(opt_background_thread) CTL_PROTO(opt_dirty_decay_ms) CTL_PROTO(opt_muzzy_decay_ms) CTL_PROTO(opt_stats_print) +CTL_PROTO(opt_stats_print_opts) CTL_PROTO(opt_junk) CTL_PROTO(opt_zero) CTL_PROTO(opt_utrace) @@ -277,6 +278,7 @@ static const ctl_named_node_t opt_node[] = { {NAME("dirty_decay_ms"), CTL(opt_dirty_decay_ms)}, {NAME("muzzy_decay_ms"), CTL(opt_muzzy_decay_ms)}, {NAME("stats_print"), CTL(opt_stats_print)}, + {NAME("stats_print_opts"), CTL(opt_stats_print_opts)}, {NAME("junk"), CTL(opt_junk)}, {NAME("zero"), CTL(opt_zero)}, {NAME("utrace"), CTL(opt_utrace)}, @@ -1557,6 +1559,7 @@ CTL_RO_NL_GEN(opt_background_thread, opt_background_thread, bool) CTL_RO_NL_GEN(opt_dirty_decay_ms, opt_dirty_decay_ms, ssize_t) CTL_RO_NL_GEN(opt_muzzy_decay_ms, opt_muzzy_decay_ms, ssize_t) CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool) +CTL_RO_NL_GEN(opt_stats_print_opts, opt_stats_print_opts, const char *) CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *) CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool) CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool) diff --git a/src/jemalloc.c b/src/jemalloc.c index dd8365f9..5e3072b5 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -724,7 +724,7 @@ stats_print_atexit(void) { } } } - je_malloc_stats_print(NULL, NULL, NULL); + je_malloc_stats_print(NULL, NULL, opt_stats_print_opts); } /* @@ -777,6 +777,31 @@ malloc_ncpus(void) { return ((result == -1) ? 1 : (unsigned)result); } +static void +init_opt_stats_print_opts(const char *v, size_t vlen) { + size_t opts_len = strlen(opt_stats_print_opts); + assert(opts_len <= stats_print_tot_num_options); + + for (size_t i = 0; i < vlen; i++) { + switch (v[i]) { +#define OPTION(o, v, d, s) case o: break; + STATS_PRINT_OPTIONS +#undef OPTION + default: continue; + } + + if (strchr(opt_stats_print_opts, v[i]) != NULL) { + /* Ignore repeated. */ + continue; + } + + opt_stats_print_opts[opts_len++] = v[i]; + opt_stats_print_opts[opts_len] = '\0'; + assert(opts_len <= stats_print_tot_num_options); + } + assert(opts_len == strlen(opt_stats_print_opts)); +} + static bool malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p, char const **v_p, size_t *vlen_p) { @@ -1099,6 +1124,10 @@ malloc_conf_init(void) { QU(SSIZE_MAX) ? NSTIME_SEC_MAX * KQU(1000) : SSIZE_MAX); CONF_HANDLE_BOOL(opt_stats_print, "stats_print") + if (CONF_MATCH("stats_print_opts")) { + init_opt_stats_print_opts(v, vlen); + continue; + } if (config_fill) { if (CONF_MATCH("junk")) { if (CONF_MATCH_VALUE("true")) { diff --git a/src/stats.c b/src/stats.c index 48d3f59b..61550d83 100644 --- a/src/stats.c +++ b/src/stats.c @@ -46,7 +46,8 @@ const char *arena_mutex_names[mutex_prof_num_arena_mutexes] = { /******************************************************************************/ /* Data. */ -bool opt_stats_print = false; +bool opt_stats_print = false; +char opt_stats_print_opts[stats_print_tot_num_options+1] = ""; /******************************************************************************/ @@ -838,12 +839,16 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, OPT_WRITE_BOOL(prof_gdump, ",") OPT_WRITE_BOOL(prof_final, ",") OPT_WRITE_BOOL(prof_leak, ",") - /* - * stats_print is always emitted, so as long as stats_print comes last - * it's safe to unconditionally omit the comma here (rather than having - * to conditionally omit it elsewhere depending on configuration). - */ - OPT_WRITE_BOOL(stats_print, "") + OPT_WRITE_BOOL(stats_print, ",") + if (json || opt_stats_print) { + /* + * stats_print_opts is always emitted for JSON, so as long as it + * comes last it's safe to unconditionally omit the comma here + * (rather than having to conditionally omit it elsewhere + * depending on configuration). + */ + OPT_WRITE_CHAR_P(stats_print_opts, "") + } if (json) { malloc_cprintf(write_cb, cbopaque, "\t\t},\n"); @@ -1228,14 +1233,9 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, int err; uint64_t epoch; size_t u64sz; - bool json = false; - bool general = true; - bool merged = config_stats; - bool destroyed = config_stats; - bool unmerged = config_stats; - bool bins = true; - bool large = true; - bool mutex = true; +#define OPTION(o, v, d, s) bool v = d; + STATS_PRINT_OPTIONS +#undef OPTION /* * Refresh stats, in case mallctl() was called by the application. @@ -1260,34 +1260,11 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque, } if (opts != NULL) { - unsigned i; - - for (i = 0; opts[i] != '\0'; i++) { + for (unsigned i = 0; opts[i] != '\0'; i++) { switch (opts[i]) { - case 'J': - json = true; - break; - case 'g': - general = false; - break; - case 'm': - merged = false; - break; - case 'd': - destroyed = false; - break; - case 'a': - unmerged = false; - break; - case 'b': - bins = false; - break; - case 'l': - large = false; - break; - case 'x': - mutex = false; - break; +#define OPTION(o, v, d, s) case o: v = s; break; + STATS_PRINT_OPTIONS +#undef OPTION default:; } } -- GitLab From a16114866a8e52a4fc8057d5c3123e2dc5c0ceab Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 25 May 2017 18:15:41 -0700 Subject: [PATCH 504/544] Fix OOM paths in extent_grow_retained(). --- src/extent.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/extent.c b/src/extent.c index fee8198e..7359a558 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1046,10 +1046,15 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, extent_init(extent, arena, ptr, alloc_size, false, NSIZES, arena_extent_sn_next(arena), extent_state_active, zeroed, committed); - if (ptr == NULL || extent_register_no_gdump_add(tsdn, extent)) { + if (ptr == NULL) { extent_dalloc(tsdn, arena, extent); return NULL; } + if (extent_register_no_gdump_add(tsdn, extent)) { + extents_leak(tsdn, arena, r_extent_hooks, + &arena->extents_retained, extent); + return NULL; + } size_t leadsize = ALIGNMENT_CEILING((uintptr_t)ptr, PAGE_CEILING(alignment)) - (uintptr_t)ptr; @@ -1070,7 +1075,8 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, leadsize, NSIZES, false, esize + trailsize, szind, slab); if (extent == NULL) { extent_deregister(tsdn, lead); - extents_leak(tsdn, arena, r_extent_hooks, false, lead); + extents_leak(tsdn, arena, r_extent_hooks, + &arena->extents_retained, lead); return NULL; } extent_record(tsdn, arena, r_extent_hooks, -- GitLab From 168793a1c1986890cb8eaeecb320c762ed3b8033 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 26 May 2017 11:06:01 -0700 Subject: [PATCH 505/544] Fix extent_grow_next management. Fix management of extent_grow_next to serialize operations that may grow retained memory. This assures that the sizes of the newly allocated extents correspond to the size classes in the intended growth sequence. Fix management of extent_grow_next to skip size classes if a request is too large to be satisfied by the next size in the growth sequence. This avoids the potential for an arbitrary number of requests to bypass triggering extent_grow_next increases. This resolves #858. --- include/jemalloc/internal/arena_structs_b.h | 5 +- include/jemalloc/internal/witness.h | 15 +- src/arena.c | 9 +- src/extent.c | 352 ++++++++++++-------- 4 files changed, 222 insertions(+), 159 deletions(-) diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index f98f45c1..160ac4fa 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -238,9 +238,10 @@ struct arena_s { * be effective even if multiple arenas' extent allocation requests are * highly interleaved. * - * Synchronization: atomic. + * Synchronization: extent_grow_mtx */ - atomic_u_t extent_grow_next; + pszind_t extent_grow_next; + malloc_mutex_t extent_grow_mtx; /* * Available extent structures that were allocated via diff --git a/include/jemalloc/internal/witness.h b/include/jemalloc/internal/witness.h index c71911f2..33be6661 100644 --- a/include/jemalloc/internal/witness.h +++ b/include/jemalloc/internal/witness.h @@ -41,13 +41,14 @@ #define WITNESS_RANK_DECAY 11U #define WITNESS_RANK_TCACHE_QL 12U -#define WITNESS_RANK_EXTENTS 13U -#define WITNESS_RANK_EXTENT_FREELIST 14U - -#define WITNESS_RANK_EXTENT_POOL 15U -#define WITNESS_RANK_RTREE 16U -#define WITNESS_RANK_BASE 17U -#define WITNESS_RANK_ARENA_LARGE 18U +#define WITNESS_RANK_EXTENT_GROW 13U +#define WITNESS_RANK_EXTENTS 14U +#define WITNESS_RANK_EXTENT_AVAIL 15U + +#define WITNESS_RANK_EXTENT_POOL 16U +#define WITNESS_RANK_RTREE 17U +#define WITNESS_RANK_BASE 18U +#define WITNESS_RANK_ARENA_LARGE 19U #define WITNESS_RANK_LEAF 0xffffffffU #define WITNESS_RANK_ARENA_BIN WITNESS_RANK_LEAF diff --git a/src/arena.c b/src/arena.c index 105d60ca..de50d8c0 100644 --- a/src/arena.c +++ b/src/arena.c @@ -2001,14 +2001,15 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { goto label_error; } - if (opt_retain) { - atomic_store_u(&arena->extent_grow_next, psz2ind(HUGEPAGE), - ATOMIC_RELAXED); + arena->extent_grow_next = psz2ind(HUGEPAGE); + if (malloc_mutex_init(&arena->extent_grow_mtx, "extent_grow", + WITNESS_RANK_EXTENT_GROW, malloc_mutex_rank_exclusive)) { + goto label_error; } extent_avail_new(&arena->extent_avail); if (malloc_mutex_init(&arena->extent_avail_mtx, "extent_avail", - WITNESS_RANK_EXTENT_FREELIST, malloc_mutex_rank_exclusive)) { + WITNESS_RANK_EXTENT_AVAIL, malloc_mutex_rank_exclusive)) { goto label_error; } diff --git a/src/extent.c b/src/extent.c index 7359a558..44e98789 100644 --- a/src/extent.c +++ b/src/extent.c @@ -16,33 +16,51 @@ mutex_pool_t extent_mutex_pool; static const bitmap_info_t extents_bitmap_info = BITMAP_INFO_INITIALIZER(NPSIZES+1); -static void *extent_alloc_default(extent_hooks_t *extent_hooks, - void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit, +static void *extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, + size_t size, size_t alignment, bool *zero, bool *commit, unsigned arena_ind); -static bool extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, +static bool extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, size_t size, bool committed, unsigned arena_ind); -static void extent_destroy_default(extent_hooks_t *extent_hooks, void *addr, +static void extent_destroy_default(extent_hooks_t *extent_hooks, void *addr, size_t size, bool committed, unsigned arena_ind); -static bool extent_commit_default(extent_hooks_t *extent_hooks, void *addr, +static bool extent_commit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); -static bool extent_decommit_default(extent_hooks_t *extent_hooks, +static bool extent_commit_impl(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, + size_t length, bool growing_retained); +static bool extent_decommit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); #ifdef PAGES_CAN_PURGE_LAZY -static bool extent_purge_lazy_default(extent_hooks_t *extent_hooks, - void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); +static bool extent_purge_lazy_default(extent_hooks_t *extent_hooks, void *addr, + size_t size, size_t offset, size_t length, unsigned arena_ind); #endif +static bool extent_purge_lazy_impl(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, + size_t length, bool growing_retained); #ifdef PAGES_CAN_PURGE_FORCED -static bool extent_purge_forced_default(extent_hooks_t *extent_hooks, +static bool extent_purge_forced_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind); #endif +static bool extent_purge_forced_impl(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, + size_t length, bool growing_retained); #ifdef JEMALLOC_MAPS_COALESCE -static bool extent_split_default(extent_hooks_t *extent_hooks, void *addr, +static bool extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t size_a, size_t size_b, bool committed, unsigned arena_ind); -static bool extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, +#endif +static extent_t *extent_split_impl(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a, + szind_t szind_a, bool slab_a, size_t size_b, szind_t szind_b, bool slab_b, + bool growing_retained); +#ifdef JEMALLOC_MAPS_COALESCE +static bool extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, void *addr_b, size_t size_b, bool committed, unsigned arena_ind); #endif +static bool extent_merge_impl(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b, + bool growing_retained); const extent_hooks_t extent_hooks_default = { extent_alloc_default, @@ -85,12 +103,13 @@ static void extent_deregister(tsdn_t *tsdn, extent_t *extent); static extent_t *extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extents_t *extents, void *new_addr, size_t usize, size_t pad, size_t alignment, bool slab, szind_t szind, - bool *zero, bool *commit); + bool *zero, bool *commit, bool growing_retained); static extent_t *extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, - extent_t *extent, bool *coalesced); + extent_t *extent, bool *coalesced, bool growing_retained); static void extent_record(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extents_t *extents, extent_t *extent); + extent_hooks_t **r_extent_hooks, extents_t *extents, extent_t *extent, + bool growing_retained); /******************************************************************************/ @@ -150,9 +169,6 @@ extent_lock_from_addr(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, void *addr) { extent_t * extent_alloc(tsdn_t *tsdn, arena_t *arena) { - witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), - WITNESS_RANK_CORE, 0); - malloc_mutex_lock(tsdn, &arena->extent_avail_mtx); extent_t *extent = extent_avail_first(&arena->extent_avail); if (extent == NULL) { @@ -166,9 +182,6 @@ extent_alloc(tsdn_t *tsdn, arena_t *arena) { void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { - witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), - WITNESS_RANK_CORE, 0); - malloc_mutex_lock(tsdn, &arena->extent_avail_mtx); extent_avail_insert(&arena->extent_avail, extent); malloc_mutex_unlock(tsdn, &arena->extent_avail_mtx); @@ -402,7 +415,7 @@ extent_try_delayed_coalesce(tsdn_t *tsdn, arena_t *arena, extent_state_set(extent, extent_state_active); bool coalesced; extent = extent_try_coalesce(tsdn, arena, r_extent_hooks, rtree_ctx, - extents, extent, &coalesced); + extents, extent, &coalesced, false); extent_state_set(extent, extents_state_get(extents)); if (!coalesced) { @@ -422,7 +435,7 @@ extents_alloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, WITNESS_RANK_CORE, 0); return extent_recycle(tsdn, arena, r_extent_hooks, extents, new_addr, - size, pad, alignment, slab, szind, zero, commit); + size, pad, alignment, slab, szind, zero, commit, false); } void @@ -436,7 +449,7 @@ extents_dalloc(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_addr_set(extent, extent_base_get(extent)); extent_zeroed_set(extent, false); - extent_record(tsdn, arena, r_extent_hooks, extents, extent); + extent_record(tsdn, arena, r_extent_hooks, extents, extent, false); } extent_t * @@ -506,16 +519,17 @@ label_return: static void extents_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extents_t *extents, extent_t *extent) { + extents_t *extents, extent_t *extent, bool growing_retained) { /* * Leak extent after making sure its pages have already been purged, so * that this is only a virtual memory leak. */ if (extents_state_get(extents) == extent_state_dirty) { - if (extent_purge_lazy_wrapper(tsdn, arena, r_extent_hooks, - extent, 0, extent_size_get(extent))) { - extent_purge_forced_wrapper(tsdn, arena, r_extent_hooks, - extent, 0, extent_size_get(extent)); + if (extent_purge_lazy_impl(tsdn, arena, r_extent_hooks, + extent, 0, extent_size_get(extent), growing_retained)) { + extent_purge_forced_impl(tsdn, arena, r_extent_hooks, + extent, 0, extent_size_get(extent), + growing_retained); } } extent_dalloc(tsdn, arena, extent); @@ -734,13 +748,10 @@ extent_deregister(tsdn_t *tsdn, extent_t *extent) { static extent_t * extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, - bool locked, void *new_addr, size_t size, size_t pad, size_t alignment, - bool slab, bool *zero, bool *commit) { + void *new_addr, size_t size, size_t pad, size_t alignment, bool slab, + bool *zero, bool *commit, bool growing_retained) { witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), - WITNESS_RANK_CORE, locked ? 1 : 0); - if (locked) { - malloc_mutex_assert_owner(tsdn, &extents->mtx); - } + WITNESS_RANK_CORE, growing_retained ? 1 : 0); assert(alignment > 0); if (config_debug && new_addr != NULL) { /* @@ -765,9 +776,7 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, if (alloc_size < esize) { return NULL; } - if (!locked) { - malloc_mutex_lock(tsdn, &extents->mtx); - } + malloc_mutex_lock(tsdn, &extents->mtx); extent_hooks_assure_initialized(arena, r_extent_hooks); extent_t *extent; if (new_addr != NULL) { @@ -791,16 +800,12 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena, extent = extents_fit_locked(tsdn, arena, extents, alloc_size); } if (extent == NULL) { - if (!locked) { - malloc_mutex_unlock(tsdn, &extents->mtx); - } + malloc_mutex_unlock(tsdn, &extents->mtx); return NULL; } extent_activate_locked(tsdn, arena, extents, extent, false); - if (!locked) { - malloc_mutex_unlock(tsdn, &extents->mtx); - } + malloc_mutex_unlock(tsdn, &extents->mtx); if (extent_zeroed_get(extent)) { *zero = true; @@ -816,7 +821,7 @@ static extent_t * extent_recycle_split(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, void *new_addr, size_t size, size_t pad, size_t alignment, bool slab, - szind_t szind, extent_t *extent) { + szind_t szind, extent_t *extent, bool growing_retained) { size_t esize = size + pad; size_t leadsize = ALIGNMENT_CEILING((uintptr_t)extent_base_get(extent), PAGE_CEILING(alignment)) - (uintptr_t)extent_base_get(extent); @@ -827,13 +832,13 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena, /* Split the lead. */ if (leadsize != 0) { extent_t *lead = extent; - extent = extent_split_wrapper(tsdn, arena, r_extent_hooks, + extent = extent_split_impl(tsdn, arena, r_extent_hooks, lead, leadsize, NSIZES, false, esize + trailsize, szind, - slab); + slab, growing_retained); if (extent == NULL) { extent_deregister(tsdn, lead); extents_leak(tsdn, arena, r_extent_hooks, extents, - lead); + lead, growing_retained); return NULL; } extent_deactivate(tsdn, arena, extents, lead, false); @@ -841,13 +846,13 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena, /* Split the trail. */ if (trailsize != 0) { - extent_t *trail = extent_split_wrapper(tsdn, arena, + extent_t *trail = extent_split_impl(tsdn, arena, r_extent_hooks, extent, esize, szind, slab, trailsize, - NSIZES, false); + NSIZES, false, growing_retained); if (trail == NULL) { extent_deregister(tsdn, extent); extents_leak(tsdn, arena, r_extent_hooks, extents, - extent); + extent, growing_retained); return NULL; } extent_deactivate(tsdn, arena, extents, trail, false); @@ -875,9 +880,10 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena, static extent_t * extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extents_t *extents, void *new_addr, size_t size, size_t pad, - size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) { + size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit, + bool growing_retained) { witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), - WITNESS_RANK_CORE, 0); + WITNESS_RANK_CORE, growing_retained ? 1 : 0); assert(new_addr == NULL || !slab); assert(pad == 0 || !slab); assert(!*zero || !slab); @@ -887,8 +893,8 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, bool committed = false; extent_t *extent = extent_recycle_extract(tsdn, arena, r_extent_hooks, - rtree_ctx, extents, false, new_addr, size, pad, alignment, slab, - zero, &committed); + rtree_ctx, extents, new_addr, size, pad, alignment, slab, zero, + &committed, growing_retained); if (extent == NULL) { return NULL; } @@ -897,16 +903,17 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, } extent = extent_recycle_split(tsdn, arena, r_extent_hooks, rtree_ctx, - extents, new_addr, size, pad, alignment, slab, szind, extent); + extents, new_addr, size, pad, alignment, slab, szind, extent, + growing_retained); if (extent == NULL) { return NULL; } if (*commit && !extent_committed_get(extent)) { - if (extent_commit_wrapper(tsdn, arena, r_extent_hooks, extent, - 0, extent_size_get(extent))) { + if (extent_commit_impl(tsdn, arena, r_extent_hooks, extent, + 0, extent_size_get(extent), growing_retained)) { extent_record(tsdn, arena, r_extent_hooks, extents, - extent); + extent, growing_retained); return NULL; } extent_zeroed_set(extent, true); @@ -1012,35 +1019,41 @@ extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, size_t size, */ static extent_t * extent_grow_retained(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, size_t pad, - size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) { + extent_hooks_t **r_extent_hooks, size_t size, size_t pad, size_t alignment, + bool slab, szind_t szind, bool *zero, bool *commit) { + malloc_mutex_assert_owner(tsdn, &arena->extent_grow_mtx); assert(pad == 0 || !slab); assert(!*zero || !slab); - /* - * Check whether the next extent size in the series would be large - * enough to satisfy this request. If no, just bail, so that e.g. a - * series of unsatisfiable allocation requests doesn't cause unused - * extent creation as a side effect. - */ size_t esize = size + pad; - size_t alloc_size = pind2sz(atomic_load_u(&arena->extent_grow_next, - ATOMIC_RELAXED)); size_t alloc_size_min = esize + PAGE_CEILING(alignment) - PAGE; /* Beware size_t wrap-around. */ if (alloc_size_min < esize) { - return NULL; + goto label_err; } - if (alloc_size < alloc_size_min) { - return NULL; + /* + * Find the next extent size in the series that would be large enough to + * satisfy this request. + */ + pszind_t egn_skip = 0; + size_t alloc_size = pind2sz(arena->extent_grow_next + egn_skip); + while (alloc_size < alloc_size_min) { + egn_skip++; + if (arena->extent_grow_next + egn_skip == NPSIZES) { + /* Outside legal range. */ + goto label_err; + } + assert(arena->extent_grow_next + egn_skip < NPSIZES); + alloc_size = pind2sz(arena->extent_grow_next + egn_skip); } + extent_t *extent = extent_alloc(tsdn, arena); if (extent == NULL) { - return NULL; + goto label_err; } bool zeroed = false; bool committed = false; - void *ptr = extent_alloc_core(tsdn, arena, new_addr, alloc_size, PAGE, + void *ptr = extent_alloc_core(tsdn, arena, NULL, alloc_size, PAGE, &zeroed, &committed, (dss_prec_t)atomic_load_u(&arena->dss_prec, ATOMIC_RELAXED)); extent_init(extent, arena, ptr, alloc_size, false, NSIZES, @@ -1048,17 +1061,16 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, committed); if (ptr == NULL) { extent_dalloc(tsdn, arena, extent); - return NULL; + goto label_err; } if (extent_register_no_gdump_add(tsdn, extent)) { extents_leak(tsdn, arena, r_extent_hooks, - &arena->extents_retained, extent); - return NULL; + &arena->extents_retained, extent, true); + goto label_err; } size_t leadsize = ALIGNMENT_CEILING((uintptr_t)ptr, PAGE_CEILING(alignment)) - (uintptr_t)ptr; - assert(new_addr == NULL || leadsize == 0); assert(alloc_size >= leadsize + esize); size_t trailsize = alloc_size - leadsize - esize; if (extent_zeroed_get(extent) && extent_committed_get(extent)) { @@ -1071,31 +1083,31 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, /* Split the lead. */ if (leadsize != 0) { extent_t *lead = extent; - extent = extent_split_wrapper(tsdn, arena, r_extent_hooks, lead, - leadsize, NSIZES, false, esize + trailsize, szind, slab); + extent = extent_split_impl(tsdn, arena, r_extent_hooks, lead, + leadsize, NSIZES, false, esize + trailsize, szind, slab, + true); if (extent == NULL) { extent_deregister(tsdn, lead); extents_leak(tsdn, arena, r_extent_hooks, - &arena->extents_retained, lead); - return NULL; + &arena->extents_retained, lead, true); + goto label_err; } extent_record(tsdn, arena, r_extent_hooks, - &arena->extents_retained, lead); + &arena->extents_retained, lead, true); } /* Split the trail. */ if (trailsize != 0) { - extent_t *trail = extent_split_wrapper(tsdn, arena, - r_extent_hooks, extent, esize, szind, slab, trailsize, - NSIZES, false); + extent_t *trail = extent_split_impl(tsdn, arena, r_extent_hooks, + extent, esize, szind, slab, trailsize, NSIZES, false, true); if (trail == NULL) { extent_deregister(tsdn, extent); extents_leak(tsdn, arena, r_extent_hooks, - &arena->extents_retained, extent); - return NULL; + &arena->extents_retained, extent, true); + goto label_err; } extent_record(tsdn, arena, r_extent_hooks, - &arena->extents_retained, trail); + &arena->extents_retained, trail, true); } else if (leadsize == 0) { /* * Splitting causes szind to be set as a side effect, but no @@ -1119,15 +1131,27 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, } if (*commit && !extent_committed_get(extent)) { - if (extent_commit_wrapper(tsdn, arena, r_extent_hooks, extent, - 0, extent_size_get(extent))) { + if (extent_commit_impl(tsdn, arena, r_extent_hooks, extent, 0, + extent_size_get(extent), true)) { extent_record(tsdn, arena, r_extent_hooks, - &arena->extents_retained, extent); - return NULL; + &arena->extents_retained, extent, true); + goto label_err; } extent_zeroed_set(extent, true); } + /* + * Increment extent_grow_next if doing so wouldn't exceed the legal + * range. + */ + if (arena->extent_grow_next + egn_skip + 1 < NPSIZES) { + arena->extent_grow_next += egn_skip + 1; + } else { + arena->extent_grow_next = NPSIZES - 1; + } + /* All opportunities for failure are past. */ + malloc_mutex_unlock(tsdn, &arena->extent_grow_mtx); + if (config_prof) { /* Adjust gdump stats now that extent is final size. */ extent_gdump_add(tsdn, extent); @@ -1150,45 +1174,38 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, memset(addr, 0, size); } } - /* - * Increment extent_grow_next, but take care to do so atomically and - * bail out if the increment would exceed the legal range. - */ - pszind_t egn = atomic_load_u(&arena->extent_grow_next, ATOMIC_RELAXED); - while (true) { - if (egn + 1 == NPSIZES) { - break; - } - assert(egn + 1 < NPSIZES); - if (atomic_compare_exchange_weak_u(&arena->extent_grow_next, - &egn, egn + 1, ATOMIC_RELAXED, ATOMIC_RELAXED)) { - break; - } - } + return extent; +label_err: + malloc_mutex_unlock(tsdn, &arena->extent_grow_mtx); + return NULL; } static extent_t * extent_alloc_retained(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, void *new_addr, size_t size, size_t pad, size_t alignment, bool slab, szind_t szind, bool *zero, bool *commit) { - extent_t *extent; - assert(size != 0); assert(alignment != 0); - extent = extent_recycle(tsdn, arena, r_extent_hooks, + malloc_mutex_lock(tsdn, &arena->extent_grow_mtx); + + extent_t *extent = extent_recycle(tsdn, arena, r_extent_hooks, &arena->extents_retained, new_addr, size, pad, alignment, slab, - szind, zero, commit); + szind, zero, commit, true); if (extent != NULL) { + malloc_mutex_unlock(tsdn, &arena->extent_grow_mtx); if (config_prof) { extent_gdump_add(tsdn, extent); } + } else if (opt_retain && new_addr == NULL) { + extent = extent_grow_retained(tsdn, arena, r_extent_hooks, size, + pad, alignment, slab, szind, zero, commit); + /* extent_grow_retained() always releases extent_grow_mtx. */ + } else { + malloc_mutex_unlock(tsdn, &arena->extent_grow_mtx); } - if (opt_retain && extent == NULL) { - extent = extent_grow_retained(tsdn, arena, r_extent_hooks, - new_addr, size, pad, alignment, slab, szind, zero, commit); - } + malloc_mutex_assert_not_owner(tsdn, &arena->extent_grow_mtx); return extent; } @@ -1222,7 +1239,7 @@ extent_alloc_wrapper_hard(tsdn_t *tsdn, arena_t *arena, } if (extent_register(tsdn, extent)) { extents_leak(tsdn, arena, r_extent_hooks, - &arena->extents_retained, extent); + &arena->extents_retained, extent, false); return NULL; } @@ -1270,7 +1287,8 @@ extent_can_coalesce(arena_t *arena, extents_t *extents, const extent_t *inner, static bool extent_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extents_t *extents, extent_t *inner, extent_t *outer, bool forward) { + extents_t *extents, extent_t *inner, extent_t *outer, bool forward, + bool growing_retained) { assert(extent_can_coalesce(arena, extents, inner, outer)); if (forward && extents->delay_coalesce) { @@ -1285,8 +1303,8 @@ extent_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extents->delay_coalesce); malloc_mutex_unlock(tsdn, &extents->mtx); - bool err = extent_merge_wrapper(tsdn, arena, r_extent_hooks, - forward ? inner : outer, forward ? outer : inner); + bool err = extent_merge_impl(tsdn, arena, r_extent_hooks, + forward ? inner : outer, forward ? outer : inner, growing_retained); malloc_mutex_lock(tsdn, &extents->mtx); if (err) { @@ -1303,7 +1321,7 @@ extent_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, static extent_t * extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, rtree_ctx_t *rtree_ctx, extents_t *extents, - extent_t *extent, bool *coalesced) { + extent_t *extent, bool *coalesced, bool growing_retained) { /* * Continue attempting to coalesce until failure, to protect against * races with other threads that are thwarted by this one. @@ -1327,7 +1345,8 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_unlock(tsdn, next); if (can_coalesce && !extent_coalesce(tsdn, arena, - r_extent_hooks, extents, extent, next, true)) { + r_extent_hooks, extents, extent, next, true, + growing_retained)) { if (extents->delay_coalesce) { /* Do minimal coalescing. */ *coalesced = true; @@ -1346,7 +1365,8 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_unlock(tsdn, prev); if (can_coalesce && !extent_coalesce(tsdn, arena, - r_extent_hooks, extents, extent, prev, false)) { + r_extent_hooks, extents, extent, prev, false, + growing_retained)) { extent = prev; if (extents->delay_coalesce) { /* Do minimal coalescing. */ @@ -1366,7 +1386,7 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, static void extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, - extents_t *extents, extent_t *extent) { + extents_t *extents, extent_t *extent, bool growing_retained) { rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); @@ -1388,7 +1408,7 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, if (!extents->delay_coalesce) { extent = extent_try_coalesce(tsdn, arena, r_extent_hooks, - rtree_ctx, extents, extent, NULL); + rtree_ctx, extents, extent, NULL, growing_retained); } extent_deactivate_locked(tsdn, arena, extents, extent, false); @@ -1405,7 +1425,7 @@ extent_dalloc_gap(tsdn_t *tsdn, arena_t *arena, extent_t *extent) { if (extent_register(tsdn, extent)) { extents_leak(tsdn, arena, &extent_hooks, - &arena->extents_retained, extent); + &arena->extents_retained, extent, false); return; } extent_dalloc_wrapper(tsdn, arena, &extent_hooks, extent); @@ -1503,7 +1523,7 @@ extent_dalloc_wrapper(tsdn_t *tsdn, arena_t *arena, } extent_record(tsdn, arena, r_extent_hooks, &arena->extents_retained, - extent); + extent, false); } static void @@ -1558,12 +1578,12 @@ extent_commit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, length); } -bool -extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, +static bool +extent_commit_impl(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, - size_t length) { + size_t length, bool growing_retained) { witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), - WITNESS_RANK_CORE, 0); + WITNESS_RANK_CORE, growing_retained ? 1 : 0); extent_hooks_assure_initialized(arena, r_extent_hooks); bool err = ((*r_extent_hooks)->commit == NULL || @@ -1573,6 +1593,14 @@ extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, return err; } +bool +extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, + size_t length) { + return extent_commit_impl(tsdn, arena, r_extent_hooks, extent, offset, + length, false); +} + static bool extent_decommit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { @@ -1614,12 +1642,12 @@ extent_purge_lazy_default(extent_hooks_t *extent_hooks, void *addr, size_t size, } #endif -bool -extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, +static bool +extent_purge_lazy_impl(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, - size_t length) { + size_t length, bool growing_retained) { witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), - WITNESS_RANK_CORE, 0); + WITNESS_RANK_CORE, growing_retained ? 1 : 0); extent_hooks_assure_initialized(arena, r_extent_hooks); return ((*r_extent_hooks)->purge_lazy == NULL || @@ -1628,6 +1656,14 @@ extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, arena_ind_get(arena))); } +bool +extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, + size_t length) { + return extent_purge_lazy_impl(tsdn, arena, r_extent_hooks, extent, + offset, length, false); +} + #ifdef PAGES_CAN_PURGE_FORCED static bool extent_purge_forced_default(extent_hooks_t *extent_hooks, void *addr, @@ -1643,12 +1679,12 @@ extent_purge_forced_default(extent_hooks_t *extent_hooks, void *addr, } #endif -bool -extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, +static bool +extent_purge_forced_impl(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, - size_t length) { + size_t length, bool growing_retained) { witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), - WITNESS_RANK_CORE, 0); + WITNESS_RANK_CORE, growing_retained ? 1 : 0); extent_hooks_assure_initialized(arena, r_extent_hooks); return ((*r_extent_hooks)->purge_forced == NULL || @@ -1657,6 +1693,14 @@ extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, arena_ind_get(arena))); } +bool +extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t offset, + size_t length) { + return extent_purge_forced_impl(tsdn, arena, r_extent_hooks, extent, + offset, length, false); +} + #ifdef JEMALLOC_MAPS_COALESCE static bool extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size, @@ -1667,13 +1711,14 @@ extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size, } #endif -extent_t * -extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, +static extent_t * +extent_split_impl(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a, - szind_t szind_a, bool slab_a, size_t size_b, szind_t szind_b, bool slab_b) { + szind_t szind_a, bool slab_a, size_t size_b, szind_t szind_b, bool slab_b, + bool growing_retained) { assert(extent_size_get(extent) == size_a + size_b); witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), - WITNESS_RANK_CORE, 0); + WITNESS_RANK_CORE, growing_retained ? 1 : 0); extent_hooks_assure_initialized(arena, r_extent_hooks); @@ -1741,6 +1786,14 @@ label_error_a: return NULL; } +extent_t * +extent_split_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a, + szind_t szind_a, bool slab_a, size_t size_b, szind_t szind_b, bool slab_b) { + return extent_split_impl(tsdn, arena, r_extent_hooks, extent, size_a, + szind_a, slab_a, size_b, szind_b, slab_b, false); +} + static bool extent_merge_default_impl(void *addr_a, void *addr_b) { if (!maps_coalesce) { @@ -1763,11 +1816,12 @@ extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, } #endif -bool -extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, - extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b) { +static bool +extent_merge_impl(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b, + bool growing_retained) { witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), - WITNESS_RANK_CORE, 0); + WITNESS_RANK_CORE, growing_retained ? 1 : 0); extent_hooks_assure_initialized(arena, r_extent_hooks); @@ -1832,6 +1886,12 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, return false; } +bool +extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena, + extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b) { + return extent_merge_impl(tsdn, arena, r_extent_hooks, a, b, false); +} + bool extent_boot(void) { if (rtree_new(&extents_rtree, true)) { -- GitLab From 4f0963b883ea8a3a9e438f91f866627546a89d0c Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 26 May 2017 09:52:33 -0700 Subject: [PATCH 506/544] Add test for excessive retained memory. --- Makefile.in | 1 + test/unit/retained.c | 179 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 test/unit/retained.c diff --git a/Makefile.in b/Makefile.in index 16fe30fd..868bf8cc 100644 --- a/Makefile.in +++ b/Makefile.in @@ -189,6 +189,7 @@ TESTS_UNIT := \ $(srcroot)test/unit/ql.c \ $(srcroot)test/unit/qr.c \ $(srcroot)test/unit/rb.c \ + $(srcroot)test/unit/retained.c \ $(srcroot)test/unit/rtree.c \ $(srcroot)test/unit/SFMT.c \ $(srcroot)test/unit/size_classes.c \ diff --git a/test/unit/retained.c b/test/unit/retained.c new file mode 100644 index 00000000..883bf4af --- /dev/null +++ b/test/unit/retained.c @@ -0,0 +1,179 @@ +#include "test/jemalloc_test.h" + +static unsigned arena_ind; +static size_t sz; +static size_t esz; +#define NEPOCHS 8 +#define PER_THD_NALLOCS 1 +static atomic_u_t epoch; +static atomic_u_t nfinished; + +static unsigned +do_arena_create(extent_hooks_t *h) { + unsigned arena_ind; + size_t sz = sizeof(unsigned); + assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, + (void *)(h != NULL ? &h : NULL), (h != NULL ? sizeof(h) : 0)), 0, + "Unexpected mallctl() failure"); + return arena_ind; +} + +static void +do_arena_destroy(unsigned arena_ind) { + size_t mib[3]; + size_t miblen; + + miblen = sizeof(mib)/sizeof(size_t); + assert_d_eq(mallctlnametomib("arena.0.destroy", mib, &miblen), 0, + "Unexpected mallctlnametomib() failure"); + mib[1] = (size_t)arena_ind; + assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0, + "Unexpected mallctlbymib() failure"); +} + +static void +do_refresh(void) { + uint64_t epoch = 1; + assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, + sizeof(epoch)), 0, "Unexpected mallctl() failure"); +} + +static size_t +do_get_size_impl(const char *cmd, unsigned arena_ind) { + size_t mib[4]; + size_t miblen = sizeof(mib) / sizeof(size_t); + size_t z = sizeof(size_t); + + assert_d_eq(mallctlnametomib(cmd, mib, &miblen), + 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd); + mib[2] = arena_ind; + size_t size; + assert_d_eq(mallctlbymib(mib, miblen, (void *)&size, &z, NULL, 0), + 0, "Unexpected mallctlbymib([\"%s\"], ...) failure", cmd); + + return size; +} + +static size_t +do_get_active(unsigned arena_ind) { + return do_get_size_impl("stats.arenas.0.pactive", arena_ind) * PAGE; +} + +static size_t +do_get_mapped(unsigned arena_ind) { + return do_get_size_impl("stats.arenas.0.mapped", arena_ind); +} + +static void * +thd_start(void *arg) { + for (unsigned next_epoch = 1; next_epoch < NEPOCHS; next_epoch++) { + /* Busy-wait for next epoch. */ + unsigned cur_epoch; + spin_t spinner = SPIN_INITIALIZER; + while ((cur_epoch = atomic_load_u(&epoch, ATOMIC_ACQUIRE)) != + next_epoch) { + spin_adaptive(&spinner); + } + assert_u_eq(cur_epoch, next_epoch, "Unexpected epoch"); + + /* + * Allocate. The main thread will reset the arena, so there's + * no need to deallocate. + */ + for (unsigned i = 0; i < PER_THD_NALLOCS; i++) { + void *p = mallocx(sz, MALLOCX_ARENA(arena_ind) | + MALLOCX_TCACHE_NONE + ); + assert_ptr_not_null(p, + "Unexpected mallocx() failure\n"); + } + + /* Let the main thread know we've finished this iteration. */ + atomic_fetch_add_u(&nfinished, 1, ATOMIC_RELEASE); + } + + return NULL; +} + +TEST_BEGIN(test_retained) { + test_skip_if(!config_stats); + + arena_ind = do_arena_create(NULL); + sz = nallocx(HUGEPAGE, 0); + esz = sz + large_pad; + + atomic_store_u(&epoch, 0, ATOMIC_RELAXED); + + unsigned nthreads = ncpus * 2; + VARIABLE_ARRAY(thd_t, threads, nthreads); + for (unsigned i = 0; i < nthreads; i++) { + thd_create(&threads[i], thd_start, NULL); + } + + for (unsigned e = 1; e < NEPOCHS; e++) { + atomic_store_u(&nfinished, 0, ATOMIC_RELEASE); + atomic_store_u(&epoch, e, ATOMIC_RELEASE); + + /* Wait for threads to finish allocating. */ + spin_t spinner = SPIN_INITIALIZER; + while (atomic_load_u(&nfinished, ATOMIC_ACQUIRE) < nthreads) { + spin_adaptive(&spinner); + } + + /* + * Assert that retained is no more than the sum of size classes + * that should have been used to satisfy the worker threads' + * requests, discounting per growth fragmentation. + */ + do_refresh(); + + size_t allocated = esz * nthreads * PER_THD_NALLOCS; + size_t active = do_get_active(arena_ind); + assert_zu_le(allocated, active, "Unexpected active memory"); + size_t mapped = do_get_mapped(arena_ind); + assert_zu_le(active, mapped, "Unexpected mapped memory"); + + arena_t *arena = arena_get(tsdn_fetch(), arena_ind, false); + size_t usable = 0; + size_t fragmented = 0; + for (pszind_t pind = psz2ind(HUGEPAGE); pind < + arena->extent_grow_next; pind++) { + size_t psz = pind2sz(pind); + size_t psz_fragmented = psz % esz; + size_t psz_usable = psz - psz_fragmented; + /* + * Only consider size classes that wouldn't be skipped. + */ + if (psz_usable > 0) { + assert_zu_lt(usable, allocated, + "Excessive retained memory " + "(%#zx[+%#zx] > %#zx)", usable, psz_usable, + allocated); + fragmented += psz_fragmented; + usable += psz_usable; + } + } + + /* + * Clean up arena. Destroying and recreating the arena + * is simpler that specifying extent hooks that deallocate + * (rather than retaining) during reset. + */ + do_arena_destroy(arena_ind); + assert_u_eq(do_arena_create(NULL), arena_ind, + "Unexpected arena index"); + } + + for (unsigned i = 0; i < nthreads; i++) { + thd_join(threads[i], NULL); + } + + do_arena_destroy(arena_ind); +} +TEST_END + +int +main(void) { + return test( + test_retained); +} -- GitLab From bf6673a070a7d0b12a4d25c1f64dcf562f61f10a Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Mon, 29 May 2017 22:47:16 -0700 Subject: [PATCH 507/544] Fix npages during arena_decay_epoch_advance(). We do not lock extents while advancing epoch. This change makes sure that we only read npages from extents once in order to avoid any inconsistency. --- src/arena.c | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/src/arena.c b/src/arena.c index de50d8c0..9b3ea235 100644 --- a/src/arena.c +++ b/src/arena.c @@ -637,15 +637,14 @@ arena_decay_backlog_npages_limit(const arena_decay_t *decay) { } static void -arena_decay_backlog_update_last(arena_decay_t *decay, extents_t *extents) { - size_t ndirty = extents_npages_get(extents); - size_t ndirty_delta = (ndirty > decay->nunpurged) ? ndirty - - decay->nunpurged : 0; - decay->backlog[SMOOTHSTEP_NSTEPS-1] = ndirty_delta; +arena_decay_backlog_update_last(arena_decay_t *decay, size_t current_npages) { + size_t npages_delta = (current_npages > decay->nunpurged) ? + current_npages - decay->nunpurged : 0; + decay->backlog[SMOOTHSTEP_NSTEPS-1] = npages_delta; if (config_debug) { - if (ndirty > decay->ceil_npages) { - decay->ceil_npages = ndirty; + if (current_npages > decay->ceil_npages) { + decay->ceil_npages = current_npages; } size_t npages_limit = arena_decay_backlog_npages_limit(decay); assert(decay->ceil_npages >= npages_limit); @@ -656,8 +655,8 @@ arena_decay_backlog_update_last(arena_decay_t *decay, extents_t *extents) { } static void -arena_decay_backlog_update(arena_decay_t *decay, extents_t *extents, - uint64_t nadvance_u64) { +arena_decay_backlog_update(arena_decay_t *decay, uint64_t nadvance_u64, + size_t current_npages) { if (nadvance_u64 >= SMOOTHSTEP_NSTEPS) { memset(decay->backlog, 0, (SMOOTHSTEP_NSTEPS-1) * sizeof(size_t)); @@ -674,7 +673,7 @@ arena_decay_backlog_update(arena_decay_t *decay, extents_t *extents, } } - arena_decay_backlog_update_last(decay, extents); + arena_decay_backlog_update_last(decay, current_npages); } static void @@ -687,8 +686,8 @@ arena_decay_try_purge(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, } static void -arena_decay_epoch_advance_helper(arena_decay_t *decay, extents_t *extents, - const nstime_t *time) { +arena_decay_epoch_advance_helper(arena_decay_t *decay, const nstime_t *time, + size_t current_npages) { assert(arena_decay_deadline_reached(decay, time)); nstime_t delta; @@ -707,25 +706,20 @@ arena_decay_epoch_advance_helper(arena_decay_t *decay, extents_t *extents, arena_decay_deadline_init(decay); /* Update the backlog. */ - arena_decay_backlog_update(decay, extents, nadvance_u64); + arena_decay_backlog_update(decay, nadvance_u64, current_npages); } static void arena_decay_epoch_advance(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, extents_t *extents, const nstime_t *time, bool purge) { - arena_decay_epoch_advance_helper(decay, extents, time); - size_t current_npages = extents_npages_get(extents); + arena_decay_epoch_advance_helper(decay, time, current_npages); + size_t npages_limit = arena_decay_backlog_npages_limit(decay); if (purge) { arena_decay_try_purge(tsdn, arena, decay, extents, current_npages, npages_limit); } - /* - * There may be concurrent ndirty fluctuation between the purge above - * and the nunpurged update below, but this is inconsequential to decay - * machinery correctness. - */ decay->nunpurged = (npages_limit > current_npages) ? npages_limit : current_npages; } -- GitLab From c606a87d2a2a946793cf0a29ca69a1962caf6008 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 30 May 2017 09:54:49 -0700 Subject: [PATCH 508/544] Add the --disable-thp option to support cross compiling. This resolves #669. --- INSTALL.md | 7 +++++- configure.ac | 25 ++++++++++++++++--- doc/jemalloc.xml.in | 11 ++++++++ .../internal/jemalloc_internal_defs.h.in | 4 +-- .../jemalloc/internal/jemalloc_preamble.h.in | 14 +++++------ src/ctl.c | 3 +++ src/stats.c | 1 + test/unit/pages.c | 2 +- 8 files changed, 53 insertions(+), 14 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 25f625af..dff7cebb 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -157,6 +157,11 @@ any of the following arguments (not a definitive list) to 'configure': Statically link against the specified libunwind.a rather than dynamically linking with -lunwind. +* `--disable-thp` + + Disable transparent huge page (THP) integration. This option can be useful + when cross compiling. + * `--disable-fill` Disable support for junk/zero filling of memory. See the "opt.junk" and @@ -224,7 +229,7 @@ any of the following arguments (not a definitive list) to 'configure': * `--with-lg-page-sizes=` Specify the comma-separated base 2 logs of the page sizes to support. This - option may be useful when cross-compiling in combination with + option may be useful when cross compiling in combination with `--with-lg-page`, but its primary use case is for integration with FreeBSD's libc, wherein jemalloc is embedded. diff --git a/configure.ac b/configure.ac index 8be4be45..bed01b7a 100644 --- a/configure.ac +++ b/configure.ac @@ -1792,11 +1792,29 @@ if test "x${je_cv_madvise}" = "xyes" ; then madvise((void *)0, 0, MADV_HUGEPAGE); madvise((void *)0, 0, MADV_NOHUGEPAGE); ], [je_cv_thp]) - if test "x${je_cv_thp}" = "xyes" ; then - AC_DEFINE([JEMALLOC_THP], [ ]) - fi fi +dnl Enable transparent huge page support by default. +AC_ARG_ENABLE([thp], + [AS_HELP_STRING([--disable-thp], + [Disable transparent huge page support])], +[if test "x$enable_thp" = "xno" -o "x${je_cv_thp}" != "xyes" ; then + enable_thp="0" +else + enable_thp="1" +fi +], +[if test "x${je_cv_thp}" = "xyes" ; then + enable_thp="1" +else + enable_thp="0" +fi +]) +if test "x$enable_thp" = "x1" ; then + AC_DEFINE([JEMALLOC_THP], [ ]) +fi +AC_SUBST([enable_thp]) + dnl ============================================================================ dnl Check whether __sync_{add,sub}_and_fetch() are available despite dnl __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n macros being undefined. @@ -2141,6 +2159,7 @@ AC_MSG_RESULT([prof : ${enable_prof}]) AC_MSG_RESULT([prof-libunwind : ${enable_prof_libunwind}]) AC_MSG_RESULT([prof-libgcc : ${enable_prof_libgcc}]) AC_MSG_RESULT([prof-gcc : ${enable_prof_gcc}]) +AC_MSG_RESULT([thp : ${enable_thp}]) AC_MSG_RESULT([fill : ${enable_fill}]) AC_MSG_RESULT([utrace : ${enable_utrace}]) AC_MSG_RESULT([xmalloc : ${enable_xmalloc}]) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index c2c0e925..a9c3d403 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -849,6 +849,17 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", build configuration. + + + config.thp + (bool) + r- + + was not specified + during build configuration, and the system supports transparent huge + page manipulation. + + config.utrace diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 75576a56..20a2358e 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -269,8 +269,8 @@ #undef JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS /* - * Defined if transparent huge pages are supported via the MADV_[NO]HUGEPAGE - * arguments to madvise(2). + * Defined if transparent huge pages (THPs) are supported via the + * MADV_[NO]HUGEPAGE arguments to madvise(2), and THP support is enabled. */ #undef JEMALLOC_THP diff --git a/include/jemalloc/internal/jemalloc_preamble.h.in b/include/jemalloc/internal/jemalloc_preamble.h.in index 0e876103..46750e99 100644 --- a/include/jemalloc/internal/jemalloc_preamble.h.in +++ b/include/jemalloc/internal/jemalloc_preamble.h.in @@ -111,6 +111,13 @@ static const bool config_stats = false #endif ; +static const bool config_thp = +#ifdef JEMALLOC_THP + true +#else + false +#endif + ; static const bool config_tls = #ifdef JEMALLOC_TLS true @@ -139,13 +146,6 @@ static const bool config_cache_oblivious = false #endif ; -static const bool have_thp = -#ifdef JEMALLOC_THP - true -#else - false -#endif - ; #ifdef JEMALLOC_HAVE_SCHED_GETCPU /* Currently percpu_arena depends on sched_getcpu. */ #define JEMALLOC_PERCPU_ARENA diff --git a/src/ctl.c b/src/ctl.c index d10c39bb..e3337e8a 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -73,6 +73,7 @@ CTL_PROTO(config_prof) CTL_PROTO(config_prof_libgcc) CTL_PROTO(config_prof_libunwind) CTL_PROTO(config_stats) +CTL_PROTO(config_thp) CTL_PROTO(config_utrace) CTL_PROTO(config_xmalloc) CTL_PROTO(opt_abort) @@ -263,6 +264,7 @@ static const ctl_named_node_t config_node[] = { {NAME("prof_libgcc"), CTL(config_prof_libgcc)}, {NAME("prof_libunwind"), CTL(config_prof_libunwind)}, {NAME("stats"), CTL(config_stats)}, + {NAME("thp"), CTL(config_thp)}, {NAME("utrace"), CTL(config_utrace)}, {NAME("xmalloc"), CTL(config_xmalloc)} }; @@ -1544,6 +1546,7 @@ CTL_RO_CONFIG_GEN(config_prof, bool) CTL_RO_CONFIG_GEN(config_prof_libgcc, bool) CTL_RO_CONFIG_GEN(config_prof_libunwind, bool) CTL_RO_CONFIG_GEN(config_stats, bool) +CTL_RO_CONFIG_GEN(config_thp, bool) CTL_RO_CONFIG_GEN(config_utrace, bool) CTL_RO_CONFIG_GEN(config_xmalloc, bool) diff --git a/src/stats.c b/src/stats.c index 61550d83..268862b0 100644 --- a/src/stats.c +++ b/src/stats.c @@ -725,6 +725,7 @@ stats_general_print(void (*write_cb)(void *, const char *), void *cbopaque, CONFIG_WRITE_BOOL_JSON(prof_libgcc, ",") CONFIG_WRITE_BOOL_JSON(prof_libunwind, ",") CONFIG_WRITE_BOOL_JSON(stats, ",") + CONFIG_WRITE_BOOL_JSON(thp, ",") CONFIG_WRITE_BOOL_JSON(utrace, ",") CONFIG_WRITE_BOOL_JSON(xmalloc, "") diff --git a/test/unit/pages.c b/test/unit/pages.c index 4457f369..67dbb4cd 100644 --- a/test/unit/pages.c +++ b/test/unit/pages.c @@ -11,7 +11,7 @@ TEST_BEGIN(test_pages_huge) { assert_ptr_not_null(pages, "Unexpected pages_map() error"); hugepage = (void *)(ALIGNMENT_CEILING((uintptr_t)pages, HUGEPAGE)); - assert_b_ne(pages_huge(hugepage, HUGEPAGE), have_thp, + assert_b_ne(pages_huge(hugepage, HUGEPAGE), config_thp, "Unexpected pages_huge() result"); assert_false(pages_nohuge(hugepage, HUGEPAGE), "Unexpected pages_nohuge() result"); -- GitLab From 685c97fc433dad4b872639b08aaf074a8db3fdb1 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 30 May 2017 13:51:33 -0700 Subject: [PATCH 509/544] More thoroughly document the *.{nmalloc,ndalloc,nrequests} mallctls. This resolves #412. --- doc/jemalloc.xml.in | 74 ++++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index a9c3d403..41e80049 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -2601,8 +2601,11 @@ struct extent_hooks_s { r- [] - Cumulative number of allocation requests served by - small bins. + Cumulative number of times a small allocation was + requested from the arena's bins, whether to fill the relevant tcache if + opt.tcache is + enabled, or to directly satisfy an allocation request + otherwise. @@ -2612,8 +2615,11 @@ struct extent_hooks_s { r- [] - Cumulative number of small objects returned to bins. - + Cumulative number of times a small allocation was + returned to the arena's bins, whether to flush the relevant tcache if + opt.tcache is + enabled, or to directly deallocate an allocation + otherwise. @@ -2623,8 +2629,8 @@ struct extent_hooks_s { r- [] - Cumulative number of small allocation requests. - + Cumulative number of allocation requests satisfied by + all bin size classes. @@ -2645,8 +2651,11 @@ struct extent_hooks_s { r- [] - Cumulative number of large allocation requests served - directly by the arena. + Cumulative number of times a large extent was allocated + from the arena, whether to fill the relevant tcache if opt.tcache is enabled and + the size class is within the range being cached, or to directly satisfy + an allocation request otherwise. @@ -2656,8 +2665,11 @@ struct extent_hooks_s { r- [] - Cumulative number of large deallocation requests served - directly by the arena. + Cumulative number of times a large extent was returned + to the arena, whether to flush the relevant tcache if opt.tcache is enabled and + the size class is within the range being cached, or to directly + deallocate an allocation otherwise. @@ -2667,8 +2679,8 @@ struct extent_hooks_s { r- [] - Cumulative number of large allocation requests. - + Cumulative number of allocation requests satisfied by + all large size classes. @@ -2678,8 +2690,11 @@ struct extent_hooks_s { r- [] - Cumulative number of allocations served by bin. - + Cumulative number of times a bin region of the + corresponding size class was allocated from the arena, whether to fill + the relevant tcache if opt.tcache is enabled, or + to directly satisfy an allocation request otherwise. @@ -2689,8 +2704,11 @@ struct extent_hooks_s { r- [] - Cumulative number of allocations returned to bin. - + Cumulative number of times a bin region of the + corresponding size class was returned to the arena, whether to flush the + relevant tcache if opt.tcache is enabled, or + to directly deallocate an allocation otherwise. @@ -2700,8 +2718,8 @@ struct extent_hooks_s { r- [] - Cumulative number of allocation - requests. + Cumulative number of allocation requests satisfied by + bin regions of the corresponding size class. @@ -2784,8 +2802,12 @@ struct extent_hooks_s { r- [] - Cumulative number of allocation requests for this size - class served directly by the arena. + Cumulative number of times a large extent of the + corresponding size class was allocated from the arena, whether to fill + the relevant tcache if opt.tcache is enabled and + the size class is within the range being cached, or to directly satisfy + an allocation request otherwise. @@ -2795,8 +2817,12 @@ struct extent_hooks_s { r- [] - Cumulative number of deallocation requests for this - size class served directly by the arena. + Cumulative number of times a large extent of the + corresponding size class was returned to the arena, whether to flush the + relevant tcache if opt.tcache is enabled and + the size class is within the range being cached, or to directly + deallocate an allocation otherwise. @@ -2806,8 +2832,8 @@ struct extent_hooks_s { r- [] - Cumulative number of allocation requests for this size - class. + Cumulative number of allocation requests satisfied by + large extents of the corresponding size class. -- GitLab From 7578b0e929f3380ba1713bd77a38c402a90f3b27 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 30 May 2017 13:17:10 -0700 Subject: [PATCH 510/544] Explicitly say so when aborting on opt_abort_conf. --- src/jemalloc.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index 5e3072b5..ed22a258 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -877,6 +877,14 @@ malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p, return false; } +static void +malloc_abort_invalid_conf(void) { + assert(opt_abort_conf); + malloc_printf(": Abort (abort_conf:true) on invalid conf " + "value (see above).\n"); + abort(); +} + static void malloc_conf_error(const char *msg, const char *k, size_t klen, const char *v, size_t vlen) { @@ -884,7 +892,7 @@ malloc_conf_error(const char *msg, const char *k, size_t klen, const char *v, (int)vlen, v); had_conf_error = true; if (opt_abort_conf) { - abort(); + malloc_abort_invalid_conf(); } } @@ -1086,7 +1094,7 @@ malloc_conf_init(void) { CONF_HANDLE_BOOL(opt_abort, "abort") CONF_HANDLE_BOOL(opt_abort_conf, "abort_conf") if (opt_abort_conf && had_conf_error) { - abort(); + malloc_abort_invalid_conf(); } CONF_HANDLE_BOOL(opt_retain, "retain") if (strncmp("dss", k, klen) == 0) { -- GitLab From ff8062a511f2f3e727891c21238d98c6757ee27e Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 30 May 2017 14:26:02 -0700 Subject: [PATCH 511/544] Add jemalloc prefix to allocator functions pruned by jeprof. This resolves #507. --- bin/jeprof.in | 26 +++++++++++++------------- configure.ac | 1 + 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/bin/jeprof.in b/bin/jeprof.in index baa80a54..e6f4af4b 100644 --- a/bin/jeprof.in +++ b/bin/jeprof.in @@ -2892,21 +2892,21 @@ sub RemoveUninterestingFrames { my %skip = (); my $skip_regexp = 'NOMATCH'; if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') { - foreach my $name ('calloc', + foreach my $name ('@JEMALLOC_PREFIX@calloc', 'cfree', - 'malloc', - 'free', - 'memalign', - 'posix_memalign', - 'aligned_alloc', + '@JEMALLOC_PREFIX@malloc', + '@JEMALLOC_PREFIX@free', + '@JEMALLOC_PREFIX@memalign', + '@JEMALLOC_PREFIX@posix_memalign', + '@JEMALLOC_PREFIX@aligned_alloc', 'pvalloc', - 'valloc', - 'realloc', - 'mallocx', # jemalloc - 'rallocx', # jemalloc - 'xallocx', # jemalloc - 'dallocx', # jemalloc - 'sdallocx', # jemalloc + '@JEMALLOC_PREFIX@valloc', + '@JEMALLOC_PREFIX@realloc', + '@JEMALLOC_PREFIX@mallocx', + '@JEMALLOC_PREFIX@rallocx', + '@JEMALLOC_PREFIX@xallocx', + '@JEMALLOC_PREFIX@dallocx', + '@JEMALLOC_PREFIX@sdallocx', 'tc_calloc', 'tc_cfree', 'tc_malloc', diff --git a/configure.ac b/configure.ac index bed01b7a..a00aab9b 100644 --- a/configure.ac +++ b/configure.ac @@ -802,6 +802,7 @@ else AC_DEFINE_UNQUOTED([JEMALLOC_PREFIX], ["$JEMALLOC_PREFIX"]) AC_DEFINE_UNQUOTED([JEMALLOC_CPREFIX], ["$JEMALLOC_CPREFIX"]) fi +AC_SUBST([JEMALLOC_PREFIX]) AC_SUBST([JEMALLOC_CPREFIX]) AC_ARG_WITH([export], -- GitLab From 2e4d1a4e30ec602a692707ca2aa576ee9df2be76 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 30 May 2017 15:56:01 -0700 Subject: [PATCH 512/544] Output total_wait_ns for bin mutexes. --- src/stats.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/src/stats.c b/src/stats.c index 268862b0..087df767 100644 --- a/src/stats.c +++ b/src/stats.c @@ -131,7 +131,7 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, "\t\t\t\t\"bins\": [\n"); } else { char *mutex_counters = " n_lock_ops n_waiting" - " n_spin_acq max_wait_ns\n"; + " n_spin_acq total_wait_ns max_wait_ns\n"; malloc_cprintf(write_cb, cbopaque, "bins: size ind allocated nmalloc" " ndalloc nrequests curregs curslabs regs" @@ -221,28 +221,11 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, not_reached(); } } - /* Output less info for bin mutexes to save space. */ - uint64_t num_ops, num_wait, max_wait; - CTL_M2_M4_GET("stats.arenas.0.bins.0.mutex.num_wait", - i, j, &num_wait, uint64_t); - CTL_M2_M4_GET( - "stats.arenas.0.bins.0.mutex.max_wait_time", i, j, - &max_wait, uint64_t); - CTL_M2_M4_GET("stats.arenas.0.bins.0.mutex.num_ops", - i, j, &num_ops, uint64_t); uint64_t mutex_stats[mutex_prof_num_counters]; if (mutex) { read_arena_bin_mutex_stats(i, j, mutex_stats); } - char rate[6]; - if (get_rate_str(num_wait, num_ops, rate)) { - if (num_ops == 0) { - malloc_snprintf(rate, sizeof(rate), - "0"); - } - } - malloc_cprintf(write_cb, cbopaque, "%20zu %3u %12zu %12" FMTu64" %12"FMTu64" %12"FMTu64" %12zu %12zu %4u" " %3zu %-5s %12"FMTu64" %12"FMTu64" %12"FMTu64 @@ -250,13 +233,16 @@ stats_arena_bins_print(void (*write_cb)(void *, const char *), void *cbopaque, nmalloc, ndalloc, nrequests, curregs, curslabs, nregs, slab_size / page, util, nfills, nflushes, nslabs, nreslabs); + + /* Output less info for bin mutexes to save space. */ if (mutex) { malloc_cprintf(write_cb, cbopaque, " %12"FMTu64" %12"FMTu64" %12"FMTu64 - " %12"FMTu64"\n", + " %14"FMTu64" %12"FMTu64"\n", mutex_stats[mutex_counter_num_ops], mutex_stats[mutex_counter_num_wait], mutex_stats[mutex_counter_num_spin_acq], + mutex_stats[mutex_counter_total_wait_time], mutex_stats[mutex_counter_max_wait_time]); } else { malloc_cprintf(write_cb, cbopaque, "\n"); -- GitLab From 66813916b52c373707ecb7f6875b0c4062873214 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 30 May 2017 18:05:27 -0700 Subject: [PATCH 513/544] Track background thread status separately at fork. Use a separate boolean to track the enabled status, instead of leaving the global background thread status inconsistent. --- src/background_thread.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/background_thread.c b/src/background_thread.c index 1e725b4e..d3e80b3d 100644 --- a/src/background_thread.c +++ b/src/background_thread.c @@ -41,6 +41,8 @@ bool background_thread_stats_read(tsdn_t *tsdn, #undef NOT_REACHED #else +static bool background_thread_enabled_at_fork; + static void background_thread_info_reinit(tsdn_t *tsdn, background_thread_info_t *info) { background_thread_wakeup_time_set(tsdn, info, 0); @@ -548,10 +550,11 @@ void background_thread_prefork0(tsdn_t *tsdn) { malloc_mutex_prefork(tsdn, &background_thread_lock); if (background_thread_enabled()) { + background_thread_enabled_at_fork = true; background_thread_enabled_set(tsdn, false); background_threads_disable(tsdn_tsd(tsdn)); - /* Enable again to re-create threads after fork. */ - background_thread_enabled_set(tsdn, true); + } else { + background_thread_enabled_at_fork = false; } assert(n_background_threads == 0); } @@ -565,7 +568,9 @@ background_thread_prefork1(tsdn_t *tsdn) { static void background_thread_postfork_init(tsdn_t *tsdn) { - if (background_thread_enabled()) { + assert(n_background_threads == 0); + if (background_thread_enabled_at_fork) { + background_thread_enabled_set(tsdn, true); background_threads_enable(tsdn_tsd(tsdn)); } } -- GitLab From 10d090aae9834e1eb24b957d4fac042c205af52e Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 30 May 2017 14:36:55 -0700 Subject: [PATCH 514/544] Pass the O_CLOEXEC flag to open(2). This resolves #528. --- src/pages.c | 7 ++++--- src/prof.c | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pages.c b/src/pages.c index 3a048e3b..fec64dd0 100644 --- a/src/pages.c +++ b/src/pages.c @@ -353,12 +353,13 @@ os_overcommits_proc(void) { ssize_t nread; #if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_open) - fd = (int)syscall(SYS_open, "/proc/sys/vm/overcommit_memory", O_RDONLY); + fd = (int)syscall(SYS_open, "/proc/sys/vm/overcommit_memory", O_RDONLY | + O_CLOEXEC); #elif defined(JEMALLOC_USE_SYSCALL) && defined(SYS_openat) fd = (int)syscall(SYS_openat, - AT_FDCWD, "/proc/sys/vm/overcommit_memory", O_RDONLY); + AT_FDCWD, "/proc/sys/vm/overcommit_memory", O_RDONLY | O_CLOEXEC); #else - fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY); + fd = open("/proc/sys/vm/overcommit_memory", O_RDONLY | O_CLOEXEC); #endif if (fd == -1) { return false; /* Error. */ diff --git a/src/prof.c b/src/prof.c index 639e5983..aa67486d 100644 --- a/src/prof.c +++ b/src/prof.c @@ -1409,7 +1409,7 @@ prof_open_maps(const char *format, ...) { va_start(ap, format); malloc_vsnprintf(filename, sizeof(filename), format, ap); va_end(ap); - mfd = open(filename, O_RDONLY); + mfd = open(filename, O_RDONLY | O_CLOEXEC); return mfd; } -- GitLab From b4b4a98bc8463cc9e4ef0a78244d5047d497eed7 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 31 May 2017 10:16:16 -0700 Subject: [PATCH 515/544] Add /run_tests.out/ to .gitignore. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 9acf374b..a25aaf7e 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,8 @@ /src/*.[od] /src/*.sym +/run_tests.out/ + /test/test.sh test/include/test/jemalloc_test.h test/include/test/jemalloc_test_defs.h -- GitLab From 44f9bd147a3df96e42adbe7ad4f0195763105bbe Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 23 May 2017 14:26:31 -0700 Subject: [PATCH 516/544] Header refactoring: unify and de-catchall rtree module. --- include/jemalloc/internal/arena_inlines_b.h | 1 + include/jemalloc/internal/extent_externs.h | 1 + .../internal/jemalloc_internal_includes.h | 4 - .../internal/jemalloc_internal_inlines_b.h | 2 + .../internal/{rtree_inlines.h => rtree.h} | 132 +++++++++++++++++- include/jemalloc/internal/rtree_ctx.h | 22 --- include/jemalloc/internal/rtree_externs.h | 45 ------ include/jemalloc/internal/rtree_structs.h | 53 ------- .../internal/{rtree_types.h => rtree_tsd.h} | 63 +++------ include/jemalloc/internal/tsd.h | 2 +- src/arena.c | 1 + src/extent.c | 1 + src/jemalloc.c | 1 + src/large.c | 1 + src/tsd.c | 1 + test/unit/arena_reset.c | 2 + test/unit/rtree.c | 2 + test/unit/spin.c | 2 + 18 files changed, 166 insertions(+), 170 deletions(-) rename include/jemalloc/internal/{rtree_inlines.h => rtree.h} (74%) delete mode 100644 include/jemalloc/internal/rtree_ctx.h delete mode 100644 include/jemalloc/internal/rtree_externs.h delete mode 100644 include/jemalloc/internal/rtree_structs.h rename include/jemalloc/internal/{rtree_types.h => rtree_tsd.h} (51%) diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 8db6e9a8..16635c1a 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/mutex.h" +#include "jemalloc/internal/rtree.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/ticker.h" diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index 9d5daf5b..96a71126 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -4,6 +4,7 @@ #include "jemalloc/internal/mutex.h" #include "jemalloc/internal/ph.h" #include "jemalloc/internal/rb.h" +#include "jemalloc/internal/rtree.h" extern rtree_t extents_rtree; extern const extent_hooks_t extent_hooks_default; diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index b1a6f17d..770bcaab 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -44,7 +44,6 @@ #include "jemalloc/internal/extent_dss_types.h" #include "jemalloc/internal/base_types.h" #include "jemalloc/internal/arena_types.h" -#include "jemalloc/internal/rtree_types.h" #include "jemalloc/internal/tcache_types.h" #include "jemalloc/internal/prof_types.h" @@ -59,7 +58,6 @@ #include "jemalloc/internal/base_structs.h" #include "jemalloc/internal/prof_structs.h" #include "jemalloc/internal/arena_structs_b.h" -#include "jemalloc/internal/rtree_structs.h" #include "jemalloc/internal/tcache_structs.h" #include "jemalloc/internal/background_thread_structs.h" @@ -73,7 +71,6 @@ #include "jemalloc/internal/extent_mmap_externs.h" #include "jemalloc/internal/base_externs.h" #include "jemalloc/internal/arena_externs.h" -#include "jemalloc/internal/rtree_externs.h" #include "jemalloc/internal/large_externs.h" #include "jemalloc/internal/tcache_externs.h" #include "jemalloc/internal/prof_externs.h" @@ -85,7 +82,6 @@ #include "jemalloc/internal/mutex_pool_inlines.h" #include "jemalloc/internal/jemalloc_internal_inlines_a.h" -#include "jemalloc/internal/rtree_inlines.h" #include "jemalloc/internal/base_inlines.h" /* * Include portions of arena code interleaved with tcache code in order to diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_b.h b/include/jemalloc/internal/jemalloc_internal_inlines_b.h index cfc52094..37493160 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_b.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_b.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_INLINES_B_H #define JEMALLOC_INTERNAL_INLINES_B_H +#include "jemalloc/internal/rtree.h" + /* Choose an arena based on a per-thread value. */ static inline arena_t * arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { diff --git a/include/jemalloc/internal/rtree_inlines.h b/include/jemalloc/internal/rtree.h similarity index 74% rename from include/jemalloc/internal/rtree_inlines.h rename to include/jemalloc/internal/rtree.h index 335a89cf..b5d4db39 100644 --- a/include/jemalloc/internal/rtree_inlines.h +++ b/include/jemalloc/internal/rtree.h @@ -1,8 +1,132 @@ -#ifndef JEMALLOC_INTERNAL_RTREE_INLINES_H -#define JEMALLOC_INTERNAL_RTREE_INLINES_H +#ifndef JEMALLOC_INTERNAL_RTREE_H +#define JEMALLOC_INTERNAL_RTREE_H +#include "jemalloc/internal/atomic.h" +#include "jemalloc/internal/mutex.h" +#include "jemalloc/internal/rtree_tsd.h" #include "jemalloc/internal/size_classes.h" -#include "jemalloc/internal/spin.h" +#include "jemalloc/internal/tsd.h" + +/* + * This radix tree implementation is tailored to the singular purpose of + * associating metadata with extents that are currently owned by jemalloc. + * + ******************************************************************************* + */ + +/* Number of high insignificant bits. */ +#define RTREE_NHIB ((1U << (LG_SIZEOF_PTR+3)) - LG_VADDR) +/* Number of low insigificant bits. */ +#define RTREE_NLIB LG_PAGE +/* Number of significant bits. */ +#define RTREE_NSB (LG_VADDR - RTREE_NLIB) +/* Number of levels in radix tree. */ +#if RTREE_NSB <= 10 +# define RTREE_HEIGHT 1 +#elif RTREE_NSB <= 36 +# define RTREE_HEIGHT 2 +#elif RTREE_NSB <= 52 +# define RTREE_HEIGHT 3 +#else +# error Unsupported number of significant virtual address bits +#endif +/* Use compact leaf representation if virtual address encoding allows. */ +#if RTREE_NHIB >= LG_CEIL_NSIZES +# define RTREE_LEAF_COMPACT +#endif + +/* Needed for initialization only. */ +#define RTREE_LEAFKEY_INVALID ((uintptr_t)1) + +typedef struct rtree_node_elm_s rtree_node_elm_t; +struct rtree_node_elm_s { + atomic_p_t child; /* (rtree_{node,leaf}_elm_t *) */ +}; + +struct rtree_leaf_elm_s { +#ifdef RTREE_LEAF_COMPACT + /* + * Single pointer-width field containing all three leaf element fields. + * For example, on a 64-bit x64 system with 48 significant virtual + * memory address bits, the index, extent, and slab fields are packed as + * such: + * + * x: index + * e: extent + * b: slab + * + * 00000000 xxxxxxxx eeeeeeee [...] eeeeeeee eeee000b + */ + atomic_p_t le_bits; +#else + atomic_p_t le_extent; /* (extent_t *) */ + atomic_u_t le_szind; /* (szind_t) */ + atomic_b_t le_slab; /* (bool) */ +#endif +}; + +typedef struct rtree_level_s rtree_level_t; +struct rtree_level_s { + /* Number of key bits distinguished by this level. */ + unsigned bits; + /* + * Cumulative number of key bits distinguished by traversing to + * corresponding tree level. + */ + unsigned cumbits; +}; + +typedef struct rtree_s rtree_t; +struct rtree_s { + malloc_mutex_t init_lock; + /* Number of elements based on rtree_levels[0].bits. */ +#if RTREE_HEIGHT > 1 + rtree_node_elm_t root[1U << (RTREE_NSB/RTREE_HEIGHT)]; +#else + rtree_leaf_elm_t root[1U << (RTREE_NSB/RTREE_HEIGHT)]; +#endif +}; + +/* + * Split the bits into one to three partitions depending on number of + * significant bits. It the number of bits does not divide evenly into the + * number of levels, place one remainder bit per level starting at the leaf + * level. + */ +static const rtree_level_t rtree_levels[] = { +#if RTREE_HEIGHT == 1 + {RTREE_NSB, RTREE_NHIB + RTREE_NSB} +#elif RTREE_HEIGHT == 2 + {RTREE_NSB/2, RTREE_NHIB + RTREE_NSB/2}, + {RTREE_NSB/2 + RTREE_NSB%2, RTREE_NHIB + RTREE_NSB} +#elif RTREE_HEIGHT == 3 + {RTREE_NSB/3, RTREE_NHIB + RTREE_NSB/3}, + {RTREE_NSB/3 + RTREE_NSB%3/2, + RTREE_NHIB + RTREE_NSB/3*2 + RTREE_NSB%3/2}, + {RTREE_NSB/3 + RTREE_NSB%3 - RTREE_NSB%3/2, RTREE_NHIB + RTREE_NSB} +#else +# error Unsupported rtree height +#endif +}; + +bool rtree_new(rtree_t *rtree, bool zeroed); + +typedef rtree_node_elm_t *(rtree_node_alloc_t)(tsdn_t *, rtree_t *, size_t); +extern rtree_node_alloc_t *JET_MUTABLE rtree_node_alloc; + +typedef rtree_leaf_elm_t *(rtree_leaf_alloc_t)(tsdn_t *, rtree_t *, size_t); +extern rtree_leaf_alloc_t *JET_MUTABLE rtree_leaf_alloc; + +typedef void (rtree_node_dalloc_t)(tsdn_t *, rtree_t *, rtree_node_elm_t *); +extern rtree_node_dalloc_t *JET_MUTABLE rtree_node_dalloc; + +typedef void (rtree_leaf_dalloc_t)(tsdn_t *, rtree_t *, rtree_leaf_elm_t *); +extern rtree_leaf_dalloc_t *JET_MUTABLE rtree_leaf_dalloc; +#ifdef JEMALLOC_JET +void rtree_delete(tsdn_t *tsdn, rtree_t *rtree); +#endif +rtree_leaf_elm_t *rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, + rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); JEMALLOC_ALWAYS_INLINE uintptr_t rtree_leafkey(uintptr_t key) { @@ -347,4 +471,4 @@ rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, rtree_leaf_elm_write(tsdn, rtree, elm, NULL, NSIZES, false); } -#endif /* JEMALLOC_INTERNAL_RTREE_INLINES_H */ +#endif /* JEMALLOC_INTERNAL_RTREE_H */ diff --git a/include/jemalloc/internal/rtree_ctx.h b/include/jemalloc/internal/rtree_ctx.h deleted file mode 100644 index fe2c8bde..00000000 --- a/include/jemalloc/internal/rtree_ctx.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_RTREE_CTX_H -#define JEMALLOC_INTERNAL_RTREE_CTX_H - -#include "jemalloc/internal/rtree_types.h" - -typedef struct rtree_ctx_cache_elm_s rtree_ctx_cache_elm_t; -struct rtree_ctx_cache_elm_s { - uintptr_t leafkey; - rtree_leaf_elm_t *leaf; -}; - -typedef struct rtree_ctx_s rtree_ctx_t; -struct rtree_ctx_s { - /* Direct mapped cache. */ - rtree_ctx_cache_elm_t cache[RTREE_CTX_NCACHE]; - /* L2 LRU cache. */ - rtree_ctx_cache_elm_t l2_cache[RTREE_CTX_NCACHE_L2]; -}; - -void rtree_ctx_data_init(rtree_ctx_t *ctx); - -#endif /* JEMALLOC_INTERNAL_RTREE_CTX_H */ diff --git a/include/jemalloc/internal/rtree_externs.h b/include/jemalloc/internal/rtree_externs.h deleted file mode 100644 index d7d81654..00000000 --- a/include/jemalloc/internal/rtree_externs.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_RTREE_EXTERNS_H -#define JEMALLOC_INTERNAL_RTREE_EXTERNS_H - -/* - * Split the bits into one to three partitions depending on number of - * significant bits. It the number of bits does not divide evenly into the - * number of levels, place one remainder bit per level starting at the leaf - * level. - */ -static const rtree_level_t rtree_levels[] = { -#if RTREE_HEIGHT == 1 - {RTREE_NSB, RTREE_NHIB + RTREE_NSB} -#elif RTREE_HEIGHT == 2 - {RTREE_NSB/2, RTREE_NHIB + RTREE_NSB/2}, - {RTREE_NSB/2 + RTREE_NSB%2, RTREE_NHIB + RTREE_NSB} -#elif RTREE_HEIGHT == 3 - {RTREE_NSB/3, RTREE_NHIB + RTREE_NSB/3}, - {RTREE_NSB/3 + RTREE_NSB%3/2, - RTREE_NHIB + RTREE_NSB/3*2 + RTREE_NSB%3/2}, - {RTREE_NSB/3 + RTREE_NSB%3 - RTREE_NSB%3/2, RTREE_NHIB + RTREE_NSB} -#else -# error Unsupported rtree height -#endif -}; - -bool rtree_new(rtree_t *rtree, bool zeroed); - -typedef rtree_node_elm_t *(rtree_node_alloc_t)(tsdn_t *, rtree_t *, size_t); -extern rtree_node_alloc_t *JET_MUTABLE rtree_node_alloc; - -typedef rtree_leaf_elm_t *(rtree_leaf_alloc_t)(tsdn_t *, rtree_t *, size_t); -extern rtree_leaf_alloc_t *JET_MUTABLE rtree_leaf_alloc; - -typedef void (rtree_node_dalloc_t)(tsdn_t *, rtree_t *, rtree_node_elm_t *); -extern rtree_node_dalloc_t *JET_MUTABLE rtree_node_dalloc; - -typedef void (rtree_leaf_dalloc_t)(tsdn_t *, rtree_t *, rtree_leaf_elm_t *); -extern rtree_leaf_dalloc_t *JET_MUTABLE rtree_leaf_dalloc; -#ifdef JEMALLOC_JET -void rtree_delete(tsdn_t *tsdn, rtree_t *rtree); -#endif -rtree_leaf_elm_t *rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree, - rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing); - -#endif /* JEMALLOC_INTERNAL_RTREE_EXTERNS_H */ diff --git a/include/jemalloc/internal/rtree_structs.h b/include/jemalloc/internal/rtree_structs.h deleted file mode 100644 index a02a1f60..00000000 --- a/include/jemalloc/internal/rtree_structs.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_RTREE_STRUCTS_H -#define JEMALLOC_INTERNAL_RTREE_STRUCTS_H - -#include "jemalloc/internal/atomic.h" -#include "jemalloc/internal/mutex.h" - -struct rtree_node_elm_s { - atomic_p_t child; /* (rtree_{node,leaf}_elm_t *) */ -}; - -struct rtree_leaf_elm_s { -#ifdef RTREE_LEAF_COMPACT - /* - * Single pointer-width field containing all three leaf element fields. - * For example, on a 64-bit x64 system with 48 significant virtual - * memory address bits, the index, extent, and slab fields are packed as - * such: - * - * x: index - * e: extent - * b: slab - * - * 00000000 xxxxxxxx eeeeeeee [...] eeeeeeee eeee000b - */ - atomic_p_t le_bits; -#else - atomic_p_t le_extent; /* (extent_t *) */ - atomic_u_t le_szind; /* (szind_t) */ - atomic_b_t le_slab; /* (bool) */ -#endif -}; - -struct rtree_level_s { - /* Number of key bits distinguished by this level. */ - unsigned bits; - /* - * Cumulative number of key bits distinguished by traversing to - * corresponding tree level. - */ - unsigned cumbits; -}; - -struct rtree_s { - malloc_mutex_t init_lock; - /* Number of elements based on rtree_levels[0].bits. */ -#if RTREE_HEIGHT > 1 - rtree_node_elm_t root[1U << (RTREE_NSB/RTREE_HEIGHT)]; -#else - rtree_leaf_elm_t root[1U << (RTREE_NSB/RTREE_HEIGHT)]; -#endif -}; - -#endif /* JEMALLOC_INTERNAL_RTREE_STRUCTS_H */ diff --git a/include/jemalloc/internal/rtree_types.h b/include/jemalloc/internal/rtree_tsd.h similarity index 51% rename from include/jemalloc/internal/rtree_types.h rename to include/jemalloc/internal/rtree_tsd.h index fd0f1409..3cdc8625 100644 --- a/include/jemalloc/internal/rtree_types.h +++ b/include/jemalloc/internal/rtree_tsd.h @@ -1,43 +1,5 @@ -#ifndef JEMALLOC_INTERNAL_RTREE_TYPES_H -#define JEMALLOC_INTERNAL_RTREE_TYPES_H - -#include "jemalloc/internal/size_classes.h" - -/* - * This radix tree implementation is tailored to the singular purpose of - * associating metadata with extents that are currently owned by jemalloc. - * - ******************************************************************************* - */ - -typedef struct rtree_node_elm_s rtree_node_elm_t; -typedef struct rtree_leaf_elm_s rtree_leaf_elm_t; -typedef struct rtree_level_s rtree_level_t; -typedef struct rtree_s rtree_t; - -/* Number of high insignificant bits. */ -#define RTREE_NHIB ((1U << (LG_SIZEOF_PTR+3)) - LG_VADDR) -/* Number of low insigificant bits. */ -#define RTREE_NLIB LG_PAGE -/* Number of significant bits. */ -#define RTREE_NSB (LG_VADDR - RTREE_NLIB) -/* Number of levels in radix tree. */ -#if RTREE_NSB <= 10 -# define RTREE_HEIGHT 1 -#elif RTREE_NSB <= 36 -# define RTREE_HEIGHT 2 -#elif RTREE_NSB <= 52 -# define RTREE_HEIGHT 3 -#else -# error Unsupported number of significant virtual address bits -#endif -/* Use compact leaf representation if virtual address encoding allows. */ -#if RTREE_NHIB >= LG_CEIL_NSIZES -# define RTREE_LEAF_COMPACT -#endif - -/* Needed for initialization only. */ -#define RTREE_LEAFKEY_INVALID ((uintptr_t)1) +#ifndef JEMALLOC_INTERNAL_RTREE_CTX_H +#define JEMALLOC_INTERNAL_RTREE_CTX_H /* * Number of leafkey/leaf pairs to cache in L1 and L2 level respectively. Each @@ -66,4 +28,23 @@ typedef struct rtree_s rtree_t; */ #define RTREE_CTX_ZERO_INITIALIZER {{{0}}} -#endif /* JEMALLOC_INTERNAL_RTREE_TYPES_H */ + +typedef struct rtree_leaf_elm_s rtree_leaf_elm_t; + +typedef struct rtree_ctx_cache_elm_s rtree_ctx_cache_elm_t; +struct rtree_ctx_cache_elm_s { + uintptr_t leafkey; + rtree_leaf_elm_t *leaf; +}; + +typedef struct rtree_ctx_s rtree_ctx_t; +struct rtree_ctx_s { + /* Direct mapped cache. */ + rtree_ctx_cache_elm_t cache[RTREE_CTX_NCACHE]; + /* L2 LRU cache. */ + rtree_ctx_cache_elm_t l2_cache[RTREE_CTX_NCACHE_L2]; +}; + +void rtree_ctx_data_init(rtree_ctx_t *ctx); + +#endif /* JEMALLOC_INTERNAL_RTREE_CTX_H */ diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h index c192a6ca..f304e1d9 100644 --- a/include/jemalloc/internal/tsd.h +++ b/include/jemalloc/internal/tsd.h @@ -6,7 +6,7 @@ #include "jemalloc/internal/jemalloc_internal_externs.h" #include "jemalloc/internal/prof_types.h" #include "jemalloc/internal/ql.h" -#include "jemalloc/internal/rtree_ctx.h" +#include "jemalloc/internal/rtree_tsd.h" #include "jemalloc/internal/tcache_types.h" #include "jemalloc/internal/tcache_structs.h" #include "jemalloc/internal/util.h" diff --git a/src/arena.c b/src/arena.c index 9b3ea235..3d0725f4 100644 --- a/src/arena.c +++ b/src/arena.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/mutex.h" +#include "jemalloc/internal/rtree.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/util.h" diff --git a/src/extent.c b/src/extent.c index 44e98789..2264a0ca 100644 --- a/src/extent.c +++ b/src/extent.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/ph.h" +#include "jemalloc/internal/rtree.h" #include "jemalloc/internal/mutex.h" /******************************************************************************/ diff --git a/src/jemalloc.c b/src/jemalloc.c index ed22a258..00b645f0 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -8,6 +8,7 @@ #include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/malloc_io.h" #include "jemalloc/internal/mutex.h" +#include "jemalloc/internal/rtree.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/spin.h" #include "jemalloc/internal/ticker.h" diff --git a/src/large.c b/src/large.c index 55ee3524..27c9bc60 100644 --- a/src/large.c +++ b/src/large.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/mutex.h" +#include "jemalloc/internal/rtree.h" #include "jemalloc/internal/util.h" /******************************************************************************/ diff --git a/src/tsd.c b/src/tsd.c index 525432b6..29a56775 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/mutex.h" +#include "jemalloc/internal/rtree.h" /******************************************************************************/ /* Data. */ diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index d1698325..678ae57c 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -2,6 +2,8 @@ #include "test/jemalloc_test.h" #endif +#include "jemalloc/internal/rtree.h" + #include "test/extent_hooks.h" static unsigned diff --git a/test/unit/rtree.c b/test/unit/rtree.c index b854afd7..752dde99 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -1,5 +1,7 @@ #include "test/jemalloc_test.h" +#include "jemalloc/internal/rtree.h" + rtree_node_alloc_t *rtree_node_alloc_orig; rtree_node_dalloc_t *rtree_node_dalloc_orig; rtree_leaf_alloc_t *rtree_leaf_alloc_orig; diff --git a/test/unit/spin.c b/test/unit/spin.c index bd368b3d..b965f742 100644 --- a/test/unit/spin.c +++ b/test/unit/spin.c @@ -1,5 +1,7 @@ #include "test/jemalloc_test.h" +#include "jemalloc/internal/spin.h" + TEST_BEGIN(test_spin) { spin_t spinner = SPIN_INITIALIZER; -- GitLab From 93284bb53d9c44a5c36297450a82aed5b8051526 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 23 May 2017 14:36:09 -0700 Subject: [PATCH 517/544] Header refactoring: unify and de-catchall extent_dss. --- include/jemalloc/internal/arena_externs.h | 1 + include/jemalloc/internal/arena_structs_b.h | 1 + include/jemalloc/internal/extent_dss.h | 26 +++++++++++++++++++ .../jemalloc/internal/extent_dss_externs.h | 14 ---------- .../jemalloc/internal/extent_dss_structs.h | 6 ----- include/jemalloc/internal/extent_dss_types.h | 14 ---------- .../internal/jemalloc_internal_includes.h | 3 --- src/arena.c | 1 + src/ctl.c | 1 + src/extent.c | 1 + src/extent_dss.c | 1 + src/jemalloc.c | 1 + 12 files changed, 33 insertions(+), 37 deletions(-) create mode 100644 include/jemalloc/internal/extent_dss.h delete mode 100644 include/jemalloc/internal/extent_dss_externs.h delete mode 100644 include/jemalloc/internal/extent_dss_structs.h delete mode 100644 include/jemalloc/internal/extent_dss_types.h diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 273705f7..08a6d174 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -1,6 +1,7 @@ #ifndef JEMALLOC_INTERNAL_ARENA_EXTERNS_H #define JEMALLOC_INTERNAL_ARENA_EXTERNS_H +#include "jemalloc/internal/extent_dss.h" #include "jemalloc/internal/pages.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/stats.h" diff --git a/include/jemalloc/internal/arena_structs_b.h b/include/jemalloc/internal/arena_structs_b.h index 160ac4fa..d1fffec1 100644 --- a/include/jemalloc/internal/arena_structs_b.h +++ b/include/jemalloc/internal/arena_structs_b.h @@ -3,6 +3,7 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/bitmap.h" +#include "jemalloc/internal/extent_dss.h" #include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/mutex.h" #include "jemalloc/internal/nstime.h" diff --git a/include/jemalloc/internal/extent_dss.h b/include/jemalloc/internal/extent_dss.h new file mode 100644 index 00000000..e8f02ce2 --- /dev/null +++ b/include/jemalloc/internal/extent_dss.h @@ -0,0 +1,26 @@ +#ifndef JEMALLOC_INTERNAL_EXTENT_DSS_H +#define JEMALLOC_INTERNAL_EXTENT_DSS_H + +typedef enum { + dss_prec_disabled = 0, + dss_prec_primary = 1, + dss_prec_secondary = 2, + + dss_prec_limit = 3 +} dss_prec_t; +#define DSS_PREC_DEFAULT dss_prec_secondary +#define DSS_DEFAULT "secondary" + +extern const char *dss_prec_names[]; + +extern const char *opt_dss; + +dss_prec_t extent_dss_prec_get(void); +bool extent_dss_prec_set(dss_prec_t dss_prec); +void *extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, + size_t size, size_t alignment, bool *zero, bool *commit); +bool extent_in_dss(void *addr); +bool extent_dss_mergeable(void *addr_a, void *addr_b); +void extent_dss_boot(void); + +#endif /* JEMALLOC_INTERNAL_EXTENT_DSS_H */ diff --git a/include/jemalloc/internal/extent_dss_externs.h b/include/jemalloc/internal/extent_dss_externs.h deleted file mode 100644 index d376fa74..00000000 --- a/include/jemalloc/internal/extent_dss_externs.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_EXTENT_DSS_EXTERNS_H -#define JEMALLOC_INTERNAL_EXTENT_DSS_EXTERNS_H - -extern const char *opt_dss; - -dss_prec_t extent_dss_prec_get(void); -bool extent_dss_prec_set(dss_prec_t dss_prec); -void *extent_alloc_dss(tsdn_t *tsdn, arena_t *arena, void *new_addr, - size_t size, size_t alignment, bool *zero, bool *commit); -bool extent_in_dss(void *addr); -bool extent_dss_mergeable(void *addr_a, void *addr_b); -void extent_dss_boot(void); - -#endif /* JEMALLOC_INTERNAL_EXTENT_DSS_EXTERNS_H */ diff --git a/include/jemalloc/internal/extent_dss_structs.h b/include/jemalloc/internal/extent_dss_structs.h deleted file mode 100644 index 2d8c6f05..00000000 --- a/include/jemalloc/internal/extent_dss_structs.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_EXTENT_DSS_STRUCTS_H -#define JEMALLOC_INTERNAL_EXTENT_DSS_STRUCTS_H - -extern const char *dss_prec_names[]; - -#endif /* JEMALLOC_INTERNAL_EXTENT_DSS_STRUCTS_H */ diff --git a/include/jemalloc/internal/extent_dss_types.h b/include/jemalloc/internal/extent_dss_types.h deleted file mode 100644 index a851c7cb..00000000 --- a/include/jemalloc/internal/extent_dss_types.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_EXTENT_DSS_TYPES_H -#define JEMALLOC_INTERNAL_EXTENT_DSS_TYPES_H - -typedef enum { - dss_prec_disabled = 0, - dss_prec_primary = 1, - dss_prec_secondary = 2, - - dss_prec_limit = 3 -} dss_prec_t; -#define DSS_PREC_DEFAULT dss_prec_secondary -#define DSS_DEFAULT "secondary" - -#endif /* JEMALLOC_INTERNAL_EXTENT_DSS_TYPES_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 770bcaab..71c856b2 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -41,7 +41,6 @@ /******************************************************************************/ #include "jemalloc/internal/extent_types.h" -#include "jemalloc/internal/extent_dss_types.h" #include "jemalloc/internal/base_types.h" #include "jemalloc/internal/arena_types.h" #include "jemalloc/internal/tcache_types.h" @@ -54,7 +53,6 @@ #include "jemalloc/internal/mutex_pool_structs.h" #include "jemalloc/internal/arena_structs_a.h" #include "jemalloc/internal/extent_structs.h" -#include "jemalloc/internal/extent_dss_structs.h" #include "jemalloc/internal/base_structs.h" #include "jemalloc/internal/prof_structs.h" #include "jemalloc/internal/arena_structs_b.h" @@ -67,7 +65,6 @@ #include "jemalloc/internal/jemalloc_internal_externs.h" #include "jemalloc/internal/extent_externs.h" -#include "jemalloc/internal/extent_dss_externs.h" #include "jemalloc/internal/extent_mmap_externs.h" #include "jemalloc/internal/base_externs.h" #include "jemalloc/internal/arena_externs.h" diff --git a/src/arena.c b/src/arena.c index 3d0725f4..01358959 100644 --- a/src/arena.c +++ b/src/arena.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/extent_dss.h" #include "jemalloc/internal/mutex.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/size_classes.h" diff --git a/src/ctl.c b/src/ctl.c index e3337e8a..e81ca417 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/ctl.h" +#include "jemalloc/internal/extent_dss.h" #include "jemalloc/internal/mutex.h" #include "jemalloc/internal/nstime.h" #include "jemalloc/internal/size_classes.h" diff --git a/src/extent.c b/src/extent.c index 2264a0ca..0929aee4 100644 --- a/src/extent.c +++ b/src/extent.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/extent_dss.h" #include "jemalloc/internal/ph.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/mutex.h" diff --git a/src/extent_dss.c b/src/extent_dss.c index 8e0ca654..e72da958 100644 --- a/src/extent_dss.c +++ b/src/extent_dss.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/extent_dss.h" #include "jemalloc/internal/spin.h" /******************************************************************************/ diff --git a/src/jemalloc.c b/src/jemalloc.c index 00b645f0..32f4a4c5 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -5,6 +5,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/ctl.h" +#include "jemalloc/internal/extent_dss.h" #include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/malloc_io.h" #include "jemalloc/internal/mutex.h" -- GitLab From 98774e64a4696c7bce6d2317aa59fe5b39bba69f Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 23 May 2017 14:42:32 -0700 Subject: [PATCH 518/544] Header refactoring: unify and de-catchall extent_mmap module. --- .../internal/{extent_mmap_externs.h => extent_mmap.h} | 6 +++--- include/jemalloc/internal/jemalloc_internal_includes.h | 1 - src/arena.c | 1 + src/base.c | 1 + src/ctl.c | 1 + src/extent.c | 1 + src/extent_mmap.c | 1 + src/jemalloc.c | 1 + src/large.c | 1 + test/unit/arena_reset.c | 1 + 10 files changed, 11 insertions(+), 4 deletions(-) rename include/jemalloc/internal/{extent_mmap_externs.h => extent_mmap.h} (57%) diff --git a/include/jemalloc/internal/extent_mmap_externs.h b/include/jemalloc/internal/extent_mmap.h similarity index 57% rename from include/jemalloc/internal/extent_mmap_externs.h rename to include/jemalloc/internal/extent_mmap.h index fe9a79ac..55f17ee4 100644 --- a/include/jemalloc/internal/extent_mmap_externs.h +++ b/include/jemalloc/internal/extent_mmap.h @@ -1,10 +1,10 @@ #ifndef JEMALLOC_INTERNAL_EXTENT_MMAP_EXTERNS_H #define JEMALLOC_INTERNAL_EXTENT_MMAP_EXTERNS_H -extern bool opt_retain; +extern bool opt_retain; -void *extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, +void *extent_alloc_mmap(void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit); -bool extent_dalloc_mmap(void *addr, size_t size); +bool extent_dalloc_mmap(void *addr, size_t size); #endif /* JEMALLOC_INTERNAL_EXTENT_MMAP_EXTERNS_H */ diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 71c856b2..837e9e41 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -65,7 +65,6 @@ #include "jemalloc/internal/jemalloc_internal_externs.h" #include "jemalloc/internal/extent_externs.h" -#include "jemalloc/internal/extent_mmap_externs.h" #include "jemalloc/internal/base_externs.h" #include "jemalloc/internal/arena_externs.h" #include "jemalloc/internal/large_externs.h" diff --git a/src/arena.c b/src/arena.c index 01358959..bf1d6e65 100644 --- a/src/arena.c +++ b/src/arena.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/extent_dss.h" +#include "jemalloc/internal/extent_mmap.h" #include "jemalloc/internal/mutex.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/size_classes.h" diff --git a/src/base.c b/src/base.c index 892c28dd..498e5c9d 100644 --- a/src/base.c +++ b/src/base.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/extent_mmap.h" #include "jemalloc/internal/mutex.h" /******************************************************************************/ diff --git a/src/ctl.c b/src/ctl.c index e81ca417..33275d70 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -5,6 +5,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/ctl.h" #include "jemalloc/internal/extent_dss.h" +#include "jemalloc/internal/extent_mmap.h" #include "jemalloc/internal/mutex.h" #include "jemalloc/internal/nstime.h" #include "jemalloc/internal/size_classes.h" diff --git a/src/extent.c b/src/extent.c index 0929aee4..6589de55 100644 --- a/src/extent.c +++ b/src/extent.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/extent_dss.h" +#include "jemalloc/internal/extent_mmap.h" #include "jemalloc/internal/ph.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/mutex.h" diff --git a/src/extent_mmap.c b/src/extent_mmap.c index 3e4e1ef7..8d607dc8 100644 --- a/src/extent_mmap.c +++ b/src/extent_mmap.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/extent_mmap.h" /******************************************************************************/ /* Data. */ diff --git a/src/jemalloc.c b/src/jemalloc.c index 32f4a4c5..1befb64d 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -6,6 +6,7 @@ #include "jemalloc/internal/atomic.h" #include "jemalloc/internal/ctl.h" #include "jemalloc/internal/extent_dss.h" +#include "jemalloc/internal/extent_mmap.h" #include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/malloc_io.h" #include "jemalloc/internal/mutex.h" diff --git a/src/large.c b/src/large.c index 27c9bc60..79d2c9da 100644 --- a/src/large.c +++ b/src/large.c @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/assert.h" +#include "jemalloc/internal/extent_mmap.h" #include "jemalloc/internal/mutex.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/util.h" diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 678ae57c..958453d1 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -2,6 +2,7 @@ #include "test/jemalloc_test.h" #endif +#include "jemalloc/internal/extent_mmap.h" #include "jemalloc/internal/rtree.h" #include "test/extent_hooks.h" -- GitLab From 041e041e1f23a03d1019330c8401a01285feb44f Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 23 May 2017 14:56:24 -0700 Subject: [PATCH 519/544] Header refactoring: unify and de-catchall mutex_pool. --- include/jemalloc/internal/extent_externs.h | 1 + include/jemalloc/internal/extent_inlines.h | 2 +- .../internal/jemalloc_internal_includes.h | 2 -- .../{mutex_pool_inlines.h => mutex_pool.h} | 18 +++++++++++------- include/jemalloc/internal/mutex_pool_structs.h | 16 ---------------- src/extent.c | 1 + src/mutex_pool.c | 1 + 7 files changed, 15 insertions(+), 26 deletions(-) rename include/jemalloc/internal/{mutex_pool_inlines.h => mutex_pool.h} (86%) delete mode 100644 include/jemalloc/internal/mutex_pool_structs.h diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index 96a71126..acb3ef49 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_EXTENT_EXTERNS_H #include "jemalloc/internal/mutex.h" +#include "jemalloc/internal/mutex_pool.h" #include "jemalloc/internal/ph.h" #include "jemalloc/internal/rb.h" #include "jemalloc/internal/rtree.h" diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index a99a6351..94c41923 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -2,7 +2,7 @@ #define JEMALLOC_INTERNAL_EXTENT_INLINES_H #include "jemalloc/internal/mutex.h" -#include "jemalloc/internal/mutex_pool_inlines.h" +#include "jemalloc/internal/mutex_pool.h" #include "jemalloc/internal/pages.h" #include "jemalloc/internal/prng.h" #include "jemalloc/internal/ql.h" diff --git a/include/jemalloc/internal/jemalloc_internal_includes.h b/include/jemalloc/internal/jemalloc_internal_includes.h index 837e9e41..437eaa40 100644 --- a/include/jemalloc/internal/jemalloc_internal_includes.h +++ b/include/jemalloc/internal/jemalloc_internal_includes.h @@ -50,7 +50,6 @@ /* STRUCTS */ /******************************************************************************/ -#include "jemalloc/internal/mutex_pool_structs.h" #include "jemalloc/internal/arena_structs_a.h" #include "jemalloc/internal/extent_structs.h" #include "jemalloc/internal/base_structs.h" @@ -76,7 +75,6 @@ /* INLINES */ /******************************************************************************/ -#include "jemalloc/internal/mutex_pool_inlines.h" #include "jemalloc/internal/jemalloc_internal_inlines_a.h" #include "jemalloc/internal/base_inlines.h" /* diff --git a/include/jemalloc/internal/mutex_pool_inlines.h b/include/jemalloc/internal/mutex_pool.h similarity index 86% rename from include/jemalloc/internal/mutex_pool_inlines.h rename to include/jemalloc/internal/mutex_pool.h index 19b5ab4c..726cece9 100644 --- a/include/jemalloc/internal/mutex_pool_inlines.h +++ b/include/jemalloc/internal/mutex_pool.h @@ -1,17 +1,21 @@ -#ifndef JEMALLOC_INTERNAL_MUTEX_POOL_INLINES_H -#define JEMALLOC_INTERNAL_MUTEX_POOL_INLINES_H +#ifndef JEMALLOC_INTERNAL_MUTEX_POOL_H +#define JEMALLOC_INTERNAL_MUTEX_POOL_H #include "jemalloc/internal/hash.h" #include "jemalloc/internal/mutex.h" -#include "jemalloc/internal/mutex_pool_structs.h" #include "jemalloc/internal/witness.h" -/* - * This file really combines "inlines" and "externs", but only transitionally. - */ +/* We do mod reductions by this value, so it should be kept a power of 2. */ +#define MUTEX_POOL_SIZE 256 + +typedef struct mutex_pool_s mutex_pool_t; +struct mutex_pool_s { + malloc_mutex_t mutexes[MUTEX_POOL_SIZE]; +}; bool mutex_pool_init(mutex_pool_t *pool, const char *name, witness_rank_t rank); +/* Internal helper - not meant to be called outside this module. */ static inline malloc_mutex_t * mutex_pool_mutex(mutex_pool_t *pool, uintptr_t key) { size_t hash_result[2]; @@ -87,4 +91,4 @@ mutex_pool_assert_owner(tsdn_t *tsdn, mutex_pool_t *pool, uintptr_t key) { malloc_mutex_assert_owner(tsdn, mutex_pool_mutex(pool, key)); } -#endif /* JEMALLOC_INTERNAL_MUTEX_POOL_INLINES_H */ +#endif /* JEMALLOC_INTERNAL_MUTEX_POOL_H */ diff --git a/include/jemalloc/internal/mutex_pool_structs.h b/include/jemalloc/internal/mutex_pool_structs.h deleted file mode 100644 index b32fb5ac..00000000 --- a/include/jemalloc/internal/mutex_pool_structs.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef JEMALLOC_INTERNAL_MUTEX_POOL_STRUCTS_H -#define JEMALLOC_INTERNAL_MUTEX_POOL_STRUCTS_H - -#include "jemalloc/internal/mutex.h" - -/* This file really combines "structs" and "types", but only transitionally. */ - -/* We do mod reductions by this value, so it should be kept a power of 2. */ -#define MUTEX_POOL_SIZE 256 - -typedef struct mutex_pool_s mutex_pool_t; -struct mutex_pool_s { - malloc_mutex_t mutexes[MUTEX_POOL_SIZE]; -}; - -#endif /* JEMALLOC_INTERNAL_MUTEX_POOL_STRUCTS_H */ diff --git a/src/extent.c b/src/extent.c index 6589de55..c3d9baae 100644 --- a/src/extent.c +++ b/src/extent.c @@ -8,6 +8,7 @@ #include "jemalloc/internal/ph.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/mutex.h" +#include "jemalloc/internal/mutex_pool.h" /******************************************************************************/ /* Data. */ diff --git a/src/mutex_pool.c b/src/mutex_pool.c index 95a45736..f24d10e4 100644 --- a/src/mutex_pool.c +++ b/src/mutex_pool.c @@ -4,6 +4,7 @@ #include "jemalloc/internal/jemalloc_internal_includes.h" #include "jemalloc/internal/mutex.h" +#include "jemalloc/internal/mutex_pool.h" bool mutex_pool_init(mutex_pool_t *pool, const char *name, witness_rank_t rank) { -- GitLab From 8261e581be517f4fe193ead2c9b662717d9ca5e0 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Tue, 30 May 2017 10:45:37 -0700 Subject: [PATCH 520/544] Header refactoring: Pull size helpers out of jemalloc module. --- Makefile.in | 1 + include/jemalloc/internal/arena_externs.h | 8 - include/jemalloc/internal/arena_inlines_b.h | 13 +- include/jemalloc/internal/arena_types.h | 2 - include/jemalloc/internal/extent_inlines.h | 3 +- include/jemalloc/internal/extent_structs.h | 2 +- .../internal/jemalloc_internal_externs.h | 17 - .../internal/jemalloc_internal_inlines_a.h | 267 --------------- .../internal/jemalloc_internal_inlines_c.h | 7 +- include/jemalloc/internal/prof_inlines_b.h | 4 +- include/jemalloc/internal/size_classes.sh | 1 + include/jemalloc/internal/sz.h | 317 ++++++++++++++++++ include/jemalloc/internal/tcache_inlines.h | 9 +- src/arena.c | 55 +-- src/base.c | 15 +- src/ckh.c | 6 +- src/ctl.c | 5 +- src/extent.c | 23 +- src/jemalloc.c | 149 ++------ src/large.c | 12 +- src/prof.c | 8 +- src/sz.c | 106 ++++++ src/tcache.c | 6 +- src/zone.c | 2 +- test/unit/arena_reset.c | 2 +- test/unit/retained.c | 8 +- test/unit/rtree.c | 3 +- test/unit/size_classes.c | 187 ++++++----- 28 files changed, 642 insertions(+), 596 deletions(-) create mode 100644 include/jemalloc/internal/sz.h create mode 100644 src/sz.c diff --git a/Makefile.in b/Makefile.in index 868bf8cc..fec1397a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -112,6 +112,7 @@ C_SRCS := $(srcroot)src/jemalloc.c \ $(srcroot)src/rtree.c \ $(srcroot)src/stats.c \ $(srcroot)src/spin.c \ + $(srcroot)src/sz.c \ $(srcroot)src/tcache.c \ $(srcroot)src/ticker.c \ $(srcroot)src/tsd.c \ diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 08a6d174..cfb7c6fb 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -6,14 +6,6 @@ #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/stats.h" -static const size_t large_pad = -#ifdef JEMALLOC_CACHE_OBLIVIOUS - PAGE -#else - 0 -#endif - ; - extern ssize_t opt_dirty_decay_ms; extern ssize_t opt_muzzy_decay_ms; diff --git a/include/jemalloc/internal/arena_inlines_b.h b/include/jemalloc/internal/arena_inlines_b.h index 16635c1a..003abe11 100644 --- a/include/jemalloc/internal/arena_inlines_b.h +++ b/include/jemalloc/internal/arena_inlines_b.h @@ -5,6 +5,7 @@ #include "jemalloc/internal/mutex.h" #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/size_classes.h" +#include "jemalloc/internal/sz.h" #include "jemalloc/internal/ticker.h" static inline szind_t @@ -127,7 +128,7 @@ arena_salloc(tsdn_t *tsdn, const void *ptr) { (uintptr_t)ptr, true); assert(szind != NSIZES); - return index2size(szind); + return sz_index2size(szind); } JEMALLOC_ALWAYS_INLINE size_t @@ -160,7 +161,7 @@ arena_vsalloc(tsdn_t *tsdn, const void *ptr) { assert(szind != NSIZES); - return index2size(szind); + return sz_index2size(szind); } static inline void @@ -257,7 +258,7 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) { * There is no risk of being confused by a promoted sampled * object, so base szind and slab on the given size. */ - szind = size2index(size); + szind = sz_size2index(size); slab = (szind < NBINS); } @@ -269,7 +270,7 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) { rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, true, &szind, &slab); - assert(szind == size2index(size)); + assert(szind == sz_size2index(size)); assert((config_prof && opt_prof) || slab == (szind < NBINS)); if (config_debug) { @@ -313,7 +314,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, rtree_szind_slab_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, true, &local_ctx.szind, &local_ctx.slab); - assert(local_ctx.szind == size2index(size)); + assert(local_ctx.szind == sz_size2index(size)); alloc_ctx = &local_ctx; } slab = alloc_ctx->slab; @@ -323,7 +324,7 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache, * There is no risk of being confused by a promoted sampled * object, so base szind and slab on the given size. */ - szind = size2index(size); + szind = sz_size2index(size); slab = (szind < NBINS); } diff --git a/include/jemalloc/internal/arena_types.h b/include/jemalloc/internal/arena_types.h index 1374eeca..01b9096a 100644 --- a/include/jemalloc/internal/arena_types.h +++ b/include/jemalloc/internal/arena_types.h @@ -1,8 +1,6 @@ #ifndef JEMALLOC_INTERNAL_ARENA_TYPES_H #define JEMALLOC_INTERNAL_ARENA_TYPES_H -#define LARGE_MINCLASS (ZU(1) << LG_LARGE_MINCLASS) - /* Maximum number of regions in one slab. */ #define LG_SLAB_MAXREGS (LG_PAGE - LG_TINY_MIN) #define SLAB_MAXREGS (1U << LG_SLAB_MAXREGS) diff --git a/include/jemalloc/internal/extent_inlines.h b/include/jemalloc/internal/extent_inlines.h index 94c41923..bb2bd699 100644 --- a/include/jemalloc/internal/extent_inlines.h +++ b/include/jemalloc/internal/extent_inlines.h @@ -6,6 +6,7 @@ #include "jemalloc/internal/pages.h" #include "jemalloc/internal/prng.h" #include "jemalloc/internal/ql.h" +#include "jemalloc/internal/sz.h" static inline void extent_lock(tsdn_t *tsdn, extent_t *extent) { @@ -65,7 +66,7 @@ extent_szind_get(const extent_t *extent) { static inline size_t extent_usize_get(const extent_t *extent) { - return index2size(extent_szind_get(extent)); + return sz_index2size(extent_szind_get(extent)); } static inline size_t diff --git a/include/jemalloc/internal/extent_structs.h b/include/jemalloc/internal/extent_structs.h index 457891df..d2979503 100644 --- a/include/jemalloc/internal/extent_structs.h +++ b/include/jemalloc/internal/extent_structs.h @@ -53,7 +53,7 @@ struct extent_s { * szind: The szind flag indicates usable size class index for * allocations residing in this extent, regardless of whether the * extent is a slab. Extent size and usable size often differ - * even for non-slabs, either due to large_pad or promotion of + * even for non-slabs, either due to sz_large_pad or promotion of * sampled small regions. * * nfree: Number of free regions in slab. diff --git a/include/jemalloc/internal/jemalloc_internal_externs.h b/include/jemalloc/internal/jemalloc_internal_externs.h index 11e16ecc..e10fb275 100644 --- a/include/jemalloc/internal/jemalloc_internal_externs.h +++ b/include/jemalloc/internal/jemalloc_internal_externs.h @@ -31,23 +31,6 @@ extern unsigned narenas_auto; */ extern atomic_p_t arenas[]; -/* - * pind2sz_tab encodes the same information as could be computed by - * pind2sz_compute(). - */ -extern size_t const pind2sz_tab[NPSIZES+1]; -/* - * index2size_tab encodes the same information as could be computed (at - * unacceptable cost in some code paths) by index2size_compute(). - */ -extern size_t const index2size_tab[NSIZES]; -/* - * size2index_tab is a compact lookup table that rounds request sizes up to - * size classes. In order to reduce cache footprint, the table is compressed, - * and all accesses are via size2index(). - */ -extern uint8_t const size2index_tab[]; - void *a0malloc(size_t size); void a0dalloc(void *ptr); void *bootstrap_malloc(size_t size); diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_a.h b/include/jemalloc/internal/jemalloc_internal_inlines_a.h index c8e26298..d0bf2eee 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_a.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_a.h @@ -7,273 +7,6 @@ #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/ticker.h" -JEMALLOC_ALWAYS_INLINE pszind_t -psz2ind(size_t psz) { - if (unlikely(psz > LARGE_MAXCLASS)) { - return NPSIZES; - } - { - pszind_t x = lg_floor((psz<<1)-1); - pszind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_PAGE) ? 0 : x - - (LG_SIZE_CLASS_GROUP + LG_PAGE); - pszind_t grp = shift << LG_SIZE_CLASS_GROUP; - - pszind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? - LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1; - - size_t delta_inverse_mask = ZD(-1) << lg_delta; - pszind_t mod = ((((psz-1) & delta_inverse_mask) >> lg_delta)) & - ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); - - pszind_t ind = grp + mod; - return ind; - } -} - -static inline size_t -pind2sz_compute(pszind_t pind) { - if (unlikely(pind == NPSIZES)) { - return LARGE_MAXCLASS + PAGE; - } - { - size_t grp = pind >> LG_SIZE_CLASS_GROUP; - size_t mod = pind & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); - - size_t grp_size_mask = ~((!!grp)-1); - size_t grp_size = ((ZU(1) << (LG_PAGE + - (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask; - - size_t shift = (grp == 0) ? 1 : grp; - size_t lg_delta = shift + (LG_PAGE-1); - size_t mod_size = (mod+1) << lg_delta; - - size_t sz = grp_size + mod_size; - return sz; - } -} - -static inline size_t -pind2sz_lookup(pszind_t pind) { - size_t ret = (size_t)pind2sz_tab[pind]; - assert(ret == pind2sz_compute(pind)); - return ret; -} - -static inline size_t -pind2sz(pszind_t pind) { - assert(pind < NPSIZES+1); - return pind2sz_lookup(pind); -} - -static inline size_t -psz2u(size_t psz) { - if (unlikely(psz > LARGE_MAXCLASS)) { - return LARGE_MAXCLASS + PAGE; - } - { - size_t x = lg_floor((psz<<1)-1); - size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? - LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1; - size_t delta = ZU(1) << lg_delta; - size_t delta_mask = delta - 1; - size_t usize = (psz + delta_mask) & ~delta_mask; - return usize; - } -} - -static inline szind_t -size2index_compute(size_t size) { - if (unlikely(size > LARGE_MAXCLASS)) { - return NSIZES; - } -#if (NTBINS != 0) - if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { - szind_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; - szind_t lg_ceil = lg_floor(pow2_ceil_zu(size)); - return (lg_ceil < lg_tmin ? 0 : lg_ceil - lg_tmin); - } -#endif - { - szind_t x = lg_floor((size<<1)-1); - szind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM) ? 0 : - x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM); - szind_t grp = shift << LG_SIZE_CLASS_GROUP; - - szind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) - ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; - - size_t delta_inverse_mask = ZD(-1) << lg_delta; - szind_t mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) & - ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); - - szind_t index = NTBINS + grp + mod; - return index; - } -} - -JEMALLOC_ALWAYS_INLINE szind_t -size2index_lookup(size_t size) { - assert(size <= LOOKUP_MAXCLASS); - { - szind_t ret = (size2index_tab[(size-1) >> LG_TINY_MIN]); - assert(ret == size2index_compute(size)); - return ret; - } -} - -JEMALLOC_ALWAYS_INLINE szind_t -size2index(size_t size) { - assert(size > 0); - if (likely(size <= LOOKUP_MAXCLASS)) { - return size2index_lookup(size); - } - return size2index_compute(size); -} - -static inline size_t -index2size_compute(szind_t index) { -#if (NTBINS > 0) - if (index < NTBINS) { - return (ZU(1) << (LG_TINY_MAXCLASS - NTBINS + 1 + index)); - } -#endif - { - size_t reduced_index = index - NTBINS; - size_t grp = reduced_index >> LG_SIZE_CLASS_GROUP; - size_t mod = reduced_index & ((ZU(1) << LG_SIZE_CLASS_GROUP) - - 1); - - size_t grp_size_mask = ~((!!grp)-1); - size_t grp_size = ((ZU(1) << (LG_QUANTUM + - (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask; - - size_t shift = (grp == 0) ? 1 : grp; - size_t lg_delta = shift + (LG_QUANTUM-1); - size_t mod_size = (mod+1) << lg_delta; - - size_t usize = grp_size + mod_size; - return usize; - } -} - -JEMALLOC_ALWAYS_INLINE size_t -index2size_lookup(szind_t index) { - size_t ret = (size_t)index2size_tab[index]; - assert(ret == index2size_compute(index)); - return ret; -} - -JEMALLOC_ALWAYS_INLINE size_t -index2size(szind_t index) { - assert(index < NSIZES); - return index2size_lookup(index); -} - -JEMALLOC_ALWAYS_INLINE size_t -s2u_compute(size_t size) { - if (unlikely(size > LARGE_MAXCLASS)) { - return 0; - } -#if (NTBINS > 0) - if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { - size_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; - size_t lg_ceil = lg_floor(pow2_ceil_zu(size)); - return (lg_ceil < lg_tmin ? (ZU(1) << lg_tmin) : - (ZU(1) << lg_ceil)); - } -#endif - { - size_t x = lg_floor((size<<1)-1); - size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) - ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; - size_t delta = ZU(1) << lg_delta; - size_t delta_mask = delta - 1; - size_t usize = (size + delta_mask) & ~delta_mask; - return usize; - } -} - -JEMALLOC_ALWAYS_INLINE size_t -s2u_lookup(size_t size) { - size_t ret = index2size_lookup(size2index_lookup(size)); - - assert(ret == s2u_compute(size)); - return ret; -} - -/* - * Compute usable size that would result from allocating an object with the - * specified size. - */ -JEMALLOC_ALWAYS_INLINE size_t -s2u(size_t size) { - assert(size > 0); - if (likely(size <= LOOKUP_MAXCLASS)) { - return s2u_lookup(size); - } - return s2u_compute(size); -} - -/* - * Compute usable size that would result from allocating an object with the - * specified size and alignment. - */ -JEMALLOC_ALWAYS_INLINE size_t -sa2u(size_t size, size_t alignment) { - size_t usize; - - assert(alignment != 0 && ((alignment - 1) & alignment) == 0); - - /* Try for a small size class. */ - if (size <= SMALL_MAXCLASS && alignment < PAGE) { - /* - * Round size up to the nearest multiple of alignment. - * - * This done, we can take advantage of the fact that for each - * small size class, every object is aligned at the smallest - * power of two that is non-zero in the base two representation - * of the size. For example: - * - * Size | Base 2 | Minimum alignment - * -----+----------+------------------ - * 96 | 1100000 | 32 - * 144 | 10100000 | 32 - * 192 | 11000000 | 64 - */ - usize = s2u(ALIGNMENT_CEILING(size, alignment)); - if (usize < LARGE_MINCLASS) { - return usize; - } - } - - /* Large size class. Beware of overflow. */ - - if (unlikely(alignment > LARGE_MAXCLASS)) { - return 0; - } - - /* Make sure result is a large size class. */ - if (size <= LARGE_MINCLASS) { - usize = LARGE_MINCLASS; - } else { - usize = s2u(size); - if (usize < size) { - /* size_t overflow. */ - return 0; - } - } - - /* - * Calculate the multi-page mapping that large_palloc() would need in - * order to guarantee the alignment. - */ - if (usize + large_pad + PAGE_CEILING(alignment) - PAGE < usize) { - /* size_t overflow. */ - return 0; - } - return usize; -} - JEMALLOC_ALWAYS_INLINE malloc_cpuid_t malloc_getcpu(void) { assert(have_percpu_arena); diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_c.h b/include/jemalloc/internal/jemalloc_internal_inlines_c.h index 80dfbeff..7ffce6fb 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_c.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_c.h @@ -2,6 +2,7 @@ #define JEMALLOC_INTERNAL_INLINES_C_H #include "jemalloc/internal/jemalloc_internal_types.h" +#include "jemalloc/internal/sz.h" #include "jemalloc/internal/witness.h" JEMALLOC_ALWAYS_INLINE arena_t * @@ -48,7 +49,7 @@ ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero, void *ret; assert(usize != 0); - assert(usize == sa2u(usize, alignment)); + assert(usize == sz_sa2u(usize, alignment)); assert(!is_internal || tcache == NULL); assert(!is_internal || arena == NULL || arena_is_auto(arena)); witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), @@ -118,7 +119,7 @@ iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, void *p; size_t usize, copysize; - usize = sa2u(size + extra, alignment); + usize = sz_sa2u(size + extra, alignment); if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { return NULL; } @@ -128,7 +129,7 @@ iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, return NULL; } /* Try again, without extra this time. */ - usize = sa2u(size, alignment); + usize = sz_sa2u(size, alignment); if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { return NULL; } diff --git a/include/jemalloc/internal/prof_inlines_b.h b/include/jemalloc/internal/prof_inlines_b.h index fba7b998..d670cb7b 100644 --- a/include/jemalloc/internal/prof_inlines_b.h +++ b/include/jemalloc/internal/prof_inlines_b.h @@ -1,6 +1,8 @@ #ifndef JEMALLOC_INTERNAL_PROF_INLINES_B_H #define JEMALLOC_INTERNAL_PROF_INLINES_B_H +#include "jemalloc/internal/sz.h" + JEMALLOC_ALWAYS_INLINE bool prof_active_get_unlocked(void) { /* @@ -113,7 +115,7 @@ prof_alloc_prep(tsd_t *tsd, size_t usize, bool prof_active, bool update) { prof_tdata_t *tdata; prof_bt_t bt; - assert(usize == s2u(usize)); + assert(usize == sz_s2u(usize)); if (!prof_active || likely(prof_sample_accum_update(tsd, usize, update, &tdata))) { diff --git a/include/jemalloc/internal/size_classes.sh b/include/jemalloc/internal/size_classes.sh index dd562db1..998994d0 100755 --- a/include/jemalloc/internal/size_classes.sh +++ b/include/jemalloc/internal/size_classes.sh @@ -334,6 +334,7 @@ for lg_z in ${lg_zarr} ; do echo "#define LOOKUP_MAXCLASS ${lookup_maxclass}" echo "#define SMALL_MAXCLASS ${small_maxclass}" echo "#define LG_LARGE_MINCLASS ${lg_large_minclass}" + echo "#define LARGE_MINCLASS (ZU(1) << LG_LARGE_MINCLASS)" echo "#define LARGE_MAXCLASS ${large_maxclass}" echo "#endif" echo diff --git a/include/jemalloc/internal/sz.h b/include/jemalloc/internal/sz.h new file mode 100644 index 00000000..7f640d55 --- /dev/null +++ b/include/jemalloc/internal/sz.h @@ -0,0 +1,317 @@ +#ifndef JEMALLOC_INTERNAL_SIZE_H +#define JEMALLOC_INTERNAL_SIZE_H + +#include "jemalloc/internal/bit_util.h" +#include "jemalloc/internal/pages.h" +#include "jemalloc/internal/size_classes.h" +#include "jemalloc/internal/util.h" + +/* + * sz module: Size computations. + * + * Some abbreviations used here: + * p: Page + * ind: Index + * s, sz: Size + * u: Usable size + * a: Aligned + * + * These are not always used completely consistently, but should be enough to + * interpret function names. E.g. sz_psz2ind converts page size to page size + * index; sz_sa2u converts a (size, alignment) allocation request to the usable + * size that would result from such an allocation. + */ + +/* + * sz_pind2sz_tab encodes the same information as could be computed by + * sz_pind2sz_compute(). + */ +extern size_t const sz_pind2sz_tab[NPSIZES+1]; +/* + * sz_index2size_tab encodes the same information as could be computed (at + * unacceptable cost in some code paths) by sz_index2size_compute(). + */ +extern size_t const sz_index2size_tab[NSIZES]; +/* + * sz_size2index_tab is a compact lookup table that rounds request sizes up to + * size classes. In order to reduce cache footprint, the table is compressed, + * and all accesses are via sz_size2index(). + */ +extern uint8_t const sz_size2index_tab[]; + +static const size_t sz_large_pad = +#ifdef JEMALLOC_CACHE_OBLIVIOUS + PAGE +#else + 0 +#endif + ; + +JEMALLOC_ALWAYS_INLINE pszind_t +sz_psz2ind(size_t psz) { + if (unlikely(psz > LARGE_MAXCLASS)) { + return NPSIZES; + } + { + pszind_t x = lg_floor((psz<<1)-1); + pszind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_PAGE) ? 0 : x - + (LG_SIZE_CLASS_GROUP + LG_PAGE); + pszind_t grp = shift << LG_SIZE_CLASS_GROUP; + + pszind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? + LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1; + + size_t delta_inverse_mask = ZD(-1) << lg_delta; + pszind_t mod = ((((psz-1) & delta_inverse_mask) >> lg_delta)) & + ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); + + pszind_t ind = grp + mod; + return ind; + } +} + +static inline size_t +sz_pind2sz_compute(pszind_t pind) { + if (unlikely(pind == NPSIZES)) { + return LARGE_MAXCLASS + PAGE; + } + { + size_t grp = pind >> LG_SIZE_CLASS_GROUP; + size_t mod = pind & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); + + size_t grp_size_mask = ~((!!grp)-1); + size_t grp_size = ((ZU(1) << (LG_PAGE + + (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask; + + size_t shift = (grp == 0) ? 1 : grp; + size_t lg_delta = shift + (LG_PAGE-1); + size_t mod_size = (mod+1) << lg_delta; + + size_t sz = grp_size + mod_size; + return sz; + } +} + +static inline size_t +sz_pind2sz_lookup(pszind_t pind) { + size_t ret = (size_t)sz_pind2sz_tab[pind]; + assert(ret == sz_pind2sz_compute(pind)); + return ret; +} + +static inline size_t +sz_pind2sz(pszind_t pind) { + assert(pind < NPSIZES+1); + return sz_pind2sz_lookup(pind); +} + +static inline size_t +sz_psz2u(size_t psz) { + if (unlikely(psz > LARGE_MAXCLASS)) { + return LARGE_MAXCLASS + PAGE; + } + { + size_t x = lg_floor((psz<<1)-1); + size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? + LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1; + size_t delta = ZU(1) << lg_delta; + size_t delta_mask = delta - 1; + size_t usize = (psz + delta_mask) & ~delta_mask; + return usize; + } +} + +static inline szind_t +sz_size2index_compute(size_t size) { + if (unlikely(size > LARGE_MAXCLASS)) { + return NSIZES; + } +#if (NTBINS != 0) + if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { + szind_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; + szind_t lg_ceil = lg_floor(pow2_ceil_zu(size)); + return (lg_ceil < lg_tmin ? 0 : lg_ceil - lg_tmin); + } +#endif + { + szind_t x = lg_floor((size<<1)-1); + szind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM) ? 0 : + x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM); + szind_t grp = shift << LG_SIZE_CLASS_GROUP; + + szind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) + ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; + + size_t delta_inverse_mask = ZD(-1) << lg_delta; + szind_t mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) & + ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); + + szind_t index = NTBINS + grp + mod; + return index; + } +} + +JEMALLOC_ALWAYS_INLINE szind_t +sz_size2index_lookup(size_t size) { + assert(size <= LOOKUP_MAXCLASS); + { + szind_t ret = (sz_size2index_tab[(size-1) >> LG_TINY_MIN]); + assert(ret == sz_size2index_compute(size)); + return ret; + } +} + +JEMALLOC_ALWAYS_INLINE szind_t +sz_size2index(size_t size) { + assert(size > 0); + if (likely(size <= LOOKUP_MAXCLASS)) { + return sz_size2index_lookup(size); + } + return sz_size2index_compute(size); +} + +static inline size_t +sz_index2size_compute(szind_t index) { +#if (NTBINS > 0) + if (index < NTBINS) { + return (ZU(1) << (LG_TINY_MAXCLASS - NTBINS + 1 + index)); + } +#endif + { + size_t reduced_index = index - NTBINS; + size_t grp = reduced_index >> LG_SIZE_CLASS_GROUP; + size_t mod = reduced_index & ((ZU(1) << LG_SIZE_CLASS_GROUP) - + 1); + + size_t grp_size_mask = ~((!!grp)-1); + size_t grp_size = ((ZU(1) << (LG_QUANTUM + + (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask; + + size_t shift = (grp == 0) ? 1 : grp; + size_t lg_delta = shift + (LG_QUANTUM-1); + size_t mod_size = (mod+1) << lg_delta; + + size_t usize = grp_size + mod_size; + return usize; + } +} + +JEMALLOC_ALWAYS_INLINE size_t +sz_index2size_lookup(szind_t index) { + size_t ret = (size_t)sz_index2size_tab[index]; + assert(ret == sz_index2size_compute(index)); + return ret; +} + +JEMALLOC_ALWAYS_INLINE size_t +sz_index2size(szind_t index) { + assert(index < NSIZES); + return sz_index2size_lookup(index); +} + +JEMALLOC_ALWAYS_INLINE size_t +sz_s2u_compute(size_t size) { + if (unlikely(size > LARGE_MAXCLASS)) { + return 0; + } +#if (NTBINS > 0) + if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { + size_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; + size_t lg_ceil = lg_floor(pow2_ceil_zu(size)); + return (lg_ceil < lg_tmin ? (ZU(1) << lg_tmin) : + (ZU(1) << lg_ceil)); + } +#endif + { + size_t x = lg_floor((size<<1)-1); + size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) + ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; + size_t delta = ZU(1) << lg_delta; + size_t delta_mask = delta - 1; + size_t usize = (size + delta_mask) & ~delta_mask; + return usize; + } +} + +JEMALLOC_ALWAYS_INLINE size_t +sz_s2u_lookup(size_t size) { + size_t ret = sz_index2size_lookup(sz_size2index_lookup(size)); + + assert(ret == sz_s2u_compute(size)); + return ret; +} + +/* + * Compute usable size that would result from allocating an object with the + * specified size. + */ +JEMALLOC_ALWAYS_INLINE size_t +sz_s2u(size_t size) { + assert(size > 0); + if (likely(size <= LOOKUP_MAXCLASS)) { + return sz_s2u_lookup(size); + } + return sz_s2u_compute(size); +} + +/* + * Compute usable size that would result from allocating an object with the + * specified size and alignment. + */ +JEMALLOC_ALWAYS_INLINE size_t +sz_sa2u(size_t size, size_t alignment) { + size_t usize; + + assert(alignment != 0 && ((alignment - 1) & alignment) == 0); + + /* Try for a small size class. */ + if (size <= SMALL_MAXCLASS && alignment < PAGE) { + /* + * Round size up to the nearest multiple of alignment. + * + * This done, we can take advantage of the fact that for each + * small size class, every object is aligned at the smallest + * power of two that is non-zero in the base two representation + * of the size. For example: + * + * Size | Base 2 | Minimum alignment + * -----+----------+------------------ + * 96 | 1100000 | 32 + * 144 | 10100000 | 32 + * 192 | 11000000 | 64 + */ + usize = sz_s2u(ALIGNMENT_CEILING(size, alignment)); + if (usize < LARGE_MINCLASS) { + return usize; + } + } + + /* Large size class. Beware of overflow. */ + + if (unlikely(alignment > LARGE_MAXCLASS)) { + return 0; + } + + /* Make sure result is a large size class. */ + if (size <= LARGE_MINCLASS) { + usize = LARGE_MINCLASS; + } else { + usize = sz_s2u(size); + if (usize < size) { + /* size_t overflow. */ + return 0; + } + } + + /* + * Calculate the multi-page mapping that large_palloc() would need in + * order to guarantee the alignment. + */ + if (usize + sz_large_pad + PAGE_CEILING(alignment) - PAGE < usize) { + /* size_t overflow. */ + return 0; + } + return usize; +} + +#endif /* JEMALLOC_INTERNAL_SIZE_H */ diff --git a/include/jemalloc/internal/tcache_inlines.h b/include/jemalloc/internal/tcache_inlines.h index 8a65ba2b..c55bcd27 100644 --- a/include/jemalloc/internal/tcache_inlines.h +++ b/include/jemalloc/internal/tcache_inlines.h @@ -3,6 +3,7 @@ #include "jemalloc/internal/jemalloc_internal_types.h" #include "jemalloc/internal/size_classes.h" +#include "jemalloc/internal/sz.h" #include "jemalloc/internal/ticker.h" #include "jemalloc/internal/util.h" @@ -95,7 +96,7 @@ tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, * statement are all static. */ if (config_prof || (slow_path && config_fill) || unlikely(zero)) { - usize = index2size(binind); + usize = sz_index2size(binind); assert(tcache_salloc(tsd_tsdn(tsd), ret) == usize); } @@ -147,7 +148,7 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, return NULL; } - ret = large_malloc(tsd_tsdn(tsd), arena, s2u(size), zero); + ret = large_malloc(tsd_tsdn(tsd), arena, sz_s2u(size), zero); if (ret == NULL) { return NULL; } @@ -157,7 +158,7 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size, /* Only compute usize on demand */ if (config_prof || (slow_path && config_fill) || unlikely(zero)) { - usize = index2size(binind); + usize = sz_index2size(binind); assert(usize <= tcache_maxclass); } @@ -221,7 +222,7 @@ tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, assert(tcache_salloc(tsd_tsdn(tsd), ptr) <= tcache_maxclass); if (slow_path && config_fill && unlikely(opt_junk_free)) { - large_dalloc_junk(ptr, index2size(binind)); + large_dalloc_junk(ptr, sz_index2size(binind)); } tbin = tcache_large_bin_get(tcache, binind); diff --git a/src/arena.c b/src/arena.c index bf1d6e65..151aad3e 100644 --- a/src/arena.c +++ b/src/arena.c @@ -289,7 +289,7 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, size_t curlextents = (size_t)(nmalloc - ndalloc); lstats[i].curlextents += curlextents; arena_stats_accum_zu(&astats->allocated_large, - curlextents * index2size(NBINS + i)); + curlextents * sz_index2size(NBINS + i)); } arena_stats_unlock(tsdn, &arena->stats); @@ -303,12 +303,12 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads, for (; i < NBINS; i++) { tcache_bin_t *tbin = tcache_small_bin_get(tcache, i); arena_stats_accum_zu(&astats->tcache_bytes, - tbin->ncached * index2size(i)); + tbin->ncached * sz_index2size(i)); } for (; i < nhbins; i++) { tcache_bin_t *tbin = tcache_large_bin_get(tcache, i); arena_stats_accum_zu(&astats->tcache_bytes, - tbin->ncached * index2size(i)); + tbin->ncached * sz_index2size(i)); } } malloc_mutex_prof_read(tsdn, @@ -467,7 +467,7 @@ arena_large_malloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t usize) { if (usize < LARGE_MINCLASS) { usize = LARGE_MINCLASS; } - index = size2index(usize); + index = sz_size2index(usize); hindex = (index >= NBINS) ? index - NBINS : 0; arena_stats_add_u64(tsdn, &arena->stats, @@ -483,7 +483,7 @@ arena_large_dalloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t usize) { if (usize < LARGE_MINCLASS) { usize = LARGE_MINCLASS; } - index = size2index(usize); + index = sz_size2index(usize); hindex = (index >= NBINS) ? index - NBINS : 0; arena_stats_add_u64(tsdn, &arena->stats, @@ -505,21 +505,22 @@ arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize, witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_CORE, 0); - szind_t szind = size2index(usize); + szind_t szind = sz_size2index(usize); size_t mapped_add; bool commit = true; extent_t *extent = extents_alloc(tsdn, arena, &extent_hooks, - &arena->extents_dirty, NULL, usize, large_pad, alignment, false, + &arena->extents_dirty, NULL, usize, sz_large_pad, alignment, false, szind, zero, &commit); if (extent == NULL) { extent = extents_alloc(tsdn, arena, &extent_hooks, - &arena->extents_muzzy, NULL, usize, large_pad, alignment, + &arena->extents_muzzy, NULL, usize, sz_large_pad, alignment, false, szind, zero, &commit); } - size_t size = usize + large_pad; + size_t size = usize + sz_large_pad; if (extent == NULL) { extent = extent_alloc_wrapper(tsdn, arena, &extent_hooks, NULL, - usize, large_pad, alignment, false, szind, zero, &commit); + usize, sz_large_pad, alignment, false, szind, zero, + &commit); if (config_stats) { /* * extent may be NULL on OOM, but in that case @@ -1146,7 +1147,7 @@ arena_reset(tsd_t *tsd, arena_t *arena) { assert(alloc_ctx.szind != NSIZES); if (config_stats || (config_prof && opt_prof)) { - usize = index2size(alloc_ctx.szind); + usize = sz_index2size(alloc_ctx.szind); assert(usize == isalloc(tsd_tsdn(tsd), ptr)); } /* Remove large allocation from prof sample set. */ @@ -1278,7 +1279,7 @@ arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, WITNESS_RANK_CORE, 0); extent_hooks_t *extent_hooks = EXTENT_HOOKS_INITIALIZER; - szind_t szind = size2index(bin_info->reg_size); + szind_t szind = sz_size2index(bin_info->reg_size); bool zero = false; bool commit = true; extent_t *slab = extents_alloc(tsdn, arena, &extent_hooks, @@ -1484,7 +1485,7 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) { assert(binind < NBINS); bin = &arena->bins[binind]; - usize = index2size(binind); + usize = sz_index2size(binind); malloc_mutex_lock(tsdn, &bin->lock); if ((slab = bin->slabcur) != NULL && extent_nfree_get(slab) > 0) { @@ -1544,7 +1545,7 @@ arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, if (likely(size <= SMALL_MAXCLASS)) { return arena_malloc_small(tsdn, arena, ind, zero); } - return large_malloc(tsdn, arena, index2size(ind), zero); + return large_malloc(tsdn, arena, sz_index2size(ind), zero); } void * @@ -1555,8 +1556,8 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, if (usize <= SMALL_MAXCLASS && (alignment < PAGE || (alignment == PAGE && (usize & PAGE_MASK) == 0))) { /* Small; alignment doesn't require special slab placement. */ - ret = arena_malloc(tsdn, arena, usize, size2index(usize), zero, - tcache, true); + ret = arena_malloc(tsdn, arena, usize, sz_size2index(usize), + zero, tcache, true); } else { if (likely(alignment <= CACHELINE)) { ret = large_malloc(tsdn, arena, usize, zero); @@ -1581,7 +1582,7 @@ arena_prof_promote(tsdn_t *tsdn, const void *ptr, size_t usize) { (uintptr_t)ptr, true); arena_t *arena = extent_arena_get(extent); - szind_t szind = size2index(usize); + szind_t szind = sz_size2index(usize); extent_szind_set(extent, szind); rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr, szind, false); @@ -1617,7 +1618,7 @@ arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache, size_t usize = arena_prof_demote(tsdn, extent, ptr); if (usize <= tcache_maxclass) { tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, - size2index(usize), slow_path); + sz_size2index(usize), slow_path); } else { large_dalloc(tsdn, extent); } @@ -1751,17 +1752,17 @@ arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, } extent_t *extent = iealloc(tsdn, ptr); - size_t usize_min = s2u(size); - size_t usize_max = s2u(size + extra); + size_t usize_min = sz_s2u(size); + size_t usize_max = sz_s2u(size + extra); if (likely(oldsize <= SMALL_MAXCLASS && usize_min <= SMALL_MAXCLASS)) { /* * Avoid moving the allocation if the size class can be left the * same. */ - assert(arena_bin_info[size2index(oldsize)].reg_size == + assert(arena_bin_info[sz_size2index(oldsize)].reg_size == oldsize); - if ((usize_max > SMALL_MAXCLASS || size2index(usize_max) != - size2index(oldsize)) && (size > oldsize || usize_max < + if ((usize_max > SMALL_MAXCLASS || sz_size2index(usize_max) != + sz_size2index(oldsize)) && (size > oldsize || usize_max < oldsize)) { return true; } @@ -1780,10 +1781,10 @@ static void * arena_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero, tcache_t *tcache) { if (alignment == 0) { - return arena_malloc(tsdn, arena, usize, size2index(usize), + return arena_malloc(tsdn, arena, usize, sz_size2index(usize), zero, tcache, true); } - usize = sa2u(usize, alignment); + usize = sz_sa2u(usize, alignment); if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { return NULL; } @@ -1793,7 +1794,7 @@ arena_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize, void * arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize, size_t size, size_t alignment, bool zero, tcache_t *tcache) { - size_t usize = s2u(size); + size_t usize = sz_s2u(size); if (unlikely(usize == 0 || size > LARGE_MAXCLASS)) { return NULL; } @@ -1998,7 +1999,7 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { goto label_error; } - arena->extent_grow_next = psz2ind(HUGEPAGE); + arena->extent_grow_next = sz_psz2ind(HUGEPAGE); if (malloc_mutex_init(&arena->extent_grow_mtx, "extent_grow", WITNESS_RANK_EXTENT_GROW, malloc_mutex_rank_exclusive)) { goto label_error; diff --git a/src/base.c b/src/base.c index 498e5c9d..8e1544fd 100644 --- a/src/base.c +++ b/src/base.c @@ -5,6 +5,7 @@ #include "jemalloc/internal/assert.h" #include "jemalloc/internal/extent_mmap.h" #include "jemalloc/internal/mutex.h" +#include "jemalloc/internal/sz.h" /******************************************************************************/ /* Data. */ @@ -121,8 +122,8 @@ base_extent_bump_alloc_post(tsdn_t *tsdn, base_t *base, extent_t *extent, * Compute the index for the largest size class that does not * exceed extent's size. */ - szind_t index_floor = size2index(extent_bsize_get(extent) + 1) - - 1; + szind_t index_floor = + sz_size2index(extent_bsize_get(extent) + 1) - 1; extent_heap_insert(&base->avail[index_floor], extent); } @@ -171,11 +172,11 @@ base_block_alloc(extent_hooks_t *extent_hooks, unsigned ind, * HUGEPAGE), or a size large enough to satisfy the requested size and * alignment, whichever is larger. */ - size_t min_block_size = HUGEPAGE_CEILING(psz2u(header_size + gap_size + - usize)); + size_t min_block_size = HUGEPAGE_CEILING(sz_psz2u(header_size + gap_size + + usize)); pszind_t pind_next = (*pind_last + 1 < NPSIZES) ? *pind_last + 1 : *pind_last; - size_t next_block_size = HUGEPAGE_CEILING(pind2sz(pind_next)); + size_t next_block_size = HUGEPAGE_CEILING(sz_pind2sz(pind_next)); size_t block_size = (min_block_size > next_block_size) ? min_block_size : next_block_size; base_block_t *block = (base_block_t *)base_map(extent_hooks, ind, @@ -183,7 +184,7 @@ base_block_alloc(extent_hooks_t *extent_hooks, unsigned ind, if (block == NULL) { return NULL; } - *pind_last = psz2ind(block_size); + *pind_last = sz_psz2ind(block_size); block->size = block_size; block->next = NULL; assert(block_size >= header_size); @@ -304,7 +305,7 @@ base_alloc_impl(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment, extent_t *extent = NULL; malloc_mutex_lock(tsdn, &base->mtx); - for (szind_t i = size2index(asize); i < NSIZES; i++) { + for (szind_t i = sz_size2index(asize); i < NSIZES; i++) { extent = extent_heap_remove_first(&base->avail[i]); if (extent != NULL) { /* Use existing space. */ diff --git a/src/ckh.c b/src/ckh.c index 013b6249..e95e0a3e 100644 --- a/src/ckh.c +++ b/src/ckh.c @@ -274,7 +274,7 @@ ckh_grow(tsd_t *tsd, ckh_t *ckh) { size_t usize; lg_curcells++; - usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); + usize = sz_sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { ret = true; goto label_return; @@ -319,7 +319,7 @@ ckh_shrink(tsd_t *tsd, ckh_t *ckh) { */ lg_prevbuckets = ckh->lg_curbuckets; lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 1; - usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); + usize = sz_sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE); if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { return; } @@ -395,7 +395,7 @@ ckh_new(tsd_t *tsd, ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh->hash = hash; ckh->keycomp = keycomp; - usize = sa2u(sizeof(ckhc_t) << lg_mincells, CACHELINE); + usize = sz_sa2u(sizeof(ckhc_t) << lg_mincells, CACHELINE); if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { ret = true; goto label_return; diff --git a/src/ctl.c b/src/ctl.c index 33275d70..1520c508 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -701,7 +701,7 @@ ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_t *ctl_arena, arena_t *arena) { for (i = 0; i < NBINS; i++) { ctl_arena->astats->allocated_small += ctl_arena->astats->bstats[i].curregs * - index2size(i); + sz_index2size(i); ctl_arena->astats->nmalloc_small += ctl_arena->astats->bstats[i].nmalloc; ctl_arena->astats->ndalloc_small += @@ -2274,7 +2274,8 @@ arenas_bin_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { } CTL_RO_NL_GEN(arenas_nlextents, NSIZES - NBINS, unsigned) -CTL_RO_NL_GEN(arenas_lextent_i_size, index2size(NBINS+(szind_t)mib[2]), size_t) +CTL_RO_NL_GEN(arenas_lextent_i_size, sz_index2size(NBINS+(szind_t)mib[2]), + size_t) static const ctl_named_node_t * arenas_lextent_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) { diff --git a/src/extent.c b/src/extent.c index c3d9baae..fb7a1468 100644 --- a/src/extent.c +++ b/src/extent.c @@ -220,7 +220,7 @@ extent_size_quantize_floor(size_t size) { assert(size > 0); assert((size & PAGE_MASK) == 0); - pind = psz2ind(size - large_pad + 1); + pind = sz_psz2ind(size - sz_large_pad + 1); if (pind == 0) { /* * Avoid underflow. This short-circuit would also do the right @@ -230,7 +230,7 @@ extent_size_quantize_floor(size_t size) { */ return size; } - ret = pind2sz(pind - 1) + large_pad; + ret = sz_pind2sz(pind - 1) + sz_large_pad; assert(ret <= size); return ret; } @@ -243,7 +243,7 @@ extent_size_quantize_ceil(size_t size) { size_t ret; assert(size > 0); - assert(size - large_pad <= LARGE_MAXCLASS); + assert(size - sz_large_pad <= LARGE_MAXCLASS); assert((size & PAGE_MASK) == 0); ret = extent_size_quantize_floor(size); @@ -256,7 +256,8 @@ extent_size_quantize_ceil(size_t size) { * search would potentially find sufficiently aligned available * memory somewhere lower. */ - ret = pind2sz(psz2ind(ret - large_pad + 1)) + large_pad; + ret = sz_pind2sz(sz_psz2ind(ret - sz_large_pad + 1)) + + sz_large_pad; } return ret; } @@ -300,7 +301,7 @@ extents_insert_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent, size_t size = extent_size_get(extent); size_t psz = extent_size_quantize_floor(size); - pszind_t pind = psz2ind(psz); + pszind_t pind = sz_psz2ind(psz); if (extent_heap_empty(&extents->heaps[pind])) { bitmap_unset(extents->bitmap, &extents_bitmap_info, (size_t)pind); @@ -329,7 +330,7 @@ extents_remove_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent, size_t size = extent_size_get(extent); size_t psz = extent_size_quantize_floor(size); - pszind_t pind = psz2ind(psz); + pszind_t pind = sz_psz2ind(psz); extent_heap_remove(&extents->heaps[pind], extent); if (extent_heap_empty(&extents->heaps[pind])) { bitmap_set(extents->bitmap, &extents_bitmap_info, @@ -354,7 +355,7 @@ extents_remove_locked(tsdn_t *tsdn, extents_t *extents, extent_t *extent, static extent_t * extents_best_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, size_t size) { - pszind_t pind = psz2ind(extent_size_quantize_ceil(size)); + pszind_t pind = sz_psz2ind(extent_size_quantize_ceil(size)); pszind_t i = (pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info, (size_t)pind); if (i < NPSIZES+1) { @@ -376,7 +377,7 @@ extents_first_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents, size_t size) { extent_t *ret = NULL; - pszind_t pind = psz2ind(extent_size_quantize_ceil(size)); + pszind_t pind = sz_psz2ind(extent_size_quantize_ceil(size)); for (pszind_t i = (pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info, (size_t)pind); i < NPSIZES+1; i = (pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info, @@ -1040,7 +1041,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, * satisfy this request. */ pszind_t egn_skip = 0; - size_t alloc_size = pind2sz(arena->extent_grow_next + egn_skip); + size_t alloc_size = sz_pind2sz(arena->extent_grow_next + egn_skip); while (alloc_size < alloc_size_min) { egn_skip++; if (arena->extent_grow_next + egn_skip == NPSIZES) { @@ -1048,7 +1049,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena, goto label_err; } assert(arena->extent_grow_next + egn_skip < NPSIZES); - alloc_size = pind2sz(arena->extent_grow_next + egn_skip); + alloc_size = sz_pind2sz(arena->extent_grow_next + egn_skip); } extent_t *extent = extent_alloc(tsdn, arena); @@ -1369,7 +1370,7 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena, extent_unlock(tsdn, prev); if (can_coalesce && !extent_coalesce(tsdn, arena, - r_extent_hooks, extents, extent, prev, false, + r_extent_hooks, extents, extent, prev, false, growing_retained)) { extent = prev; if (extents->delay_coalesce) { diff --git a/src/jemalloc.c b/src/jemalloc.c index 1befb64d..268d19c9 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -13,6 +13,7 @@ #include "jemalloc/internal/rtree.h" #include "jemalloc/internal/size_classes.h" #include "jemalloc/internal/spin.h" +#include "jemalloc/internal/sz.h" #include "jemalloc/internal/ticker.h" #include "jemalloc/internal/util.h" @@ -107,110 +108,6 @@ enum { }; static uint8_t malloc_slow_flags; -JEMALLOC_ALIGNED(CACHELINE) -const size_t pind2sz_tab[NPSIZES+1] = { -#define PSZ_yes(lg_grp, ndelta, lg_delta) \ - (((ZU(1)<alignment == 0) ? s2u(LARGE_MINCLASS) : - sa2u(LARGE_MINCLASS, dopts->alignment)) == LARGE_MINCLASS); - ind_large = size2index(LARGE_MINCLASS); - bumped_usize = s2u(LARGE_MINCLASS); + assert(((dopts->alignment == 0) ? sz_s2u(LARGE_MINCLASS) : + sz_sa2u(LARGE_MINCLASS, dopts->alignment)) + == LARGE_MINCLASS); + ind_large = sz_size2index(LARGE_MINCLASS); + bumped_usize = sz_s2u(LARGE_MINCLASS); ret = imalloc_no_sample(sopts, dopts, tsd, bumped_usize, bumped_usize, ind_large); if (unlikely(ret == NULL)) { @@ -1792,16 +1690,16 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) { /* This is the beginning of the "core" algorithm. */ if (dopts->alignment == 0) { - ind = size2index(size); + ind = sz_size2index(size); if (unlikely(ind >= NSIZES)) { goto label_oom; } if (config_stats || (config_prof && opt_prof)) { - usize = index2size(ind); + usize = sz_index2size(ind); assert(usize > 0 && usize <= LARGE_MAXCLASS); } } else { - usize = sa2u(size, dopts->alignment); + usize = sz_sa2u(size, dopts->alignment); if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { goto label_oom; } @@ -2155,10 +2053,10 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { size_t usize; if (config_prof && opt_prof) { - usize = index2size(alloc_ctx.szind); + usize = sz_index2size(alloc_ctx.szind); prof_free(tsd, ptr, usize, &alloc_ctx); } else if (config_stats) { - usize = index2size(alloc_ctx.szind); + usize = sz_index2size(alloc_ctx.szind); } if (config_stats) { *tsd_thread_deallocatedp_get(tsd) += usize; @@ -2192,7 +2090,7 @@ isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) { rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd); rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx, (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab); - assert(alloc_ctx.szind == size2index(usize)); + assert(alloc_ctx.szind == sz_size2index(usize)); ctx = &alloc_ctx; prof_free(tsd, ptr, usize, ctx); } else { @@ -2247,16 +2145,16 @@ je_realloc(void *ptr, size_t size) { rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx, (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab); assert(alloc_ctx.szind != NSIZES); - old_usize = index2size(alloc_ctx.szind); + old_usize = sz_index2size(alloc_ctx.szind); assert(old_usize == isalloc(tsd_tsdn(tsd), ptr)); if (config_prof && opt_prof) { - usize = s2u(size); + usize = sz_s2u(size); ret = unlikely(usize == 0 || usize > LARGE_MAXCLASS) ? NULL : irealloc_prof(tsd, ptr, old_usize, usize, &alloc_ctx); } else { if (config_stats) { - usize = s2u(size); + usize = sz_s2u(size); } ret = iralloc(tsd, ptr, old_usize, size, 0, false); } @@ -2601,10 +2499,11 @@ je_rallocx(void *ptr, size_t size, int flags) { rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx, (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab); assert(alloc_ctx.szind != NSIZES); - old_usize = index2size(alloc_ctx.szind); + old_usize = sz_index2size(alloc_ctx.szind); assert(old_usize == isalloc(tsd_tsdn(tsd), ptr)); if (config_prof && opt_prof) { - usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment); + usize = (alignment == 0) ? + sz_s2u(size) : sz_sa2u(size, alignment); if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) { goto label_oom; } @@ -2685,10 +2584,10 @@ ixallocx_prof(tsd_t *tsd, void *ptr, size_t old_usize, size_t size, * prof_realloc() will use the actual usize to decide whether to sample. */ if (alignment == 0) { - usize_max = s2u(size+extra); + usize_max = sz_s2u(size+extra); assert(usize_max > 0 && usize_max <= LARGE_MAXCLASS); } else { - usize_max = sa2u(size+extra, alignment); + usize_max = sz_sa2u(size+extra, alignment); if (unlikely(usize_max == 0 || usize_max > LARGE_MAXCLASS)) { /* * usize_max is out of range, and chances are that @@ -2737,7 +2636,7 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) { rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx, (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab); assert(alloc_ctx.szind != NSIZES); - old_usize = index2size(alloc_ctx.szind); + old_usize = sz_index2size(alloc_ctx.szind); assert(old_usize == isalloc(tsd_tsdn(tsd), ptr)); /* * The API explicitly absolves itself of protecting against (size + @@ -2847,9 +2746,9 @@ inallocx(tsdn_t *tsdn, size_t size, int flags) { size_t usize; if (likely((flags & MALLOCX_LG_ALIGN_MASK) == 0)) { - usize = s2u(size); + usize = sz_s2u(size); } else { - usize = sa2u(size, MALLOCX_ALIGN_GET_SPECIFIED(flags)); + usize = sz_sa2u(size, MALLOCX_ALIGN_GET_SPECIFIED(flags)); } witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); return usize; diff --git a/src/large.c b/src/large.c index 79d2c9da..27a2c679 100644 --- a/src/large.c +++ b/src/large.c @@ -12,7 +12,7 @@ void * large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero) { - assert(usize == s2u(usize)); + assert(usize == sz_s2u(usize)); return large_palloc(tsdn, arena, usize, CACHELINE, zero); } @@ -27,7 +27,7 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, assert(!tsdn_null(tsdn) || arena != NULL); - ausize = sa2u(usize, alignment); + ausize = sz_sa2u(usize, alignment); if (unlikely(ausize == 0 || ausize > LARGE_MAXCLASS)) { return NULL; } @@ -97,7 +97,7 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { arena_t *arena = extent_arena_get(extent); size_t oldusize = extent_usize_get(extent); extent_hooks_t *extent_hooks = extent_hooks_get(arena); - size_t diff = extent_size_get(extent) - (usize + large_pad); + size_t diff = extent_size_get(extent) - (usize + sz_large_pad); assert(oldusize > usize); @@ -108,8 +108,8 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) { /* Split excess pages. */ if (diff != 0) { extent_t *trail = extent_split_wrapper(tsdn, arena, - &extent_hooks, extent, usize + large_pad, size2index(usize), - false, diff, NSIZES, false); + &extent_hooks, extent, usize + sz_large_pad, + sz_size2index(usize), false, diff, NSIZES, false); if (trail == NULL) { return true; } @@ -178,7 +178,7 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize, } rtree_ctx_t rtree_ctx_fallback; rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback); - szind_t szind = size2index(usize); + szind_t szind = sz_size2index(usize); extent_szind_set(extent, szind); rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)extent_addr_get(extent), szind, false); diff --git a/src/prof.c b/src/prof.c index aa67486d..61dfa2ce 100644 --- a/src/prof.c +++ b/src/prof.c @@ -556,7 +556,7 @@ prof_gctx_create(tsdn_t *tsdn, prof_bt_t *bt) { */ size_t size = offsetof(prof_gctx_t, vec) + (bt->len * sizeof(void *)); prof_gctx_t *gctx = (prof_gctx_t *)iallocztm(tsdn, size, - size2index(size), false, NULL, true, arena_get(TSDN_NULL, 0, true), + sz_size2index(size), false, NULL, true, arena_get(TSDN_NULL, 0, true), true); if (gctx == NULL) { return NULL; @@ -819,7 +819,7 @@ prof_lookup(tsd_t *tsd, prof_bt_t *bt) { /* Link a prof_tctx_t into gctx for this thread. */ ret.v = iallocztm(tsd_tsdn(tsd), sizeof(prof_tctx_t), - size2index(sizeof(prof_tctx_t)), false, NULL, true, + sz_size2index(sizeof(prof_tctx_t)), false, NULL, true, arena_ichoose(tsd, NULL), true); if (ret.p == NULL) { if (new_gctx) { @@ -1899,7 +1899,7 @@ prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim, /* Initialize an empty cache for this thread. */ tdata = (prof_tdata_t *)iallocztm(tsd_tsdn(tsd), sizeof(prof_tdata_t), - size2index(sizeof(prof_tdata_t)), false, NULL, true, + sz_size2index(sizeof(prof_tdata_t)), false, NULL, true, arena_get(TSDN_NULL, 0, true), true); if (tdata == NULL) { return NULL; @@ -2135,7 +2135,7 @@ prof_thread_name_alloc(tsdn_t *tsdn, const char *thread_name) { return ""; } - ret = iallocztm(tsdn, size, size2index(size), false, NULL, true, + ret = iallocztm(tsdn, size, sz_size2index(size), false, NULL, true, arena_get(TSDN_NULL, 0, true), true); if (ret == NULL) { return NULL; diff --git a/src/sz.c b/src/sz.c new file mode 100644 index 00000000..0986615f --- /dev/null +++ b/src/sz.c @@ -0,0 +1,106 @@ +#include "jemalloc/internal/jemalloc_preamble.h" +#include "jemalloc/internal/sz.h" + +JEMALLOC_ALIGNED(CACHELINE) +const size_t sz_pind2sz_tab[NPSIZES+1] = { +#define PSZ_yes(lg_grp, ndelta, lg_delta) \ + (((ZU(1)<avail == NULL); size_t size = stack_nelms * sizeof(void *); /* Avoid false cacheline sharing. */ - size = sa2u(size, CACHELINE); + size = sz_sa2u(size, CACHELINE); void *avail_array = ipallocztm(tsd_tsdn(tsd), size, CACHELINE, true, NULL, true, arena_get(TSDN_NULL, 0, true)); @@ -430,7 +430,7 @@ tcache_create_explicit(tsd_t *tsd) { stack_offset = size; size += stack_nelms * sizeof(void *); /* Avoid false cacheline sharing. */ - size = sa2u(size, CACHELINE); + size = sz_sa2u(size, CACHELINE); tcache = ipallocztm(tsd_tsdn(tsd), size, CACHELINE, true, NULL, true, arena_get(TSDN_NULL, 0, true)); @@ -655,7 +655,7 @@ tcache_boot(tsdn_t *tsdn) { return true; } - nhbins = size2index(tcache_maxclass) + 1; + nhbins = sz_size2index(tcache_maxclass) + 1; /* Initialize tcache_bin_info. */ tcache_bin_info = (tcache_bin_info_t *)base_alloc(tsdn, b0get(), nhbins diff --git a/src/zone.c b/src/zone.c index 37bc8da9..9d3b7b49 100644 --- a/src/zone.c +++ b/src/zone.c @@ -244,7 +244,7 @@ zone_good_size(malloc_zone_t *zone, size_t size) { if (size == 0) { size = 1; } - return s2u(size); + return sz_s2u(size); } static kern_return_t diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 958453d1..6409a922 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -81,7 +81,7 @@ vsalloc(tsdn_t *tsdn, const void *ptr) { return 0; } - return index2size(szind); + return sz_index2size(szind); } static unsigned diff --git a/test/unit/retained.c b/test/unit/retained.c index 883bf4af..d51a5981 100644 --- a/test/unit/retained.c +++ b/test/unit/retained.c @@ -1,5 +1,7 @@ #include "test/jemalloc_test.h" +#include "jemalloc/internal/spin.h" + static unsigned arena_ind; static size_t sz; static size_t esz; @@ -100,7 +102,7 @@ TEST_BEGIN(test_retained) { arena_ind = do_arena_create(NULL); sz = nallocx(HUGEPAGE, 0); - esz = sz + large_pad; + esz = sz + sz_large_pad; atomic_store_u(&epoch, 0, ATOMIC_RELAXED); @@ -136,9 +138,9 @@ TEST_BEGIN(test_retained) { arena_t *arena = arena_get(tsdn_fetch(), arena_ind, false); size_t usable = 0; size_t fragmented = 0; - for (pszind_t pind = psz2ind(HUGEPAGE); pind < + for (pszind_t pind = sz_psz2ind(HUGEPAGE); pind < arena->extent_grow_next; pind++) { - size_t psz = pind2sz(pind); + size_t psz = sz_pind2sz(pind); size_t psz_fragmented = psz % esz; size_t psz_usable = psz - psz_fragmented; /* diff --git a/test/unit/rtree.c b/test/unit/rtree.c index 752dde99..814837bf 100644 --- a/test/unit/rtree.c +++ b/test/unit/rtree.c @@ -86,7 +86,8 @@ TEST_END TEST_BEGIN(test_rtree_extrema) { extent_t extent_a, extent_b; extent_init(&extent_a, NULL, NULL, LARGE_MINCLASS, false, - size2index(LARGE_MINCLASS), 0, extent_state_active, false, false); + sz_size2index(LARGE_MINCLASS), 0, extent_state_active, false, + false); extent_init(&extent_b, NULL, NULL, 0, false, NSIZES, 0, extent_state_active, false, false); diff --git a/test/unit/size_classes.c b/test/unit/size_classes.c index 70a86ad9..bcff5609 100644 --- a/test/unit/size_classes.c +++ b/test/unit/size_classes.c @@ -27,11 +27,11 @@ TEST_BEGIN(test_size_classes) { szind_t index, max_index; max_size_class = get_max_size_class(); - max_index = size2index(max_size_class); + max_index = sz_size2index(max_size_class); - for (index = 0, size_class = index2size(index); index < max_index || + for (index = 0, size_class = sz_index2size(index); index < max_index || size_class < max_size_class; index++, size_class = - index2size(index)) { + sz_index2size(index)) { assert_true(index < max_index, "Loop conditionals should be equivalent; index=%u, " "size_class=%zu (%#zx)", index, size_class, size_class); @@ -39,42 +39,44 @@ TEST_BEGIN(test_size_classes) { "Loop conditionals should be equivalent; index=%u, " "size_class=%zu (%#zx)", index, size_class, size_class); - assert_u_eq(index, size2index(size_class), - "size2index() does not reverse index2size(): index=%u -->" - " size_class=%zu --> index=%u --> size_class=%zu", index, - size_class, size2index(size_class), - index2size(size2index(size_class))); - assert_zu_eq(size_class, index2size(size2index(size_class)), - "index2size() does not reverse size2index(): index=%u -->" - " size_class=%zu --> index=%u --> size_class=%zu", index, - size_class, size2index(size_class), - index2size(size2index(size_class))); - - assert_u_eq(index+1, size2index(size_class+1), + assert_u_eq(index, sz_size2index(size_class), + "sz_size2index() does not reverse sz_index2size(): index=%u" + " --> size_class=%zu --> index=%u --> size_class=%zu", + index, size_class, sz_size2index(size_class), + sz_index2size(sz_size2index(size_class))); + assert_zu_eq(size_class, + sz_index2size(sz_size2index(size_class)), + "sz_index2size() does not reverse sz_size2index(): index=%u" + " --> size_class=%zu --> index=%u --> size_class=%zu", + index, size_class, sz_size2index(size_class), + sz_index2size(sz_size2index(size_class))); + + assert_u_eq(index+1, sz_size2index(size_class+1), "Next size_class does not round up properly"); assert_zu_eq(size_class, (index > 0) ? - s2u(index2size(index-1)+1) : s2u(1), - "s2u() does not round up to size class"); - assert_zu_eq(size_class, s2u(size_class-1), - "s2u() does not round up to size class"); - assert_zu_eq(size_class, s2u(size_class), - "s2u() does not compute same size class"); - assert_zu_eq(s2u(size_class+1), index2size(index+1), - "s2u() does not round up to next size class"); + sz_s2u(sz_index2size(index-1)+1) : sz_s2u(1), + "sz_s2u() does not round up to size class"); + assert_zu_eq(size_class, sz_s2u(size_class-1), + "sz_s2u() does not round up to size class"); + assert_zu_eq(size_class, sz_s2u(size_class), + "sz_s2u() does not compute same size class"); + assert_zu_eq(sz_s2u(size_class+1), sz_index2size(index+1), + "sz_s2u() does not round up to next size class"); } - assert_u_eq(index, size2index(index2size(index)), - "size2index() does not reverse index2size()"); - assert_zu_eq(max_size_class, index2size(size2index(max_size_class)), - "index2size() does not reverse size2index()"); - - assert_zu_eq(size_class, s2u(index2size(index-1)+1), - "s2u() does not round up to size class"); - assert_zu_eq(size_class, s2u(size_class-1), - "s2u() does not round up to size class"); - assert_zu_eq(size_class, s2u(size_class), - "s2u() does not compute same size class"); + assert_u_eq(index, sz_size2index(sz_index2size(index)), + "sz_size2index() does not reverse sz_index2size()"); + assert_zu_eq(max_size_class, sz_index2size( + sz_size2index(max_size_class)), + "sz_index2size() does not reverse sz_size2index()"); + + assert_zu_eq(size_class, sz_s2u(sz_index2size(index-1)+1), + "sz_s2u() does not round up to size class"); + assert_zu_eq(size_class, sz_s2u(size_class-1), + "sz_s2u() does not round up to size class"); + assert_zu_eq(size_class, sz_s2u(size_class), + "sz_s2u() does not compute same size class"); } TEST_END @@ -83,10 +85,11 @@ TEST_BEGIN(test_psize_classes) { pszind_t pind, max_pind; max_psz = get_max_size_class() + PAGE; - max_pind = psz2ind(max_psz); + max_pind = sz_psz2ind(max_psz); - for (pind = 0, size_class = pind2sz(pind); pind < max_pind || size_class - < max_psz; pind++, size_class = pind2sz(pind)) { + for (pind = 0, size_class = sz_pind2sz(pind); + pind < max_pind || size_class < max_psz; + pind++, size_class = sz_pind2sz(pind)) { assert_true(pind < max_pind, "Loop conditionals should be equivalent; pind=%u, " "size_class=%zu (%#zx)", pind, size_class, size_class); @@ -94,42 +97,42 @@ TEST_BEGIN(test_psize_classes) { "Loop conditionals should be equivalent; pind=%u, " "size_class=%zu (%#zx)", pind, size_class, size_class); - assert_u_eq(pind, psz2ind(size_class), - "psz2ind() does not reverse pind2sz(): pind=%u -->" + assert_u_eq(pind, sz_psz2ind(size_class), + "sz_psz2ind() does not reverse sz_pind2sz(): pind=%u -->" " size_class=%zu --> pind=%u --> size_class=%zu", pind, - size_class, psz2ind(size_class), - pind2sz(psz2ind(size_class))); - assert_zu_eq(size_class, pind2sz(psz2ind(size_class)), - "pind2sz() does not reverse psz2ind(): pind=%u -->" + size_class, sz_psz2ind(size_class), + sz_pind2sz(sz_psz2ind(size_class))); + assert_zu_eq(size_class, sz_pind2sz(sz_psz2ind(size_class)), + "sz_pind2sz() does not reverse sz_psz2ind(): pind=%u -->" " size_class=%zu --> pind=%u --> size_class=%zu", pind, - size_class, psz2ind(size_class), - pind2sz(psz2ind(size_class))); + size_class, sz_psz2ind(size_class), + sz_pind2sz(sz_psz2ind(size_class))); - assert_u_eq(pind+1, psz2ind(size_class+1), + assert_u_eq(pind+1, sz_psz2ind(size_class+1), "Next size_class does not round up properly"); assert_zu_eq(size_class, (pind > 0) ? - psz2u(pind2sz(pind-1)+1) : psz2u(1), - "psz2u() does not round up to size class"); - assert_zu_eq(size_class, psz2u(size_class-1), - "psz2u() does not round up to size class"); - assert_zu_eq(size_class, psz2u(size_class), - "psz2u() does not compute same size class"); - assert_zu_eq(psz2u(size_class+1), pind2sz(pind+1), - "psz2u() does not round up to next size class"); + sz_psz2u(sz_pind2sz(pind-1)+1) : sz_psz2u(1), + "sz_psz2u() does not round up to size class"); + assert_zu_eq(size_class, sz_psz2u(size_class-1), + "sz_psz2u() does not round up to size class"); + assert_zu_eq(size_class, sz_psz2u(size_class), + "sz_psz2u() does not compute same size class"); + assert_zu_eq(sz_psz2u(size_class+1), sz_pind2sz(pind+1), + "sz_psz2u() does not round up to next size class"); } - assert_u_eq(pind, psz2ind(pind2sz(pind)), - "psz2ind() does not reverse pind2sz()"); - assert_zu_eq(max_psz, pind2sz(psz2ind(max_psz)), - "pind2sz() does not reverse psz2ind()"); - - assert_zu_eq(size_class, psz2u(pind2sz(pind-1)+1), - "psz2u() does not round up to size class"); - assert_zu_eq(size_class, psz2u(size_class-1), - "psz2u() does not round up to size class"); - assert_zu_eq(size_class, psz2u(size_class), - "psz2u() does not compute same size class"); + assert_u_eq(pind, sz_psz2ind(sz_pind2sz(pind)), + "sz_psz2ind() does not reverse sz_pind2sz()"); + assert_zu_eq(max_psz, sz_pind2sz(sz_psz2ind(max_psz)), + "sz_pind2sz() does not reverse sz_psz2ind()"); + + assert_zu_eq(size_class, sz_psz2u(sz_pind2sz(pind-1)+1), + "sz_psz2u() does not round up to size class"); + assert_zu_eq(size_class, sz_psz2u(size_class-1), + "sz_psz2u() does not round up to size class"); + assert_zu_eq(size_class, sz_psz2u(size_class), + "sz_psz2u() does not compute same size class"); } TEST_END @@ -139,35 +142,35 @@ TEST_BEGIN(test_overflow) { max_size_class = get_max_size_class(); max_psz = max_size_class + PAGE; - assert_u_eq(size2index(max_size_class+1), NSIZES, - "size2index() should return NSIZES on overflow"); - assert_u_eq(size2index(ZU(PTRDIFF_MAX)+1), NSIZES, - "size2index() should return NSIZES on overflow"); - assert_u_eq(size2index(SIZE_T_MAX), NSIZES, - "size2index() should return NSIZES on overflow"); - - assert_zu_eq(s2u(max_size_class+1), 0, - "s2u() should return 0 for unsupported size"); - assert_zu_eq(s2u(ZU(PTRDIFF_MAX)+1), 0, - "s2u() should return 0 for unsupported size"); - assert_zu_eq(s2u(SIZE_T_MAX), 0, - "s2u() should return 0 on overflow"); - - assert_u_eq(psz2ind(max_size_class+1), NPSIZES, - "psz2ind() should return NPSIZES on overflow"); - assert_u_eq(psz2ind(ZU(PTRDIFF_MAX)+1), NPSIZES, - "psz2ind() should return NPSIZES on overflow"); - assert_u_eq(psz2ind(SIZE_T_MAX), NPSIZES, - "psz2ind() should return NPSIZES on overflow"); - - assert_zu_eq(psz2u(max_size_class+1), max_psz, - "psz2u() should return (LARGE_MAXCLASS + PAGE) for unsupported" + assert_u_eq(sz_size2index(max_size_class+1), NSIZES, + "sz_size2index() should return NSIZES on overflow"); + assert_u_eq(sz_size2index(ZU(PTRDIFF_MAX)+1), NSIZES, + "sz_size2index() should return NSIZES on overflow"); + assert_u_eq(sz_size2index(SIZE_T_MAX), NSIZES, + "sz_size2index() should return NSIZES on overflow"); + + assert_zu_eq(sz_s2u(max_size_class+1), 0, + "sz_s2u() should return 0 for unsupported size"); + assert_zu_eq(sz_s2u(ZU(PTRDIFF_MAX)+1), 0, + "sz_s2u() should return 0 for unsupported size"); + assert_zu_eq(sz_s2u(SIZE_T_MAX), 0, + "sz_s2u() should return 0 on overflow"); + + assert_u_eq(sz_psz2ind(max_size_class+1), NPSIZES, + "sz_psz2ind() should return NPSIZES on overflow"); + assert_u_eq(sz_psz2ind(ZU(PTRDIFF_MAX)+1), NPSIZES, + "sz_psz2ind() should return NPSIZES on overflow"); + assert_u_eq(sz_psz2ind(SIZE_T_MAX), NPSIZES, + "sz_psz2ind() should return NPSIZES on overflow"); + + assert_zu_eq(sz_psz2u(max_size_class+1), max_psz, + "sz_psz2u() should return (LARGE_MAXCLASS + PAGE) for unsupported" " size"); - assert_zu_eq(psz2u(ZU(PTRDIFF_MAX)+1), max_psz, - "psz2u() should return (LARGE_MAXCLASS + PAGE) for unsupported " + assert_zu_eq(sz_psz2u(ZU(PTRDIFF_MAX)+1), max_psz, + "sz_psz2u() should return (LARGE_MAXCLASS + PAGE) for unsupported " "size"); - assert_zu_eq(psz2u(SIZE_T_MAX), max_psz, - "psz2u() should return (LARGE_MAXCLASS + PAGE) on overflow"); + assert_zu_eq(sz_psz2u(SIZE_T_MAX), max_psz, + "sz_psz2u() should return (LARGE_MAXCLASS + PAGE) on overflow"); } TEST_END -- GitLab From 9a86c9bd30e06daa20e4a4872d9292d177d66c8a Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 31 May 2017 14:15:53 -0700 Subject: [PATCH 521/544] Clean source directory before building tests in object directories. --- scripts/gen_run_tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/gen_run_tests.py b/scripts/gen_run_tests.py index 1d70057f..39e2be24 100755 --- a/scripts/gen_run_tests.py +++ b/scripts/gen_run_tests.py @@ -31,6 +31,7 @@ possible_malloc_conf_opts = [ ] print 'set -e' +print 'if [ -f Makefile ] ; then make relclean ; fi' print 'autoconf' print 'rm -rf run_tests.out' print 'mkdir run_tests.out' -- GitLab From 508f54b02bd08ac0d250df1fa15cf87d574ce8a1 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 30 May 2017 20:45:29 -0700 Subject: [PATCH 522/544] Use real pthread_create for creating background threads. --- src/background_thread.c | 10 ++++++++-- src/mutex.c | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/background_thread.c b/src/background_thread.c index d3e80b3d..ccb50a21 100644 --- a/src/background_thread.c +++ b/src/background_thread.c @@ -364,7 +364,11 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) { pre_reentrancy(tsd); int err; load_pthread_create_fptr(); - if ((err = pthread_create(&info->thread, NULL, + /* + * To avoid complications (besides reentrancy), create internal + * background threads with the underlying pthread_create. + */ + if ((err = pthread_create_fptr(&info->thread, NULL, background_thread_entry, (void *)thread_ind)) != 0) { malloc_printf(": arena %u background thread creation " "failed (%d).\n", arena_ind, err); @@ -645,7 +649,9 @@ load_pthread_create_fptr(void) { if (pthread_create_fptr) { return pthread_create_fptr; } - +#ifdef JEMALLOC_LAZY_LOCK + isthreaded = true; +#endif pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create"); if (pthread_create_fptr == NULL) { malloc_write(": Error in dlsym(RTLD_NEXT, " diff --git a/src/mutex.c b/src/mutex.c index 48e2940a..24852226 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -30,7 +30,7 @@ static malloc_mutex_t *postponed_mutexes = NULL; static void pthread_create_once(void) { pthread_create_fptr = load_pthread_create_fptr(); - isthreaded = true; + assert(isthreaded); } JEMALLOC_EXPORT int -- GitLab From fa35463d56be52a3a6e6b513fbb6cc6e63d9bcc7 Mon Sep 17 00:00:00 2001 From: David Goldblatt Date: Wed, 31 May 2017 09:43:43 -0700 Subject: [PATCH 523/544] Witness assertions: only assert locklessness when non-reentrant. Previously we could still hit these assertions down error paths or in the extended API. --- src/jemalloc.c | 111 +++++++++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 49 deletions(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index 268d19c9..02e32dad 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -627,6 +627,31 @@ stats_print_atexit(void) { je_malloc_stats_print(NULL, NULL, opt_stats_print_opts); } +/* + * Ensure that we don't hold any locks upon entry to or exit from allocator + * code (in a "broad" sense that doesn't count a reentrant allocation as an + * entrance or exit). + */ +JEMALLOC_ALWAYS_INLINE void +check_entry_exit_locking(tsdn_t *tsdn) { + if (!config_debug) { + return; + } + if (tsdn_null(tsdn)) { + return; + } + tsd_t *tsd = tsdn_tsd(tsdn); + /* + * It's possible we hold locks at entry/exit if we're in a nested + * allocation. + */ + int8_t reentrancy_level = tsd_reentrancy_level_get(tsd); + if (reentrancy_level != 0) { + return; + } + witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); +} + /* * End miscellaneous support functions. */ @@ -1705,15 +1730,13 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) { } } + check_entry_exit_locking(tsd_tsdn(tsd)); /* * If we need to handle reentrancy, we can do it out of a * known-initialized arena (i.e. arena 0). */ reentrancy_level = tsd_reentrancy_level_get(tsd); - if (reentrancy_level == 0) { - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); - } if (sopts->slow && unlikely(reentrancy_level > 0)) { /* * We should never specify particular arenas or tcaches from @@ -1788,9 +1811,7 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) { } /* Success! */ - if (reentrancy_level == 0) { - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); - } + check_entry_exit_locking(tsd_tsdn(tsd)); *dopts->result = allocation; return 0; @@ -1804,7 +1825,7 @@ label_oom: UTRACE(NULL, size, NULL); } - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); if (sopts->set_errno_on_error) { set_errno(ENOMEM); @@ -1835,7 +1856,7 @@ label_invalid_alignment: UTRACE(NULL, size, NULL); } - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); if (sopts->null_out_result_on_error) { *dopts->result = NULL; @@ -2036,9 +2057,8 @@ ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) { if (!slow_path) { tsd_assert_fast(tsd); } - if (tsd_reentrancy_level_get(tsd) == 0) { - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); - } else { + check_entry_exit_locking(tsd_tsdn(tsd)); + if (tsd_reentrancy_level_get(tsd) != 0) { assert(slow_path); } @@ -2076,9 +2096,8 @@ isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) { if (!slow_path) { tsd_assert_fast(tsd); } - if (tsd_reentrancy_level_get(tsd) == 0) { - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); - } else { + check_entry_exit_locking(tsd_tsdn(tsd)); + if (tsd_reentrancy_level_get(tsd) != 0) { assert(slow_path); } @@ -2138,7 +2157,7 @@ je_realloc(void *ptr, size_t size) { assert(malloc_initialized() || IS_INITIALIZER); tsd_t *tsd = tsd_fetch(); - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); alloc_ctx_t alloc_ctx; rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd); @@ -2181,7 +2200,7 @@ je_realloc(void *ptr, size_t size) { *tsd_thread_deallocatedp_get(tsd) += old_usize; } UTRACE(ptr, size, ret); - witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); + check_entry_exit_locking(tsdn); return ret; } @@ -2190,10 +2209,7 @@ je_free(void *ptr) { UTRACE(ptr, 0, 0); if (likely(ptr != NULL)) { tsd_t *tsd = tsd_fetch(); - if (tsd_reentrancy_level_get(tsd) == 0) { - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn( - tsd))); - } + check_entry_exit_locking(tsd_tsdn(tsd)); tcache_t *tcache; if (likely(tsd_fast(tsd))) { @@ -2209,10 +2225,7 @@ je_free(void *ptr) { } ifree(tsd, ptr, tcache, true); } - if (tsd_reentrancy_level_get(tsd) == 0) { - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn( - tsd))); - } + check_entry_exit_locking(tsd_tsdn(tsd)); } } @@ -2472,7 +2485,7 @@ je_rallocx(void *ptr, size_t size, int flags) { assert(size != 0); assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); if (unlikely((flags & MALLOCX_ARENA_MASK) != 0)) { unsigned arena_ind = MALLOCX_ARENA_GET(flags); @@ -2529,7 +2542,7 @@ je_rallocx(void *ptr, size_t size, int flags) { *tsd_thread_deallocatedp_get(tsd) += old_usize; } UTRACE(ptr, size, p); - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); return p; label_oom: if (config_xmalloc && unlikely(opt_xmalloc)) { @@ -2537,7 +2550,7 @@ label_oom: abort(); } UTRACE(ptr, size, 0); - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); return NULL; } @@ -2629,7 +2642,7 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) { assert(SIZE_T_MAX - size >= extra); assert(malloc_initialized() || IS_INITIALIZER); tsd = tsd_fetch(); - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); alloc_ctx_t alloc_ctx; rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd); @@ -2672,7 +2685,7 @@ je_xallocx(void *ptr, size_t size, size_t extra, int flags) { } label_not_resized: UTRACE(ptr, size, ptr); - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); return usize; } @@ -2686,7 +2699,7 @@ je_sallocx(const void *ptr, int flags) { assert(ptr != NULL); tsdn = tsdn_fetch(); - witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); + check_entry_exit_locking(tsdn); if (config_debug || force_ivsalloc) { usize = ivsalloc(tsdn, ptr); @@ -2695,7 +2708,7 @@ je_sallocx(const void *ptr, int flags) { usize = isalloc(tsdn, ptr); } - witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); + check_entry_exit_locking(tsdn); return usize; } @@ -2706,7 +2719,7 @@ je_dallocx(void *ptr, int flags) { tsd_t *tsd = tsd_fetch(); bool fast = tsd_fast(tsd); - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); tcache_t *tcache; if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { @@ -2737,12 +2750,12 @@ je_dallocx(void *ptr, int flags) { } else { ifree(tsd, ptr, tcache, true); } - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); } JEMALLOC_ALWAYS_INLINE size_t inallocx(tsdn_t *tsdn, size_t size, int flags) { - witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); + check_entry_exit_locking(tsdn); size_t usize; if (likely((flags & MALLOCX_LG_ALIGN_MASK) == 0)) { @@ -2750,7 +2763,7 @@ inallocx(tsdn_t *tsdn, size_t size, int flags) { } else { usize = sz_sa2u(size, MALLOCX_ALIGN_GET_SPECIFIED(flags)); } - witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); + check_entry_exit_locking(tsdn); return usize; } @@ -2763,7 +2776,7 @@ je_sdallocx(void *ptr, size_t size, int flags) { bool fast = tsd_fast(tsd); size_t usize = inallocx(tsd_tsdn(tsd), size, flags); assert(usize == isalloc(tsd_tsdn(tsd), ptr)); - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); tcache_t *tcache; if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) { @@ -2794,7 +2807,7 @@ je_sdallocx(void *ptr, size_t size, int flags) { } else { isfree(tsd, ptr, usize, tcache, true); } - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); } JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW @@ -2810,14 +2823,14 @@ je_nallocx(size_t size, int flags) { } tsdn = tsdn_fetch(); - witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); + check_entry_exit_locking(tsdn); usize = inallocx(tsdn, size, flags); if (unlikely(usize > LARGE_MAXCLASS)) { return 0; } - witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); + check_entry_exit_locking(tsdn); return usize; } @@ -2832,9 +2845,9 @@ je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp, } tsd = tsd_fetch(); - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); ret = ctl_byname(tsd, name, oldp, oldlenp, newp, newlen); - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); return ret; } @@ -2848,9 +2861,9 @@ je_mallctlnametomib(const char *name, size_t *mibp, size_t *miblenp) { } tsdn = tsdn_fetch(); - witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); + check_entry_exit_locking(tsdn); ret = ctl_nametomib(tsdn, name, mibp, miblenp); - witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); + check_entry_exit_locking(tsdn); return ret; } @@ -2865,9 +2878,9 @@ je_mallctlbymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, } tsd = tsd_fetch(); - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); ret = ctl_bymib(tsd, mib, miblen, oldp, oldlenp, newp, newlen); - witness_assert_lockless(tsdn_witness_tsdp_get(tsd_tsdn(tsd))); + check_entry_exit_locking(tsd_tsdn(tsd)); return ret; } @@ -2877,9 +2890,9 @@ je_malloc_stats_print(void (*write_cb)(void *, const char *), void *cbopaque, tsdn_t *tsdn; tsdn = tsdn_fetch(); - witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); + check_entry_exit_locking(tsdn); stats_print(write_cb, cbopaque, opts); - witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); + check_entry_exit_locking(tsdn); } JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW @@ -2890,7 +2903,7 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) { assert(malloc_initialized() || IS_INITIALIZER); tsdn = tsdn_fetch(); - witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); + check_entry_exit_locking(tsdn); if (unlikely(ptr == NULL)) { ret = 0; @@ -2903,7 +2916,7 @@ je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) { } } - witness_assert_lockless(tsdn_witness_tsdp_get(tsdn)); + check_entry_exit_locking(tsdn); return ret; } -- GitLab From 596b479d839d9f85538a6ff756a81e1ef8d4abb3 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 31 May 2017 21:34:26 -0700 Subject: [PATCH 524/544] Skip default tcache testing if !opt_tcache. --- test/unit/mallctl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 8339e8c5..80b84a06 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -210,12 +210,12 @@ TEST_BEGIN(test_manpage_example) { TEST_END TEST_BEGIN(test_tcache_none) { - void *p0, *q, *p1; + test_skip_if(!opt_tcache); /* Allocate p and q. */ - p0 = mallocx(42, 0); + void *p0 = mallocx(42, 0); assert_ptr_not_null(p0, "Unexpected mallocx() failure"); - q = mallocx(42, 0); + void *q = mallocx(42, 0); assert_ptr_not_null(q, "Unexpected mallocx() failure"); /* Deallocate p and q, but bypass the tcache for q. */ @@ -223,7 +223,7 @@ TEST_BEGIN(test_tcache_none) { dallocx(q, MALLOCX_TCACHE_NONE); /* Make sure that tcache-based allocation returns p, not q. */ - p1 = mallocx(42, 0); + void *p1 = mallocx(42, 0); assert_ptr_not_null(p1, "Unexpected mallocx() failure"); assert_ptr_eq(p0, p1, "Expected tcache to allocate cached region"); -- GitLab From b511232fcd8aeb85d5dc8e0515539baa5d333991 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 31 May 2017 16:45:14 -0700 Subject: [PATCH 525/544] Refactor/fix background_thread/percpu_arena bootstrapping. Refactor bootstrapping such that dlsym() is called during the bootstrapping phase that can tolerate reentrant allocation. --- include/jemalloc/internal/arena_externs.h | 5 +- include/jemalloc/internal/arena_types.h | 24 +++- .../internal/background_thread_externs.h | 8 +- .../internal/background_thread_structs.h | 4 + .../internal/jemalloc_internal_inlines_a.h | 18 +-- .../internal/jemalloc_internal_inlines_b.h | 7 +- src/arena.c | 9 +- src/background_thread.c | 116 ++++++++++-------- src/ctl.c | 7 +- src/jemalloc.c | 63 ++++++---- src/mutex.c | 12 +- test/unit/mallctl.c | 12 +- 12 files changed, 161 insertions(+), 124 deletions(-) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index cfb7c6fb..9ad9786f 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -11,9 +11,8 @@ extern ssize_t opt_muzzy_decay_ms; extern const arena_bin_info_t arena_bin_info[NBINS]; -extern percpu_arena_mode_t percpu_arena_mode; -extern const char *opt_percpu_arena; -extern const char *percpu_arena_mode_names[]; +extern percpu_arena_mode_t opt_percpu_arena; +extern const char *percpu_arena_mode_names[]; extern const uint64_t h_steps[SMOOTHSTEP_NSTEPS]; diff --git a/include/jemalloc/internal/arena_types.h b/include/jemalloc/internal/arena_types.h index 01b9096a..a691bd81 100644 --- a/include/jemalloc/internal/arena_types.h +++ b/include/jemalloc/internal/arena_types.h @@ -20,14 +20,26 @@ typedef struct arena_tdata_s arena_tdata_t; typedef struct alloc_ctx_s alloc_ctx_t; typedef enum { - percpu_arena_disabled = 0, - percpu_arena = 1, - per_phycpu_arena = 2, /* i.e. hyper threads share arena. */ + percpu_arena_mode_names_base = 0, /* Used for options processing. */ - percpu_arena_mode_limit = 3 + /* + * *_uninit are used only during bootstrapping, and must correspond + * to initialized variant plus percpu_arena_mode_enabled_base. + */ + percpu_arena_uninit = 0, + per_phycpu_arena_uninit = 1, + + /* All non-disabled modes must come after percpu_arena_disabled. */ + percpu_arena_disabled = 2, + + percpu_arena_mode_names_limit = 3, /* Used for options processing. */ + percpu_arena_mode_enabled_base = 3, + + percpu_arena = 3, + per_phycpu_arena = 4 /* Hyper threads share arena. */ } percpu_arena_mode_t; -#define PERCPU_ARENA_MODE_DEFAULT percpu_arena_disabled -#define OPT_PERCPU_ARENA_DEFAULT "disabled" +#define PERCPU_ARENA_ENABLED(m) ((m) >= percpu_arena_mode_enabled_base) +#define PERCPU_ARENA_DEFAULT percpu_arena_disabled #endif /* JEMALLOC_INTERNAL_ARENA_TYPES_H */ diff --git a/include/jemalloc/internal/background_thread_externs.h b/include/jemalloc/internal/background_thread_externs.h index fe25acfe..a2d95a73 100644 --- a/include/jemalloc/internal/background_thread_externs.h +++ b/include/jemalloc/internal/background_thread_externs.h @@ -8,7 +8,6 @@ extern size_t n_background_threads; extern background_thread_info_t *background_thread_info; bool background_thread_create(tsd_t *tsd, unsigned arena_ind); -bool background_threads_init(tsd_t *tsd); bool background_threads_enable(tsd_t *tsd); bool background_threads_disable(tsd_t *tsd); bool background_threads_disable_single(tsd_t *tsd, @@ -22,10 +21,11 @@ void background_thread_postfork_child(tsdn_t *tsdn); bool background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats); -#if defined(JEMALLOC_BACKGROUND_THREAD) || defined(JEMALLOC_LAZY_LOCK) -extern int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *, +#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER +extern int pthread_create_wrapper(pthread_t *__restrict, const pthread_attr_t *, void *(*)(void *), void *__restrict); -void *load_pthread_create_fptr(void); #endif +bool background_thread_boot0(void); +bool background_thread_boot1(tsdn_t *tsdn); #endif /* JEMALLOC_INTERNAL_BACKGROUND_THREAD_EXTERNS_H */ diff --git a/include/jemalloc/internal/background_thread_structs.h b/include/jemalloc/internal/background_thread_structs.h index 9507abcd..edf90fe2 100644 --- a/include/jemalloc/internal/background_thread_structs.h +++ b/include/jemalloc/internal/background_thread_structs.h @@ -3,6 +3,10 @@ /* This file really combines "structs" and "types", but only transitionally. */ +#if defined(JEMALLOC_BACKGROUND_THREAD) || defined(JEMALLOC_LAZY_LOCK) +# define JEMALLOC_PTHREAD_CREATE_WRAPPER +#endif + #define BACKGROUND_THREAD_INDEFINITE_SLEEP UINT64_MAX struct background_thread_info_s { diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_a.h b/include/jemalloc/internal/jemalloc_internal_inlines_a.h index d0bf2eee..854fb1e2 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_a.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_a.h @@ -21,17 +21,17 @@ malloc_getcpu(void) { /* Return the chosen arena index based on current cpu. */ JEMALLOC_ALWAYS_INLINE unsigned percpu_arena_choose(void) { - unsigned arena_ind; - assert(have_percpu_arena && (percpu_arena_mode != - percpu_arena_disabled)); + assert(have_percpu_arena && PERCPU_ARENA_ENABLED(opt_percpu_arena)); malloc_cpuid_t cpuid = malloc_getcpu(); assert(cpuid >= 0); - if ((percpu_arena_mode == percpu_arena) || - ((unsigned)cpuid < ncpus / 2)) { + + unsigned arena_ind; + if ((opt_percpu_arena == percpu_arena) || ((unsigned)cpuid < ncpus / + 2)) { arena_ind = cpuid; } else { - assert(percpu_arena_mode == per_phycpu_arena); + assert(opt_percpu_arena == per_phycpu_arena); /* Hyper threads on the same physical CPU share arena. */ arena_ind = cpuid - ncpus / 2; } @@ -41,9 +41,9 @@ percpu_arena_choose(void) { /* Return the limit of percpu auto arena range, i.e. arenas[0...ind_limit). */ JEMALLOC_ALWAYS_INLINE unsigned -percpu_arena_ind_limit(void) { - assert(have_percpu_arena && (percpu_arena_mode != percpu_arena_disabled)); - if (percpu_arena_mode == per_phycpu_arena && ncpus > 1) { +percpu_arena_ind_limit(percpu_arena_mode_t mode) { + assert(have_percpu_arena && PERCPU_ARENA_ENABLED(mode)); + if (mode == per_phycpu_arena && ncpus > 1) { if (ncpus % 2) { /* This likely means a misconfig. */ return ncpus / 2 + 1; diff --git a/include/jemalloc/internal/jemalloc_internal_inlines_b.h b/include/jemalloc/internal/jemalloc_internal_inlines_b.h index 37493160..2e76e5d8 100644 --- a/include/jemalloc/internal/jemalloc_internal_inlines_b.h +++ b/include/jemalloc/internal/jemalloc_internal_inlines_b.h @@ -43,9 +43,10 @@ arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) { * auto percpu arena range, (i.e. thread is assigned to a manually * managed arena), then percpu arena is skipped. */ - if (have_percpu_arena && (percpu_arena_mode != percpu_arena_disabled) && - !internal && (arena_ind_get(ret) < percpu_arena_ind_limit()) && - (ret->last_thd != tsd_tsdn(tsd))) { + if (have_percpu_arena && PERCPU_ARENA_ENABLED(opt_percpu_arena) && + !internal && (arena_ind_get(ret) < + percpu_arena_ind_limit(opt_percpu_arena)) && (ret->last_thd != + tsd_tsdn(tsd))) { unsigned ind = percpu_arena_choose(); if (arena_ind_get(ret) != ind) { percpu_arena_update(tsd, ind); diff --git a/src/arena.c b/src/arena.c index 151aad3e..dedbb3e3 100644 --- a/src/arena.c +++ b/src/arena.c @@ -13,13 +13,18 @@ /******************************************************************************/ /* Data. */ +/* + * Define names for both unininitialized and initialized phases, so that + * options and mallctl processing are straightforward. + */ const char *percpu_arena_mode_names[] = { + "percpu", + "phycpu", "disabled", "percpu", "phycpu" }; -const char *opt_percpu_arena = OPT_PERCPU_ARENA_DEFAULT; -percpu_arena_mode_t percpu_arena_mode = PERCPU_ARENA_MODE_DEFAULT; +percpu_arena_mode_t opt_percpu_arena = PERCPU_ARENA_DEFAULT; ssize_t opt_dirty_decay_ms = DIRTY_DECAY_MS_DEFAULT; ssize_t opt_muzzy_decay_ms = MUZZY_DECAY_MS_DEFAULT; diff --git a/src/background_thread.c b/src/background_thread.c index ccb50a21..800526f5 100644 --- a/src/background_thread.c +++ b/src/background_thread.c @@ -25,7 +25,6 @@ background_thread_info_t *background_thread_info; #ifndef JEMALLOC_BACKGROUND_THREAD #define NOT_REACHED { not_reached(); } bool background_thread_create(tsd_t *tsd, unsigned arena_ind) NOT_REACHED -bool background_threads_init(tsd_t *tsd) NOT_REACHED bool background_threads_enable(tsd_t *tsd) NOT_REACHED bool background_threads_disable(tsd_t *tsd) NOT_REACHED bool background_threads_disable_single(tsd_t *tsd, @@ -53,44 +52,6 @@ background_thread_info_reinit(tsdn_t *tsdn, background_thread_info_t *info) { } } -bool -background_threads_init(tsd_t *tsd) { - assert(have_background_thread); - assert(narenas_total_get() > 0); - - background_thread_enabled_set(tsd_tsdn(tsd), opt_background_thread); - if (malloc_mutex_init(&background_thread_lock, - "background_thread_global", - WITNESS_RANK_BACKGROUND_THREAD_GLOBAL, - malloc_mutex_rank_exclusive)) { - return true; - } - background_thread_info = (background_thread_info_t *)base_alloc( - tsd_tsdn(tsd), b0get(), ncpus * sizeof(background_thread_info_t), - CACHELINE); - if (background_thread_info == NULL) { - return true; - } - - for (unsigned i = 0; i < ncpus; i++) { - background_thread_info_t *info = &background_thread_info[i]; - if (malloc_mutex_init(&info->mtx, "background_thread", - WITNESS_RANK_BACKGROUND_THREAD, - malloc_mutex_rank_exclusive)) { - return true; - } - if (pthread_cond_init(&info->cond, NULL)) { - return true; - } - malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); - info->started = false; - background_thread_info_reinit(tsd_tsdn(tsd), info); - malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); - } - - return false; -} - static inline bool set_current_thread_affinity(UNUSED int cpu) { #if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY) @@ -363,12 +324,11 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) { pre_reentrancy(tsd); int err; - load_pthread_create_fptr(); /* * To avoid complications (besides reentrancy), create internal * background threads with the underlying pthread_create. */ - if ((err = pthread_create_fptr(&info->thread, NULL, + if ((err = pthread_create_wrapper(&info->thread, NULL, background_thread_entry, (void *)thread_ind)) != 0) { malloc_printf(": arena %u background thread creation " "failed (%d).\n", arena_ind, err); @@ -638,28 +598,84 @@ background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats) { #endif /* defined(JEMALLOC_BACKGROUND_THREAD) */ -#if defined(JEMALLOC_BACKGROUND_THREAD) || defined(JEMALLOC_LAZY_LOCK) +#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER #include -int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *, +static int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *, void *(*)(void *), void *__restrict); -void * -load_pthread_create_fptr(void) { - if (pthread_create_fptr) { - return pthread_create_fptr; - } +static void +pthread_create_wrapper_once(void) { #ifdef JEMALLOC_LAZY_LOCK isthreaded = true; #endif +} + +int +pthread_create_wrapper(pthread_t *__restrict thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *__restrict arg) { + static pthread_once_t once_control = PTHREAD_ONCE_INIT; + + pthread_once(&once_control, pthread_create_wrapper_once); + + return pthread_create_fptr(thread, attr, start_routine, arg); +} +#endif + +bool +background_thread_boot0(void) { + if (!have_background_thread && opt_background_thread) { + malloc_printf(": option background_thread currently " + "supports pthread only. \n"); + return true; + } + +#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER pthread_create_fptr = dlsym(RTLD_NEXT, "pthread_create"); if (pthread_create_fptr == NULL) { malloc_write(": Error in dlsym(RTLD_NEXT, " "\"pthread_create\")\n"); abort(); } - - return pthread_create_fptr; +#endif + return false; } +bool +background_thread_boot1(tsdn_t *tsdn) { +#ifdef JEMALLOC_BACKGROUND_THREAD + assert(have_background_thread); + assert(narenas_total_get() > 0); + + background_thread_enabled_set(tsdn, opt_background_thread); + if (malloc_mutex_init(&background_thread_lock, + "background_thread_global", + WITNESS_RANK_BACKGROUND_THREAD_GLOBAL, + malloc_mutex_rank_exclusive)) { + return true; + } + background_thread_info = (background_thread_info_t *)base_alloc(tsdn, + b0get(), ncpus * sizeof(background_thread_info_t), CACHELINE); + if (background_thread_info == NULL) { + return true; + } + + for (unsigned i = 0; i < ncpus; i++) { + background_thread_info_t *info = &background_thread_info[i]; + if (malloc_mutex_init(&info->mtx, "background_thread", + WITNESS_RANK_BACKGROUND_THREAD, + malloc_mutex_rank_exclusive)) { + return true; + } + if (pthread_cond_init(&info->cond, NULL)) { + return true; + } + malloc_mutex_lock(tsdn, &info->mtx); + info->started = false; + background_thread_info_reinit(tsdn, info); + malloc_mutex_unlock(tsdn, &info->mtx); + } #endif + + return false; +} diff --git a/src/ctl.c b/src/ctl.c index 1520c508..70059886 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1559,7 +1559,8 @@ CTL_RO_NL_GEN(opt_abort_conf, opt_abort_conf, bool) CTL_RO_NL_GEN(opt_retain, opt_retain, bool) CTL_RO_NL_GEN(opt_dss, opt_dss, const char *) CTL_RO_NL_GEN(opt_narenas, opt_narenas, unsigned) -CTL_RO_NL_GEN(opt_percpu_arena, opt_percpu_arena, const char *) +CTL_RO_NL_GEN(opt_percpu_arena, percpu_arena_mode_names[opt_percpu_arena], + const char *) CTL_RO_NL_GEN(opt_background_thread, opt_background_thread, bool) CTL_RO_NL_GEN(opt_dirty_decay_ms, opt_dirty_decay_ms, ssize_t) CTL_RO_NL_GEN(opt_muzzy_decay_ms, opt_muzzy_decay_ms, ssize_t) @@ -1610,8 +1611,8 @@ thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, } if (have_percpu_arena && - (percpu_arena_mode != percpu_arena_disabled)) { - if (newind < percpu_arena_ind_limit()) { + PERCPU_ARENA_ENABLED(opt_percpu_arena)) { + if (newind < percpu_arena_ind_limit(opt_percpu_arena)) { /* * If perCPU arena is enabled, thread_arena * control is not allowed for the auto arena diff --git a/src/jemalloc.c b/src/jemalloc.c index 02e32dad..c3983a5d 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -463,7 +463,7 @@ arena_t * arena_choose_hard(tsd_t *tsd, bool internal) { arena_t *ret JEMALLOC_CC_SILENCE_INIT(NULL); - if (have_percpu_arena && percpu_arena_mode != percpu_arena_disabled) { + if (have_percpu_arena && PERCPU_ARENA_ENABLED(opt_percpu_arena)) { unsigned choose = percpu_arena_choose(); ret = arena_get(tsd_tsdn(tsd), choose, true); assert(ret != NULL); @@ -1100,17 +1100,16 @@ malloc_conf_init(void) { if (strncmp("percpu_arena", k, klen) == 0) { int i; bool match = false; - for (i = 0; i < percpu_arena_mode_limit; i++) { + for (i = percpu_arena_mode_names_base; i < + percpu_arena_mode_names_limit; i++) { if (strncmp(percpu_arena_mode_names[i], - v, vlen) == 0) { + v, vlen) == 0) { if (!have_percpu_arena) { malloc_conf_error( "No getcpu support", k, klen, v, vlen); } - percpu_arena_mode = i; - opt_percpu_arena = - percpu_arena_mode_names[i]; + opt_percpu_arena = i; match = true; break; } @@ -1276,6 +1275,10 @@ malloc_init_hard_recursible(void) { } #endif + if (background_thread_boot0()) { + return true; + } + return false; } @@ -1293,13 +1296,25 @@ malloc_narenas_default(void) { } } +static percpu_arena_mode_t +percpu_arena_as_initialized(percpu_arena_mode_t mode) { + assert(!malloc_initialized()); + assert(mode <= percpu_arena_disabled); + + if (mode != percpu_arena_disabled) { + mode += percpu_arena_mode_enabled_base; + } + + return mode; +} + static bool malloc_init_narenas(void) { assert(ncpus > 0); - if (percpu_arena_mode != percpu_arena_disabled) { + if (opt_percpu_arena != percpu_arena_disabled) { if (!have_percpu_arena || malloc_getcpu() < 0) { - percpu_arena_mode = percpu_arena_disabled; + opt_percpu_arena = percpu_arena_disabled; malloc_printf(": perCPU arena getcpu() not " "available. Setting narenas to %u.\n", opt_narenas ? opt_narenas : malloc_narenas_default()); @@ -1315,8 +1330,9 @@ malloc_init_narenas(void) { } return true; } - if ((percpu_arena_mode == per_phycpu_arena) && - (ncpus % 2 != 0)) { + /* NB: opt_percpu_arena isn't fully initialized yet. */ + if (percpu_arena_as_initialized(opt_percpu_arena) == + per_phycpu_arena && ncpus % 2 != 0) { malloc_printf(": invalid " "configuration -- per physical CPU arena " "with odd number (%u) of CPUs (no hyper " @@ -1324,7 +1340,8 @@ malloc_init_narenas(void) { if (opt_abort) abort(); } - unsigned n = percpu_arena_ind_limit(); + unsigned n = percpu_arena_ind_limit( + percpu_arena_as_initialized(opt_percpu_arena)); if (opt_narenas < n) { /* * If narenas is specified with percpu_arena @@ -1363,26 +1380,16 @@ malloc_init_narenas(void) { return false; } -static bool -malloc_init_background_threads(tsd_t *tsd) { - malloc_mutex_assert_owner(tsd_tsdn(tsd), &init_lock); - if (!have_background_thread) { - if (opt_background_thread) { - malloc_printf(": option background_thread " - "currently supports pthread only. \n"); - return true; - } else { - return false; - } - } - - return background_threads_init(tsd); +static void +malloc_init_percpu(void) { + opt_percpu_arena = percpu_arena_as_initialized(opt_percpu_arena); } static bool malloc_init_hard_finish(void) { - if (malloc_mutex_boot()) + if (malloc_mutex_boot()) { return true; + } malloc_init_state = malloc_init_initialized; malloc_slow_flag_init(); @@ -1421,7 +1428,7 @@ malloc_init_hard(void) { malloc_mutex_lock(tsd_tsdn(tsd), &init_lock); /* Initialize narenas before prof_boot2 (for allocation). */ - if (malloc_init_narenas() || malloc_init_background_threads(tsd)) { + if (malloc_init_narenas() || background_thread_boot1(tsd_tsdn(tsd))) { malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); return true; } @@ -1431,6 +1438,8 @@ malloc_init_hard(void) { return true; } + malloc_init_percpu(); + if (malloc_init_hard_finish()) { malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); return true; diff --git a/src/mutex.c b/src/mutex.c index 24852226..a528ef0c 100644 --- a/src/mutex.c +++ b/src/mutex.c @@ -27,21 +27,11 @@ static malloc_mutex_t *postponed_mutexes = NULL; */ #if defined(JEMALLOC_LAZY_LOCK) && !defined(_WIN32) -static void -pthread_create_once(void) { - pthread_create_fptr = load_pthread_create_fptr(); - assert(isthreaded); -} - JEMALLOC_EXPORT int pthread_create(pthread_t *__restrict thread, const pthread_attr_t *__restrict attr, void *(*start_routine)(void *), void *__restrict arg) { - static pthread_once_t once_control = PTHREAD_ONCE_INIT; - - pthread_once(&once_control, pthread_create_once); - - return pthread_create_fptr(thread, attr, start_routine, arg); + return pthread_create_wrapper(thread, attr, start_routine, arg); } #endif diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c index 80b84a06..f6116549 100644 --- a/test/unit/mallctl.c +++ b/test/unit/mallctl.c @@ -327,18 +327,18 @@ TEST_END TEST_BEGIN(test_thread_arena) { unsigned old_arena_ind, new_arena_ind, narenas; - const char *opt_percpu_arena; - size_t sz = sizeof(opt_percpu_arena); - assert_d_eq(mallctl("opt.percpu_arena", &opt_percpu_arena, &sz, NULL, - 0), 0, "Unexpected mallctl() failure"); + const char *opa; + size_t sz = sizeof(opa); + assert_d_eq(mallctl("opt.percpu_arena", &opa, &sz, NULL, 0), 0, + "Unexpected mallctl() failure"); sz = sizeof(unsigned); assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); assert_u_eq(narenas, opt_narenas, "Number of arenas incorrect"); - if (strcmp(opt_percpu_arena, "disabled") == 0) { + if (strcmp(opa, "disabled") == 0) { new_arena_ind = narenas - 1; assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz, (void *)&new_arena_ind, sizeof(unsigned)), 0, @@ -350,7 +350,7 @@ TEST_BEGIN(test_thread_arena) { } else { assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz, NULL, 0), 0, "Unexpected mallctl() failure"); - new_arena_ind = percpu_arena_ind_limit() - 1; + new_arena_ind = percpu_arena_ind_limit(opt_percpu_arena) - 1; if (old_arena_ind != new_arena_ind) { assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz, (void *)&new_arena_ind, -- GitLab From fd0fa003e188e94beab8871ff0c17ea4a8a2c706 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Wed, 31 May 2017 11:56:31 -0700 Subject: [PATCH 526/544] Test with background_thread:true. Add testing for background_thread:true, and condition a xallocx() --> rallocx() escalation assertion to allow for spurious in-place rallocx() following xallocx() failure. --- .travis.yml | 22 ++++++++++++++++++++++ scripts/gen_run_tests.py | 4 +++- scripts/gen_travis.py | 4 +++- test/unit/junk.c | 11 +++++++---- 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 917314fa..418fc6fd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,6 +26,8 @@ matrix: env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: osx @@ -54,6 +56,8 @@ matrix: env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=clang CXX=clang++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--enable-debug" EXTRA_CFLAGS="-Werror -Wno-array-bounds" addons: @@ -90,6 +94,12 @@ matrix: apt: packages: - gcc-multilib + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="-m32" CONFIGURE_FLAGS="--with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + addons: + apt: + packages: + - gcc-multilib - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux @@ -100,6 +110,8 @@ matrix: env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --disable-stats" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux @@ -108,18 +120,28 @@ matrix: env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-prof --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=tcache:false" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--disable-stats --with-malloc-conf=background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,dss:primary" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=tcache:false,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" - os: linux env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary,percpu_arena:percpu" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=dss:primary,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" + - os: linux + env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--with-malloc-conf=percpu_arena:percpu,background_thread:true" EXTRA_CFLAGS="-Werror -Wno-array-bounds" before_script: diff --git a/scripts/gen_run_tests.py b/scripts/gen_run_tests.py index 39e2be24..ddf21533 100755 --- a/scripts/gen_run_tests.py +++ b/scripts/gen_run_tests.py @@ -28,6 +28,7 @@ possible_malloc_conf_opts = [ 'tcache:false', 'dss:primary', 'percpu_arena:percpu', + 'background_thread:true', ] print 'set -e' @@ -57,7 +58,8 @@ for cc, cxx in possible_compilers: ) # Per CPU arenas are only supported on Linux. - linux_supported = ('percpu_arena:percpu' in malloc_conf_opts) + linux_supported = ('percpu_arena:percpu' in malloc_conf_opts \ + or 'background_thread:true' in malloc_conf_opts) # Heap profiling and dss are not supported on OS X. darwin_unsupported = ('--enable-prof' in config_opts or \ 'dss:primary' in malloc_conf_opts) diff --git a/scripts/gen_travis.py b/scripts/gen_travis.py index 26997b25..6dd39290 100755 --- a/scripts/gen_travis.py +++ b/scripts/gen_travis.py @@ -49,6 +49,7 @@ malloc_conf_unusuals = [ 'tcache:false', 'dss:primary', 'percpu_arena:percpu', + 'background_thread:true', ] all_unusuals = ( @@ -80,7 +81,8 @@ for unusual_combination in unusual_combinations_to_test: x for x in unusual_combination if x in malloc_conf_unusuals] # Filter out unsupported configurations on OS X. if os == 'osx' and ('dss:primary' in malloc_conf or \ - 'percpu_arena:percpu' in malloc_conf): + 'percpu_arena:percpu' in malloc_conf or 'background_thread:true' \ + in malloc_conf): continue if len(malloc_conf) > 0: configure_flags.append('--with-malloc-conf=' + ",".join(malloc_conf)) diff --git a/test/unit/junk.c b/test/unit/junk.c index f9390e41..fd0e65b1 100644 --- a/test/unit/junk.c +++ b/test/unit/junk.c @@ -96,12 +96,15 @@ test_junk(size_t sz_min, size_t sz_max) { t = (uint8_t *)rallocx(s, sz+1, 0); assert_ptr_not_null((void *)t, "Unexpected rallocx() failure"); - assert_ptr_ne(s, t, "Unexpected in-place rallocx()"); assert_zu_ge(sallocx(t, 0), sz+1, "Unexpectedly small rallocx() result"); - assert_true(!opt_junk_free || saw_junking, - "Expected region of size %zu to be junk-filled", - sz); + if (!background_thread_enabled()) { + assert_ptr_ne(s, t, + "Unexpected in-place rallocx()"); + assert_true(!opt_junk_free || saw_junking, + "Expected region of size %zu to be " + "junk-filled", sz); + } s = t; } } -- GitLab From c84ec3e9da66162943ee33afe73c7f898fa134e2 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Thu, 1 Jun 2017 00:04:56 -0700 Subject: [PATCH 527/544] Fix background thread creation. The state initialization should be done before pthread_create. --- src/background_thread.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/background_thread.c b/src/background_thread.c index 800526f5..a89cad2e 100644 --- a/src/background_thread.c +++ b/src/background_thread.c @@ -317,34 +317,38 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) { bool need_new_thread; malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); need_new_thread = background_thread_enabled() && !info->started; + if (need_new_thread) { + info->started = true; + background_thread_info_reinit(tsd_tsdn(tsd), info); + n_background_threads++; + } malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); if (!need_new_thread) { return false; } pre_reentrancy(tsd); - int err; /* * To avoid complications (besides reentrancy), create internal * background threads with the underlying pthread_create. */ - if ((err = pthread_create_wrapper(&info->thread, NULL, - background_thread_entry, (void *)thread_ind)) != 0) { + int err = pthread_create_wrapper(&info->thread, NULL, + background_thread_entry, (void *)thread_ind); + post_reentrancy(tsd); + + if (err != 0) { malloc_printf(": arena %u background thread creation " "failed (%d).\n", arena_ind, err); - } - post_reentrancy(tsd); + malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); + info->started = false; + n_background_threads--; + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); - malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); - assert(info->started == false); - if (err == 0) { - info->started = true; - background_thread_info_reinit(tsd_tsdn(tsd), info); - n_background_threads++; + return true; } - malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); + assert(info->started); - return (err != 0); + return false; } bool -- GitLab From 340071f0cf6902a79102328960f5cf1ced87f3c2 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Thu, 1 Jun 2017 12:52:09 -0700 Subject: [PATCH 528/544] Set isthreaded when enabling background_thread. --- .../internal/background_thread_externs.h | 1 + src/background_thread.c | 62 ++++++++++++------- src/ctl.c | 1 + 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/include/jemalloc/internal/background_thread_externs.h b/include/jemalloc/internal/background_thread_externs.h index a2d95a73..aef1c90b 100644 --- a/include/jemalloc/internal/background_thread_externs.h +++ b/include/jemalloc/internal/background_thread_externs.h @@ -20,6 +20,7 @@ void background_thread_postfork_parent(tsdn_t *tsdn); void background_thread_postfork_child(tsdn_t *tsdn); bool background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats); +void background_thread_ctl_init(tsdn_t *tsdn); #ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER extern int pthread_create_wrapper(pthread_t *__restrict, const pthread_attr_t *, diff --git a/src/background_thread.c b/src/background_thread.c index a89cad2e..64eba1a7 100644 --- a/src/background_thread.c +++ b/src/background_thread.c @@ -22,6 +22,29 @@ background_thread_info_t *background_thread_info; /******************************************************************************/ +#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER +#include + +static int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *, + void *(*)(void *), void *__restrict); +static pthread_once_t once_control = PTHREAD_ONCE_INIT; + +static void +pthread_create_wrapper_once(void) { +#ifdef JEMALLOC_LAZY_LOCK + isthreaded = true; +#endif +} + +int +pthread_create_wrapper(pthread_t *__restrict thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *__restrict arg) { + pthread_once(&once_control, pthread_create_wrapper_once); + + return pthread_create_fptr(thread, attr, start_routine, arg); +} +#endif /* JEMALLOC_PTHREAD_CREATE_WRAPPER */ + #ifndef JEMALLOC_BACKGROUND_THREAD #define NOT_REACHED { not_reached(); } bool background_thread_create(tsd_t *tsd, unsigned arena_ind) NOT_REACHED @@ -37,6 +60,7 @@ void background_thread_postfork_parent(tsdn_t *tsdn) NOT_REACHED void background_thread_postfork_child(tsdn_t *tsdn) NOT_REACHED bool background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats) NOT_REACHED +void background_thread_ctl_init(tsdn_t *tsdn) NOT_REACHED #undef NOT_REACHED #else @@ -600,31 +624,19 @@ background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats) { #undef BILLION #undef BACKGROUND_THREAD_MIN_INTERVAL_NS -#endif /* defined(JEMALLOC_BACKGROUND_THREAD) */ - -#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER -#include - -static int (*pthread_create_fptr)(pthread_t *__restrict, const pthread_attr_t *, - void *(*)(void *), void *__restrict); - -static void -pthread_create_wrapper_once(void) { -#ifdef JEMALLOC_LAZY_LOCK - isthreaded = true; -#endif -} - -int -pthread_create_wrapper(pthread_t *__restrict thread, const pthread_attr_t *attr, - void *(*start_routine)(void *), void *__restrict arg) { - static pthread_once_t once_control = PTHREAD_ONCE_INIT; - +/* + * When lazy lock is enabled, we need to make sure setting isthreaded before + * taking any background_thread locks. This is called early in ctl (instead of + * wait for the pthread_create calls to trigger) because the mutex is required + * before creating background threads. + */ +void +background_thread_ctl_init(tsdn_t *tsdn) { + malloc_mutex_assert_not_owner(tsdn, &background_thread_lock); pthread_once(&once_control, pthread_create_wrapper_once); - - return pthread_create_fptr(thread, attr, start_routine, arg); } -#endif + +#endif /* defined(JEMALLOC_BACKGROUND_THREAD) */ bool background_thread_boot0(void) { @@ -658,6 +670,10 @@ background_thread_boot1(tsdn_t *tsdn) { malloc_mutex_rank_exclusive)) { return true; } + if (opt_background_thread) { + background_thread_ctl_init(tsdn); + } + background_thread_info = (background_thread_info_t *)base_alloc(tsdn, b0get(), ncpus * sizeof(background_thread_info_t), CACHELINE); if (background_thread_info == NULL) { diff --git a/src/ctl.c b/src/ctl.c index 70059886..c3514bdd 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1499,6 +1499,7 @@ background_thread_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, if (!have_background_thread) { return ENOENT; } + background_thread_ctl_init(tsd_tsdn(tsd)); malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock); if (newp == NULL) { -- GitLab From 530c07a45ba3ea744b280c9df5d94165839f7b09 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 31 May 2017 15:21:10 -0700 Subject: [PATCH 529/544] Set reentrancy level to 1 during init. This makes sure we go down slow path w/ a0 in init. --- src/jemalloc.c | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index c3983a5d..7e695d66 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1397,6 +1397,18 @@ malloc_init_hard_finish(void) { return false; } +static void +malloc_init_hard_cleanup(tsdn_t *tsdn, bool reentrancy_set) { + malloc_mutex_assert_owner(tsdn, &init_lock); + malloc_mutex_unlock(tsdn, &init_lock); + if (reentrancy_set) { + assert(!tsdn_null(tsdn)); + tsd_t *tsd = tsdn_tsd(tsdn); + assert(tsd_reentrancy_level_get(tsd) > 0); + post_reentrancy(tsd); + } +} + static bool malloc_init_hard(void) { tsd_t *tsd; @@ -1405,15 +1417,18 @@ malloc_init_hard(void) { _init_init_lock(); #endif malloc_mutex_lock(TSDN_NULL, &init_lock); + +#define UNLOCK_RETURN(tsdn, ret, reentrancy) \ + malloc_init_hard_cleanup(tsdn, reentrancy); \ + return ret; + if (!malloc_init_hard_needed()) { - malloc_mutex_unlock(TSDN_NULL, &init_lock); - return false; + UNLOCK_RETURN(TSDN_NULL, false, false) } if (malloc_init_state != malloc_init_a0_initialized && malloc_init_hard_a0_locked()) { - malloc_mutex_unlock(TSDN_NULL, &init_lock); - return true; + UNLOCK_RETURN(TSDN_NULL, true, false) } malloc_mutex_unlock(TSDN_NULL, &init_lock); @@ -1425,29 +1440,27 @@ malloc_init_hard(void) { if (malloc_init_hard_recursible()) { return true; } - malloc_mutex_lock(tsd_tsdn(tsd), &init_lock); + malloc_mutex_lock(tsd_tsdn(tsd), &init_lock); + /* Set reentrancy level to 1 during init. */ + pre_reentrancy(tsd); /* Initialize narenas before prof_boot2 (for allocation). */ if (malloc_init_narenas() || background_thread_boot1(tsd_tsdn(tsd))) { - malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); - return true; + UNLOCK_RETURN(tsd_tsdn(tsd), true, true) } - if (config_prof && prof_boot2(tsd)) { - malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); - return true; + UNLOCK_RETURN(tsd_tsdn(tsd), true, true) } malloc_init_percpu(); if (malloc_init_hard_finish()) { - malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); - return true; + UNLOCK_RETURN(tsd_tsdn(tsd), true, true) } - + post_reentrancy(tsd); malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock); - malloc_tsd_boot1(); + malloc_tsd_boot1(); /* Update TSD after tsd_boot1. */ tsd = tsd_fetch(); if (opt_background_thread) { @@ -1463,7 +1476,7 @@ malloc_init_hard(void) { return true; } } - +#undef UNLOCK_RETURN return false; } -- GitLab From 3a813946fb9b0ad93279ea30834df917b261a5a5 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 2 Jun 2017 16:27:05 -0700 Subject: [PATCH 530/544] Take background thread lock when setting extent hooks. --- include/jemalloc/internal/extent_externs.h | 3 ++- src/ctl.c | 2 +- src/extent.c | 14 ++++++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/include/jemalloc/internal/extent_externs.h b/include/jemalloc/internal/extent_externs.h index acb3ef49..489a813c 100644 --- a/include/jemalloc/internal/extent_externs.h +++ b/include/jemalloc/internal/extent_externs.h @@ -15,7 +15,8 @@ extent_t *extent_alloc(tsdn_t *tsdn, arena_t *arena); void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent); extent_hooks_t *extent_hooks_get(arena_t *arena); -extent_hooks_t *extent_hooks_set(arena_t *arena, extent_hooks_t *extent_hooks); +extent_hooks_t *extent_hooks_set(tsd_t *tsd, arena_t *arena, + extent_hooks_t *extent_hooks); #ifdef JEMALLOC_JET size_t extent_size_quantize_floor(size_t size); diff --git a/src/ctl.c b/src/ctl.c index c3514bdd..2c3f9945 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -2154,7 +2154,7 @@ arena_i_extent_hooks_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, extent_hooks_t *new_extent_hooks JEMALLOC_CC_SILENCE_INIT(NULL); WRITE(new_extent_hooks, extent_hooks_t *); - old_extent_hooks = extent_hooks_set(arena, + old_extent_hooks = extent_hooks_set(tsd, arena, new_extent_hooks); READ(old_extent_hooks, extent_hooks_t *); } else { diff --git a/src/extent.c b/src/extent.c index fb7a1468..e95858e3 100644 --- a/src/extent.c +++ b/src/extent.c @@ -197,8 +197,18 @@ extent_hooks_get(arena_t *arena) { } extent_hooks_t * -extent_hooks_set(arena_t *arena, extent_hooks_t *extent_hooks) { - return base_extent_hooks_set(arena->base, extent_hooks); +extent_hooks_set(tsd_t *tsd, arena_t *arena, extent_hooks_t *extent_hooks) { + background_thread_info_t *info; + if (have_background_thread) { + info = arena_background_thread_info_get(arena); + malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); + } + extent_hooks_t *ret = base_extent_hooks_set(arena->base, extent_hooks); + if (have_background_thread) { + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); + } + + return ret; } static void -- GitLab From 29c2577ee0bfa57009a5827bd44cab04b738a914 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Sat, 3 Jun 2017 17:00:48 -0700 Subject: [PATCH 531/544] Remove assertions on extent_hooks being default. It's possible to customize the extent_hooks while still using part of the default implementation. --- src/extent.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/extent.c b/src/extent.c index e95858e3..386a7ce6 100644 --- a/src/extent.c +++ b/src/extent.c @@ -1013,8 +1013,6 @@ extent_alloc_default(extent_hooks_t *extent_hooks, void *new_addr, size_t size, tsdn_t *tsdn; arena_t *arena; - assert(extent_hooks == &extent_hooks_default); - tsdn = tsdn_fetch(); arena = arena_get(tsdn, arena_ind, false); /* @@ -1457,8 +1455,6 @@ extent_dalloc_default_impl(void *addr, size_t size) { static bool extent_dalloc_default(extent_hooks_t *extent_hooks, void *addr, size_t size, bool committed, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); - return extent_dalloc_default_impl(addr, size); } @@ -1551,8 +1547,6 @@ extent_destroy_default_impl(void *addr, size_t size) { static void extent_destroy_default(extent_hooks_t *extent_hooks, void *addr, size_t size, bool committed, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); - extent_destroy_default_impl(addr, size); } @@ -1587,8 +1581,6 @@ extent_destroy_wrapper(tsdn_t *tsdn, arena_t *arena, static bool extent_commit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); - return pages_commit((void *)((uintptr_t)addr + (uintptr_t)offset), length); } @@ -1619,8 +1611,6 @@ extent_commit_wrapper(tsdn_t *tsdn, arena_t *arena, static bool extent_decommit_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); - return pages_decommit((void *)((uintptr_t)addr + (uintptr_t)offset), length); } @@ -1646,7 +1636,6 @@ extent_decommit_wrapper(tsdn_t *tsdn, arena_t *arena, static bool extent_purge_lazy_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); assert(addr != NULL); assert((offset & PAGE_MASK) == 0); assert(length != 0); @@ -1683,7 +1672,6 @@ extent_purge_lazy_wrapper(tsdn_t *tsdn, arena_t *arena, static bool extent_purge_forced_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t offset, size_t length, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); assert(addr != NULL); assert((offset & PAGE_MASK) == 0); assert(length != 0); @@ -1720,8 +1708,6 @@ extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena, static bool extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size, size_t size_a, size_t size_b, bool committed, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); - return !maps_coalesce; } #endif @@ -1825,8 +1811,6 @@ extent_merge_default_impl(void *addr_a, void *addr_b) { static bool extent_merge_default(extent_hooks_t *extent_hooks, void *addr_a, size_t size_a, void *addr_b, size_t size_b, bool committed, unsigned arena_ind) { - assert(extent_hooks == &extent_hooks_default); - return extent_merge_default_impl(addr_a, addr_b); } #endif -- GitLab From 00869e39a334f3d869dfb9f8e651c2de3dded76f Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Tue, 6 Jun 2017 21:44:39 -0700 Subject: [PATCH 532/544] Make tsd no-cleanup during tsd reincarnation. Since tsd cleanup isn't guaranteed when reincarnated, we set up tsd in a way that needs no cleanup, by making it going through slow path instead. --- include/jemalloc/internal/tsd.h | 2 +- src/jemalloc.c | 3 +- src/tsd.c | 66 +++++++++++++++++++++++---------- test/unit/tsd.c | 4 +- 4 files changed, 51 insertions(+), 24 deletions(-) diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h index f304e1d9..4efaf4e2 100644 --- a/include/jemalloc/internal/tsd.h +++ b/include/jemalloc/internal/tsd.h @@ -154,7 +154,6 @@ void malloc_tsd_dalloc(void *wrapper); void malloc_tsd_cleanup_register(bool (*f)(void)); tsd_t *malloc_tsd_boot0(void); void malloc_tsd_boot1(void); -bool tsd_data_init(void *arg); void tsd_cleanup(void *arg); tsd_t *tsd_fetch_slow(tsd_t *tsd); void tsd_slow_update(tsd_t *tsd); @@ -228,6 +227,7 @@ MALLOC_TSD #define O(n, t, nt) \ JEMALLOC_ALWAYS_INLINE void \ tsd_##n##_set(tsd_t *tsd, t val) { \ + assert(tsd->state != tsd_state_reincarnated); \ *tsd_##n##p_get(tsd) = val; \ } MALLOC_TSD diff --git a/src/jemalloc.c b/src/jemalloc.c index 7e695d66..9a5685b4 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1764,7 +1764,8 @@ imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) { * We should never specify particular arenas or tcaches from * within our internal allocations. */ - assert(dopts->tcache_ind == TCACHE_IND_AUTOMATIC); + assert(dopts->tcache_ind == TCACHE_IND_AUTOMATIC || + dopts->tcache_ind == TCACHE_IND_NONE); assert(dopts->arena_ind = ARENA_IND_AUTOMATIC); dopts->tcache_ind = TCACHE_IND_NONE; /* We know that arena 0 has already been initialized. */ diff --git a/src/tsd.c b/src/tsd.c index 29a56775..6eb3b883 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -63,6 +63,45 @@ tsd_slow_update(tsd_t *tsd) { } } +static bool +tsd_data_init(tsd_t *tsd) { + /* + * We initialize the rtree context first (before the tcache), since the + * tcache initialization depends on it. + */ + rtree_ctx_data_init(tsd_rtree_ctxp_get_unsafe(tsd)); + + return tsd_tcache_enabled_data_init(tsd); +} + +static void +assert_tsd_data_cleanup_done(tsd_t *tsd) { + assert(!tsd_nominal(tsd)); + assert(*tsd_arenap_get_unsafe(tsd) == NULL); + assert(*tsd_iarenap_get_unsafe(tsd) == NULL); + assert(*tsd_arenas_tdata_bypassp_get_unsafe(tsd) == true); + assert(*tsd_arenas_tdatap_get_unsafe(tsd) == NULL); + assert(*tsd_tcache_enabledp_get_unsafe(tsd) == false); + assert(*tsd_prof_tdatap_get_unsafe(tsd) == NULL); +} + +static bool +tsd_data_init_nocleanup(tsd_t *tsd) { + assert(tsd->state == tsd_state_reincarnated); + /* + * During reincarnation, there is no guarantee that the cleanup function + * will be called (deallocation may happen after all tsd destructors). + * We set up tsd in a way that no cleanup is needed. + */ + rtree_ctx_data_init(tsd_rtree_ctxp_get_unsafe(tsd)); + *tsd_arenas_tdata_bypassp_get(tsd) = true; + *tsd_tcache_enabledp_get_unsafe(tsd) = false; + *tsd_reentrancy_levelp_get(tsd) = 1; + assert_tsd_data_cleanup_done(tsd); + + return false; +} + tsd_t * tsd_fetch_slow(tsd_t *tsd) { if (tsd->state == tsd_state_nominal_slow) { @@ -79,7 +118,7 @@ tsd_fetch_slow(tsd_t *tsd) { } else if (tsd->state == tsd_state_purgatory) { tsd->state = tsd_state_reincarnated; tsd_set(tsd); - tsd_data_init(tsd); + tsd_data_init_nocleanup(tsd); } else { assert(tsd->state == tsd_state_reincarnated); } @@ -131,21 +170,6 @@ malloc_tsd_cleanup_register(bool (*f)(void)) { ncleanups++; } -bool -tsd_data_init(void *arg) { - tsd_t *tsd = (tsd_t *)arg; - /* - * We initialize the rtree context first (before the tcache), since the - * tcache initialization depends on it. - */ - rtree_ctx_data_init(tsd_rtree_ctxp_get_unsafe(tsd)); - - if (tsd_tcache_enabled_data_init(tsd)) { - return true; - } - return false; -} - static void tsd_do_data_cleanup(tsd_t *tsd) { prof_tdata_cleanup(tsd); @@ -164,14 +188,16 @@ tsd_cleanup(void *arg) { case tsd_state_uninitialized: /* Do nothing. */ break; - case tsd_state_nominal: - case tsd_state_nominal_slow: case tsd_state_reincarnated: /* * Reincarnated means another destructor deallocated memory - * after this destructor was called. Reset state to - * tsd_state_purgatory and request another callback. + * after the destructor was called. Cleanup isn't required but + * is still called for testing and completeness. */ + assert_tsd_data_cleanup_done(tsd); + /* Fall through. */ + case tsd_state_nominal: + case tsd_state_nominal_slow: tsd_do_data_cleanup(tsd); tsd->state = tsd_state_purgatory; tsd_set(tsd); diff --git a/test/unit/tsd.c b/test/unit/tsd.c index c9a7d809..6c479139 100644 --- a/test/unit/tsd.c +++ b/test/unit/tsd.c @@ -106,8 +106,8 @@ thd_start_reincarnated(void *arg) { "TSD state should be reincarnated\n"); p = mallocx(1, MALLOCX_TCACHE_NONE); assert_ptr_not_null(p, "Unexpected malloc() failure"); - assert_ptr_not_null(*tsd_arenap_get_unsafe(tsd), - "Should have tsd arena set after reincarnation."); + assert_ptr_null(*tsd_arenap_get_unsafe(tsd), + "Should not have tsd arena set after reincarnation."); free(p); tsd_cleanup((void *)tsd); -- GitLab From 73713fbb27cd1cf6754259b19a960e91a16c3638 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 7 Jun 2017 15:49:09 -0700 Subject: [PATCH 533/544] Drop high rank locks when creating threads. Avoid holding arenas_lock and background_thread_lock when creating background threads, because pthread_create may take internal locks, and potentially cause deadlock with jemalloc internal locks. --- include/jemalloc/internal/arena_externs.h | 1 + src/arena.c | 11 ------- src/background_thread.c | 5 +++- src/ctl.c | 3 ++ src/jemalloc.c | 36 ++++++++++++++++++++++- 5 files changed, 43 insertions(+), 13 deletions(-) diff --git a/include/jemalloc/internal/arena_externs.h b/include/jemalloc/internal/arena_externs.h index 9ad9786f..3a85bcbb 100644 --- a/include/jemalloc/internal/arena_externs.h +++ b/include/jemalloc/internal/arena_externs.h @@ -15,6 +15,7 @@ extern percpu_arena_mode_t opt_percpu_arena; extern const char *percpu_arena_mode_names[]; extern const uint64_t h_steps[SMOOTHSTEP_NSTEPS]; +extern malloc_mutex_t arenas_lock; void arena_stats_large_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats, szind_t szind, uint64_t nrequests); diff --git a/src/arena.c b/src/arena.c index dedbb3e3..0912df31 100644 --- a/src/arena.c +++ b/src/arena.c @@ -2050,17 +2050,6 @@ arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { hooks_arena_new_hook(); } post_reentrancy(tsdn_tsd(tsdn)); - - /* background_thread_create() handles reentrancy internally. */ - if (have_background_thread) { - bool err; - malloc_mutex_lock(tsdn, &background_thread_lock); - err = background_thread_create(tsdn_tsd(tsdn), ind); - malloc_mutex_unlock(tsdn, &background_thread_lock); - if (err) { - goto label_error; - } - } } return arena; diff --git a/src/background_thread.c b/src/background_thread.c index 64eba1a7..50812c36 100644 --- a/src/background_thread.c +++ b/src/background_thread.c @@ -352,12 +352,15 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) { } pre_reentrancy(tsd); + malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock); /* * To avoid complications (besides reentrancy), create internal - * background threads with the underlying pthread_create. + * background threads with the underlying pthread_create, and drop + * background_thread_lock (pthread_create may take internal locks). */ int err = pthread_create_wrapper(&info->thread, NULL, background_thread_entry, (void *)thread_ind); + malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock); post_reentrancy(tsd); if (err != 0) { diff --git a/src/ctl.c b/src/ctl.c index 2c3f9945..134dbac9 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1501,6 +1501,7 @@ background_thread_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, } background_thread_ctl_init(tsd_tsdn(tsd)); + malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock); if (newp == NULL) { oldval = background_thread_enabled(); @@ -1535,6 +1536,8 @@ background_thread_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, ret = 0; label_return: malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock); + malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); + return ret; } diff --git a/src/jemalloc.c b/src/jemalloc.c index 9a5685b4..5a0baf8f 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -70,7 +70,7 @@ unsigned opt_narenas = 0; unsigned ncpus; /* Protects arenas initialization. */ -static malloc_mutex_t arenas_lock; +malloc_mutex_t arenas_lock; /* * Arenas that are used to service external requests. Not all elements of the * arenas array are necessarily used; arenas are created lazily as needed. @@ -335,6 +335,25 @@ arena_init_locked(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { return arena; } +static void +arena_new_create_background_thread(tsdn_t *tsdn, unsigned ind) { + if (ind == 0) { + return; + } + /* background_thread_create() handles reentrancy internally. */ + if (have_background_thread) { + bool err; + malloc_mutex_lock(tsdn, &background_thread_lock); + err = background_thread_create(tsdn_tsd(tsdn), ind); + malloc_mutex_unlock(tsdn, &background_thread_lock); + if (err) { + malloc_printf(": error in background thread " + "creation for arena %u. Abort.\n", ind); + abort(); + } + } +} + arena_t * arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { arena_t *arena; @@ -342,6 +361,9 @@ arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) { malloc_mutex_lock(tsdn, &arenas_lock); arena = arena_init_locked(tsdn, ind, extent_hooks); malloc_mutex_unlock(tsdn, &arenas_lock); + + arena_new_create_background_thread(tsdn, ind); + return arena; } @@ -475,6 +497,7 @@ arena_choose_hard(tsd_t *tsd, bool internal) { if (narenas_auto > 1) { unsigned i, j, choose[2], first_null; + bool is_new_arena[2]; /* * Determine binding for both non-internal and internal @@ -486,6 +509,7 @@ arena_choose_hard(tsd_t *tsd, bool internal) { for (j = 0; j < 2; j++) { choose[j] = 0; + is_new_arena[j] = false; } first_null = narenas_auto; @@ -545,6 +569,7 @@ arena_choose_hard(tsd_t *tsd, bool internal) { &arenas_lock); return NULL; } + is_new_arena[j] = true; if (!!j == internal) { ret = arena; } @@ -552,6 +577,15 @@ arena_choose_hard(tsd_t *tsd, bool internal) { arena_bind(tsd, choose[j], !!j); } malloc_mutex_unlock(tsd_tsdn(tsd), &arenas_lock); + + for (j = 0; j < 2; j++) { + if (is_new_arena[j]) { + assert(choose[j] > 0); + arena_new_create_background_thread( + tsd_tsdn(tsd), choose[j]); + } + } + } else { ret = arena_get(tsd_tsdn(tsd), 0, false); arena_bind(tsd, 0, false); -- GitLab From 5642f03cae54eb8798dc4fa5ea28d9569572c1af Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Wed, 7 Jun 2017 16:12:50 -0700 Subject: [PATCH 534/544] Add internal tsd for background_thread. --- include/jemalloc/internal/tsd.h | 15 ++++++++++----- src/background_thread.c | 9 ++++----- src/tsd.c | 11 ++++++++++- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h index 4efaf4e2..cab0b2fe 100644 --- a/include/jemalloc/internal/tsd.h +++ b/include/jemalloc/internal/tsd.h @@ -155,7 +155,7 @@ void malloc_tsd_cleanup_register(bool (*f)(void)); tsd_t *malloc_tsd_boot0(void); void malloc_tsd_boot1(void); void tsd_cleanup(void *arg); -tsd_t *tsd_fetch_slow(tsd_t *tsd); +tsd_t *tsd_fetch_slow(tsd_t *tsd, bool internal); void tsd_slow_update(tsd_t *tsd); /* @@ -250,7 +250,7 @@ tsd_fast(tsd_t *tsd) { } JEMALLOC_ALWAYS_INLINE tsd_t * -tsd_fetch_impl(bool init) { +tsd_fetch_impl(bool init, bool internal) { tsd_t *tsd = tsd_get(init); if (!init && tsd_get_allocates() && tsd == NULL) { @@ -259,7 +259,7 @@ tsd_fetch_impl(bool init) { assert(tsd != NULL); if (unlikely(tsd->state != tsd_state_nominal)) { - return tsd_fetch_slow(tsd); + return tsd_fetch_slow(tsd, internal); } assert(tsd_fast(tsd)); tsd_assert_fast(tsd); @@ -267,9 +267,14 @@ tsd_fetch_impl(bool init) { return tsd; } +JEMALLOC_ALWAYS_INLINE tsd_t * +tsd_internal_fetch(void) { + return tsd_fetch_impl(true, true); +} + JEMALLOC_ALWAYS_INLINE tsd_t * tsd_fetch(void) { - return tsd_fetch_impl(true); + return tsd_fetch_impl(true, false); } static inline bool @@ -283,7 +288,7 @@ tsdn_fetch(void) { return NULL; } - return tsd_tsdn(tsd_fetch_impl(false)); + return tsd_tsdn(tsd_fetch_impl(false, false)); } JEMALLOC_ALWAYS_INLINE rtree_ctx_t * diff --git a/src/background_thread.c b/src/background_thread.c index 50812c36..190fa2fd 100644 --- a/src/background_thread.c +++ b/src/background_thread.c @@ -316,12 +316,11 @@ background_thread_entry(void *ind_arg) { set_current_thread_affinity((int)thread_ind); } /* - * Start periodic background work. We avoid fetching tsd to keep the - * background thread "outside", since there may be side effects, for - * example triggering new arena creation (which in turn triggers - * background thread creation). + * Start periodic background work. We use internal tsd which avoids + * side effects, for example triggering new arena creation (which in + * turn triggers another background thread creation). */ - background_work(TSDN_NULL, thread_ind); + background_work(tsd_tsdn(tsd_internal_fetch()), thread_ind); assert(pthread_equal(pthread_self(), background_thread_info[thread_ind].thread)); diff --git a/src/tsd.c b/src/tsd.c index 6eb3b883..97330332 100644 --- a/src/tsd.c +++ b/src/tsd.c @@ -103,7 +103,16 @@ tsd_data_init_nocleanup(tsd_t *tsd) { } tsd_t * -tsd_fetch_slow(tsd_t *tsd) { +tsd_fetch_slow(tsd_t *tsd, bool internal) { + if (internal) { + /* For internal background threads use only. */ + assert(tsd->state == tsd_state_uninitialized); + tsd->state = tsd_state_reincarnated; + tsd_set(tsd); + tsd_data_init_nocleanup(tsd); + return tsd; + } + if (tsd->state == tsd_state_nominal_slow) { /* On slow path but no work needed. */ assert(malloc_slow || !tsd_tcache_enabled_get(tsd) || -- GitLab From faaf458bad62daf67fc913f60e9e14f54aa55827 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 8 Jun 2017 12:19:29 -0700 Subject: [PATCH 535/544] Remove redundant typedefs. Pre-C11 compilers do not support typedef redefinition. --- include/jemalloc/internal/tsd.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/jemalloc/internal/tsd.h b/include/jemalloc/internal/tsd.h index cab0b2fe..631fbf1f 100644 --- a/include/jemalloc/internal/tsd.h +++ b/include/jemalloc/internal/tsd.h @@ -108,7 +108,6 @@ enum { typedef uint8_t tsd_state_t; /* The actual tsd. */ -typedef struct tsd_s tsd_t; struct tsd_s { /* * The contents should be treated as totally opaque outside the tsd @@ -127,7 +126,6 @@ MALLOC_TSD * between tsd_t and tsdn_t, where tsdn_t is "nullable" and has to be * explicitly converted to tsd_t, which is non-nullable. */ -typedef struct tsdn_s tsdn_t; struct tsdn_s { tsd_t tsd; }; -- GitLab From 94d655b8bd1eac3d969dfe3c15aa7a6b1d26373d Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 8 Jun 2017 12:55:59 -0700 Subject: [PATCH 536/544] Update a UTRACE() size argument. --- src/jemalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jemalloc.c b/src/jemalloc.c index 5a0baf8f..e2865d25 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -1930,7 +1930,7 @@ imalloc(static_opts_t *sopts, dynamic_opts_t *dopts) { malloc_write(sopts->oom_string); abort(); } - UTRACE(NULL, size, NULL); + UTRACE(NULL, dopts->num_items * dopts->item_size, NULL); set_errno(ENOMEM); *dopts->result = NULL; -- GitLab From 13685ab1b767091d817cb4959d24a42447a6fb78 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Thu, 8 Jun 2017 22:07:21 -0700 Subject: [PATCH 537/544] Normalize background thread configuration. Also fix a compilation error #ifndef JEMALLOC_PTHREAD_CREATE_WRAPPER. --- configure.ac | 10 ++++++++++ include/jemalloc/internal/jemalloc_internal_defs.h.in | 5 +++++ include/jemalloc/internal/jemalloc_preamble.h.in | 6 ------ src/background_thread.c | 2 ++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/configure.ac b/configure.ac index a00aab9b..32ae02c2 100644 --- a/configure.ac +++ b/configure.ac @@ -1452,6 +1452,7 @@ if test "x$abi" != "xpecoff" ; then [AC_SEARCH_LIBS([pthread_create], , , AC_MSG_ERROR([libpthread is missing]))]) wrap_syms="${wrap_syms} pthread_create" + have_pthread="1" dnl Check if we have dlsym support. have_dlsym="1" AC_CHECK_HEADERS([dlfcn.h], @@ -1933,6 +1934,15 @@ if test "x${enable_zone_allocator}" = "x1" ; then AC_DEFINE([JEMALLOC_ZONE], [ ]) fi +dnl ============================================================================ +dnl Enable background threads if possible. + +if test "x${have_pthread}" = "x1" -a "x${have_dlsym}" = "x1" \ + -a "x${je_cv_os_unfair_lock}" != "xyes" \ + -a "x${je_cv_osspin}" != "xyes" ; then + AC_DEFINE([JEMALLOC_BACKGROUND_THREAD]) +fi + dnl ============================================================================ dnl Check for glibc malloc hooks diff --git a/include/jemalloc/internal/jemalloc_internal_defs.h.in b/include/jemalloc/internal/jemalloc_internal_defs.h.in index 20a2358e..2bf9dea1 100644 --- a/include/jemalloc/internal/jemalloc_internal_defs.h.in +++ b/include/jemalloc/internal/jemalloc_internal_defs.h.in @@ -316,6 +316,11 @@ /* GNU specific sched_setaffinity support */ #undef JEMALLOC_HAVE_SCHED_SETAFFINITY +/* + * If defined, all the features necessary for background threads are present. + */ +#undef JEMALLOC_BACKGROUND_THREAD + /* * If defined, jemalloc symbols are not exported (doesn't work when * JEMALLOC_PREFIX is not defined). diff --git a/include/jemalloc/internal/jemalloc_preamble.h.in b/include/jemalloc/internal/jemalloc_preamble.h.in index 46750e99..18539a09 100644 --- a/include/jemalloc/internal/jemalloc_preamble.h.in +++ b/include/jemalloc/internal/jemalloc_preamble.h.in @@ -168,12 +168,6 @@ static const bool force_ivsalloc = false #endif ; - -#if (defined(JEMALLOC_HAVE_PTHREAD) && defined(JEMALLOC_HAVE_DLSYM) \ - && !defined(JEMALLOC_OSSPIN) && !defined(JEMALLOC_OS_UNFAIR_LOCK)) -/* Currently background thread supports pthread only. */ -#define JEMALLOC_BACKGROUND_THREAD -#endif static const bool have_background_thread = #ifdef JEMALLOC_BACKGROUND_THREAD true diff --git a/src/background_thread.c b/src/background_thread.c index 190fa2fd..51d23cb9 100644 --- a/src/background_thread.c +++ b/src/background_thread.c @@ -635,7 +635,9 @@ background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats) { void background_thread_ctl_init(tsdn_t *tsdn) { malloc_mutex_assert_not_owner(tsdn, &background_thread_lock); +#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER pthread_once(&once_control, pthread_create_wrapper_once); +#endif } #endif /* defined(JEMALLOC_BACKGROUND_THREAD) */ -- GitLab From 464cb60490efda800625b16fedd5bcd238e1526e Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Thu, 8 Jun 2017 22:46:31 -0700 Subject: [PATCH 538/544] Move background thread creation to background_thread_0. To avoid complications, avoid invoking pthread_create "internally", instead rely on thread0 to launch new threads, and also terminating threads when asked. --- .../internal/background_thread_externs.h | 2 - .../internal/background_thread_structs.h | 2 + src/background_thread.c | 381 +++++++++++------- src/ctl.c | 12 +- 4 files changed, 251 insertions(+), 146 deletions(-) diff --git a/include/jemalloc/internal/background_thread_externs.h b/include/jemalloc/internal/background_thread_externs.h index aef1c90b..7c883697 100644 --- a/include/jemalloc/internal/background_thread_externs.h +++ b/include/jemalloc/internal/background_thread_externs.h @@ -10,8 +10,6 @@ extern background_thread_info_t *background_thread_info; bool background_thread_create(tsd_t *tsd, unsigned arena_ind); bool background_threads_enable(tsd_t *tsd); bool background_threads_disable(tsd_t *tsd); -bool background_threads_disable_single(tsd_t *tsd, - background_thread_info_t *info); void background_thread_interval_check(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, size_t npages_new); void background_thread_prefork0(tsdn_t *tsdn); diff --git a/include/jemalloc/internal/background_thread_structs.h b/include/jemalloc/internal/background_thread_structs.h index edf90fe2..f6ad4adb 100644 --- a/include/jemalloc/internal/background_thread_structs.h +++ b/include/jemalloc/internal/background_thread_structs.h @@ -18,6 +18,8 @@ struct background_thread_info_s { malloc_mutex_t mtx; /* Whether the thread has been created. */ bool started; + /* Pause execution (for arena reset / destroy). */ + bool pause; /* When true, it means no wakeup scheduled. */ atomic_b_t indefinite_sleep; /* Next scheduled wakeup time (absolute time in ns). */ diff --git a/src/background_thread.c b/src/background_thread.c index 51d23cb9..f2bc474a 100644 --- a/src/background_thread.c +++ b/src/background_thread.c @@ -50,8 +50,6 @@ pthread_create_wrapper(pthread_t *__restrict thread, const pthread_attr_t *attr, bool background_thread_create(tsd_t *tsd, unsigned arena_ind) NOT_REACHED bool background_threads_enable(tsd_t *tsd) NOT_REACHED bool background_threads_disable(tsd_t *tsd) NOT_REACHED -bool background_threads_disable_single(tsd_t *tsd, - background_thread_info_t *info) NOT_REACHED void background_thread_interval_check(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, size_t npages_new) NOT_REACHED void background_thread_prefork0(tsdn_t *tsdn) NOT_REACHED @@ -67,8 +65,9 @@ void background_thread_ctl_init(tsdn_t *tsdn) NOT_REACHED static bool background_thread_enabled_at_fork; static void -background_thread_info_reinit(tsdn_t *tsdn, background_thread_info_t *info) { +background_thread_info_init(tsdn_t *tsdn, background_thread_info_t *info) { background_thread_wakeup_time_set(tsdn, info, 0); + info->pause = false; info->npages_to_purge_new = 0; if (config_stats) { info->tot_n_runs = 0; @@ -210,107 +209,227 @@ arena_decay_compute_purge_interval(tsdn_t *tsdn, arena_t *arena) { return i1 < i2 ? i1 : i2; } -static inline uint64_t -background_work_once(tsdn_t *tsdn, unsigned ind) { - arena_t *arena; - unsigned i, narenas; - uint64_t min_interval; +static void +background_thread_sleep(tsdn_t *tsdn, background_thread_info_t *info, + uint64_t interval) { + if (config_stats) { + info->tot_n_runs++; + } + info->npages_to_purge_new = 0; + + struct timeval tv; + /* Specific clock required by timedwait. */ + gettimeofday(&tv, NULL); + nstime_t before_sleep; + nstime_init2(&before_sleep, tv.tv_sec, tv.tv_usec * 1000); + + int ret; + if (interval == BACKGROUND_THREAD_INDEFINITE_SLEEP) { + assert(background_thread_indefinite_sleep(info)); + ret = pthread_cond_wait(&info->cond, &info->mtx.lock); + assert(ret == 0); + } else { + assert(interval >= BACKGROUND_THREAD_MIN_INTERVAL_NS && + interval <= BACKGROUND_THREAD_INDEFINITE_SLEEP); + /* We need malloc clock (can be different from tv). */ + nstime_t next_wakeup; + nstime_init(&next_wakeup, 0); + nstime_update(&next_wakeup); + nstime_iadd(&next_wakeup, interval); + assert(nstime_ns(&next_wakeup) < + BACKGROUND_THREAD_INDEFINITE_SLEEP); + background_thread_wakeup_time_set(tsdn, info, + nstime_ns(&next_wakeup)); + + nstime_t ts_wakeup; + nstime_copy(&ts_wakeup, &before_sleep); + nstime_iadd(&ts_wakeup, interval); + struct timespec ts; + ts.tv_sec = (size_t)nstime_sec(&ts_wakeup); + ts.tv_nsec = (size_t)nstime_nsec(&ts_wakeup); + + assert(!background_thread_indefinite_sleep(info)); + ret = pthread_cond_timedwait(&info->cond, &info->mtx.lock, &ts); + assert(ret == ETIMEDOUT || ret == 0); + background_thread_wakeup_time_set(tsdn, info, + BACKGROUND_THREAD_INDEFINITE_SLEEP); + } + if (config_stats) { + gettimeofday(&tv, NULL); + nstime_t after_sleep; + nstime_init2(&after_sleep, tv.tv_sec, tv.tv_usec * 1000); + if (nstime_compare(&after_sleep, &before_sleep) > 0) { + nstime_subtract(&after_sleep, &before_sleep); + nstime_add(&info->tot_sleep_time, &after_sleep); + } + } + while (info->pause) { + malloc_mutex_unlock(tsdn, &info->mtx); + /* Wait on global lock to update status. */ + malloc_mutex_lock(tsdn, &background_thread_lock); + malloc_mutex_unlock(tsdn, &background_thread_lock); + malloc_mutex_lock(tsdn, &info->mtx); + } +} - min_interval = BACKGROUND_THREAD_INDEFINITE_SLEEP; - narenas = narenas_total_get(); - for (i = ind; i < narenas; i += ncpus) { - arena = arena_get(tsdn, i, false); +static inline void +background_work_sleep_once(tsdn_t *tsdn, background_thread_info_t *info, unsigned ind) { + uint64_t min_interval = BACKGROUND_THREAD_INDEFINITE_SLEEP; + unsigned narenas = narenas_total_get(); + + for (unsigned i = ind; i < narenas; i += ncpus) { + arena_t *arena = arena_get(tsdn, i, false); if (!arena) { continue; } - arena_decay(tsdn, arena, true, false); + if (min_interval == BACKGROUND_THREAD_MIN_INTERVAL_NS) { + /* Min interval will be used. */ + continue; + } uint64_t interval = arena_decay_compute_purge_interval(tsdn, arena); - if (interval == BACKGROUND_THREAD_MIN_INTERVAL_NS) { - return interval; - } - - assert(interval > BACKGROUND_THREAD_MIN_INTERVAL_NS); + assert(interval >= BACKGROUND_THREAD_MIN_INTERVAL_NS); if (min_interval > interval) { min_interval = interval; } } + background_thread_sleep(tsdn, info, min_interval); +} + +static bool +background_threads_disable_single(tsd_t *tsd, background_thread_info_t *info) { + if (info == &background_thread_info[0]) { + malloc_mutex_assert_owner(tsd_tsdn(tsd), + &background_thread_lock); + } else { + malloc_mutex_assert_not_owner(tsd_tsdn(tsd), + &background_thread_lock); + } + + pre_reentrancy(tsd); + malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); + bool has_thread; + if (info->started) { + has_thread = true; + info->started = false; + pthread_cond_signal(&info->cond); + } else { + has_thread = false; + } + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); + + if (!has_thread) { + post_reentrancy(tsd); + return false; + } + void *ret; + if (pthread_join(info->thread, &ret)) { + post_reentrancy(tsd); + return true; + } + assert(ret == NULL); + n_background_threads--; + post_reentrancy(tsd); - return min_interval; + return false; } +static void *background_thread_entry(void *ind_arg); + static void -background_work(tsdn_t *tsdn, unsigned ind) { - int ret; - background_thread_info_t *info = &background_thread_info[ind]; +check_background_thread_creation(tsd_t *tsd, unsigned *n_created, + bool *created_threads) { + if (likely(*n_created == n_background_threads)) { + return; + } - malloc_mutex_lock(tsdn, &info->mtx); - background_thread_wakeup_time_set(tsdn, info, - BACKGROUND_THREAD_INDEFINITE_SLEEP); - while (info->started) { - uint64_t interval = background_work_once(tsdn, ind); - if (config_stats) { - info->tot_n_runs++; + for (unsigned i = 1; i < ncpus; i++) { + if (created_threads[i]) { + continue; } - info->npages_to_purge_new = 0; + background_thread_info_t *info = &background_thread_info[i]; + malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); + if (info->started) { + pre_reentrancy(tsd); + int err = pthread_create_wrapper(&info->thread, NULL, + background_thread_entry, (void *)(uintptr_t)i); + post_reentrancy(tsd); + + if (err == 0) { + (*n_created)++; + created_threads[i] = true; + } else { + malloc_printf(": background thread " + "creation failed (%d)\n", err); + if (opt_abort) { + abort(); + } + } + } + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); + } +} - struct timeval tv; - /* Specific clock required by timedwait. */ - gettimeofday(&tv, NULL); - nstime_t before_sleep; - nstime_init2(&before_sleep, tv.tv_sec, tv.tv_usec * 1000); +static void +background_thread0_work(tsd_t *tsd) { + /* Thread0 is also responsible for launching / terminating threads. */ + VARIABLE_ARRAY(bool, created_threads, ncpus); + unsigned i; + for (i = 1; i < ncpus; i++) { + created_threads[i] = false; + } + /* Start working, and create more threads when asked. */ + unsigned n_created = 1; + while (background_thread_info[0].started) { + check_background_thread_creation(tsd, &n_created, + (bool *)&created_threads); + background_work_sleep_once(tsd_tsdn(tsd), + &background_thread_info[0], 0); + } - if (interval == BACKGROUND_THREAD_INDEFINITE_SLEEP) { - assert(background_thread_indefinite_sleep(info)); - ret = pthread_cond_wait(&info->cond, &info->mtx.lock); - assert(ret == 0); + /* + * Shut down other threads at exit. Note that the ctl thread is holding + * the global background_thread mutex (and is waiting) for us. + */ + assert(!background_thread_enabled()); + for (i = 1; i < ncpus; i++) { + background_thread_info_t *info = &background_thread_info[i]; + if (created_threads[i]) { + background_threads_disable_single(tsd, info); } else { - assert(interval >= BACKGROUND_THREAD_MIN_INTERVAL_NS && - interval <= BACKGROUND_THREAD_INDEFINITE_SLEEP); - /* We need malloc clock (can be different from tv). */ - nstime_t next_wakeup; - nstime_init(&next_wakeup, 0); - nstime_update(&next_wakeup); - nstime_iadd(&next_wakeup, interval); - assert(nstime_ns(&next_wakeup) < - BACKGROUND_THREAD_INDEFINITE_SLEEP); - background_thread_wakeup_time_set(tsdn, info, - nstime_ns(&next_wakeup)); - - nstime_t ts_wakeup; - nstime_copy(&ts_wakeup, &before_sleep); - nstime_iadd(&ts_wakeup, interval); - struct timespec ts; - ts.tv_sec = (size_t)nstime_sec(&ts_wakeup); - ts.tv_nsec = (size_t)nstime_nsec(&ts_wakeup); - - assert(!background_thread_indefinite_sleep(info)); - ret = pthread_cond_timedwait(&info->cond, - &info->mtx.lock, &ts); - assert(ret == ETIMEDOUT || ret == 0); - background_thread_wakeup_time_set(tsdn, info, - BACKGROUND_THREAD_INDEFINITE_SLEEP); + malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); + /* Clear in case the thread wasn't created. */ + info->started = false; + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); } + } + background_thread_info[0].started = false; + assert(n_background_threads == 1); +} - if (config_stats) { - gettimeofday(&tv, NULL); - nstime_t after_sleep; - nstime_init2(&after_sleep, tv.tv_sec, tv.tv_usec * 1000); - if (nstime_compare(&after_sleep, &before_sleep) > 0) { - nstime_subtract(&after_sleep, &before_sleep); - nstime_add(&info->tot_sleep_time, &after_sleep); - } +static void +background_work(tsd_t *tsd, unsigned ind) { + background_thread_info_t *info = &background_thread_info[ind]; + + malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); + background_thread_wakeup_time_set(tsd_tsdn(tsd), info, + BACKGROUND_THREAD_INDEFINITE_SLEEP); + if (ind == 0) { + background_thread0_work(tsd); + } else { + while (info->started) { + background_work_sleep_once(tsd_tsdn(tsd), info, ind); } } - background_thread_wakeup_time_set(tsdn, info, 0); - malloc_mutex_unlock(tsdn, &info->mtx); + background_thread_wakeup_time_set(tsd_tsdn(tsd), info, 0); + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); } static void * background_thread_entry(void *ind_arg) { unsigned thread_ind = (unsigned)(uintptr_t)ind_arg; - assert(thread_ind < narenas_total_get() && thread_ind < ncpus); + assert(thread_ind < ncpus); if (opt_percpu_arena != percpu_arena_disabled) { set_current_thread_affinity((int)thread_ind); @@ -320,13 +439,21 @@ background_thread_entry(void *ind_arg) { * side effects, for example triggering new arena creation (which in * turn triggers another background thread creation). */ - background_work(tsd_tsdn(tsd_internal_fetch()), thread_ind); + background_work(tsd_internal_fetch(), thread_ind); assert(pthread_equal(pthread_self(), background_thread_info[thread_ind].thread)); return NULL; } +static void +background_thread_init(tsd_t *tsd, background_thread_info_t *info) { + malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock); + info->started = true; + background_thread_info_init(tsd_tsdn(tsd), info); + n_background_threads++; +} + /* Create a new background thread if needed. */ bool background_thread_create(tsd_t *tsd, unsigned arena_ind) { @@ -341,30 +468,35 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) { malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); need_new_thread = background_thread_enabled() && !info->started; if (need_new_thread) { - info->started = true; - background_thread_info_reinit(tsd_tsdn(tsd), info); - n_background_threads++; + background_thread_init(tsd, info); } malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); if (!need_new_thread) { return false; } + if (arena_ind != 0) { + /* Threads are created asynchronously by Thread 0. */ + background_thread_info_t *t0 = &background_thread_info[0]; + malloc_mutex_lock(tsd_tsdn(tsd), &t0->mtx); + assert(t0->started); + pthread_cond_signal(&t0->cond); + malloc_mutex_unlock(tsd_tsdn(tsd), &t0->mtx); + + return false; + } pre_reentrancy(tsd); - malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock); /* * To avoid complications (besides reentrancy), create internal - * background threads with the underlying pthread_create, and drop - * background_thread_lock (pthread_create may take internal locks). + * background threads with the underlying pthread_create. */ int err = pthread_create_wrapper(&info->thread, NULL, background_thread_entry, (void *)thread_ind); - malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock); post_reentrancy(tsd); if (err != 0) { - malloc_printf(": arena %u background thread creation " - "failed (%d).\n", arena_ind, err); + malloc_printf(": arena 0 background thread creation " + "failed (%d)\n", err); malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); info->started = false; n_background_threads--; @@ -372,7 +504,6 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) { return true; } - assert(info->started); return false; } @@ -383,72 +514,43 @@ background_threads_enable(tsd_t *tsd) { assert(background_thread_enabled()); malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock); - VARIABLE_ARRAY(bool, created, ncpus); - unsigned i, ncreated; + VARIABLE_ARRAY(bool, marked, ncpus); + unsigned i, nmarked; for (i = 0; i < ncpus; i++) { - created[i] = false; + marked[i] = false; } - ncreated = 0; - + nmarked = 0; + /* Mark the threads we need to create for thread 0. */ unsigned n = narenas_total_get(); - for (i = 0; i < n; i++) { - if (created[i % ncpus] || + for (i = 1; i < n; i++) { + if (marked[i % ncpus] || arena_get(tsd_tsdn(tsd), i, false) == NULL) { continue; } - if (background_thread_create(tsd, i)) { - return true; - } - created[i % ncpus] = true; - if (++ncreated == ncpus) { + background_thread_info_t *info = &background_thread_info[i]; + malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); + assert(!info->started); + background_thread_init(tsd, info); + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); + marked[i % ncpus] = true; + if (++nmarked == ncpus) { break; } } - return false; + return background_thread_create(tsd, 0); } bool -background_threads_disable_single(tsd_t *tsd, background_thread_info_t *info) { +background_threads_disable(tsd_t *tsd) { + assert(!background_thread_enabled()); malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock); - pre_reentrancy(tsd); - bool has_thread; - malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); - if (info->started) { - has_thread = true; - info->started = false; - pthread_cond_signal(&info->cond); - } else { - has_thread = false; - } - malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); - - if (!has_thread) { - post_reentrancy(tsd); - return false; - } - void *ret; - if (pthread_join(info->thread, &ret)) { - post_reentrancy(tsd); + /* Thread 0 will be responsible for terminating other threads. */ + if (background_threads_disable_single(tsd, + &background_thread_info[0])) { return true; } - assert(ret == NULL); - n_background_threads--; - post_reentrancy(tsd); - - return false; -} - -bool -background_threads_disable(tsd_t *tsd) { - assert(!background_thread_enabled()); - for (unsigned i = 0; i < ncpus; i++) { - background_thread_info_t *info = &background_thread_info[i]; - if (background_threads_disable_single(tsd, info)) { - return true; - } - } assert(n_background_threads == 0); return false; @@ -460,7 +562,6 @@ background_thread_interval_check(tsdn_t *tsdn, arena_t *arena, arena_decay_t *decay, size_t npages_new) { background_thread_info_t *info = arena_background_thread_info_get( arena); - if (malloc_mutex_trylock(tsdn, &info->mtx)) { /* * Background thread may hold the mutex for a long period of @@ -474,7 +575,6 @@ background_thread_interval_check(tsdn_t *tsdn, arena_t *arena, if (!info->started) { goto label_done; } - assert(background_thread_enabled()); if (malloc_mutex_trylock(tsdn, &decay->mtx)) { goto label_done; } @@ -646,7 +746,7 @@ bool background_thread_boot0(void) { if (!have_background_thread && opt_background_thread) { malloc_printf(": option background_thread currently " - "supports pthread only. \n"); + "supports pthread only\n"); return true; } @@ -686,9 +786,10 @@ background_thread_boot1(tsdn_t *tsdn) { for (unsigned i = 0; i < ncpus; i++) { background_thread_info_t *info = &background_thread_info[i]; + /* Thread mutex is rank_inclusive because of thread0. */ if (malloc_mutex_init(&info->mtx, "background_thread", WITNESS_RANK_BACKGROUND_THREAD, - malloc_mutex_rank_exclusive)) { + malloc_mutex_address_ordered)) { return true; } if (pthread_cond_init(&info->cond, NULL)) { @@ -696,7 +797,7 @@ background_thread_boot1(tsdn_t *tsdn) { } malloc_mutex_lock(tsdn, &info->mtx); info->started = false; - background_thread_info_reinit(tsdn, info); + background_thread_info_init(tsdn, info); malloc_mutex_unlock(tsdn, &info->mtx); } #endif diff --git a/src/ctl.c b/src/ctl.c index 134dbac9..242b36d4 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1948,8 +1948,10 @@ arena_reset_prepare_background_thread(tsd_t *tsd, unsigned arena_ind) { unsigned ind = arena_ind % ncpus; background_thread_info_t *info = &background_thread_info[ind]; - assert(info->started); - background_threads_disable_single(tsd, info); + assert(info->started && !info->pause); + malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); + info->pause = true; + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); } } } @@ -1961,8 +1963,10 @@ arena_reset_finish_background_thread(tsd_t *tsd, unsigned arena_ind) { unsigned ind = arena_ind % ncpus; background_thread_info_t *info = &background_thread_info[ind]; - assert(!info->started); - background_thread_create(tsd, ind); + assert(info->started && info->pause); + malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); + info->pause = false; + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); } malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock); } -- GitLab From b83b5ad44a51a18d9b9813906d22c7e008d2b517 Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 9 Jun 2017 00:00:48 -0700 Subject: [PATCH 539/544] Not re-enable background thread after fork. Avoid calling pthread_create in postfork handlers. --- doc/jemalloc.xml.in | 5 ++- src/background_thread.c | 81 +++++++++++++++++++++++------------------ src/jemalloc.c | 1 - 3 files changed, 50 insertions(+), 37 deletions(-) diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in index 41e80049..21e401ac 100644 --- a/doc/jemalloc.xml.in +++ b/doc/jemalloc.xml.in @@ -750,7 +750,10 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay", background threads will be no more than the number of CPUs or active arenas). Threads run periodically, and handle purging asynchronously. When switching - off, background threads are terminated synchronously. See fork2 + function, the state in the child process will be disabled regardless + the state in parent process. See stats.background_thread for related stats. opt.background_thread diff --git a/src/background_thread.c b/src/background_thread.c index f2bc474a..09e08b0b 100644 --- a/src/background_thread.c +++ b/src/background_thread.c @@ -350,24 +350,38 @@ check_background_thread_creation(tsd_t *tsd, unsigned *n_created, } background_thread_info_t *info = &background_thread_info[i]; malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); - if (info->started) { - pre_reentrancy(tsd); - int err = pthread_create_wrapper(&info->thread, NULL, - background_thread_entry, (void *)(uintptr_t)i); - post_reentrancy(tsd); - - if (err == 0) { - (*n_created)++; - created_threads[i] = true; - } else { - malloc_printf(": background thread " - "creation failed (%d)\n", err); - if (opt_abort) { - abort(); - } + + bool create = info->started; + malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); + if (!create) { + continue; + } + + /* + * To avoid deadlock with prefork handlers (which waits for the + * mutex held here), unlock before calling pthread_create(). + */ + malloc_mutex_unlock(tsd_tsdn(tsd), + &background_thread_info[0].mtx); + pre_reentrancy(tsd); + int err = pthread_create_wrapper(&info->thread, NULL, + background_thread_entry, (void *)(uintptr_t)i); + post_reentrancy(tsd); + malloc_mutex_lock(tsd_tsdn(tsd), + &background_thread_info[0].mtx); + + if (err == 0) { + (*n_created)++; + created_threads[i] = true; + } else { + malloc_printf(": background thread " + "creation failed (%d)\n", err); + if (opt_abort) { + abort(); } } - malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); + /* Since we unlocked and may miss signals, restart. */ + i = 1; } } @@ -643,14 +657,7 @@ label_done: void background_thread_prefork0(tsdn_t *tsdn) { malloc_mutex_prefork(tsdn, &background_thread_lock); - if (background_thread_enabled()) { - background_thread_enabled_at_fork = true; - background_thread_enabled_set(tsdn, false); - background_threads_disable(tsdn_tsd(tsdn)); - } else { - background_thread_enabled_at_fork = false; - } - assert(n_background_threads == 0); + background_thread_enabled_at_fork = background_thread_enabled(); } void @@ -660,22 +667,12 @@ background_thread_prefork1(tsdn_t *tsdn) { } } -static void -background_thread_postfork_init(tsdn_t *tsdn) { - assert(n_background_threads == 0); - if (background_thread_enabled_at_fork) { - background_thread_enabled_set(tsdn, true); - background_threads_enable(tsdn_tsd(tsdn)); - } -} - void background_thread_postfork_parent(tsdn_t *tsdn) { for (unsigned i = 0; i < ncpus; i++) { malloc_mutex_postfork_parent(tsdn, &background_thread_info[i].mtx); } - background_thread_postfork_init(tsdn); malloc_mutex_postfork_parent(tsdn, &background_thread_lock); } @@ -686,9 +683,23 @@ background_thread_postfork_child(tsdn_t *tsdn) { &background_thread_info[i].mtx); } malloc_mutex_postfork_child(tsdn, &background_thread_lock); + if (!background_thread_enabled_at_fork) { + return; + } + /* Clear background_thread state (reset to disabled for child). */ malloc_mutex_lock(tsdn, &background_thread_lock); - background_thread_postfork_init(tsdn); + n_background_threads = 0; + background_thread_enabled_set(tsdn, false); + for (unsigned i = 0; i < ncpus; i++) { + background_thread_info_t *info = &background_thread_info[i]; + malloc_mutex_lock(tsdn, &info->mtx); + info->started = false; + int ret = pthread_cond_init(&info->cond, NULL); + assert(ret == 0); + background_thread_info_init(tsdn, info); + malloc_mutex_unlock(tsdn, &info->mtx); + } malloc_mutex_unlock(tsdn, &background_thread_lock); } diff --git a/src/jemalloc.c b/src/jemalloc.c index e2865d25..52c86aa6 100644 --- a/src/jemalloc.c +++ b/src/jemalloc.c @@ -340,7 +340,6 @@ arena_new_create_background_thread(tsdn_t *tsdn, unsigned ind) { if (ind == 0) { return; } - /* background_thread_create() handles reentrancy internally. */ if (have_background_thread) { bool err; malloc_mutex_lock(tsdn, &background_thread_lock); -- GitLab From 394df9519d53e1d264d6d2f5375bb2fd70e0e5ed Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Fri, 9 Jun 2017 15:45:25 -0700 Subject: [PATCH 540/544] Combine background_thread started / paused into state. --- .../internal/background_thread_structs.h | 12 ++-- src/background_thread.c | 71 ++++++++++++------- src/ctl.c | 8 +-- test/unit/background_thread.c | 2 +- 4 files changed, 59 insertions(+), 34 deletions(-) diff --git a/include/jemalloc/internal/background_thread_structs.h b/include/jemalloc/internal/background_thread_structs.h index f6ad4adb..e69a7d02 100644 --- a/include/jemalloc/internal/background_thread_structs.h +++ b/include/jemalloc/internal/background_thread_structs.h @@ -9,6 +9,13 @@ #define BACKGROUND_THREAD_INDEFINITE_SLEEP UINT64_MAX +typedef enum { + background_thread_stopped, + background_thread_started, + /* Thread waits on the global lock when paused (for arena_reset). */ + background_thread_paused, +} background_thread_state_t; + struct background_thread_info_s { #ifdef JEMALLOC_BACKGROUND_THREAD /* Background thread is pthread specific. */ @@ -16,10 +23,7 @@ struct background_thread_info_s { pthread_cond_t cond; #endif malloc_mutex_t mtx; - /* Whether the thread has been created. */ - bool started; - /* Pause execution (for arena reset / destroy). */ - bool pause; + background_thread_state_t state; /* When true, it means no wakeup scheduled. */ atomic_b_t indefinite_sleep; /* Next scheduled wakeup time (absolute time in ns). */ diff --git a/src/background_thread.c b/src/background_thread.c index 09e08b0b..a7403b85 100644 --- a/src/background_thread.c +++ b/src/background_thread.c @@ -67,7 +67,6 @@ static bool background_thread_enabled_at_fork; static void background_thread_info_init(tsdn_t *tsdn, background_thread_info_t *info) { background_thread_wakeup_time_set(tsdn, info, 0); - info->pause = false; info->npages_to_purge_new = 0; if (config_stats) { info->tot_n_runs = 0; @@ -263,13 +262,20 @@ background_thread_sleep(tsdn_t *tsdn, background_thread_info_t *info, nstime_add(&info->tot_sleep_time, &after_sleep); } } - while (info->pause) { +} + +static bool +background_thread_pause_check(tsdn_t *tsdn, background_thread_info_t *info) { + if (unlikely(info->state == background_thread_paused)) { malloc_mutex_unlock(tsdn, &info->mtx); /* Wait on global lock to update status. */ malloc_mutex_lock(tsdn, &background_thread_lock); malloc_mutex_unlock(tsdn, &background_thread_lock); malloc_mutex_lock(tsdn, &info->mtx); + return true; } + + return false; } static inline void @@ -310,9 +316,10 @@ background_threads_disable_single(tsd_t *tsd, background_thread_info_t *info) { pre_reentrancy(tsd); malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); bool has_thread; - if (info->started) { + assert(info->state != background_thread_paused); + if (info->state == background_thread_started) { has_thread = true; - info->started = false; + info->state = background_thread_stopped; pthread_cond_signal(&info->cond); } else { has_thread = false; @@ -344,14 +351,17 @@ check_background_thread_creation(tsd_t *tsd, unsigned *n_created, return; } + malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_info[0].mtx); +label_restart: + malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock); for (unsigned i = 1; i < ncpus; i++) { if (created_threads[i]) { continue; } background_thread_info_t *info = &background_thread_info[i]; malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); - - bool create = info->started; + assert(info->state != background_thread_paused); + bool create = (info->state == background_thread_started); malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); if (!create) { continue; @@ -361,14 +371,12 @@ check_background_thread_creation(tsd_t *tsd, unsigned *n_created, * To avoid deadlock with prefork handlers (which waits for the * mutex held here), unlock before calling pthread_create(). */ - malloc_mutex_unlock(tsd_tsdn(tsd), - &background_thread_info[0].mtx); + malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock); + pre_reentrancy(tsd); int err = pthread_create_wrapper(&info->thread, NULL, background_thread_entry, (void *)(uintptr_t)i); post_reentrancy(tsd); - malloc_mutex_lock(tsd_tsdn(tsd), - &background_thread_info[0].mtx); if (err == 0) { (*n_created)++; @@ -380,9 +388,11 @@ check_background_thread_creation(tsd_t *tsd, unsigned *n_created, abort(); } } - /* Since we unlocked and may miss signals, restart. */ - i = 1; + /* Restart since we unlocked. */ + goto label_restart; } + malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_info[0].mtx); + malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock); } static void @@ -395,7 +405,11 @@ background_thread0_work(tsd_t *tsd) { } /* Start working, and create more threads when asked. */ unsigned n_created = 1; - while (background_thread_info[0].started) { + while (background_thread_info[0].state != background_thread_stopped) { + if (background_thread_pause_check(tsd_tsdn(tsd), + &background_thread_info[0])) { + continue; + } check_background_thread_creation(tsd, &n_created, (bool *)&created_threads); background_work_sleep_once(tsd_tsdn(tsd), @@ -409,16 +423,17 @@ background_thread0_work(tsd_t *tsd) { assert(!background_thread_enabled()); for (i = 1; i < ncpus; i++) { background_thread_info_t *info = &background_thread_info[i]; + assert(info->state != background_thread_paused); if (created_threads[i]) { background_threads_disable_single(tsd, info); } else { malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); /* Clear in case the thread wasn't created. */ - info->started = false; + info->state = background_thread_stopped; malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); } } - background_thread_info[0].started = false; + background_thread_info[0].state = background_thread_stopped; assert(n_background_threads == 1); } @@ -432,10 +447,15 @@ background_work(tsd_t *tsd, unsigned ind) { if (ind == 0) { background_thread0_work(tsd); } else { - while (info->started) { + while (info->state != background_thread_stopped) { + if (background_thread_pause_check(tsd_tsdn(tsd), + info)) { + continue; + } background_work_sleep_once(tsd_tsdn(tsd), info, ind); } } + assert(info->state == background_thread_stopped); background_thread_wakeup_time_set(tsd_tsdn(tsd), info, 0); malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); } @@ -463,7 +483,7 @@ background_thread_entry(void *ind_arg) { static void background_thread_init(tsd_t *tsd, background_thread_info_t *info) { malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock); - info->started = true; + info->state = background_thread_started; background_thread_info_init(tsd_tsdn(tsd), info); n_background_threads++; } @@ -480,7 +500,8 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) { bool need_new_thread; malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); - need_new_thread = background_thread_enabled() && !info->started; + need_new_thread = background_thread_enabled() && + (info->state == background_thread_stopped); if (need_new_thread) { background_thread_init(tsd, info); } @@ -492,7 +513,7 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) { /* Threads are created asynchronously by Thread 0. */ background_thread_info_t *t0 = &background_thread_info[0]; malloc_mutex_lock(tsd_tsdn(tsd), &t0->mtx); - assert(t0->started); + assert(t0->state == background_thread_started); pthread_cond_signal(&t0->cond); malloc_mutex_unlock(tsd_tsdn(tsd), &t0->mtx); @@ -512,7 +533,7 @@ background_thread_create(tsd_t *tsd, unsigned arena_ind) { malloc_printf(": arena 0 background thread creation " "failed (%d)\n", err); malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); - info->started = false; + info->state = background_thread_stopped; n_background_threads--; malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); @@ -543,7 +564,7 @@ background_threads_enable(tsd_t *tsd) { } background_thread_info_t *info = &background_thread_info[i]; malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); - assert(!info->started); + assert(info->state == background_thread_stopped); background_thread_init(tsd, info); malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); marked[i % ncpus] = true; @@ -586,7 +607,7 @@ background_thread_interval_check(tsdn_t *tsdn, arena_t *arena, return; } - if (!info->started) { + if (info->state != background_thread_started) { goto label_done; } if (malloc_mutex_trylock(tsdn, &decay->mtx)) { @@ -694,7 +715,7 @@ background_thread_postfork_child(tsdn_t *tsdn) { for (unsigned i = 0; i < ncpus; i++) { background_thread_info_t *info = &background_thread_info[i]; malloc_mutex_lock(tsdn, &info->mtx); - info->started = false; + info->state = background_thread_stopped; int ret = pthread_cond_init(&info->cond, NULL); assert(ret == 0); background_thread_info_init(tsdn, info); @@ -718,7 +739,7 @@ background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats) { for (unsigned i = 0; i < ncpus; i++) { background_thread_info_t *info = &background_thread_info[i]; malloc_mutex_lock(tsdn, &info->mtx); - if (info->started) { + if (info->state != background_thread_stopped) { num_runs += info->tot_n_runs; nstime_add(&stats->run_interval, &info->tot_sleep_time); } @@ -807,7 +828,7 @@ background_thread_boot1(tsdn_t *tsdn) { return true; } malloc_mutex_lock(tsdn, &info->mtx); - info->started = false; + info->state = background_thread_stopped; background_thread_info_init(tsdn, info); malloc_mutex_unlock(tsdn, &info->mtx); } diff --git a/src/ctl.c b/src/ctl.c index 242b36d4..b3ae4aab 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1948,9 +1948,9 @@ arena_reset_prepare_background_thread(tsd_t *tsd, unsigned arena_ind) { unsigned ind = arena_ind % ncpus; background_thread_info_t *info = &background_thread_info[ind]; - assert(info->started && !info->pause); + assert(info->state == background_thread_started); malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); - info->pause = true; + info->state = background_thread_paused; malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); } } @@ -1963,9 +1963,9 @@ arena_reset_finish_background_thread(tsd_t *tsd, unsigned arena_ind) { unsigned ind = arena_ind % ncpus; background_thread_info_t *info = &background_thread_info[ind]; - assert(info->started && info->pause); + assert(info->state = background_thread_paused); malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx); - info->pause = false; + info->state = background_thread_started; malloc_mutex_unlock(tsd_tsdn(tsd), &info->mtx); } malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock); diff --git a/test/unit/background_thread.c b/test/unit/background_thread.c index 81f8aeed..f7bd37c4 100644 --- a/test/unit/background_thread.c +++ b/test/unit/background_thread.c @@ -80,7 +80,7 @@ TEST_BEGIN(test_background_thread_running) { test_repeat_background_thread_ctl(false); test_switch_background_thread_ctl(true); - assert_b_eq(info->started, true, + assert_b_eq(info->state, background_thread_started, "Background_thread did not start.\n"); nstime_t start, now; -- GitLab From 813643c6a7be11f957b3a3412022435e328b6c0d Mon Sep 17 00:00:00 2001 From: Qi Wang Date: Sun, 11 Jun 2017 11:40:59 -0700 Subject: [PATCH 541/544] Prevent background threads from running in post_reset(). We lookup freed extents for testing in post_reset. Take background_thread lock so that the extents are not modified at the same time. --- test/unit/arena_reset.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/test/unit/arena_reset.c b/test/unit/arena_reset.c index 6409a922..f5fb24d1 100644 --- a/test/unit/arena_reset.c +++ b/test/unit/arena_reset.c @@ -134,17 +134,25 @@ do_arena_reset_pre(unsigned arena_ind, void ***ptrs, unsigned *nptrs) { } static void -do_arena_reset_post(void **ptrs, unsigned nptrs) { +do_arena_reset_post(void **ptrs, unsigned nptrs, unsigned arena_ind) { tsdn_t *tsdn; unsigned i; tsdn = tsdn_fetch(); + if (have_background_thread) { + malloc_mutex_lock(tsdn, + &background_thread_info[arena_ind % ncpus].mtx); + } /* Verify allocations no longer exist. */ for (i = 0; i < nptrs; i++) { assert_zu_eq(vsalloc(tsdn, ptrs[i]), 0, "Allocation should no longer exist"); } + if (have_background_thread) { + malloc_mutex_unlock(tsdn, + &background_thread_info[arena_ind % ncpus].mtx); + } free(ptrs); } @@ -180,7 +188,7 @@ TEST_BEGIN(test_arena_reset) { arena_ind = do_arena_create(NULL); do_arena_reset_pre(arena_ind, &ptrs, &nptrs); do_arena_reset(arena_ind); - do_arena_reset_post(ptrs, nptrs); + do_arena_reset_post(ptrs, nptrs, arena_ind); } TEST_END @@ -239,7 +247,7 @@ TEST_BEGIN(test_arena_destroy_hooks_default) { assert_true(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false), "Destroyed arena stats should be initialized"); - do_arena_reset_post(ptrs, nptrs); + do_arena_reset_post(ptrs, nptrs, arena_ind); arena_ind_prev = arena_ind; arena_ind = do_arena_create(NULL); @@ -247,7 +255,7 @@ TEST_BEGIN(test_arena_destroy_hooks_default) { assert_u_eq(arena_ind, arena_ind_prev, "Arena index should have been recycled"); do_arena_destroy(arena_ind); - do_arena_reset_post(ptrs, nptrs); + do_arena_reset_post(ptrs, nptrs, arena_ind); do_arena_destroy(arena_ind_another); } @@ -320,7 +328,7 @@ TEST_BEGIN(test_arena_destroy_hooks_unmap) { assert_true(arena_i_initialized(MALLCTL_ARENAS_DESTROYED, false), "Destroyed arena stats should be initialized"); - do_arena_reset_post(ptrs, nptrs); + do_arena_reset_post(ptrs, nptrs, arena_ind); memcpy(&hooks, &hooks_orig, sizeof(extent_hooks_t)); } -- GitLab From bff8db439c1b3222c83554d30c1e5f774eba7b48 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Mon, 5 Jun 2017 13:34:32 -0700 Subject: [PATCH 542/544] Update copyright dates. --- COPYING | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/COPYING b/COPYING index 104b1f8b..e308632a 100644 --- a/COPYING +++ b/COPYING @@ -1,10 +1,10 @@ Unless otherwise specified, files in the jemalloc source distribution are subject to the following license: -------------------------------------------------------------------------------- -Copyright (C) 2002-2016 Jason Evans . +Copyright (C) 2002-2017 Jason Evans . All rights reserved. Copyright (C) 2007-2012 Mozilla Foundation. All rights reserved. -Copyright (C) 2009-2016 Facebook, Inc. All rights reserved. +Copyright (C) 2009-2017 Facebook, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -- GitLab From aae8fd95fbde0af427719875810aee6cafeca539 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 9 Jun 2017 09:41:09 -0700 Subject: [PATCH 543/544] Update ChangeLog for 5.0.0. --- ChangeLog | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) diff --git a/ChangeLog b/ChangeLog index e630595b..98c12f20 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,193 @@ brevity. Much more detail can be found in the git revision history: https://github.com/jemalloc/jemalloc +* 5.0.0 (June 13, 2017) + + Unlike all previous jemalloc releases, this release does not use naturally + aligned "chunks" for virtual memory management, and instead uses page-aligned + "extents". This change has few externally visible effects, but the internal + impacts are... extensive. Many other internal changes combine to make this + the most cohesively designed version of jemalloc so far, with ample + opportunity for further enhancements. + + Continuous integration is now an integral aspect of development thanks to the + efforts of @davidtgoldblatt, and the dev branch tends to remain reasonably + stable on the tested platforms (Linux, FreeBSD, macOS, and Windows). As a + side effect the official release frequency may decrease over time. + + New features: + - Implement optional per-CPU arena support; threads choose which arena to use + based on current CPU rather than on fixed thread-->arena associations. + (@interwq) + - Implement two-phase decay of unused dirty pages. Pages transition from + dirty-->muzzy-->clean, where the first phase transition relies on + madvise(... MADV_FREE) semantics, and the second phase transition discards + pages such that they are replaced with demand-zeroed pages on next access. + (@jasone) + - Increase decay time resolution from seconds to milliseconds. (@jasone) + - Implement opt-in per CPU background threads, and use them for asynchronous + decay-driven unused dirty page purging. (@interwq) + - Add mutex profiling, which collects a variety of statistics useful for + diagnosing overhead/contention issues. (@interwq) + - Add C++ new/delete operator bindings. (@djwatson) + - Support manually created arena destruction, such that all data and metadata + are discarded. Add MALLCTL_ARENAS_DESTROYED for accessing merged stats + associated with destroyed arenas. (@jasone) + - Add MALLCTL_ARENAS_ALL as a fixed index for use in accessing + merged/destroyed arena statistics via mallctl. (@jasone) + - Add opt.abort_conf to optionally abort if invalid configuration options are + detected during initialization. (@interwq) + - Add opt.stats_print_opts, so that e.g. JSON output can be selected for the + stats dumped during exit if opt.stats_print is true. (@jasone) + - Add --with-version=VERSION for use when embedding jemalloc into another + project's git repository. (@jasone) + - Add --disable-thp to support cross compiling. (@jasone) + - Add --with-lg-hugepage to support cross compiling. (@jasone) + - Add mallctl interfaces (various authors): + + background_thread + + opt.abort_conf + + opt.retain + + opt.percpu_arena + + opt.background_thread + + opt.{dirty,muzzy}_decay_ms + + opt.stats_print_opts + + arena..initialized + + arena..destroy + + arena..{dirty,muzzy}_decay_ms + + arena..extent_hooks + + arenas.{dirty,muzzy}_decay_ms + + arenas.bin..slab_size + + arenas.nlextents + + arenas.lextent..size + + arenas.create + + stats.background_thread.{num_threads,num_runs,run_interval} + + stats.mutexes.{ctl,background_thread,prof,reset}. + {num_ops,num_spin_acq,num_wait,max_wait_time,total_wait_time,max_num_thds, + num_owner_switch} + + stats.arenas..{dirty,muzzy}_decay_ms + + stats.arenas..uptime + + stats.arenas..{pmuzzy,base,internal,resident} + + stats.arenas..{dirty,muzzy}_{npurge,nmadvise,purged} + + stats.arenas..bins..{nslabs,reslabs,curslabs} + + stats.arenas..bins..mutex. + {num_ops,num_spin_acq,num_wait,max_wait_time,total_wait_time,max_num_thds, + num_owner_switch} + + stats.arenas..lextents..{nmalloc,ndalloc,nrequests,curlextents} + + stats.arenas.i.mutexes.{large,extent_avail,extents_dirty,extents_muzzy, + extents_retained,decay_dirty,decay_muzzy,base,tcache_list}. + {num_ops,num_spin_acq,num_wait,max_wait_time,total_wait_time,max_num_thds, + num_owner_switch} + + Portability improvements: + - Improve reentrant allocation support, such that deadlock is less likely if + e.g. a system library call in turn allocates memory. (@davidtgoldblatt, + @interwq) + - Support static linking of jemalloc with glibc. (@djwatson) + + Optimizations and refactors: + - Organize virtual memory as "extents" of virtual memory pages, rather than as + naturally aligned "chunks", and store all metadata in arbitrarily distant + locations. This reduces virtual memory external fragmentation, and will + interact better with huge pages (not yet explicitly supported). (@jasone) + - Fold large and huge size classes together; only small and large size classes + remain. (@jasone) + - Unify the allocation paths, and merge most fast-path branching decisions. + (@davidtgoldblatt, @interwq) + - Embed per thread automatic tcache into thread-specific data, which reduces + conditional branches and dereferences. Also reorganize tcache to increase + fast-path data locality. (@interwq) + - Rewrite atomics to closely model the C11 API, convert various + synchronization from mutex-based to atomic, and use the explicit memory + ordering control to resolve various hypothetical races without increasing + synchronization overhead. (@davidtgoldblatt) + - Extensively optimize rtree via various methods: + + Add multiple layers of rtree lookup caching, since rtree lookups are now + part of fast-path deallocation. (@interwq) + + Determine rtree layout at compile time. (@jasone) + + Make the tree shallower for common configurations. (@jasone) + + Embed the root node in the top-level rtree data structure, thus avoiding + one level of indirection. (@jasone) + + Further specialize leaf elements as compared to internal node elements, + and directly embed extent metadata needed for fast-path deallocation. + (@jasone) + + Ignore leading always-zero address bits (architecture-specific). + (@jasone) + - Reorganize headers (ongoing work) to make them hermetic, and disentangle + various module dependencies. (@davidtgoldblatt) + - Convert various internal data structures such as size class metadata from + boot-time-initialized to compile-time-initialized. Propagate resulting data + structure simplifications, such as making arena metadata fixed-size. + (@jasone) + - Simplify size class lookups when constrained to size classes that are + multiples of the page size. This speeds lookups, but the primary benefit is + complexity reduction in code that was the source of numerous regressions. + (@jasone) + - Lock individual extents when possible for localized extent operations, + rather than relying on a top-level arena lock. (@davidtgoldblatt, @jasone) + - Use first fit layout policy instead of best fit, in order to improve + packing. (@jasone) + - If munmap(2) is not in use, use an exponential series to grow each arena's + virtual memory, so that the number of disjoint virtual memory mappings + remains low. (@jasone) + - Implement per arena base allocators, so that arenas never share any virtual + memory pages. (@jasone) + - Automatically generate private symbol name mangling macros. (@jasone) + + Incompatible changes: + - Replace chunk hooks with an expanded/normalized set of extent hooks. + (@jasone) + - Remove ratio-based purging. (@jasone) + - Remove --disable-tcache. (@jasone) + - Remove --disable-tls. (@jasone) + - Remove --enable-ivsalloc. (@jasone) + - Remove --with-lg-size-class-group. (@jasone) + - Remove --with-lg-tiny-min. (@jasone) + - Remove --disable-cc-silence. (@jasone) + - Remove --enable-code-coverage. (@jasone) + - Remove --disable-munmap (replaced by opt.retain). (@jasone) + - Remove Valgrind support. (@jasone) + - Remove quarantine support. (@jasone) + - Remove redzone support. (@jasone) + - Remove mallctl interfaces (various authors): + + config.munmap + + config.tcache + + config.tls + + config.valgrind + + opt.lg_chunk + + opt.purge + + opt.lg_dirty_mult + + opt.decay_time + + opt.quarantine + + opt.redzone + + opt.thp + + arena..lg_dirty_mult + + arena..decay_time + + arena..chunk_hooks + + arenas.initialized + + arenas.lg_dirty_mult + + arenas.decay_time + + arenas.bin..run_size + + arenas.nlruns + + arenas.lrun..size + + arenas.nhchunks + + arenas.hchunk..size + + arenas.extend + + stats.cactive + + stats.arenas..lg_dirty_mult + + stats.arenas..decay_time + + stats.arenas..metadata.{mapped,allocated} + + stats.arenas..{npurge,nmadvise,purged} + + stats.arenas..huge.{allocated,nmalloc,ndalloc,nrequests} + + stats.arenas..bins..{nruns,reruns,curruns} + + stats.arenas..lruns..{nmalloc,ndalloc,nrequests,curruns} + + stats.arenas..hchunks..{nmalloc,ndalloc,nrequests,curhchunks} + + Bug fixes: + - Improve interval-based profile dump triggering to dump only one profile when + a single allocation's size exceeds the interval. (@jasone) + - Use prefixed function names (as controlled by --with-jemalloc-prefix) when + pruning backtrace frames in jeprof. (@jasone) + * 4.5.0 (February 28, 2017) This is the first release to benefit from much broader continuous integration -- GitLab From ba29113e5a58caeb6b4a65b1db6d8efae79cae45 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Tue, 13 Jun 2017 11:01:24 -0700 Subject: [PATCH 544/544] Update MSVC project files. --- .../projects/vc2015/jemalloc/jemalloc.vcxproj | 11 ++++++---- .../vc2015/jemalloc/jemalloc.vcxproj.filters | 21 +++++++++++++------ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj index 832ff69d..2addd295 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj @@ -36,6 +36,7 @@ + @@ -49,6 +50,7 @@ + @@ -56,6 +58,7 @@ + @@ -227,7 +230,7 @@ Level3 Disabled - _REENTRANT;_WINDLL;DLLEXPORT;JEMALLOC_DEBUG;_DEBUG;%(PreprocessorDefinitions) + JEMALLOC_NO_PRIVATE_NAMESPACE;_REENTRANT;_WINDLL;DLLEXPORT;JEMALLOC_DEBUG;_DEBUG;%(PreprocessorDefinitions) ..\..\..\..\include;..\..\..\..\include\msvc_compat;%(AdditionalIncludeDirectories) 4090;4146;4267;4334 $(OutputPath)$(TargetName).pdb @@ -243,7 +246,7 @@ Level3 Disabled - JEMALLOC_DEBUG;_REENTRANT;JEMALLOC_EXPORT=;_DEBUG;_LIB;%(PreprocessorDefinitions) + JEMALLOC_NO_PRIVATE_NAMESPACE;JEMALLOC_DEBUG;_REENTRANT;JEMALLOC_EXPORT=;_DEBUG;_LIB;%(PreprocessorDefinitions) ..\..\..\..\include;..\..\..\..\include\msvc_compat;%(AdditionalIncludeDirectories) MultiThreadedDebug 4090;4146;4267;4334 @@ -305,7 +308,7 @@ true true ..\..\..\..\include;..\..\..\..\include\msvc_compat;%(AdditionalIncludeDirectories) - _REENTRANT;_WINDLL;DLLEXPORT;NDEBUG;%(PreprocessorDefinitions) + JEMALLOC_NO_PRIVATE_NAMESPACE;_REENTRANT;_WINDLL;DLLEXPORT;NDEBUG;%(PreprocessorDefinitions) 4090;4146;4267;4334 $(OutputPath)$(TargetName).pdb @@ -324,7 +327,7 @@ MaxSpeed true true - _REENTRANT;JEMALLOC_EXPORT=;NDEBUG;_LIB;%(PreprocessorDefinitions) + JEMALLOC_NO_PRIVATE_NAMESPACE;_REENTRANT;JEMALLOC_EXPORT=;NDEBUG;_LIB;%(PreprocessorDefinitions) ..\..\..\..\include;..\..\..\..\include\msvc_compat;%(AdditionalIncludeDirectories) MultiThreaded 4090;4146;4267;4334 diff --git a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters index 9d4a7c7d..4edf09b4 100644 --- a/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters +++ b/msvc/projects/vc2015/jemalloc/jemalloc.vcxproj.filters @@ -10,6 +10,9 @@ Source Files + + Source Files + Source Files @@ -34,15 +37,24 @@ Source Files + + Source Files + Source Files Source Files + + Source Files + Source Files + + Source Files + Source Files @@ -64,6 +76,9 @@ Source Files + + Source Files + Source Files @@ -76,11 +91,5 @@ Source Files - - Source Files - - - Source Files - \ No newline at end of file -- GitLab